All of lore.kernel.org
 help / color / mirror / Atom feed
From: Steven Rostedt <rostedt@goodmis.org>
To: linux-trace-devel@vger.kernel.org
Cc: Ross Zwisler <zwisler@google.com>,
	"Steven Rostedt (Google)" <rostedt@goodmis.org>
Subject: [PATCH v2 2/5] libtraceeval: Add man pages for creating and releasing the traceeval descriptor
Date: Fri,  6 Oct 2023 15:55:33 -0400	[thread overview]
Message-ID: <20231006195536.1384287-3-rostedt@goodmis.org> (raw)
In-Reply-To: <20231006195536.1384287-1-rostedt@goodmis.org>

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

Add man pages for:

 traceeval_init()
 traceeval_init_size()
 traceeval_release()

Link: https://lore.kernel.org/linux-trace-devel/20231005232450.1311519-3-rostedt@goodmis.org

Cc: Ross Zwisler <zwisler@google.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
 Documentation/Makefile              |   4 +-
 Documentation/libtraceeval-init.txt | 395 ++++++++++++++++++++++++++++
 Documentation/libtraceeval.txt      |   5 +
 3 files changed, 403 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/libtraceeval-init.txt

diff --git a/Documentation/Makefile b/Documentation/Makefile
index 3540440e1dae..d6c0c05fcc99 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -7,9 +7,11 @@ include $(src)/scripts/utils.mk
 # and modified for libtraceeval
 
 MAN3_TXT= \
+	$(wildcard libtraceeval-*.txt) \
 	libtraceeval.txt
 
-MAN1_TEXT=
+MAN1_TEXT= \
+	$(wildcard libtraceeval-*.txt.1)
 
 MAN_TXT = $(MAN3_TXT)
 _MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT))
