All of lore.kernel.org
 help / color / mirror / Atom feed
From: Steven Rostedt <rostedt@goodmis.org>
To: linux-trace-devel@vger.kernel.org
Cc: "Steven Rostedt (Google)" <rostedt@goodmis.org>
Subject: [PATCH v2 17/22] libtracefs: Add API to extract ring buffer statistics
Date: Thu, 28 Dec 2023 16:52:12 -0500	[thread overview]
Message-ID: <20231228215433.54854-18-rostedt@goodmis.org> (raw)
In-Reply-To: <20231228215433.54854-1-rostedt@goodmis.org>

From: "Steven Rostedt (Google)" <rostedt@goodmis.org>

Add the API that reads the tracefs/per_cpu/cpu*/stats

  tracefs_instance_get_stat()
  tracefs_instance_put_stat()
  tracefs_buffer_stat_entries()
  tracefs_buffer_stat_overrun()
  tracefs_buffer_stat_commit_overrun()
  tracefs_buffer_stat_bytes()
  tracefs_buffer_stat_event_timestamp()
  tracefs_buffer_stat_timestamp()
  tracefs_buffer_stat_dropped_events()
  tracefs_buffer_stat_read_events()

Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
 Documentation/libtracefs-instances-stat.txt | 183 ++++++++++++++++++++
 Documentation/libtracefs.txt                |  12 ++
 include/tracefs-local.h                     |  11 ++
 include/tracefs.h                           |  13 ++
 samples/Makefile                            |   1 +
 src/Makefile                                |   1 +
 src/tracefs-stats.c                         | 162 +++++++++++++++++
 7 files changed, 383 insertions(+)
 create mode 100644 Documentation/libtracefs-instances-stat.txt
 create mode 100644 src/tracefs-stats.c

