new file mode 100644
@@ -0,0 +1,390 @@
+libtraceeval(3)
+===============
+
+NAME
+----
+traceeval_insert, traceeval_insert_size, traceeval_remove, traceeval_remove_size,
+traceeval_query, traceeval_query_size, traceeval_results_release, traceeval_count - Insert, remove and query traceeval elements
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <traceeval.h>*
+
+int *traceeval_insert*(struct traceeval pass:[*]_teval_,
+ const struct traceeval_data pass:[*]_keys_,
+ const struct traceeval_data pass:[*]_vals_);
+
+int *traceeval_insert_size*(struct traceeval pass:[*]_teval_,
+ const struct traceeval_data pass:[*]_keys_, size_t _nr_keys_,
+ const struct traceeval_data pass:[*]_vals_, size_t _nr_vals_);
+
+int *traceeval_remove*(struct traceeval pass:[*]_teval_, const struct traceeval_data pass:[*]_keys_);
+
+int *traceeval_remove_size*(struct traceeval pass:[*]_teval_,
+ const struct traceeval_data pass:[*]_keys_, size_t _nr_keys_);
+
+int *traceeval_query*(struct traceeval pass:[*]_teval_, const struct traceeval_data pass:[*]_keys_,
+ const struct traceeval_data pass:[**]_results_);
+
+int *traceeval_query_size*(struct traceeval pass:[*]_teval_, const struct traceeval_data pass:[*]_keys_,
+ size_t _nr_keys_, const struct traceeval_data pass:[**]_results_);
+
+void *traceeval_results_release*(struct traceeval pass:[*]_teval_,
+ const struct traceeval_data pass:[**]_results_);
+
+size_t *traceeval_count*(struct traceeval pass:[*]_teval_);
+--
+
+DESCRIPTION
+-----------
+These functions deal with inserting, finding and removing elements from the
+traceeval descriptor.
+
+The *traceeval_insert()* will add a new or update a current element into the
+given _teval_. The _keys_ must be a static array that is the same size as the
+key types given to *traceeval_init*(3). The same is true for the _vals_, as
+they must be an array of the same size as the val type array given. Both _keys_
+and _vals_ are of type struct traceeval_data.
+
+[verse]
+--
+struct traceeval_data {
+ enum traceeval_data_type type;
+ union {
+ char *string;
+ const char *cstring;
+ void *pointer;
+ unsigned long number;
+ unsigned long long number_64;
+ unsigned int number_32;
+ unsigned short number_16;
+ unsigned char number_8;
+ };
+};
+--
+
+For each _keys_ and _vals_ their types must match the keys and vals of the
+types passed to *traceeval_init*(3).
+
+The struct traceeval_data then has a union that represent each of the types.
+For example, a data field with a key type defined as TRACEEVAL_TYPE_POINTER,
+must use the _pointer_ union field.
+
+*traceveal_insert()* will make a copy of each of the _keys_ and _vals_ passed
+in. As to pass in a constant string, the field _cstring_ was added to allow
+constants to be passed to the function.
+
+Like *traceeval_init*(3), elements can also be inserted or updated updated with
+dynamically allocatend _keys_ and _vals_ with *traceeval_insert_size()*. This
+takes two more values: _nr_keys_ and _nr_vals_ to denote the size. This is to
+test against the key and val types registered in *traceeval_init*(3) to make
+sure they match. Once again, *traceeval_insert()* is really just a macro
+defined to pass in the array sizes to *traceeval_insert_size()*.
+
+In order to facilitate assgining the struct traceeval_data to the proper types,
+macros should be used.
+
+For initializing data:
+
+[verse]
+--
+*DEFINE_TRACEEVAL_NUMBER*(_data_) - assign a natural word size (size_t).
+*DEFINE_TRACEEVAL_NUMBER_8*(_data_) - assign an 8 bit value (char).
+*DEFINE_TRACEEVAL_NUMBER_16*(_data_) - assign a 16 bit value (short)
+*DEFINE_TRACEEVAL_NUMBER_32*(_data_) - assign a 32 bit value (int)
+*DEFINE_TRACEEVAL_NUMBER_64*(_data_) - assign a 64 bit value (long long).
+*DEFINE_TRACEEVAL_STRING*(_data_) - assign a nul terminated string value.
+*DEFINE_TRACEEVAL_CSTRING*(_data_) - assign a constant nul terminated string value.
+*DEFINE_TRACEEVAL_POINTER*(_data_) - assign a pointer value.
+
+static int foo(const char *str, int val)
+{
+ struct traceeval_data keys[] = {
+ DEFINE_TRACEEVAL_CSTRING( str ),
+ DEFINE_TRACEEVAL_NUMBER( val ),
+ };
+ [..]
+--
+
+There are also macros to set the data later:
+
+[verse]
+--
+TRACEEVAL_SET_NUMBER(_data_, _val_) - assign a natural word size (size_t)
+TRACEEVAL_SET_NUMBER_8(_data_, _val_) - assign an 8 bit value (char).
+TRACEEVAL_SET_NUMBER_16(_data_, _val_) - assign an 16 bit value (short).
+TRACEEVAL_SET_NUMBER_32(_data_, _val_) - assign an 32 bit value (int).
+TRACEEVAL_SET_NUMBER_64(_data_, _val_) - assign an 64 bit value (long long).
+--
+
+
+The *traceeval_query()* will return the element that matches the _keys_. The
+_keys_ must be a static array that is the same size as the key types defined by
+*traceeval_init()*. If an element is found, it will fill in the _results_
+pointer to point to the content of the values for the given element. The
+results must be released with *traceeval_results_release()*.
+
+Similar to *traceeval_init*(3) and *traceeval_insert()*, there's a
+*traceeval_queury_size()* that takes the size of the key array and allows for
+dynamic arrays to be passed to it.
+
+The *traceeval_results_release()* will release any necessary resources that a
+*traceeval_query()* may have added to return the _results_.
+
+The *traceeval_count()* will return the number of elements in the _teval_.
+
+RETURN VALUE
+------------
+The *traceeval_insert()* and *traceeval_insert_size()* return 0 on succes and -1 on error.
+
+The *traceeval_remove()* and *traceeval_remove_size()* returns 1 if the item was found and removed,
+0 if the item was not found, and -1 on an error (like invalid keys).
+
+The *traceeval_query()* and *traceveal_query_size()* return 1 if the item is found that matches
+the _keys_ and _results_ will contain the values of the last values of that time. It will return
+0 if not found, and -1 on error (like invalid keys).
+
+The *traceeval_count()* returns the number of elements currently in the _teval_.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <unistd.h>
+#include <sys/wait.h>
+#include <tracefs.h>
+#include <traceeval.h>
+
+struct data {
+ struct traceeval *teval_wakeup;
+ struct traceeval *teval_sched;
+};
+
+struct traceeval_type wakeup_keys[] = {
+ {
+ .name = "PID",
+ .type = TRACEEVAL_TYPE_NUMBER,
+ }
+};
+
+struct traceeval_type wakeup_vals[] = {
+ {
+ .name = "timestamp",
+ .flags = TRACEEVAL_FL_TIMESTAMP,
+ .type = TRACEEVAL_TYPE_NUMBER_64,
+ }
+};
+
+struct traceeval_type sched_keys[] = {
+ {
+ .name = "COMM",
+ .type = TRACEEVAL_TYPE_STRING,
+ },
+ {
+ .name = "PID",
+ .type = TRACEEVAL_TYPE_NUMBER,
+ }
+};
+
+struct traceeval_type sched_vals[] = {
+ {
+ .name = "timestamp",
+ .flags = TRACEEVAL_FL_TIMESTAMP,
+ .type = TRACEEVAL_TYPE_NUMBER_64,
+ },
+ {
+ .name = "delta",
+ .flags = TRACEEVAL_FL_STAT,
+ .type = TRACEEVAL_TYPE_NUMBER_64,
+ }
+};
+
+static int wakeup_callback(struct tep_event *event, struct tep_record *record, int cpu, void *d)
+{
+ static struct tep_format_field *pid_field;
+ struct data *data = d;
+ unsigned long long val;
+ long pid;
+ struct traceeval_data keys[1];
+ struct traceeval_data vals[1];
+
+ if (!pid_field)
+ pid_field = tep_find_field(event, "pid");
+
+ tep_read_number_field(pid_field, record->data, &val);
+ pid = val;
+
+ TRACEEVAL_SET_NUMBER(keys[0], pid);
+ TRACEEVAL_SET_NUMBER_64(vals[0], record->ts);
+
+ traceeval_insert(data->teval_wakeup, keys, vals);
+
+ return 0;
+}
+
+static int sched_callback(struct tep_event *event, struct tep_record *record, int cpu, void *d)
+{
+ static struct tep_format_field *next_pid_field;
+ static struct tep_format_field *next_comm_field;
+ struct data *data = d;
+ unsigned long long delta;
+ unsigned long long val;
+ long pid;
+ struct traceeval_data wakeup_keys[1];
+ struct traceeval_data keys[2];
+ struct traceeval_data vals[2];
+ const struct traceeval_data *results;
+
+ if (!next_pid_field) {
+ next_pid_field = tep_find_field(event, "next_pid");
+ next_comm_field = tep_find_field(event, "next_comm");
+ }
+
+ tep_read_number_field(next_pid_field, record->data, &val);
+ pid = val;
+
+ TRACEEVAL_SET_NUMBER(wakeup_keys[0], pid);
+
+ if (traceeval_query(data->teval_wakeup, wakeup_keys, &results) <= 0)
+ return 0;
+
+ delta = record->ts - results[0].number_64;
+ traceeval_results_release(data->teval_wakeup, results);
+
+ TRACEEVAL_SET_CSTRING(keys[0], record->data + next_comm_field->offset);
+ TRACEEVAL_SET_NUMBER(keys[1], pid);
+
+ TRACEEVAL_SET_NUMBER_64(vals[0], record->ts);
+ TRACEEVAL_SET_NUMBER_64(vals[1], delta);
+
+ traceeval_insert(data->teval_sched, keys, vals);
+
+ return 0;
+}
+
+static pid_t call_code(struct tracefs_instance *instance, int argc, char **argv)
+{
+ char pid_str[64];
+ pid_t pid;
+
+ pid = fork();
+
+ if (pid)
+ return pid;
+
+ sprintf(pid_str, "%d", getpid());
+
+ tracefs_instance_file_write(instance, "set_event_pid", pid_str);
+ tracefs_trace_on(instance);
+
+ execvp(argv[0], argv);
+ exit(-1);
+}
+
+static void show_latency(struct data *data)
+{
+ struct traceeval_iterator *iter = traceeval_iterator_get(data->teval_sched);
+ const struct traceeval_data *keys;
+
+ printf("\n");
+ while (traceeval_iterator_next(iter, &keys) > 0) {
+ struct traceeval_stat *stat;
+
+ stat = traceeval_iterator_stat(iter, sched_vals[1].name);
+ if (!stat)
+ continue;
+
+ printf("%s-%ld max:%lld min:%lld total:%lld count:%lld\n",
+ keys[0].string, keys[1].number,
+ traceeval_stat_max(stat),
+ traceeval_stat_min(stat),
+ traceeval_stat_total(stat),
+ traceeval_stat_count(stat));
+ }
+ traceeval_iterator_put(iter);
+}
+
+static pid_t wait_pid;
+static bool done;
+
+static void sig(int sig)
+{
+ pid_t ret;
+
+ ret = waitpid(wait_pid, NULL, WNOHANG);
+ if (ret == wait_pid)
+ done = true;
+}
+
+int main (int argc, char **argv)
+{
+ struct tracefs_instance *instance;
+ struct tep_handle *tep;
+ struct data data;
+
+ if (argc < 2) {
+ printf("usage: wakeup_latency exec\n");
+ exit(-1);
+ }
+
+ data.teval_wakeup = traceeval_init(wakeup_keys, wakeup_vals);
+ data.teval_sched = traceeval_init(sched_keys, sched_vals);
+
+ tep = tracefs_local_events(NULL);
+
+ instance = tracefs_instance_create("wakeup_latency");
+ tracefs_trace_off(instance);
+ tracefs_event_enable(instance, "sched", "sched_waking");
+ tracefs_event_enable(instance, "sched", "sched_switch");
+
+ tracefs_follow_event(tep, instance, "sched", "sched_waking", wakeup_callback, &data);
+ tracefs_follow_event(tep, instance, "sched", "sched_switch", sched_callback, &data);
+
+ signal(SIGCHLD, sig);
+
+ wait_pid = call_code(instance, argc - 1, argv + 1);
+
+ do {
+ tracefs_iterate_raw_events(tep, instance, NULL, 0, NULL, NULL);
+ } while (!done);
+
+ tracefs_event_disable(instance, NULL, NULL);
+ tracefs_instance_destroy(instance);
+ tracefs_instance_free(instance);
+
+ show_latency(&data);
+
+ 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.
+
@@ -16,6 +16,31 @@ Creating and releasing the traceeval resources:
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_);
+
+Inserting and removing elements from the traceeval:
+ int *traceeval_insert*(struct traceeval pass:[*]_teval_,
+ const struct traceeval_data pass:[*]_keys_,
+ const struct traceeval_data pass:[*]_vals_);
+
+ int *traceeval_insert_size*(struct traceeval pass:[*]_teval_,
+ const struct traceeval_data pass:[*]_keys_, size_t _nr_keys_,
+ const struct traceeval_data pass:[*]_vals_, size_t _nr_vals_);
+
+ int *traceeval_remove*(struct traceeval pass:[*]_teval_, const struct traceeval_data pass:[*]_keys_);
+
+ int *traceeval_remove_size*(struct traceeval pass:[*]_teval_,
+ const struct traceeval_data pass:[*]_keys_, size_t _nr_keys_);
+
+ int *traceeval_query*(struct traceeval pass:[*]_teval_, const struct traceeval_data pass:[*]_keys_,
+ const struct traceeval_data pass:[**]_results_);
+
+ int *traceeval_query_size*(struct traceeval pass:[*]_teval_, const struct traceeval_data pass:[*]_keys_,
+ size_t _nr_keys_, const struct traceeval_data pass:[**]_results_);
+
+ void *traceeval_results_release*(struct traceeval pass:[*]_teval_,
+ const struct traceeval_data pass:[**]_results_);
+
+ size_t *traceeval_count*(struct traceeval pass:[*]_teval_);
--
DESCRIPTION