diff --git a/Documentation/libtraceeval-init.txt b/Documentation/libtraceeval-init.txt
new file mode 100644
index 000000000000..ed505d11713c
--- /dev/null
+++ b/Documentation/libtraceeval-init.txt
@@ -0,0 +1,395 @@
+libtraceeval(3)
+===============
+
+NAME
+----
+traceeval_init, traceeval_init_size, traceeval_release - Create a trace evaluation helper mechanism.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <traceeval.h>*
+
+struct traceeval pass:[*]*traceeval_init*(struct traceeval_type pass:[*]_keys_, struct traceeval_type pass:[*]_vals_);
+struct traceeval pass:[*]*traceeval_init_size*(struct traceeval_type pass:[*]_keys_, struct traceeval_type pass:[*]_vals_,
+				       int _nr_keys_, int _nr_vals_);
+void *traceeval_release*(struct traceeval pass:[*]_teval_);
+--
+
+DESCRIPTION
+-----------
+The traceeval utility is to help simplify analysis of tracing data by doing
+most of the tedious work that is usually done. For example, if one had a trace
+of the all the times all tasks were woken up and then later the time for those
+tasks when they were  scheduled on the CPU, the traceeval tooling would allow
+the program to record the time of the wake up at the wake up event, then on the
+scheduling event the tool could query for the last event that hold where the
+given task woke up, take the delta from the current timestamp, subtract it from
+the wake up timestamp, and then record the delta (wake up latency) into anther
+traceeval instance. At the end of the program, the traceeval instance can be
+iterated over and report the maximum and minimum deltas (with the timestamps
+where they occurred), along with the total of all deltas and the number of
+times it work up.
+
+The *traceeval_init()* function will take a static array of _keys_ to use as
+how to query for the elements in the traceeval. It also takes an option static
+array of _vals_ that are associated to each of the elements in the traceveal.
+The _keys_ are mandatory as they are used to find and differentiate the
+elements in the traceeval.
+
+Both the _keys_ and the _vals_ are defined by the *struct traceeval_data*
+structure.
+
+[verse]
+--
+struct traceeval_type {
+	char				pass:[*]name;
+	enum traceeval_data_type	type;
+	size_t				flags;
+	size_t				index;
+	size_t				id;
+	traceeval_data_release_fn	release;
+	traceeval_data_cmp_fn		cmp;
+	traceeval_data_copy_fn		copy;
+	traceeval_data_hash_fn		hash;
+};
+--
+
+The _name_ is the name of the field. For example it could be "PID" or "Timestamp".
+
+The _type_ is an enum that defines what the content of this field will be. See *TYPE ENUMS* below.
+
+The _flags_ defines characteristics of the field. See *FLAGS* below.
+
+The _index_ is the index into the array passed to *traceeval_init()*. The user does not need
+to updated this. This will be updated by *traceeval_init()*, so the array passed in must not be
+a constant. The index is updated so that the type can be used by other functions where a lookup
+into the internal array can be quicker than searching for matching _name_s.
+
+The _id_ is free for the application to define.
+
+The next fields are function pointers:
+
+The _release_() function is called when the data is being replaced or removed from the trace_eval.
+This will be called by any type, but it comes in handy with the _POINTER_ type, if the pointer
+needs to clean up anything allocated before being inserted.
+
+The _cmp_() function pointer is required for the _POINTER_ type, but also may be used
+to override any of the other types. It is used for sorting of the data in the traceeval for
+iterating over the elements.
+
+The _copy_() function pointer is required for the _POINTER_ type, but also may be used
+to override any of the other types. This is used to copy a field when updating an existing
+element.
+
+The _hash_() function pointer is required for the _POINTER_ key type, but may also be used
+to override the default of other types. The _hash_() function is used to hash the field
+of the element for look ups.
+
+*TYPE ENUMS*:
+
+[verse]
+--
+enum traceeval_data_type {
+	TRACEEVAL_TYPE_NONE,
+	TRACEEVAL_TYPE_NUMBER_8,
+	TRACEEVAL_TYPE_NUMBER_16,
+	TRACEEVAL_TYPE_NUMBER_32,
+	TRACEEVAL_TYPE_NUMBER_64,
+	TRACEEVAL_TYPE_NUMBER,
+	TRACEEVAL_TYPE_POINTER,
+	TRACEEVAL_TYPE_STRING,
+};
+--
+
+Where _NONE_ is just a place holder.
+
+_NUMBER_8_ means the type is just 8 bits in size (for example, *char*).
+
+_NUMBER_16_ means the type is 16 bits in size (*short*).
+
+_NUMBER_32_ means the type is 32 bits in size (*int*)
+
+_NUMBER_64_ means the type is 64 bits in size (*unsigned long long*).
+
+_NUMBER_ means the type is of the natural word length (*size_t*).
+
+_POINTER_ means that the type points to something.
+
+_STRING_ meants that the type is a character array with an nul ('\0') terminating byte.
+
+
+*FLAGS*:
+
+[verse]
+--
+enum traceeval_flags {
+	TRACEEVAL_FL_KEY		= (1 << 0),
+	TRACEEVAL_FL_VALUE		= (1 << 1),
+	TRACEEVAL_FL_SIGNED		= (1 << 2),
+	TRACEEVAL_FL_TIMESTAMP		= (1 << 3),
+	TRACEEVAL_FL_STAT		= (1 << 4),
+};
+--
+
+The _KEY_ and _VALUE_ flags will be set by *traceeval_init()* for the types that associate
+to _keys_ or _vals_, and does not need to be set by the user.
+
+The _SIGNED_ flag is for the user to denote that the type is signed. This is useful for
+the compare operations in the sorts.
+
+The _TIMESTAMP_ flag denotes that the field is a timestamp. These have some meaning in
+which the statitics will record this field if defined. Note the TIMESTAMP and STAT flags
+are mutually exclusive. The _TIMESTAMP_ flag is ignored for _KEYS_.
+
+The _STAT_ flag denotes that the field should have its statistics recorded (maximum, minimum, etc).
+This is only valid for one of the _NUMBER_pass:[*]_ types.
+
+
+As the *traceeval_init()* requires that the passed in _keys_ and _vals_ must be a static
+array, if an dynamic array needs to be used, then *traceeval_init_size()* can be used.
+This function takes in two new parameters, _nr_keys_ and _nr_vals_. These must mach the
+size of the _keys_ and _vals_ arrays respectively. The reason that the *traceeval_init()*
+requires static size arrays is because it is really just a macro that calles
+*traceeval_init_size()*.
+
+[verse]
+--
+#define TRACEEVAL_ARRAY_SIZE(data)	(sizeof(data) / sizeof(data[0]))
+#define traceeval_init(keys, vals)					\
+	traceeval_init_size(keys, vals,					\
+			    TRACEEVAL_ARRAY_SIZE(keys),			\
+			    (void *)vals == NULL ?  0 : TRACEEVAL_ARRAY_SIZE(vals))
+--
+
+The *traceeval_release()* function releases and frees all the resources of
+a traceeval returned by *traceeval_init()* and *traceeval_init_size()*.
+
+RETURN VALUE
+------------
+The *traceeval_init()* and *traceeval_init_size()* both return a descriptor
+to the traceeval or NULL on error.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <signal.h>
+#include <errno.h>
+#include <tracefs.h>
+#include <traceeval.h>
+
+static bool done;
+
+static void pdie(const char *str)
+{
+	perror(str);
+	exit(-1);
+
+}
+
+struct traceeval_type sched_keys[] = {
+	{
+		.type = TRACEEVAL_TYPE_STRING,
+		.name = "COMM",
+	},
+	{
+		.type = TRACEEVAL_TYPE_NUMBER,
+		.name = "PID",
+	},
+	{
+		.type = TRACEEVAL_TYPE_NUMBER,
+		.name = "State",
+	},
+};
+
+
+struct traceeval_type sched_vals[] = {
+	{
+		.type = TRACEEVAL_TYPE_NUMBER_64,
+		.name = "Hitcount",
+	},
+};
+
+static int sched_callback(struct tep_event *event, struct tep_record *record,
+			  int cpu, void *data)
+{
+	static struct tep_format_field *pid_field;
+	static struct tep_format_field *comm_field;
+	static struct tep_format_field *state_field;
+	const struct traceeval_data *results;
+	struct traceeval_data keys[3];
+	struct traceeval_data vals[1];
+	struct traceeval *teval = data;
+	unsigned long long hits = 0;
+	unsigned long long val;
+	char *comm;
+	int state;
+	int pid;
+	int ret;
+
+	if (!pid_field) {
+		pid_field = tep_find_field(event, "prev_pid");
+		comm_field = tep_find_field(event, "prev_comm");
+		state_field = tep_find_field(event, "prev_state");
+
+		if (!pid_field || !comm_field || !state_field)
+			pdie("Could not find sched_switch required fields");
+	}
+
+	tep_read_number_field(pid_field, record->data, &val);
+	pid = val;
+
+	tep_read_number_field(state_field, record->data, &val);
+	state = val;
+
+	comm = record->data + comm_field->offset;
+
+	TRACEEVAL_SET_STRING(keys[0], comm);
+	TRACEEVAL_SET_NUMBER(keys[1], pid);
+	TRACEEVAL_SET_NUMBER(keys[2], state);
+
+	ret = traceeval_query(teval, keys, &results);
+	if (ret < 0)
+		pdie("Failed to query keys");
+
+	if (ret) {
+		hits = results[0].number_64;
+		traceeval_results_release(teval, results);
+	}
+
+	hits++;
+
+	TRACEEVAL_SET_NUMBER_64(vals[0], hits);
+
+	traceeval_insert(teval, keys, vals);
+
+	return 0;
+}
+
+static char *get_state(int state)
+{
+	switch (state & 7) {
+	case 0:
+		return "R";
+	case 1:
+		return "S";
+	case 2:
+		return "D";
+	}
+	return "X";
+}
+
+static void display_teval(struct traceeval *teval)
+{
+	struct traceeval_iterator *iter = traceeval_iterator_get(teval);
+	const struct traceeval_data *results;
+	const struct traceeval_data *keys;
+
+	/* Sort comms first. */
+	traceeval_iterator_sort(iter, sched_keys[0].name, 0, true);
+	/* Sort pids next */
+	traceeval_iterator_sort(iter, sched_keys[1].name, 1, true);
+	/* Sort state last */
+	traceeval_iterator_sort(iter, sched_keys[2].name, 2, true);
+
+	while (traceeval_iterator_next(iter, &keys) > 0) {
+		traceeval_iterator_query(iter, &results);
+
+		printf("%s [%ld] %s: %lld\n",
+		       keys[0].string, keys[1].number, get_state(keys[2].number),
+		       results[0].number_64);
+	}
+	traceeval_iterator_put(iter);
+}
+
+static void stop(int s)
+{
+	done = true;
+}
+
+int main (int argc, char **argv)
+{
+	struct tracefs_instance *instance;
+	struct tep_handle *tep;
+	const char *systems[] = { "sched", NULL };
+	struct traceeval *teval;
+	bool finished = false;
+	int ret;
+
+	teval = traceeval_init(sched_keys, sched_vals);
+	if (!teval)
+		pdie("Creating traceeval");
+
+	instance = tracefs_instance_create("sched-counter");
+	if (!instance)
+		pdie("Could not create instance");
+
+	tep = tracefs_local_events_system(NULL, systems);
+	if (!tep)
+		pdie("Could not read system events");
+
+	tracefs_trace_off(instance);
+
+	tracefs_event_enable(instance, "sched", "sched_switch");
+
+	ret = tracefs_follow_event(tep, instance, "sched", "sched_switch",
+				   sched_callback, teval);
+	if (ret < 0)
+		pdie("Could not follow sched event");
+
+	signal(SIGTERM, stop);
+	signal(SIGINT, stop);
+
+	printf("Hit Ctrl^C to stop\n");
+
+	tracefs_trace_on(instance);
+	do {
+		if (done) {
+			tracefs_trace_off(instance);
+			finished = true;
+		}
+
+		tracefs_iterate_raw_events(tep, instance, NULL, 0, NULL, NULL);
+
+	} while (!finished);
+
+	tracefs_event_disable(instance, NULL, NULL);
+	tracefs_instance_destroy(instance);
+	tracefs_instance_free(instance);
+
+	display_teval(teval);
+
+	return 0;
+}
+--
+
+FILES
+-----
+[verse]
+--
+*traceval.h*
+	Header file to include in order to have access to the library APIs.
+*-ltraceeval*
+	Linker switch to add when building a program that uses the library.
+--
+
+SEE ALSO
+--------
+*libtraceeval*(3)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceeval*.
+--
+REPORTING BUGS
+--------------
+Report bugs to  <linux-trace-devel@vger.kernel.org>
+
+LICENSE
+-------
+libtraceeval is licensed under MIT.
+
diff --git a/Documentation/libtraceeval.txt b/Documentation/libtraceeval.txt
index d3b97805d6ca..83d69b6eeda1 100644
--- a/Documentation/libtraceeval.txt
+++ b/Documentation/libtraceeval.txt
@@ -11,6 +11,11 @@ SYNOPSIS
 --
 *#include <traceeval.h>*
 