diff --git a/Documentation/libtracefs-instances-stat.txt b/Documentation/libtracefs-instances-stat.txt
new file mode 100644
index 000000000000..d3bb3c93d9d1
--- /dev/null
+++ b/Documentation/libtracefs-instances-stat.txt
@@ -0,0 +1,183 @@
+libtracefs(3)
+=============
+
+NAME
+----
+tracefs_instance_get_stat, tracefs_instance_put_stat, tracefs_buffer_stat_entries, tracefs_buffer_stat_overrun,
+tracefs_buffer_stat_commit_overrun, tracefs_buffer_stat_bytes, tracefs_buffer_stat_event_timestamp,
+tracefs_buffer_stat_timestamp, tracefs_buffer_stat_dropped_events, tracefs_buffer_stat_read_events
+- Handling tracing buffer stats
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <tracefs.h>*
+
+struct tracefs_buffer_stat pass:[*]*tracefs_instance_get_stat*(struct tracefs_instance pass:[*]_instance_, int _cpu_);
+void *tracefs_instance_put_stat*(struct tracefs_buffer_stat pass:[*]_tstat_);
+ssize_t *tracefs_buffer_stat_entries*(struct tracefs_buffer_stat pass:[*]_tstat_);
+ssize_t *tracefs_buffer_stat_overrun*(struct tracefs_buffer_stat pass:[*]_tstat_);
+ssize_t *tracefs_buffer_stat_commit_overrun*(struct tracefs_buffer_stat pass:[*]_tstat_);
+ssize_t *tracefs_buffer_stat_bytes*(struct tracefs_buffer_stat pass:[*]_tstat_);
+long long *tracefs_buffer_stat_event_timestamp*(struct tracefs_buffer_stat pass:[*]_tstat_);
+long long *tracefs_buffer_stat_timestamp*(struct tracefs_buffer_stat pass:[*]_tstat_);
+ssize_t *tracefs_buffer_stat_dropped_events*(struct tracefs_buffer_stat pass:[*]_tstat_);
+ssize_t *tracefs_buffer_stat_read_events*(struct tracefs_buffer_stat pass:[*]_tstat_);
+--
+
+DESCRIPTION
+-----------
+This set of functions read and parse the tracefs/per_cpu/cpuX/stats file.
+These files hold the statistics of the per CPU ring buffer, such as how
+many events are in the ring buffer, how many have been read and so on.
+
+The *tracefs_instance_get_stat()* function will read and parse a given statistics
+file for a given _instance_ and _cpu_. As the ring buffer is split into per_cpu buffers,
+the information is only associated to the given _cpu_. The returned tracefs_buffer_stat
+pointer can be used with the other *tracefs_buffer_stat* functions and must be freed with
+*tracefs_instance_put_stat()*.
+
+The *tracefs_instance_put_stat()* will free the resources allocated for the given _stat_
+that was created by *tracefs_instance_get_stat()*.
+
+The *tracefs_buffer_stat_entries()* returns the number of events that are currently
+in the ring buffer associated with _tstat_.
+
+The *tracefs_buffer_stat_overrun()* returns the number of events that were lost by
+the ring buffer writer overrunning the reader.
+
+The *tracefs_buffer_stat_commit_overrun()* returns the number of events that were
+lost because the ring buffer was too small and an interrupt interrupted a lower
+context event being recorded and it added more events than the ring buffer could
+hold. Note this is not a common occurrence and when it happens it means that
+something was not set up properly.
+
+The *tracefs_buffer_stat_bytes()* returns the number of bytes that the current events
+take up. Note, it includes the meta data for the events, but does not include the
+meta data for the sub-buffers.
+
+The *tracefs_buffer_stat_event_timestamp()* returns the timestamp of the last event in the
+ring buffer.
+
+The *tracefs_buffer_stat_timestamp()* returns the current timestamp of the ring buffer.
+Note, it is only read when *tracefs_instance_get_stat()* is called. It will have the
+timestamp of the ring buffer when that function was called.
+
+The *tracefs_buffer_stat_dropped_events()* returns the number of events that were
+dropped if overwrite mode is disabled. It will show the events that were lost because
+the writer caught up to the reader and could not write any more events.
+
+The *tracefs_buffer_stat_read_events()* returns the number of events that were consumed
+by a reader.
+
+
+RETURN VALUE
+------------
+The *tracefs_instance_get_stat()* returns a tracefs_buffer_stat structure that can
+be used to retrieve the statistics via the other functions. It must be freed with
+*tracefs_instance_put_stat()*.
+
+The other functions that return different values from the tracefs_buffer_stat structure
+all return the value, or -1 if the value was not found.
+
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdlib.h>
+#include <unistd.h>
+#include <tracefs.h>
+
+int main(int argc, char **argv)
+{
+	char *trace;
+	char buf[1000];
+	int ret;
+	int i;
+
+	for (i = 0; i < sizeof(buf) - 1; i++) {
+		buf[i] = '0' + i % 10;
+	}
+	buf[i] = '\0';
+
+	tracefs_instance_clear(NULL);
+
+	for (i = 0; i < 4; i++) {
+		ret = tracefs_printf(NULL, "%s\n", buf);
+		if (ret < 0)
+			perror("write");
+	}
+
+	trace = tracefs_instance_file_read(NULL, "trace", NULL);
+	printf("%s\n", trace);
+	free(trace);
+
+	for (i = 0; i < sysconf(_SC_NPROCESSORS_CONF); i++) {
+		struct tracefs_buffer_stat *tstat;
+		ssize_t entries, eread;
+
+		tstat = tracefs_instance_get_stat(NULL, i);
+		if (!tstat)
+			continue;
+
+		entries = tracefs_buffer_stat_entries(tstat);
+		eread = tracefs_buffer_stat_read_events(tstat);
+		if (!entries && !eread) {
+			tracefs_instance_put_stat(tstat);
+			continue;
+		}
+
+		printf("CPU: %d\n", i);;
+		printf("\tentries: %zd\n", entries);
+		printf("\toverrun: %zd\n", tracefs_buffer_stat_overrun(tstat));
+		printf("\tcommit_overrun: %zd\n", tracefs_buffer_stat_commit_overrun(tstat));
+		printf("\tbytes: %zd\n", tracefs_buffer_stat_bytes(tstat));
+		printf("\tevent_timestamp: %lld\n", tracefs_buffer_stat_event_timestamp(tstat));
+		printf("\ttimestamp: %lld\n", tracefs_buffer_stat_timestamp(tstat));
+		printf("\tdropped_events: %zd\n", tracefs_buffer_stat_dropped_events(tstat));
+		printf("\tread_events: %zd\n", eread);
+
+		tracefs_instance_put_stat(tstat);
+	}
+}
+--
+FILES
+-----
+[verse]
+--
+*tracefs.h*
+	Header file to include in order to have access to the library APIs.
+*-ltracefs*
+	Linker switch to add when building a program that uses the library.
+--
+
+SEE ALSO
+--------
+*libtracefs*(3),
+*libtraceevent*(3),
+*trace-cmd*(1)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>
+--
+REPORTING BUGS
+--------------
+Report bugs to  <linux-trace-devel@vger.kernel.org>
+
+LICENSE
+-------
+libtracefs is Free Software licensed under the GNU LGPL 2.1
+
+RESOURCES
+---------
+https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/
+
+COPYING
+-------
+Copyright \(C) 2020 VMware, Inc. Free use of this software is granted under
+the terms of the GNU Public License (GPL).
diff --git a/Documentation/libtracefs.txt b/Documentation/libtracefs.txt
index 70bd8116b2b1..6752ed3c9b98 100644
--- a/Documentation/libtracefs.txt
+++ b/Documentation/libtracefs.txt
@@ -155,6 +155,18 @@ Writing data in the trace buffer:
 Control library logs:
 	int *tracefs_set_loglevel*(enum tep_loglevel _level_);
 
