From patchwork Thu Oct 5 23:24:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 13410876 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A156243AA1 for ; Thu, 5 Oct 2023 23:23:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=none Received: by smtp.kernel.org (Postfix) with ESMTPSA id 41CFFC433C9; Thu, 5 Oct 2023 23:23:41 +0000 (UTC) Received: from rostedt by gandalf with local (Exim 4.96) (envelope-from ) id 1qoXi7-005VCd-31; Thu, 05 Oct 2023 19:24:51 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: Ross Zwisler , "Steven Rostedt (Google)" Subject: [PATCH 5/5] libtraceeval: Add man pages for traceeval statistics Date: Thu, 5 Oct 2023 19:24:50 -0400 Message-Id: <20231005232450.1311519-6-rostedt@goodmis.org> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20231005232450.1311519-1-rostedt@goodmis.org> References: <20231005232450.1311519-1-rostedt@goodmis.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: "Steven Rostedt (Google)" Add man pages for: traceeval_stat() traceeval_stat_size() traceeval_stat_max() traceeval_stat_min() traceeval_stat_max_timestamp() traceeval_stat_min_timestamp() traceeval_stat_total() traceeval_stat_count() Signed-off-by: Steven Rostedt (Google) --- Documentation/libtraceeval-stat.txt | 307 ++++++++++++++++++++++++++++ Documentation/libtraceeval.txt | 16 ++ 2 files changed, 323 insertions(+) create mode 100644 Documentation/libtraceeval-stat.txt diff --git a/Documentation/libtraceeval-stat.txt b/Documentation/libtraceeval-stat.txt new file mode 100644 index 000000000000..6e9866f4daf2 --- /dev/null +++ b/Documentation/libtraceeval-stat.txt @@ -0,0 +1,307 @@ +libtraceeval(3) +=============== + +NAME +---- +traceeval_stat, traceeval_stat_size, traceeval_stat_max, traceeval_stat_min, traceeval_stat_max_timestamp, +traceeval_stat_min_timestamp, traceeval_stat_total, traceeval_stat_count - Get statistics of an elements value/key in a traceeval. + +SYNOPSIS +-------- +[verse] +-- +*#include * + +struct traceeval_stat pass:[*]*traceeval_stat*(struct traceeval pass:[*]_teval_, + const struct traceeval_data pass:[*]_keys_, + const char pass:[*]_val_name_); +struct traceeval_stat pass:[*]*traceeval_stat_size*(struct traceeval pass:[*]_teval_, + const struct traceeval_data pass:[*]_keys_, + size_t _nr_keys_, + const char pass:[*]_val_name_); + +unsigned long long *traceeval_stat_max*(struct traceeval_stat pass:[*]_stat_); +unsigned long long *traceeval_stat_min*(struct traceeval_stat pass:[*]_stat_); +unsigned long long *traceeval_stat_max_timestamp*(struct traceeval_stat pass:[*]_stat_, unsigned long long pass:[*]ts); +unsigned long long *traceeval_stat_min_timestamp*(struct traceeval_stat pass:[*]_stat_, unsigned long long pass:[*]ts); +unsigned long long *traceeval_stat_total*(struct traceeval_stat pass:[*]_stat_); +unsigned long long *traceeval_stat_count*(struct traceeval_stat pass:[*]_stat_); +-- + +DESCRIPTION +----------- +If a type of a value is numeric (*TRACEEVAL_TYPE_NUMBERpass:[*]*) and has the +*TRACEEVAL_FL_STAT* flag set, then every instance added will save the maximum, +minimum, count and total for that value. These functions are used to retrieve +that information. + +If one of the values has *TRACEEVAL_FL_TIMESTAMP* set, that value will also be used +to record that value for when a maximum or minimum stat value is hit. Note that +a value can not have both the *TRACEEVAL_FL_TIMESTAMP* and *TRACEEVAL_FL_STAT* flags set. +That will cause an error when creating the traceeval via *traceeval_init*(3). +Note that fields marked with *TRACEEVAL_FL_TIMESTAMP* must also be of the +*TRACEEVAL_TYPE_NUMBERpass:[*]* types. + +The *traceeval_stat()* will return a struct traceeval_stat descriptor for the +given field that is numeric and is marked as a stat type. The _teval_ is the +traceeval descriptor that contains the elements, the _keys_ are the keys to find +the element to get the stats of the vals, and _val_name_ is the name of the value +field to retrieve the stats from (this is the same name for the field passed to +*traceeval_init*(3)). Note that the _keys_ passed in must be a static array. +If only a dynamic array (pointer) is available, then *traceeval_stat_size()* needs to +be used instead. This is because *traceeval_stat()* is a macro that will calculate +the size of the array. + +Once a traceeval_stat descriptor is retrieved, then it can be used to extract the +statistics for that give value field whith the below functions. + +The *traceeval_stat_max()* will return the maximum value for the value represented by +the _stat_ descriptor passed in. + +The *traceeval_stat_min()* will return the minimum value for the value represented by +the _stat_ descriptor passed in. + +The *traceeval_stat_max_timestamp()* and *traceeval_stat_min_timestamp()* functions +return the same result as the *traceeval_stat_max()* and *traceeval_stat_min()* functions +respectively, but they take another parameter. The _ts_ is a pointer to a unsigend long long that +if not NULL, will be used to return the timestamp of when the maximum or minimum values +respectively were retrieved. This only works if another field of the traceeval descriptor +values was marked as *TRACEEVAL_FL_TIMESTAMP*. That field is saved when a new maximum or +minimum is found. + +The *traceeval_stat_total()* returns the sum of all the values of the field that the _stat_ +represents. + +The *traceeval_stat_count()* returns the number of times the value was calculated. Note that +this may not be the same as *traceveal_count*(3) as that function returns the number +of instances currently in the traceeval. If *traceeval_remove*(3) is called on the traceeval +descriptor to remove an element, the *traceeval_count*(3) will return one less. The removal +of elements does not affect the count of the traceeval_stat, and the same goes for +the total count. The number returned from this function can safely be used against the number +returned by *traceeval_stat_total()* to calculate the average. + +RETURN VALUE +------------ +The *traceeval_stat()* and *traceeval_stat_size()* both return a descriptor to a traceeval_stat +on success, and NULL on error. + +The *traceeval_stat_max()* and *traceeval_stat_max_timestamp()* both return the maximum value that +the traceeval_stat represtents. The *traceeval_stat_max_timestamp()* also returns the timestamp +that was recorded when the maximum was found. Note, if no other value field was marked with +*TRACEEVAL_FL_TIMESTAMP* then the timestamp _ts_ will contain zero. + +The *traceeval_stat_min()* and *traceeval_stat_min_timestamp()* both return the minimum value that +the traceeval_stat represtents. The *traceeval_stat_min_timestamp()* also returns the timestamp +that was recorded when the minimum was found. Note, if no other value field was marked with +*TRACEEVAL_FL_TIMESTAMP* then the timestamp _ts_ will contain zero. + +The *traceeval_stat_total()* returns the total sum of all the values that the traceeval_stat +represents. + +The *traceeval_stat_count()* returns the number of times the traceeval_stat total was updated. + +EXAMPLE +------- +[source,c] +-- +#include +#include +#include +#include + +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 tracecmd_input *handle, 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 tracecmd_input *handle, 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 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; + unsigned long long val; + unsigned long long ts; + + stat = traceeval_iterator_stat(iter, sched_vals[1].name); + if (!stat) + continue; + + printf("%s-%ld\n", keys[0].string, keys[1].number); + + val = traceeval_stat_max_timestamp(stat, &ts), + + printf("\tmax:%lld at %lld\n", val, ts); + + val = traceeval_stat_min_timestamp(stat, &ts); + printf("\tmin:%lld at %lld\n", val, ts); + printf("\ttotal:%lld count:%lld\n", + traceeval_stat_total(stat), + traceeval_stat_count(stat)); + } +} + +int main (int argc, char **argv) +{ + struct tracecmd_input *handle; + struct data data; + + if (argc < 2) { + printf("usage: wake-lat trace.dat\n"); + exit(-1); + } + + data.teval_wakeup = traceeval_init(wakeup_keys, wakeup_vals); + data.teval_sched = traceeval_init(sched_keys, sched_vals); + + handle = tracecmd_open(argv[1], TRACECMD_FL_LOAD_NO_PLUGINS); + if (!handle) { + perror(argv[0]); + exit(-1); + } + + tracecmd_follow_event(handle, "sched", "sched_waking", wakeup_callback, &data); + tracecmd_follow_event(handle, "sched", "sched_switch", sched_callback, &data); + + tracecmd_iterate_events(handle, NULL, 0, NULL, NULL); + + 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* , author of *libtraceeval*. +-- +REPORTING BUGS +-------------- +Report bugs to + +LICENSE +------- +libtraceeval is licensed under MIT. + diff --git a/Documentation/libtraceeval.txt b/Documentation/libtraceeval.txt index fc7c621878ac..173b1ddb3df8 100644 --- a/Documentation/libtraceeval.txt +++ b/Documentation/libtraceeval.txt @@ -58,6 +58,22 @@ Functions for iterating over the elements of the libtraceeval: struct traceeval_stat pass:[*]*traceeval_iterator_stat*(struct traceeval_iterator pass:[*]_iter_, struct traceeval_type pass:[*]_type_); int *traceeval_iterator_remove*(struct traceeval_iterator pass:[*]_iter_); + +Functions to manage statistics of values of a traceeval: + struct traceeval_stat pass:[*]*traceeval_stat*(struct traceeval pass:[*]_teval_, + const struct traceeval_data pass:[*]_keys_, + const char pass:[*]_val_name_); + struct traceeval_stat pass:[*]*traceeval_stat_size*(struct traceeval pass:[*]_teval_, + const struct traceeval_data pass:[*]_keys_, + size_t _nr_keys_, + const char pass:[*]_val_name_); + + unsigned long long *traceeval_stat_max*(struct traceeval_stat pass:[*]_stat_); + unsigned long long *traceeval_stat_min*(struct traceeval_stat pass:[*]_stat_); + unsigned long long *traceeval_stat_max_timestamp*(struct traceeval_stat pass:[*]_stat_, unsigned long long pass:[*]ts); + unsigned long long *traceeval_stat_min_timestamp*(struct traceeval_stat pass:[*]_stat_, unsigned long long pass:[*]ts); + unsigned long long *traceeval_stat_total*(struct traceeval_stat pass:[*]_stat_); + unsigned long long *traceeval_stat_count*(struct traceeval_stat pass:[*]_stat_); -- DESCRIPTION