+Creating and releasing the traceeval resources:
+	struct traceeval pass:[*]*traceeval_init*(struct traceeval_type pass:[*]_keys_, struct traceeval_type pass:[*]_vals_);
+	struct traceeval pass:[*]*traceeval_init_size*(struct traceeval_type pass:[*]_keys_, struct traceeval_type pass:[*]_vals_,
+				       int _nr_keys_, int _nr_vals_);
+	void *traceeval_release*(struct traceeval pass:[*]_teval_);
 --
 
 DESCRIPTION
-- 
2.40.1


  parent reply	other threads:[~2023-10-06 19:54 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-06 19:55 [PATCH v2 0/5] libtraceeval: Add man pages Steven Rostedt
2023-10-06 19:55 ` [PATCH v2 1/5] libtraceeval: Start creating the documentation " Steven Rostedt
2023-10-06 19:55 ` Steven Rostedt [this message]
2023-10-06 19:55 ` [PATCH v2 3/5] libtraceeval: Add man pages for insertion and removal of elements in a traceeval Steven Rostedt
2023-10-06 19:55 ` [PATCH v2 4/5] libtraceeval: Add man pages for the traceeval iterator functions Steven Rostedt
2023-10-06 19:55 ` [PATCH v2 5/5] libtraceeval: Add man pages for traceeval statistics 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=20231006195536.1384287-3-rostedt@goodmis.org \
    --to=rostedt@goodmis.org \
    --cc=linux-trace-devel@vger.kernel.org \
    --cc=zwisler@google.com \
    /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.