+Read the ring buffer statistics:
+	struct tracefs_buffer_stat pass:[*]*tracefs_instance_get_stat*(struct tracefs_instance pass:[*]_instance_, int _cpu_);
+	void *tracefs_instance_put_stat*(struct tracefs_buffer_stat pass:[*]_tstat_);
+	ssize_t *tracefs_buffer_stat_entries*(struct tracefs_buffer_stat pass:[*]_tstat_);
+	ssize_t *tracefs_buffer_stat_overrun*(struct tracefs_buffer_stat pass:[*]_tstat_);
+	ssize_t *tracefs_buffer_stat_commit_overrun*(struct tracefs_buffer_stat pass:[*]_tstat_);
+	ssize_t *tracefs_buffer_stat_bytes*(struct tracefs_buffer_stat pass:[*]_tstat_);
+	long long *tracefs_buffer_stat_event_timestamp*(struct tracefs_buffer_stat pass:[*]_tstat_);
+	long long *tracefs_buffer_stat_timestamp*(struct tracefs_buffer_stat pass:[*]_tstat_);
+	ssize_t *tracefs_buffer_stat_dropped_events*(struct tracefs_buffer_stat pass:[*]_tstat_);
+	ssize_t *tracefs_buffer_stat_read_events*(struct tracefs_buffer_stat pass:[*]_tstat_);
+
 Dynamic event generic APIs:
 	struct *tracefs_dynevent*;
 	enum *tracefs_dynevent_type*;
diff --git a/include/tracefs-local.h b/include/tracefs-local.h
index 9e5a568468b4..9cae73c8b806 100644
--- a/include/tracefs-local.h
+++ b/include/tracefs-local.h
@@ -51,6 +51,17 @@ struct tracefs_instance {
 	bool				iterate_keep_going;
 };
 
+struct tracefs_buffer_stat {
+	ssize_t				entries;
+	ssize_t				overrun;
+	ssize_t				commit_overrun;
+	ssize_t				bytes;
+	long long			oldest_ts;
+	long long			now_ts;
+	ssize_t				dropped_events;
+	ssize_t				read_events;
+};
+
 extern const struct tep_format_field common_stacktrace;
 
 extern pthread_mutex_t toplevel_lock;
diff --git a/include/tracefs.h b/include/tracefs.h
index 95bff1f244f9..3ae78d4f3af7 100644
--- a/include/tracefs.h
+++ b/include/tracefs.h
@@ -68,6 +68,19 @@ char **tracefs_instances(const char *regex);
 int tracefs_instance_get_buffer_percent(struct tracefs_instance *instance);
 int tracefs_instance_set_buffer_percent(struct tracefs_instance *instance, int val);
 
+struct tracefs_buffer_stat;
+
+struct tracefs_buffer_stat *tracefs_instance_get_stat(struct tracefs_instance *instance, int cpu);
+void tracefs_instance_put_stat(struct tracefs_buffer_stat *tstat);
+ssize_t tracefs_buffer_stat_entries(struct tracefs_buffer_stat *tstat);
+ssize_t tracefs_buffer_stat_overrun(struct tracefs_buffer_stat *tstat);
+ssize_t tracefs_buffer_stat_commit_overrun(struct tracefs_buffer_stat *tstat);
+ssize_t tracefs_buffer_stat_bytes(struct tracefs_buffer_stat *tstat);
+long long tracefs_buffer_stat_event_timestamp(struct tracefs_buffer_stat *tstat);
+long long tracefs_buffer_stat_timestamp(struct tracefs_buffer_stat *tstat);
+ssize_t tracefs_buffer_stat_dropped_events(struct tracefs_buffer_stat *tstat);
+ssize_t tracefs_buffer_stat_read_events(struct tracefs_buffer_stat *tstat);
+
 bool tracefs_instance_exists(const char *name);
 bool tracefs_file_exists(struct tracefs_instance *instance, const char *name);
 bool tracefs_dir_exists(struct tracefs_instance *instance, const char *name);
diff --git a/samples/Makefile b/samples/Makefile
index 13ad99579ea3..787d28769051 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -24,6 +24,7 @@ EXAMPLES += instances-affinity
 EXAMPLES += cpu
 EXAMPLES += guest
 EXAMPLES += cpu-buf
+EXAMPLES += instances-stat
 
 TARGETS :=
 TARGETS += sqlhist
diff --git a/src/Makefile b/src/Makefile
index 90bd88df44c2..faa3b25c4002 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -10,6 +10,7 @@ OBJS += tracefs-tools.o
 OBJS += tracefs-marker.o
 OBJS += tracefs-kprobes.o
 OBJS += tracefs-hist.o
+OBJS += tracefs-stats.o
 OBJS += tracefs-filter.o
 OBJS += tracefs-dynevents.o
 OBJS += tracefs-eprobes.o
diff --git a/src/tracefs-stats.c b/src/tracefs-stats.c
new file mode 100644
index 000000000000..d43235bc0b38
--- /dev/null
+++ b/src/tracefs-stats.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: LGPL-2.1
+/*
+ * Copyright (C) 2023 Google LLC, Steven Rostedt <rostedt@goodmis.org>
+ */
+#include <stdlib.h>
+#include <ctype.h>
+#include "tracefs.h"
+#include "tracefs-local.h"
+
+static long long convert_ts(char *value)
+{
+	long long ts;
+	char *saveptr;
+	char *secs;
+	char *usecs;
+
+	secs = strtok_r(value, ".", &saveptr);
+	if (!secs)
+		return -1LL;
+
+	ts = strtoll(secs, NULL, 0);
+
+	usecs = strtok_r(NULL, ".", &saveptr);
+	if (!usecs)
+		return ts;
+
+	/* Could be in nanoseconds */
+	if (strlen(usecs) > 6)
+		ts *= 1000000000LL;
+	else
+		ts *= 1000000LL;
+
+	ts += strtoull(usecs, NULL, 0);
+
+	return ts;
+}
+
+struct tracefs_buffer_stat *
+tracefs_instance_get_stat(struct tracefs_instance *instance, int cpu)
+{
+	struct tracefs_buffer_stat *tstat;
+	char *saveptr;
+	char *value;
+	char *field;
+	char *path;
+	char *line;
+	char *next;
+	char *buf;
+	int len;
+	int ret;
+
+	ret = asprintf(&path, "per_cpu/cpu%d/stats", cpu);
+	if (ret < 0)
+		return NULL;
+
+	buf = tracefs_instance_file_read(instance, path, &len);
+	free(path);
+
+	if (!buf)
+		return NULL;
+
+	tstat = malloc(sizeof(*tstat));
+	if (!tstat) {
+		free(buf);
+		return NULL;
+	}
+
+	/* Set everything to -1 */
+	memset(tstat, -1, sizeof(*tstat));
+
+	next = buf;
+	while ((line = strtok_r(next, "\n", &saveptr))) {
+		char *save2;
+
+		next = NULL;
+
+		field = strtok_r(line, ":", &save2);
+		if (!field)
+			break;
+
+		value = strtok_r(NULL, ":", &save2);
+		if (!value)
+			break;
+
+		while (isspace(*value))
+			value++;
+
+		if (strcmp(field, "entries") == 0) {
+			tstat->entries = strtoull(value, NULL, 0);
+
+		} else if (strcmp(field, "overrun") == 0) {
+			tstat->overrun = strtoull(value, NULL, 0);
+
+		} else if (strcmp(field, "commit overrun") == 0) {
+			tstat->commit_overrun = strtoull(value, NULL, 0);
+
+		} else if (strcmp(field, "bytes") == 0) {
+			tstat->bytes = strtoull(value, NULL, 0);
+
+		} else if (strcmp(field, "oldest event ts") == 0) {
+			tstat->oldest_ts = convert_ts(value);
+
+		} else if (strcmp(field, "now ts") == 0) {
+			tstat->now_ts = convert_ts(value);
+
+		} else if (strcmp(field, "dropped events") == 0) {
+			tstat->dropped_events = strtoull(value, NULL, 0);
+
+		} else if (strcmp(field, "read events") == 0) {
+			tstat->read_events = strtoull(value, NULL, 0);
+		}
+	}
+	free(buf);
+
+	return tstat;
+}
+
+void tracefs_instance_put_stat(struct tracefs_buffer_stat *tstat)
+{
+	free(tstat);
+}
+
+ssize_t tracefs_buffer_stat_entries(struct tracefs_buffer_stat *tstat)
+{
+	return tstat->entries;
+}
+
+ssize_t tracefs_buffer_stat_overrun(struct tracefs_buffer_stat *tstat)
+{
+	return tstat->overrun;
+}
+
+ssize_t tracefs_buffer_stat_commit_overrun(struct tracefs_buffer_stat *tstat)
+{
+	return tstat->commit_overrun;
+}
+
+ssize_t tracefs_buffer_stat_bytes(struct tracefs_buffer_stat *tstat)
+{
+	return tstat->bytes;
+}
+
+long long tracefs_buffer_stat_event_timestamp(struct tracefs_buffer_stat *tstat)
+{
+	return tstat->oldest_ts;
+}
+
+long long tracefs_buffer_stat_timestamp(struct tracefs_buffer_stat *tstat)
+{
+	return tstat->now_ts;
+}
+
+ssize_t tracefs_buffer_stat_dropped_events(struct tracefs_buffer_stat *tstat)
+{
+	return tstat->dropped_events;
+}
+
+ssize_t tracefs_buffer_stat_read_events(struct tracefs_buffer_stat *tstat)
+{
+	return tstat->read_events;
+}
+
-- 
2.42.0


  parent reply	other threads:[~2023-12-28 21:53 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-12-28 21:51 [PATCH v2 00/22] libtracefs: Several updates Steven Rostedt
2023-12-28 21:51 ` [PATCH v2 01/22] libtracefs Documentation: Fix tracefs_event_file_exists() issues Steven Rostedt
2023-12-28 21:51 ` [PATCH v2 02/22] libtracefs testing: Use one tep handle for most tests Steven Rostedt
2023-12-28 21:51 ` [PATCH v2 03/22] libtracefs: Free "missed_followers" of instance Steven Rostedt
2023-12-28 21:51 ` [PATCH v2 04/22] libtracefs: Free buf in clear_func_filter() Steven Rostedt
2023-12-28 21:52 ` [PATCH v2 05/22] libtracefs: Free tracing_dir in case of remount Steven Rostedt
2023-12-28 21:52 ` [PATCH v2 06/22] libtracefs: Free dynamic event list in utest Steven Rostedt
2023-12-28 21:52 ` [PATCH v2 07/22] libtracefs: Reset tracing before and after unit tests Steven Rostedt
2023-12-28 21:52 ` [PATCH v2 08/22] libtracefs: Add API to remove followers from an instance or toplevel Steven Rostedt
2023-12-28 21:52 ` [PATCH v2 09/22] libtracefs: Increase splice to use pipe max size Steven Rostedt
2023-12-28 21:52 ` [PATCH v2 10/22] libtracefs: Add tracefs_instance_file_write_number() Steven Rostedt
2023-12-28 21:52 ` [PATCH v2 11/22] libtracefs: Add API to read tracefs_cpu and return a kbuffer Steven Rostedt
2023-12-28 21:52 ` [PATCH v2 12/22] libtracefs: Add tracefs_instance_get/set_buffer_percent() Steven Rostedt
2023-12-28 21:52 ` [PATCH v2 13/22] libtracefs: Add tracefs_instance_clear() API Steven Rostedt
2023-12-28 21:52 ` [PATCH v2 14/22] libtracefs utest: Add test to test tracefs_instance_set/get_buffer_percent() Steven Rostedt
2023-12-28 21:52 ` [PATCH v2 15/22] libtracefs: Add kerneldoc comments to tracefs_instance_set_buffer_size() Steven Rostedt
2023-12-28 21:52 ` [PATCH v2 16/22] libtracefs: Add tracefs_load_headers() API Steven Rostedt
2023-12-28 21:52 ` Steven Rostedt [this message]
2023-12-28 21:52 ` [PATCH v2 18/22] libtracefs: Add tracefs_instance_set/get_subbuf_size() Steven Rostedt
2023-12-28 21:52 ` [PATCH v2 19/22] libtracefs: Add TIMESTAMP_USECS_DELTA to simplify SQL timestamp compares Steven Rostedt
2023-12-28 21:52 ` [PATCH v2 20/22] libtracefs: Also clear max_graph_depth on reset Steven Rostedt
2023-12-28 21:52 ` [PATCH v2 21/22] libtracefs: Add PID filtering API Steven Rostedt
2023-12-28 21:52 ` [PATCH v2 22/22] libtracefs: Add updating and reading snapshot buffers Steven Rostedt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231228215433.54854-18-rostedt@goodmis.org \
    --to=rostedt@goodmis.org \
    --cc=linux-trace-devel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.