From patchwork Tue Aug 10 20:48:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 495520 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.9 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 465B8C19F3B for ; Tue, 10 Aug 2021 20:48:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 25FE5610FD for ; Tue, 10 Aug 2021 20:48:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233648AbhHJUsy (ORCPT ); Tue, 10 Aug 2021 16:48:54 -0400 Received: from mail.kernel.org ([198.145.29.99]:44286 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232424AbhHJUss (ORCPT ); Tue, 10 Aug 2021 16:48:48 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 4211C6056B; Tue, 10 Aug 2021 20:48:25 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mDYfg-003hA5-2b; Tue, 10 Aug 2021 16:48:24 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tom Zanussi , Daniel Bristot de Oliveira , Masami Hiramatsu , Namhyung Kim , linux-rt-users , Clark Williams , "Steven Rostedt (VMware)" Subject: [PATCH 1/9] tracefs: Add API tracefs_hist_data_parse() Date: Tue, 10 Aug 2021 16:48:10 -0400 Message-Id: <20210810204818.880714-2-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210810204818.880714-1-rostedt@goodmis.org> References: <20210810204818.880714-1-rostedt@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-rt-users@vger.kernel.org From: "Steven Rostedt (VMware)" Add a function tracefs_hist_data_parse() that will take the content of a trace event's hist data file, and parse it into a "tracefs_hist_data" descriptor that can be used to read the raw data from the file. Signed-off-by: Steven Rostedt (VMware) --- include/tracefs.h | 7 + src/Makefile | 7 + src/tracefs-hist-data.c | 861 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 875 insertions(+) create mode 100644 src/tracefs-hist-data.c diff --git a/include/tracefs.h b/include/tracefs.h index 17020de0108a..6bd40d72cb25 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -413,6 +413,13 @@ static inline int tracefs_hist_destroy(struct tracefs_instance *instance, return tracefs_hist_command(instance, hist, TRACEFS_HIST_CMD_DESTROY); } +struct tracefs_hist_data; + +struct tracefs_hist_data *tracefs_hist_data_parse(const char *buffer, + const char **next_buffer, + char **err); +void tracefs_hist_data_free(struct tracefs_hist_data *hdata); + struct tracefs_synth; /* diff --git a/src/Makefile b/src/Makefile index 9248efc5c7fd..1ab181416b82 100644 --- a/src/Makefile +++ b/src/Makefile @@ -17,6 +17,10 @@ OBJS += sqlhist-lex.o OBJS += sqlhist.tab.o OBJS += tracefs-sqlhist.o +# Order matters for the the two below +OBJS += hist-lex.o +OBJS += tracefs-hist-data.o + OBJS := $(OBJS:%.o=$(bdir)/%.o) DEPS := $(OBJS:$(bdir)/%.o=$(bdir)/.%.d) @@ -45,6 +49,9 @@ sqlhist.tab.c: sqlhist.y sqlhist.tab.h sqlhist-lex.c: sqlhist.l sqlhist.tab.c flex -o $@ $< +hist-lex.c: hist.l + flex -P hist_ -o $@ $< + $(bdir)/%.o: %.c $(Q)$(call do_fpic_compile) diff --git a/src/tracefs-hist-data.c b/src/tracefs-hist-data.c new file mode 100644 index 000000000000..497ab9ce97b4 --- /dev/null +++ b/src/tracefs-hist-data.c @@ -0,0 +1,861 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * Copyright (C) 2021 VMware Inc, Steven Rostedt + * + * Updates: + * Copyright (C) 2021, VMware, Tzvetomir Stoyanov + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include "tracefs.h" +#include "tracefs-local.h" + +#define HIST_FILE "hist" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hist.h" + +#define offset_of(type, field) ((unsigned long )(&((type *)0)->field)) +#define container_of(p, type, field) ((type *)((void *)(p) - offset_of(type, field))); + +extern int hist_lex_init_extra(void *data, void* ptr_yy_globals); +extern int hist_lex_destroy(void *scanner); + +int hist_yyinput(void *extra, char *buf, int max) +{ + struct hist_data *data = extra; + + if (!data || !data->buffer) + return -1; + + if (data->buffer_idx + max > data->buffer_size) + max = data->buffer_size - data->buffer_idx; + + if (max) + memcpy(buf, data->buffer + data->buffer_idx, max); + + data->buffer_idx += max; + + return max; +} + +extern int hist_yylex(void *data, void *scanner); + +static char *name_token(enum yytokentype type) +{ + switch (type) { + case YYEMPTY: + return "YYEMPTY"; + case YYEOF: + return "YYEOF"; + case YYerror: + return "YYerror"; + case YYUNDEF: + return "YYUNDEF"; + case NUMBER: + return "NUMBER"; + case HEX: + return "HEX"; + case NEWLINE: + return "NEWLINE"; + case STRING: + return "STRING"; + case KEY_TYPE: + return "KEY_TYPE"; + case KEY_VAL: + return "KEY_VAL"; + case START_RANGE: + return "START_RANGE"; + case RANGE_LINEAR: + return "RANGE_LINEAR"; + case RANGE_EXPONENT: + return "RANGE_EXPONENT"; + case RAW_VAL: + return "RAW_VAL"; + case STACKTRACE: + return "STACKTRACE"; + case STACK_ITEM: + return "STACK_ITEM"; + case STACK_MOD: + return "STACK_MOD"; + case VALUE: + return "VALUE"; + case TOTALS: + return "TOTALS"; + case HITS: + return "HITS"; + case ENTRIES: + return "ENTRIES"; + case DROPPED: + return "DROPPED"; + case COMMENT: + return "COMMENT"; + case COLON: + return "COLON"; + case COMMA: + return "COMMA"; + } + return NULL; +} + +enum tracefs_bucket_key_type { + TRACEFS_BUCKET_KEY_UNDEF, + TRACEFS_BUCKET_KEY_SINGLE, + TRACEFS_BUCKET_KEY_RANGE, +}; + +struct tracefs_hist_bucket_key_single { + long long val; + char *sym; +}; + +struct tracefs_hist_bucket_key_range { + long long start; + long long end; +}; + +struct tracefs_hist_bucket_key { + struct tracefs_hist_bucket_key *next; + enum tracefs_bucket_key_type type; + union { + struct tracefs_hist_bucket_key_single single; + struct tracefs_hist_bucket_key_range range; + }; +}; + +struct tracefs_hist_bucket_val { + struct tracefs_hist_bucket_val *next; + long long val; +}; + +struct tracefs_hist_bucket { + struct tracefs_hist_bucket *next; + struct tracefs_hist_bucket_key *keys; + struct tracefs_hist_bucket_key **next_key; + struct tracefs_hist_bucket_val *vals; + struct tracefs_hist_bucket_val **next_val; +}; + +struct tracefs_hist_data { + char **key_names; + char **value_names; + struct tracefs_hist_bucket *buckets; + struct tracefs_hist_bucket **next_bucket; + unsigned long long hits; + unsigned long long entries; + unsigned long long dropped; +}; + +static int do_comment(struct tracefs_hist_data *hdata, const char *comment) +{ + return 0; +} + +static int do_key_type(struct tracefs_hist_data *hdata, const char *key) +{ + char **tmp; + + tmp = tracefs_list_add(hdata->key_names, key); + if (!tmp) + return -1; + hdata->key_names = tmp; + + return 0; +} + +static int do_value_type(struct tracefs_hist_data *hdata, const char *key) +{ + char **tmp; + + tmp = tracefs_list_add(hdata->value_names, key); + if (!tmp) + return -1; + hdata->value_names = tmp; + + return 0; +} + +static int start_new_row(struct tracefs_hist_data *hdata) +{ + struct tracefs_hist_bucket *bucket; + struct tracefs_hist_bucket_key *key; + + bucket = calloc(1, sizeof(*bucket)); + if (!bucket) + return -1; + + key = calloc(1, sizeof(*key)); + if (!key) { + free(bucket); + return -1; + } + + bucket->keys = key; + bucket->next_key = &key->next; + + bucket->next_val = &bucket->vals; + + *hdata->next_bucket = bucket; + hdata->next_bucket = &bucket->next; + return 0; +} + +static int start_new_key(struct tracefs_hist_data *hdata) +{ + struct tracefs_hist_bucket *bucket; + struct tracefs_hist_bucket_key *key; + + bucket = container_of(hdata->next_bucket, struct tracefs_hist_bucket, next); + + key = calloc(1, sizeof(*key)); + if (!key) { + free(bucket); + return -1; + } + + *bucket->next_key = key; + bucket->next_key = &key->next; + + return 0; +} + +static char *chomp(char *text) +{ + char *p; + int len; + + while (isspace(*text)) + text++; + + len = strlen(text); + p = text + len - 1; + while (p >= text && isspace(*p)) + p--; + + p[1] = '\0'; + + return text; +} + +static int __do_key_val(struct tracefs_hist_data *hdata, + char *text, const char *delim, const char *end) +{ + struct tracefs_hist_bucket *bucket; + struct tracefs_hist_bucket_key *key; + struct tracefs_hist_bucket_key_single *k; + char *val; + int len; + + text = chomp(text); + + bucket = container_of(hdata->next_bucket, struct tracefs_hist_bucket, next); + + key = container_of(bucket->next_key, struct tracefs_hist_bucket_key, next); + if (!key->type) + key->type = TRACEFS_BUCKET_KEY_SINGLE; + + if (key->type != TRACEFS_BUCKET_KEY_SINGLE) + return -1; + + k = &key->single; + + len = strlen(text); + len += k->sym ? strlen(k->sym) + strlen(delim) : 0; + if (end) + len += strlen(end); + + val = realloc(k->sym, len + 1); + if (!val) + return -1; + + if (k->sym) + strcat(val, delim); + else + val[0] = '\0'; + + strcat(val, text); + if (end) + strcat(val, end); + + k->sym = val; + + return 0; +} + +static int do_key_val(struct tracefs_hist_data *hdata, char *text) +{ + return __do_key_val(hdata, text, " ", NULL); +} + +static int do_key_stack(struct tracefs_hist_data *hdata, char *text) +{ + return __do_key_val(hdata, text, "\n", NULL); +} + +static int do_key_stack_mod(struct tracefs_hist_data *hdata, char *text) +{ + return __do_key_val(hdata, text, " [", "]"); +} + +static int do_key_raw(struct tracefs_hist_data *hdata, char *text) +{ + struct tracefs_hist_bucket *bucket; + struct tracefs_hist_bucket_key *key; + struct tracefs_hist_bucket_key_single *k; + + text = chomp(text); + + bucket = container_of(hdata->next_bucket, struct tracefs_hist_bucket, next); + + key = container_of(bucket->next_key, struct tracefs_hist_bucket_key, next); + if (key->type != TRACEFS_BUCKET_KEY_SINGLE) + return -1; + + k = &key->single; + + if (k->val) + return -1; + + k->val = strtoll(text, NULL, 0); + + return 0; +} + +static int do_key_range(struct tracefs_hist_data *hdata, long long start, + long long end) +{ + struct tracefs_hist_bucket *bucket; + struct tracefs_hist_bucket_key *key; + struct tracefs_hist_bucket_key_range *k; + + bucket = container_of(hdata->next_bucket, struct tracefs_hist_bucket, next); + + key = container_of(bucket->next_key, struct tracefs_hist_bucket_key, next); + + if (!key->type) + key->type = TRACEFS_BUCKET_KEY_RANGE; + + if (key->type != TRACEFS_BUCKET_KEY_RANGE) + return -1; + + k = &key->range; + + k->start = start; + k->end = end; + + return 0; +} + +static int do_value_num(struct tracefs_hist_data *hdata, long long num) +{ + struct tracefs_hist_bucket *bucket; + struct tracefs_hist_bucket_val *val; + + bucket = container_of(hdata->next_bucket, struct tracefs_hist_bucket, next); + val = calloc(1, sizeof(*val)); + if (!val) + return -1; + + val->val = num; + + *bucket->next_val = val; + bucket->next_val = &val->next; + + return 0; +} + +static long long expo(unsigned int e, long long exp) +{ + long long ret; + + if (exp < 0) + exp = 0; + + if (e == 2) + return 1LL << exp; + + ret = 1; + for (; exp > 0; exp--) + ret *= e; + return e; +} + +enum hist_state { + HIST_START, + HIST_KEYS_START, + HIST_KEYS, + HIST_KEY_VALS, + HIST_RANGE, + HIST_VALUES, + HIST_NEXT_KEY, + HIST_STACK, + HIST_ENTRIES, + HIST_DROPPED, + HIST_END, +}; + +static const char *find_buffer_line(const char *buffer, int line_no) +{ + int line = 0; + int i; + + for (i = 0; buffer[i]; i++) { + if (buffer[i] == '\n') { + line++; + if (line >= line_no) { + i++; + break; + } + } + } + return buffer + i; +} + +static void print_line(struct trace_seq *seq, struct hist_data *data) +{ + const char *buffer = data->buffer; + int i; + + buffer = find_buffer_line(buffer, data->line_no); + + for (i = 0; buffer[i]; i++) { + if (buffer[i] == '\n') + break; + } + + trace_seq_printf(seq, "%.*s (line:%d idx:%d)\n", i, buffer, + data->line_no, data->line_idx); + trace_seq_printf(seq, "%*s\n", data->line_idx, "^"); +} + +static void print_error(struct hist_data *data, char **err, + enum hist_state state, enum yytokentype type) +{ + struct trace_seq seq; + char *tname; + + if (!err) + return; + + trace_seq_init(&seq); + + print_line(&seq, data); + + trace_seq_printf(&seq, "Error in "); + switch (state) { + case HIST_START: + trace_seq_printf(&seq, "HIST_START"); + break; + case HIST_KEYS_START: + trace_seq_printf(&seq, "HIST_KEYS_START"); + break; + case HIST_KEYS: + trace_seq_printf(&seq, "HIST_KEYS"); + break; + case HIST_KEY_VALS: + trace_seq_printf(&seq, "HIST_KEY_VALS"); + break; + case HIST_RANGE: + trace_seq_printf(&seq, "HIST_RANGE"); + break; + case HIST_VALUES: + trace_seq_printf(&seq, "HIST_VALUES"); + break; + case HIST_NEXT_KEY: + trace_seq_printf(&seq, "HIST_NEXT_KEY"); + case HIST_STACK: + trace_seq_printf(&seq, "HIST_STACK"); + break; + case HIST_ENTRIES: + trace_seq_printf(&seq, "HIST_ENTRIES"); + break; + case HIST_DROPPED: + trace_seq_printf(&seq, "HIST_DROPPED"); + break; + case HIST_END: + trace_seq_printf(&seq, "HIST_END"); + break; + } + trace_seq_printf(&seq, " with token "); + tname = name_token(type); + if (tname) + trace_seq_printf(&seq, "%s", tname); + else + trace_seq_printf(&seq, "(unknown %d)", type); + + trace_seq_printf(&seq, " last token %s\n", data->text); + trace_seq_terminate(&seq); + if (seq.buffer) + *err = seq.buffer; + seq.buffer = NULL; + trace_seq_destroy(&seq); +} + +static void update_next(const char **next_buffer, struct hist_data *data) +{ + if (!next_buffer) + return; + + *next_buffer = find_buffer_line(data->buffer, data->line_no - 1); +} + +/** + * tracefs_hist_data_free - free a created hist data descriptor + * @hdata: The tracefs_hist_data descriptor to free. + * + * Frees the data allocated by tracefs_hist_data_parse(). + */ +void tracefs_hist_data_free(struct tracefs_hist_data *hdata) +{ + struct tracefs_hist_bucket *bucket; + struct tracefs_hist_bucket_key *key; + struct tracefs_hist_bucket_val *val; + + if (!hdata) + return; + + tracefs_list_free(hdata->key_names); + tracefs_list_free(hdata->value_names); + + while ((bucket = hdata->buckets)) { + hdata->buckets = bucket->next; + while ((key = bucket->keys)) { + bucket->keys = key->next; + switch (key->type) { + case TRACEFS_BUCKET_KEY_SINGLE: + free(key->single.sym); + break; + default: + break; + } + free(key); + } + while ((val = bucket->vals)) { + bucket->vals = val->next; + free(val); + } + free(bucket); + } + + free(hdata); +} + +/* Used for debugging in gdb */ +static void breakpoint(char *text) +{ +} + +/** + * tracefs_hist_data_parse - parse a hist file of a trace event + * @buffer: The buffer containing the hist file content + * @next_buffer: If not NULL will point to the next hist in the buffer + * @err: If not NULL, will load the error message on error + * + * Reads and parses the content of a "hist" file of a trace event. + * It will return a descriptor that can be used to read the content and + * create a histogram table. + * + * Because "hist" files may contain more than one histogram, and this + * function will only parse one of the histograms, if there are more + * than one histogram in the buffer, and @next_buffer is not NULL, then + * it will return the location of the next histogram in @next_buffer. + * + * If there's an error in the parsing, then @err will contain an error + * message about what went wrong. + * + * Returns a desrciptor of a histogram representing the hist file content. + * NULL on error. + * The descriptor must be freed with tracefs_hist_data_free(). + */ +struct tracefs_hist_data * +tracefs_hist_data_parse(const char *buffer, const char **next_buffer, char **err) +{ + struct tracefs_hist_data *hdata; + struct hist_data data; + enum hist_state state = 0; + long long start_range, end_range; + bool first = false; + unsigned int e; + int buffer_size; + bool done = false; + char *text; + enum yytokentype type; + int ret; + + if (!buffer) + return NULL; + + hdata = calloc(1, sizeof(*hdata)); + if (!hdata) + return NULL; + + hdata->next_bucket = &hdata->buckets; + + memset(&data, 0, sizeof(data)); + + buffer_size = strlen(buffer); + data.buffer = buffer; + data.buffer_size = buffer_size; + data.text = malloc(buffer_size); + if (!data.text) { + free(hdata); + perror("text"); + exit(-1); + } + + ret = hist_lex_init_extra(&data, &data.scanner); + if (ret < 0) { + perror("ylex_init"); + return NULL; + } + while (!done) { + type = hist_yylex(&data, data.scanner); + if (type < 0) + break; + text = data.text; + breakpoint(text); + switch (state) { + case HIST_START: + switch (type) { + case COMMENT: + first = true; + ret = do_comment(hdata, text); + if (ret < 0) + goto error; + break; + case KEY_TYPE: + goto key_type; + case STACKTRACE: + goto stacktrace; + default: + goto error; + } + break; + case HIST_KEYS_START: + switch (type) { + case KEY_TYPE: + key_type: + if (first) { + ret = do_key_type(hdata, text); + if (ret < 0) + goto error; + } + ret = start_new_row(hdata); + state = HIST_KEY_VALS; + break; + case STACKTRACE: + stacktrace: + if (first) { + ret = do_key_type(hdata, "stacktrace"); + if (ret < 0) + goto error; + } + ret = start_new_row(hdata); + state = HIST_STACK; + break; + case HITS: + hdata->hits = strtoll(text, NULL, 0); + state = HIST_ENTRIES; + break; + default: + goto error; + } + break; + case HIST_KEYS: + switch (type) { + case KEY_TYPE: + if (first) { + ret = do_key_type(hdata, text); + if (ret < 0) + goto error; + } + ret = start_new_key(hdata); + state = HIST_KEY_VALS; + break; + case STACKTRACE: + if (first) { + ret = do_key_type(hdata, "stacktrace"); + if (ret < 0) + goto error; + } + ret = start_new_key(hdata); + state = HIST_STACK; + break; + case NEWLINE: + break; + case COLON: + state = HIST_VALUES; + break; + default: + goto error; + } + break; + case HIST_NEXT_KEY: + switch (type) { + case COLON: + state = HIST_VALUES; + break; + case COMMA: + state = HIST_KEYS; + break; + default: + goto error; + } + break; + case HIST_KEY_VALS: + switch (type) { + case NEWLINE: + continue; + case START_RANGE: + start_range = strtoll(text, NULL, 0); + state = HIST_RANGE; + break; + case KEY_VAL: + ret = do_key_val(hdata, text); + if (ret < 0) + goto error; + break; + case RAW_VAL: + ret = do_key_raw(hdata, text); + if (ret < 0) + goto error; + state = HIST_NEXT_KEY; + break; + case COLON: + state = HIST_VALUES; + break; + case COMMA: + state = HIST_KEYS; + break; + default: + goto error; + } + break; + case HIST_STACK: + switch (type) { + case NEWLINE: + break; + case STACK_ITEM: + ret = do_key_stack(hdata, text); + if (ret < 0) + goto error; + break; + case STACK_MOD: + ret = do_key_stack_mod(hdata, text); + if (ret < 0) + goto error; + break; + case COLON: + state = HIST_VALUES; + break; + case COMMA: + state = HIST_KEYS; + break; + default: + goto error; + } + break; + case HIST_RANGE: + switch (type) { + case RANGE_LINEAR: + do_key_range(hdata, start_range, + strtoll(text, NULL, 0)); + break; + case RANGE_EXPONENT: + end_range = strtoll(text, NULL, 0); + e = (unsigned int)start_range; + start_range = expo(e, end_range - 1); + end_range = expo(e, end_range); + do_key_range(hdata, start_range, end_range); + break; + default: + goto error; + } + state = HIST_KEYS; + break; + case HIST_VALUES: + switch (type) { + case VALUE: + if (first) { + ret = do_value_type(hdata, text); + if (ret < 0) + goto error; + } + break; + case NUMBER: + ret = do_value_num(hdata, strtoll(text, NULL, 0)); + if (ret < 0) + goto error; + break; + case NEWLINE: + state = HIST_KEYS_START; + first = false; + break; + default: + goto error; + } + break; + case HIST_ENTRIES: + switch (type) { + case ENTRIES: + hdata->entries = strtoll(text, NULL, 0); + state = HIST_DROPPED; + break; + default: + goto error; + } + break; + case HIST_DROPPED: + switch (type) { + case DROPPED: + hdata->dropped = strtoll(text, NULL, 0); + state = HIST_END; + break; + default: + goto error; + } + break; + case HIST_END: + done = true; + switch (type) { + case COMMENT: + update_next(next_buffer, &data); + break; + case YYEOF: + /* Fall through */ + default: + /* Do at end, as next_buffer may point to buffer*/ + if (next_buffer) + *next_buffer = NULL; + break; + } + break; + } + } + + hist_lex_destroy(data.scanner); + free(data.text); + + return hdata; + error: + print_error(&data, err, state, type); + hist_lex_destroy(data.scanner); + free(data.text); + tracefs_hist_data_free(hdata); + return NULL; +} From patchwork Tue Aug 10 20:48:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 494662 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D0268C432BE for ; Tue, 10 Aug 2021 20:48:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BDCBE610A3 for ; Tue, 10 Aug 2021 20:48:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230295AbhHJUsw (ORCPT ); Tue, 10 Aug 2021 16:48:52 -0400 Received: from mail.kernel.org ([198.145.29.99]:44288 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232739AbhHJUss (ORCPT ); Tue, 10 Aug 2021 16:48:48 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 51CB261073; Tue, 10 Aug 2021 20:48:25 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mDYfg-003hA7-3t; Tue, 10 Aug 2021 16:48:24 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tom Zanussi , Daniel Bristot de Oliveira , Masami Hiramatsu , Namhyung Kim , linux-rt-users , Clark Williams , "Steven Rostedt (VMware)" Subject: [PATCH 2/9] libtracefs: Parse comment for hist data information Date: Tue, 10 Aug 2021 16:48:11 -0400 Message-Id: <20210810204818.880714-3-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210810204818.880714-1-rostedt@goodmis.org> References: <20210810204818.880714-1-rostedt@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-rt-users@vger.kernel.org From: "Steven Rostedt (VMware)" The comments at the top of a hist file for a trace event includes the string used to create the hist file. Parse it for the key names as well as for the key types. Signed-off-by: Steven Rostedt (VMware) --- src/tracefs-hist-data.c | 211 +++++++++++++++++++++++++++++++++++----- 1 file changed, 185 insertions(+), 26 deletions(-) diff --git a/src/tracefs-hist-data.c b/src/tracefs-hist-data.c index 497ab9ce97b4..6ec262e8b180 100644 --- a/src/tracefs-hist-data.c +++ b/src/tracefs-hist-data.c @@ -151,21 +151,26 @@ struct tracefs_hist_bucket { struct tracefs_hist_bucket_val **next_val; }; +struct key_types { + struct key_types *next; + enum tracefs_hist_key_type type; +}; + struct tracefs_hist_data { + char *hist_str; char **key_names; char **value_names; + struct key_types *key_types; + struct key_types **next_key_type; + struct key_types *current_key_type; struct tracefs_hist_bucket *buckets; struct tracefs_hist_bucket **next_bucket; unsigned long long hits; unsigned long long entries; unsigned long long dropped; + int current_key; }; -static int do_comment(struct tracefs_hist_data *hdata, const char *comment) -{ - return 0; -} - static int do_key_type(struct tracefs_hist_data *hdata, const char *key) { char **tmp; @@ -234,6 +239,23 @@ static int start_new_key(struct tracefs_hist_data *hdata) return 0; } +static int do_add_key_type(struct tracefs_hist_data *hdata, + enum tracefs_hist_key_type type) +{ + struct key_types *key_type; + + key_type = calloc(1, sizeof(*key_type)); + if (!key_type) + return -1; + + key_type->type = type; + + *hdata->next_key_type = key_type; + hdata->next_key_type = &key_type->next; + + return 0; +} + static char *chomp(char *text) { char *p; @@ -252,6 +274,100 @@ static char *chomp(char *text) return text; } +static int do_comment(struct tracefs_hist_data *hdata, char *comment) +{ + enum tracefs_hist_key_type key_type; + const char trigger_info[] = "trigger info: "; + const char hist[] = "hist:"; + const char keys[] = "keys="; + char *name; + int ret; + + comment = chomp(comment); + if (!comment) + return -1; + + if (!strcmp(comment, "event histogram")) + return 0; + + if (strncmp(comment, trigger_info, strlen(trigger_info)) != 0) + return 0; + + comment += strlen(trigger_info); + comment = chomp(comment); + + if (strncmp(comment, hist, strlen(hist)) != 0) + return -1; + + hdata->hist_str = strdup(comment); + if (!hdata->hist_str) + return -1; + + comment += strlen(hist); + + if (strncmp(comment, keys, strlen(keys)) != 0) + return -1; + comment += strlen(keys); + + name = comment; + + while (*comment) { + bool comma = false; + + if (*comment == ':') + break; + switch (*comment) { + case ',': + comma = true; + case '.': + *comment = '\0'; + do_key_type(hdata, name); + comment++; + if (comma) { + name = comment; + ret = do_add_key_type(hdata, 0); + if (ret < 0) + return -1; + continue; + } + if (!strncmp(comment, "hex", 3)) { + key_type = TRACEFS_HIST_KEY_HEX; + } else if (!strncmp(comment, "sym-offset", 10)) { + key_type = TRACEFS_HIST_KEY_SYM_OFFSET; + } else if (!strncmp(comment, "sym", 3)) { + key_type = TRACEFS_HIST_KEY_SYM; + } else if (!strncmp(comment, "syscall", 3)) { + key_type = TRACEFS_HIST_KEY_SYSCALL; + } else if (!strncmp(comment, "execname", 3)) { + key_type = TRACEFS_HIST_KEY_EXECNAME; + } else if (!strncmp(comment, "log2", 3)) { + key_type = TRACEFS_HIST_KEY_LOG; + } else if (!strncmp(comment, "usecs", 3)) { + key_type = TRACEFS_HIST_KEY_USECS; + } else { + key_type = 0; + } + + ret = do_add_key_type(hdata, key_type); + if (ret < 0) + return -1; + while (*comment) { + if (*comment == ',') { + comment++; + name = comment; + break; + } + if (*comment == ':') + break; + comment++; + } + continue; + } + comment++; + } + return 0; +} + static int __do_key_val(struct tracefs_hist_data *hdata, char *text, const char *delim, const char *end) { @@ -261,6 +377,9 @@ static int __do_key_val(struct tracefs_hist_data *hdata, char *val; int len; + if (!hdata->current_key_type) + return -1; + text = chomp(text); bucket = container_of(hdata->next_bucket, struct tracefs_hist_bucket, next); @@ -294,6 +413,16 @@ static int __do_key_val(struct tracefs_hist_data *hdata, k->sym = val; + switch (hdata->current_key_type->type) { + case TRACEFS_HIST_KEY_HEX: + k->val = strtoll(k->sym, NULL, 16); + break; + case TRACEFS_HIST_KEY_USECS: + k->val = strtoll(k->sym, NULL, 0); + default: + break; + } + return 0; } @@ -318,6 +447,9 @@ static int do_key_raw(struct tracefs_hist_data *hdata, char *text) struct tracefs_hist_bucket_key *key; struct tracefs_hist_bucket_key_single *k; + if (!hdata->current_key_type) + return -1; + text = chomp(text); bucket = container_of(hdata->next_bucket, struct tracefs_hist_bucket, next); @@ -331,7 +463,15 @@ static int do_key_raw(struct tracefs_hist_data *hdata, char *text) if (k->val) return -1; - k->val = strtoll(text, NULL, 0); + switch (hdata->current_key_type->type) { + case TRACEFS_HIST_KEY_SYM: + case TRACEFS_HIST_KEY_SYM_OFFSET: + k->val = strtoll(text, NULL, 16); + break; + default: + k->val = strtoll(text, NULL, 0); + break; + } return 0; } @@ -514,6 +654,27 @@ static void update_next(const char **next_buffer, struct hist_data *data) *next_buffer = find_buffer_line(data->buffer, data->line_no - 1); } +static int test_key(struct tracefs_hist_data *hdata, const char *key) +{ + if (tracefs_list_size(hdata->key_names) <= hdata->current_key) + return -1; + + return strcmp(key, hdata->key_names[hdata->current_key]) == 0 ? 0 : -1; +} + +static void reset_key_test(struct tracefs_hist_data *hdata) +{ + hdata->current_key = 0; + hdata->current_key_type = hdata->key_types; +} + +static void inc_key_test(struct tracefs_hist_data *hdata) +{ + hdata->current_key++; + if (hdata->current_key_type) + hdata->current_key_type = hdata->current_key_type->next; +} + /** * tracefs_hist_data_free - free a created hist data descriptor * @hdata: The tracefs_hist_data descriptor to free. @@ -529,6 +690,7 @@ void tracefs_hist_data_free(struct tracefs_hist_data *hdata) if (!hdata) return; + free(hdata->hist_str); tracefs_list_free(hdata->key_names); tracefs_list_free(hdata->value_names); @@ -605,6 +767,7 @@ tracefs_hist_data_parse(const char *buffer, const char **next_buffer, char **err return NULL; hdata->next_bucket = &hdata->buckets; + hdata->next_key_type = &hdata->key_types; memset(&data, 0, sizeof(data)); @@ -650,21 +813,19 @@ tracefs_hist_data_parse(const char *buffer, const char **next_buffer, char **err switch (type) { case KEY_TYPE: key_type: - if (first) { - ret = do_key_type(hdata, text); - if (ret < 0) - goto error; - } + reset_key_test(hdata); + ret = test_key(hdata, text); + if (ret < 0) + goto error; ret = start_new_row(hdata); state = HIST_KEY_VALS; break; case STACKTRACE: stacktrace: - if (first) { - ret = do_key_type(hdata, "stacktrace"); - if (ret < 0) - goto error; - } + reset_key_test(hdata); + ret = test_key(hdata, "stacktrace"); + if (ret < 0) + goto error; ret = start_new_row(hdata); state = HIST_STACK; break; @@ -679,20 +840,18 @@ tracefs_hist_data_parse(const char *buffer, const char **next_buffer, char **err case HIST_KEYS: switch (type) { case KEY_TYPE: - if (first) { - ret = do_key_type(hdata, text); - if (ret < 0) - goto error; - } + inc_key_test(hdata); + ret = test_key(hdata, text); + if (ret < 0) + goto error; ret = start_new_key(hdata); state = HIST_KEY_VALS; break; case STACKTRACE: - if (first) { - ret = do_key_type(hdata, "stacktrace"); - if (ret < 0) - goto error; - } + inc_key_test(hdata); + ret = test_key(hdata, "stacktrace"); + if (ret < 0) + goto error; ret = start_new_key(hdata); state = HIST_STACK; break; From patchwork Tue Aug 10 20:48:12 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 495522 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C8338C41537 for ; Tue, 10 Aug 2021 20:48:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A82CE6112E for ; Tue, 10 Aug 2021 20:48:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233445AbhHJUsu (ORCPT ); Tue, 10 Aug 2021 16:48:50 -0400 Received: from mail.kernel.org ([198.145.29.99]:44258 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231338AbhHJUsr (ORCPT ); Tue, 10 Aug 2021 16:48:47 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 4A8D361077; Tue, 10 Aug 2021 20:48:25 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mDYfg-003hA9-4u; Tue, 10 Aug 2021 16:48:24 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tom Zanussi , Daniel Bristot de Oliveira , Masami Hiramatsu , Namhyung Kim , linux-rt-users , Clark Williams , "Steven Rostedt (VMware)" Subject: [PATCH 3/9] libtracefs: Change hist_data_key type to flags Date: Tue, 10 Aug 2021 16:48:12 -0400 Message-Id: <20210810204818.880714-4-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210810204818.880714-1-rostedt@goodmis.org> References: <20210810204818.880714-1-rostedt@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-rt-users@vger.kernel.org From: "Steven Rostedt (VMware)" As the tracefs_hist_bucket_key will be exposed to users of the library, have the type be flags, where it can be modified in the future, and not break backward compatibility. Signed-off-by: Steven Rostedt (VMware) --- src/tracefs-hist-data.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/tracefs-hist-data.c b/src/tracefs-hist-data.c index 6ec262e8b180..c7e110559ee8 100644 --- a/src/tracefs-hist-data.c +++ b/src/tracefs-hist-data.c @@ -113,10 +113,10 @@ static char *name_token(enum yytokentype type) return NULL; } -enum tracefs_bucket_key_type { - TRACEFS_BUCKET_KEY_UNDEF, - TRACEFS_BUCKET_KEY_SINGLE, - TRACEFS_BUCKET_KEY_RANGE, +enum tracefs_bucket_key_flags { + TRACEFS_BUCKET_KEY_FL_UNDEF = (1 << 29), + TRACEFS_BUCKET_KEY_FL_SINGLE = (1 << 30), + TRACEFS_BUCKET_KEY_FL_RANGE = (1 << 31), }; struct tracefs_hist_bucket_key_single { @@ -131,7 +131,7 @@ struct tracefs_hist_bucket_key_range { struct tracefs_hist_bucket_key { struct tracefs_hist_bucket_key *next; - enum tracefs_bucket_key_type type; + unsigned int flags; union { struct tracefs_hist_bucket_key_single single; struct tracefs_hist_bucket_key_range range; @@ -210,6 +210,8 @@ static int start_new_row(struct tracefs_hist_data *hdata) return -1; } + key->flags = TRACEFS_BUCKET_KEY_FL_UNDEF; + bucket->keys = key; bucket->next_key = &key->next; @@ -233,6 +235,8 @@ static int start_new_key(struct tracefs_hist_data *hdata) return -1; } + key->flags = TRACEFS_BUCKET_KEY_FL_UNDEF; + *bucket->next_key = key; bucket->next_key = &key->next; @@ -385,12 +389,13 @@ static int __do_key_val(struct tracefs_hist_data *hdata, bucket = container_of(hdata->next_bucket, struct tracefs_hist_bucket, next); key = container_of(bucket->next_key, struct tracefs_hist_bucket_key, next); - if (!key->type) - key->type = TRACEFS_BUCKET_KEY_SINGLE; - - if (key->type != TRACEFS_BUCKET_KEY_SINGLE) + if (!(key->flags & + (TRACEFS_BUCKET_KEY_FL_UNDEF | TRACEFS_BUCKET_KEY_FL_SINGLE))) return -1; + key->flags &= ~TRACEFS_BUCKET_KEY_FL_UNDEF; + key->flags |= TRACEFS_BUCKET_KEY_FL_SINGLE; + k = &key->single; len = strlen(text); @@ -455,7 +460,7 @@ static int do_key_raw(struct tracefs_hist_data *hdata, char *text) bucket = container_of(hdata->next_bucket, struct tracefs_hist_bucket, next); key = container_of(bucket->next_key, struct tracefs_hist_bucket_key, next); - if (key->type != TRACEFS_BUCKET_KEY_SINGLE) + if (!(key->flags & TRACEFS_BUCKET_KEY_FL_SINGLE)) return -1; k = &key->single; @@ -487,12 +492,13 @@ static int do_key_range(struct tracefs_hist_data *hdata, long long start, key = container_of(bucket->next_key, struct tracefs_hist_bucket_key, next); - if (!key->type) - key->type = TRACEFS_BUCKET_KEY_RANGE; - - if (key->type != TRACEFS_BUCKET_KEY_RANGE) + if (!(key->flags & + (TRACEFS_BUCKET_KEY_FL_UNDEF | TRACEFS_BUCKET_KEY_FL_RANGE))) return -1; + key->flags &= ~TRACEFS_BUCKET_KEY_FL_UNDEF; + key->flags |= TRACEFS_BUCKET_KEY_FL_RANGE; + k = &key->range; k->start = start; @@ -698,13 +704,8 @@ void tracefs_hist_data_free(struct tracefs_hist_data *hdata) hdata->buckets = bucket->next; while ((key = bucket->keys)) { bucket->keys = key->next; - switch (key->type) { - case TRACEFS_BUCKET_KEY_SINGLE: + if (key->flags & TRACEFS_BUCKET_KEY_FL_SINGLE) free(key->single.sym); - break; - default: - break; - } free(key); } while ((val = bucket->vals)) { From patchwork Tue Aug 10 20:48:13 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 494661 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 585B0C4320E for ; Tue, 10 Aug 2021 20:48:33 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3966861101 for ; Tue, 10 Aug 2021 20:48:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233590AbhHJUsx (ORCPT ); Tue, 10 Aug 2021 16:48:53 -0400 Received: from mail.kernel.org ([198.145.29.99]:44284 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231894AbhHJUss (ORCPT ); Tue, 10 Aug 2021 16:48:48 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 679F7610CC; Tue, 10 Aug 2021 20:48:25 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mDYfg-003hAE-5n; Tue, 10 Aug 2021 16:48:24 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tom Zanussi , Daniel Bristot de Oliveira , Masami Hiramatsu , Namhyung Kim , linux-rt-users , Clark Williams , "Steven Rostedt (VMware)" Subject: [PATCH 4/9] libtracefs: Add API tracefs_hist_data_read() Date: Tue, 10 Aug 2021 16:48:13 -0400 Message-Id: <20210810204818.880714-5-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210810204818.880714-1-rostedt@goodmis.org> References: <20210810204818.880714-1-rostedt@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-rt-users@vger.kernel.org From: "Steven Rostedt (VMware)" Adds an API to read a "hist" file of a trace event and create a list of tracefs_hist_data descriptors for every histogram that exists in the "hist" file. Signed-off-by: Steven Rostedt (VMware) --- include/tracefs.h | 7 ++++ src/tracefs-hist-data.c | 74 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/include/tracefs.h b/include/tracefs.h index 6bd40d72cb25..f1e4ffa0d65f 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -418,7 +418,14 @@ struct tracefs_hist_data; struct tracefs_hist_data *tracefs_hist_data_parse(const char *buffer, const char **next_buffer, char **err); + +struct tracefs_hist_data **tracefs_hist_data_read(struct tracefs_instance *instance, + const char *system, + const char *event, + char **err); + void tracefs_hist_data_free(struct tracefs_hist_data *hdata); +void tracefs_hist_data_free_list(struct tracefs_hist_data **hdata_list); struct tracefs_synth; diff --git a/src/tracefs-hist-data.c b/src/tracefs-hist-data.c index c7e110559ee8..ab1ae824f59b 100644 --- a/src/tracefs-hist-data.c +++ b/src/tracefs-hist-data.c @@ -718,6 +718,24 @@ void tracefs_hist_data_free(struct tracefs_hist_data *hdata) free(hdata); } +/** + * tracefs_hist_data_free_list - frees a list of created hist data descriptors + * @hdata_list: The tracefs_hist_data descriptor list to free. + * + * Frees the data allocated by tracefs_hist_data_read(). + */ +void tracefs_hist_data_free_list(struct tracefs_hist_data **hdata_list) +{ + int i; + + if (!hdata_list) + return; + + for (i = 0; hdata_list[i]; i++) + tracefs_hist_data_free(hdata_list[i]); + free(hdata_list); +} + /* Used for debugging in gdb */ static void breakpoint(char *text) { @@ -1019,3 +1037,59 @@ tracefs_hist_data_parse(const char *buffer, const char **next_buffer, char **err tracefs_hist_data_free(hdata); return NULL; } + +/** + * tracefs_hist_data_read - Reads and parses the trace event "hist" file + * @instance: The instance the trace event is in (NULL for top level) + * @system: The system of the @event (NULL to pick first event) + * @event: The trace event name to read the hist file from + * @err: On parsing errors, @err will be set to a message explaining what failed. + * + * Reads the content of a trace @event hist file and parses it. + * + * Returns an array of tracefs_hist_data descriptors, as a hist file + * may contain more than one histogram. Must be freed with + * tracefs_hist_data_free_list(). + * + * Returns NULL on error, and if there was a parsing error, @err will contain + * a message explaining what failed. + */ +struct tracefs_hist_data ** +tracefs_hist_data_read(struct tracefs_instance *instance, + const char *system, const char *event, char **err) +{ + struct tracefs_hist_data **tmp, **hdata_list = NULL; + const char *buffer; + char *content; + int cnt = 0; + + if (err) + *err = NULL; + + content = tracefs_event_file_read(instance, system, event, "hist", NULL); + if (!content) + return NULL; + + buffer = content; + do { + tmp = realloc(hdata_list, sizeof(*tmp) * (cnt + 2)); + if (!tmp) + goto error; + tmp[cnt + 1] = NULL; + tmp[cnt] = tracefs_hist_data_parse(buffer, &buffer, err); + if (!tmp[cnt]) + goto error; + hdata_list = tmp; + if (buffer) + cnt++; + } while (buffer); + + free(content); + return hdata_list; + + error: + free(content); + tracefs_hist_data_free_list(hdata_list); + return NULL; +} + From patchwork Tue Aug 10 20:48:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 494664 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 13B88C4320A for ; Tue, 10 Aug 2021 20:48:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E47E16109E for ; Tue, 10 Aug 2021 20:48:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233080AbhHJUss (ORCPT ); Tue, 10 Aug 2021 16:48:48 -0400 Received: from mail.kernel.org ([198.145.29.99]:44240 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230181AbhHJUsr (ORCPT ); Tue, 10 Aug 2021 16:48:47 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 4471361058; Tue, 10 Aug 2021 20:48:25 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mDYfg-003hAH-6e; Tue, 10 Aug 2021 16:48:24 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tom Zanussi , Daniel Bristot de Oliveira , Masami Hiramatsu , Namhyung Kim , linux-rt-users , Clark Williams , "Steven Rostedt (VMware)" Subject: [PATCH 5/9] libtracefs: Add API tracefs_list_dup() Date: Tue, 10 Aug 2021 16:48:14 -0400 Message-Id: <20210810204818.880714-6-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210810204818.880714-1-rostedt@goodmis.org> References: <20210810204818.880714-1-rostedt@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-rt-users@vger.kernel.org From: "Steven Rostedt (VMware)" Add an API tracefs_list_dup() that will duplicate an existing list. Signed-off-by: Steven Rostedt (VMware) --- include/tracefs.h | 1 + src/tracefs-utils.c | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/include/tracefs.h b/include/tracefs.h index f1e4ffa0d65f..6fb66c44afc7 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -67,6 +67,7 @@ void tracefs_list_free(char **list); char **tracefs_list_add(char **list, const char *string); int tracefs_list_size(char **list); int tracefs_list_pop(char **list); +char **tracefs_list_dup(char **list); /** * tracefs_trace_on_get_fd - Get a file descriptor of "tracing_on" in given instance diff --git a/src/tracefs-utils.c b/src/tracefs-utils.c index 63bb413298fe..8c92d6c54ab1 100644 --- a/src/tracefs-utils.c +++ b/src/tracefs-utils.c @@ -489,3 +489,29 @@ int tracefs_list_size(char **list) list--; return (int)*(unsigned long *)list; } + +/** + * tracefs_list_dup - create a duplicate list + * @list: The list to duplicate + * + * Allocates a new list that can be modified and freed separately. + * + * Returns a new allocated list that must be freed with + * tracefs_list_free(), or NULL on error. + */ +char **tracefs_list_dup(char **list) +{ + char **new = NULL; + char **tmp; + int i; + + for (i = 0; list[i]; i++) { + tmp = tracefs_list_add(new, list[i]); + if (!tmp) { + free(new); + return NULL; + } + new = tmp; + } + return new; +} From patchwork Tue Aug 10 20:48:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 494663 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 90AABC04FE3 for ; Tue, 10 Aug 2021 20:48:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 73AEC610FD for ; Tue, 10 Aug 2021 20:48:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233498AbhHJUsv (ORCPT ); Tue, 10 Aug 2021 16:48:51 -0400 Received: from mail.kernel.org ([198.145.29.99]:44272 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231705AbhHJUsr (ORCPT ); Tue, 10 Aug 2021 16:48:47 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 54BA16108F; Tue, 10 Aug 2021 20:48:25 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mDYfg-003hAK-7R; Tue, 10 Aug 2021 16:48:24 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tom Zanussi , Daniel Bristot de Oliveira , Masami Hiramatsu , Namhyung Kim , linux-rt-users , Clark Williams , "Steven Rostedt (VMware)" Subject: [PATCH 6/9] libtracefs: Add APIs tracefs_hist_data_keys/value_names() Date: Tue, 10 Aug 2021 16:48:15 -0400 Message-Id: <20210810204818.880714-7-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210810204818.880714-1-rostedt@goodmis.org> References: <20210810204818.880714-1-rostedt@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-rt-users@vger.kernel.org From: "Steven Rostedt (VMware)" Add the APIs tracefs_hist_data_key_names() tracefs_hist_data_value_names() To get the names of the keys and values respectively. Signed-off-by: Steven Rostedt (VMware) --- include/tracefs.h | 3 +++ src/tracefs-hist-data.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/include/tracefs.h b/include/tracefs.h index 6fb66c44afc7..7aa6a3e5673a 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -428,6 +428,9 @@ struct tracefs_hist_data **tracefs_hist_data_read(struct tracefs_instance *insta void tracefs_hist_data_free(struct tracefs_hist_data *hdata); void tracefs_hist_data_free_list(struct tracefs_hist_data **hdata_list); +char **tracefs_hist_data_key_names(struct tracefs_hist_data *hdata); +char **tracefs_hist_data_value_names(struct tracefs_hist_data *hdata); + struct tracefs_synth; /* diff --git a/src/tracefs-hist-data.c b/src/tracefs-hist-data.c index ab1ae824f59b..c93c27453255 100644 --- a/src/tracefs-hist-data.c +++ b/src/tracefs-hist-data.c @@ -1093,3 +1093,33 @@ tracefs_hist_data_read(struct tracefs_instance *instance, return NULL; } +/** + * tracefs_hist_data_key_names - return key names + * @hdata: The hist data descriptor to get the names from + * + * Returns a copy of the key names of the keys. The list of keys + * will be in the same order as the keys are listed. + * Returns NULL on error. + * + * Must be freed with tracefs_list_free(); + */ +char **tracefs_hist_data_key_names(struct tracefs_hist_data *hdata) +{ + return tracefs_list_dup(hdata->key_names); +} + +/** + * tracefs_hist_data_value_names - return value names + * @hdata: The hist data descriptor to get the names from + * + * Returns a copy of the value names of the keys. The list of keys + * will be in the same order as the values are listed. + * Returns NULL on error. + * + * Must be freed with tracefs_list_free(); + */ +char **tracefs_hist_data_value_names(struct tracefs_hist_data *hdata) +{ + return tracefs_list_dup(hdata->value_names); +} + From patchwork Tue Aug 10 20:48:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 495521 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D89E4C3F6A3 for ; Tue, 10 Aug 2021 20:48:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AB77B6112E for ; Tue, 10 Aug 2021 20:48:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233529AbhHJUsx (ORCPT ); Tue, 10 Aug 2021 16:48:53 -0400 Received: from mail.kernel.org ([198.145.29.99]:44290 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232453AbhHJUss (ORCPT ); Tue, 10 Aug 2021 16:48:48 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 5494161078; Tue, 10 Aug 2021 20:48:25 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mDYfg-003hAN-8L; Tue, 10 Aug 2021 16:48:24 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tom Zanussi , Daniel Bristot de Oliveira , Masami Hiramatsu , Namhyung Kim , linux-rt-users , Clark Williams , "Steven Rostedt (VMware)" Subject: [PATCH 7/9] libtracefs: Add API tracefs_hist_data_keys/values() and next_bucket() Date: Tue, 10 Aug 2021 16:48:16 -0400 Message-Id: <20210810204818.880714-8-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210810204818.880714-1-rostedt@goodmis.org> References: <20210810204818.880714-1-rostedt@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-rt-users@vger.kernel.org From: "Steven Rostedt (VMware)" Add APIs: tracefs_hist_data_keys() tracefs_hist_data_values() tracefs_hist_data_next_bucket() tracefs_hist_data_first_bucket() Signed-off-by: Steven Rostedt (VMware) --- include/tracefs.h | 36 ++++++++++++++ src/tracefs-hist-data.c | 107 +++++++++++++++++++++++++++++----------- 2 files changed, 113 insertions(+), 30 deletions(-) diff --git a/include/tracefs.h b/include/tracefs.h index 7aa6a3e5673a..db0a1d73f091 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -431,6 +431,42 @@ void tracefs_hist_data_free_list(struct tracefs_hist_data **hdata_list); char **tracefs_hist_data_key_names(struct tracefs_hist_data *hdata); char **tracefs_hist_data_value_names(struct tracefs_hist_data *hdata); +enum tracefs_bucket_key_flags { + TRACEFS_BUCKET_KEY_FL_UNDEF = (1 << 29), + TRACEFS_BUCKET_KEY_FL_SINGLE = (1 << 30), + TRACEFS_BUCKET_KEY_FL_RANGE = (1 << 31), +}; + +struct tracefs_hist_bucket_key_single { + long long val; + char *sym; +}; + +struct tracefs_hist_bucket_key_range { + long long start; + long long end; +}; + +struct tracefs_hist_bucket_key { + struct tracefs_hist_bucket_key *next; + unsigned int flags; + union { + struct tracefs_hist_bucket_key_single single; + struct tracefs_hist_bucket_key_range range; + }; +}; + +struct tracefs_hist_bucket_val { + struct tracefs_hist_bucket_val *next; + long long val; +}; + +const struct tracefs_hist_bucket_key *tracefs_hist_data_keys(struct tracefs_hist_data *hdata); +const struct tracefs_hist_bucket_val *tracefs_hist_data_values(struct tracefs_hist_data *hdata); + +int tracefs_hist_data_next_bucket(struct tracefs_hist_data *hdata); +int tracefs_hist_data_first_bucket(struct tracefs_hist_data *hdata); + struct tracefs_synth; /* diff --git a/src/tracefs-hist-data.c b/src/tracefs-hist-data.c index c93c27453255..0f811d6e3154 100644 --- a/src/tracefs-hist-data.c +++ b/src/tracefs-hist-data.c @@ -113,36 +113,6 @@ static char *name_token(enum yytokentype type) return NULL; } -enum tracefs_bucket_key_flags { - TRACEFS_BUCKET_KEY_FL_UNDEF = (1 << 29), - TRACEFS_BUCKET_KEY_FL_SINGLE = (1 << 30), - TRACEFS_BUCKET_KEY_FL_RANGE = (1 << 31), -}; - -struct tracefs_hist_bucket_key_single { - long long val; - char *sym; -}; - -struct tracefs_hist_bucket_key_range { - long long start; - long long end; -}; - -struct tracefs_hist_bucket_key { - struct tracefs_hist_bucket_key *next; - unsigned int flags; - union { - struct tracefs_hist_bucket_key_single single; - struct tracefs_hist_bucket_key_range range; - }; -}; - -struct tracefs_hist_bucket_val { - struct tracefs_hist_bucket_val *next; - long long val; -}; - struct tracefs_hist_bucket { struct tracefs_hist_bucket *next; struct tracefs_hist_bucket_key *keys; @@ -165,6 +135,7 @@ struct tracefs_hist_data { struct key_types *current_key_type; struct tracefs_hist_bucket *buckets; struct tracefs_hist_bucket **next_bucket; + struct tracefs_hist_bucket *current_bucket; unsigned long long hits; unsigned long long entries; unsigned long long dropped; @@ -1029,6 +1000,9 @@ tracefs_hist_data_parse(const char *buffer, const char **next_buffer, char **err hist_lex_destroy(data.scanner); free(data.text); + /* Set to read the first bucket after creation */ + tracefs_hist_data_first_bucket(hdata); + return hdata; error: print_error(&data, err, state, type); @@ -1123,3 +1097,76 @@ char **tracefs_hist_data_value_names(struct tracefs_hist_data *hdata) return tracefs_list_dup(hdata->value_names); } +/** + * tracefs_hist_data_keys - Return the content of the keys + * @hdata: The hist data descriptor of the keys + * + * Returns the actual pointer to the key data list in the @hdata descriptor. + * It must not be modified or freed. + */ +const struct tracefs_hist_bucket_key * +tracefs_hist_data_keys(struct tracefs_hist_data *hdata) +{ + if (!hdata || !hdata->current_bucket) + return NULL; + + return hdata->current_bucket->keys; +} + +/** + * tracefs_hist_data_values - Return the content of the values + * @hdata: The hist data descriptor of the values + * + * Returns the actual pointer to the value data list in the @hdata descriptor. + * It must not be modified or freed. + */ +const struct tracefs_hist_bucket_val * +tracefs_hist_data_values(struct tracefs_hist_data *hdata) +{ + if (!hdata || !hdata->current_bucket) + return NULL; + + return hdata->current_bucket->vals; +} + +/** + * tracefs_hist_data_next_bucket - Move to the next bucket with content + * @hdata: The hist data desrciptor + * + * Move the "cursor" of the bucket that tracefs_hist_data_keys() + * and tracefs_hist_data_values() will return their data from. + * + * Returns -1 if @hdata is NULL or already hit the last bucket. + * Returns 0 if there's still data after going to the next bucket + * Returns 1 if there's no more data left. + */ +int tracefs_hist_data_next_bucket(struct tracefs_hist_data *hdata) +{ + if (!hdata || !hdata->current_bucket) + return -1; + + hdata->current_bucket = hdata->current_bucket->next; + + return !hdata->current_bucket; +} + +/** + * tracefs_hist_data_first_bucket - Reset to the first bucket + * @hdata: The hist data desrciptor + * + * Move the "cursor" of the bucket that tracefs_hist_data_keys() + * and tracefs_hist_data_values() will return their data from + * to the first bucket in the @hlist. + * + * Returns -1 if @hdata is NULL or already hit the last bucket. + * Returns 0 if there's still data after going to the next bucket + * Returns 1 if there's no more data left. + */ +int tracefs_hist_data_first_bucket(struct tracefs_hist_data *hdata) +{ + if (!hdata || !hdata->buckets) + return -1; + + hdata->current_bucket = hdata->buckets; + return !hdata->current_bucket; +} From patchwork Tue Aug 10 20:48:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 495519 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 72848C432BE for ; Tue, 10 Aug 2021 20:48:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5621B61075 for ; Tue, 10 Aug 2021 20:48:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233362AbhHJUsu (ORCPT ); Tue, 10 Aug 2021 16:48:50 -0400 Received: from mail.kernel.org ([198.145.29.99]:44260 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230419AbhHJUsr (ORCPT ); Tue, 10 Aug 2021 16:48:47 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 572876108C; Tue, 10 Aug 2021 20:48:25 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mDYfg-003hAQ-9N; Tue, 10 Aug 2021 16:48:24 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tom Zanussi , Daniel Bristot de Oliveira , Masami Hiramatsu , Namhyung Kim , linux-rt-users , Clark Williams , "Steven Rostedt (VMware)" Subject: [PATCH 8/9] libtracefs: Have tracefs_hist_bucket_key flags save the type Date: Tue, 10 Aug 2021 16:48:17 -0400 Message-Id: <20210810204818.880714-9-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210810204818.880714-1-rostedt@goodmis.org> References: <20210810204818.880714-1-rostedt@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-rt-users@vger.kernel.org From: "Steven Rostedt (VMware)" Add the key_type enum as a bit flag in the key->flags for tracefs_hist_bucket_key such that a user could know how to handle the type. Signed-off-by: Steven Rostedt (VMware) --- src/tracefs-hist-data.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tracefs-hist-data.c b/src/tracefs-hist-data.c index 0f811d6e3154..90c9cb2c7df8 100644 --- a/src/tracefs-hist-data.c +++ b/src/tracefs-hist-data.c @@ -399,6 +399,9 @@ static int __do_key_val(struct tracefs_hist_data *hdata, break; } + if (hdata->current_key_type->type < TRACEFS_HIST_KEY_MAX) + key->flags |= (1 << hdata->current_key_type->type); + return 0; } From patchwork Tue Aug 10 20:48:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 494660 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-21.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, MENTIONS_GIT_HOSTING, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 60C72C4320A for ; Tue, 10 Aug 2021 20:48:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 40180610A8 for ; Tue, 10 Aug 2021 20:48:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233527AbhHJUs4 (ORCPT ); Tue, 10 Aug 2021 16:48:56 -0400 Received: from mail.kernel.org ([198.145.29.99]:44292 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232783AbhHJUss (ORCPT ); Tue, 10 Aug 2021 16:48:48 -0400 Received: from gandalf.local.home (cpe-66-24-58-225.stny.res.rr.com [66.24.58.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 473D861052; Tue, 10 Aug 2021 20:48:25 +0000 (UTC) Received: from rostedt by gandalf.local.home with local (Exim 4.94.2) (envelope-from ) id 1mDYfg-003hAT-AF; Tue, 10 Aug 2021 16:48:24 -0400 From: Steven Rostedt To: linux-trace-devel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Tom Zanussi , Daniel Bristot de Oliveira , Masami Hiramatsu , Namhyung Kim , linux-rt-users , Clark Williams , "Steven Rostedt (VMware)" Subject: [PATCH 9/9] libtracefs: Add man pages for tracefs_hist_data functions Date: Tue, 10 Aug 2021 16:48:18 -0400 Message-Id: <20210810204818.880714-10-rostedt@goodmis.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210810204818.880714-1-rostedt@goodmis.org> References: <20210810204818.880714-1-rostedt@goodmis.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-rt-users@vger.kernel.org From: "Steven Rostedt (VMware)" Add man pages for: tracefs_hist_data_parse() tracefs_hist_data_read() tracefs_hist_data_free() tracefs_hist_data_free_list() tracefs_hist_data_key_names() tracefs_hist_data_value_names() tracefs_hist_data_keys() tracefs_hist_data_values() tracefs_hist_data_next_bucket() tracefs_hist_data_first_bucket() Signed-off-by: Steven Rostedt (VMware) --- Documentation/libtracefs-hist-data-2.txt | 346 +++++++++++++++++++++++ Documentation/libtracefs-hist-data.txt | 294 +++++++++++++++++++ 2 files changed, 640 insertions(+) create mode 100644 Documentation/libtracefs-hist-data-2.txt create mode 100644 Documentation/libtracefs-hist-data.txt diff --git a/Documentation/libtracefs-hist-data-2.txt b/Documentation/libtracefs-hist-data-2.txt new file mode 100644 index 000000000000..c5b11aaa650a --- /dev/null +++ b/Documentation/libtracefs-hist-data-2.txt @@ -0,0 +1,346 @@ +libtracefs(3) +============= + +NAME +---- +tracefs_hist_data_key_names, tracefs_hist_data_key_values, tracefs_hist_data_keys, tracefs_hist_data_values, +tracefs_hist_data_next_bucket, tracefs_hist_data_first_bucket - Read an allocated tracefs_hist_data descriptor + +SYNOPSIS +-------- +[verse] +-- +*#include * + + +char pass:[**]tracefs_hist_data_key_names(struct tracefs_hist_data pass:[*]hdata); +char pass:[**]tracefs_hist_data_value_names(struct tracefs_hist_data pass:[*]hdata); + +const struct tracefs_hist_bucket_key pass:[*]tracefs_hist_data_keys(struct tracefs_hist_data pass:[*]hdata); +const struct tracefs_hist_bucket_val pass:[*]tracefs_hist_data_values(struct tracefs_hist_data pass:[*]hdata); + +int tracefs_hist_data_next_bucket(struct tracefs_hist_data pass:[*]hdata); +int tracefs_hist_data_first_bucket(struct tracefs_hist_data pass:[*]hdata); +-- + +DESCRIPTION +----------- +The _hist_ trigger for trace events will create a histogram that can be read in +the trace event's _hist_ file. The file is human readable ASCII format, but that +makes it difficult to process in programs. The *tracefs_hist_data_*pass:[*]() +functions convert the histogram ASCII format into structures that can be processed +and converted into tables. + +*tracefs_hist_data_key_names*() Returns an allocated list of strings containing the +names of the keys in the order that they are saved in the list returned by +*tracefs_hist_data_keys*(3). The _hdata_ is a _tracefs_hist_data_ descriptor that +was created by either *tracefs_hist_data_parse*(3) or tracefs_hist_data_read*(3). + +*tracefs_hist_data_value_names*() Returns an allocated list of strings containing the +names of the values in the order that they are saved in the list returned by +*tracefs_hist_data_values*(3). The _hdata_ is a _tracefs_hist_data_ descriptor that +was created by either *tracefs_hist_data_parse*(3) or *tracefs_hist_data_read*(3). + +*tracefs_hist_data_keys*() returns a link list of _tracefs_hist_data_bucket_key_ +descriptors that contain the content of the keys of the current bucket. Each key +has its own descriptor, and the _key_->next will link to the next descriptor. The +returned link list is an actual internal construct of the _tracefs_hist_data_ +and must not be modified or freed. + +*tracefs_hist_data_values*() returns a link list of _tracefs_hist_data_bucket_val_ +descriptors that contain the content of the values of the current bucket. Each value +has its own descriptor, and the _value_->next will link to the next descriptor. The +returned link list is an actual internal construct of the _tracefs_hist_data_ +and must not be modified or freed. + +After the _tracefs_hist_data_ has been created, it will keep track of the internal +bucket, and this is not reentrant, so care must be taken when using with threads. +The *tracefs_hist_data_keys*() or *tracefs_hist_data_values*() will return the list +of keys or values respectively for the current bucket. + +*tracefs_hist_data_next_bucket*() will move the internal cursor of the _tracefs_hist_data_ +to the next bucket, where following this call, *tracefs_hist_data_keys*() and +*tracefs_hist_data_values*() will return the keys and values from the new bucket. + +*tracefs_hist_data_first_bucket*() will reset the index such that following calls +to *tracefs_hist_data_keys*() or tracefs_hist_data_values*() will return the link +list of keys or values for the first bucket, and the list can be traversed again +with *tracefs_hist_data_next_bucket*(). + +RETURN VALUE +------------ +*tracefs_hist_data_key_names*() on success, returns an allocated list of the names of the +keys in _hdata_ and must be freed with *tracefs_list_free*(3). Returns NULL +on failure. + +*tracefs_hist_data_value_names*() on success, returns an allocated list of the names of the +values in _hdata_ and must be freed with *tracefs_list_free*(3). Returns NULL +on failure. + +*tracefs_hist_data_keys*() on success, returns a link list of _tracefs_hist_bucket_key_ descriptors. +Returns NULL on error. + +struct tracefs_hist_bucket_key { + struct tracefs_hist_bucket_key *next; + unsigned int flags; + union { + struct tracefs_hist_bucket_key_single single; + struct tracefs_hist_bucket_key_range range; + }; +}; + +To traverse to the next key in the list, use the _key_->next, where the last key will have +its _next_ pointer be NULL. + +If the flag TRACEFS_BUCKET_KEY_FL_SINGLE is set, then the "single" union structure should +be used, otherwise the TRACEFS_BUCKET_KEY_FL_RANGE bit should be set. + +The other lower bits map to the type of the key, defined by the _tracefs_hist_key_type_ enum. + +struct tracefs_hist_bucket_key_single { + long long val; + char *sym; +}; + +Depending on the flags set, _val_ may be the integer representation of the _sym_. +See the EXAMPLE below. + +struct tracefs_hist_bucket_key_range { + long long start; + long long end; +}; + +If the key is a range, then the tracefs_hist_bucket_key_range should be used +to get the _start_ and _end_ values of that range inclusive. + +*tracefs_hist_data_next_bucket*() Returns -1 on error, 0 on succes and the +cursor is pointing to the next bucket to read from, or 1 on success but there +are on more buckets to read. + +*tracefs_hist_data_first_bucket*() Returns -1 on error, 0 on succes and the +cursor is pointing to the next bucket to read from, or 1 on success but there +are on more buckets to read. + +EXAMPLE +------- +[source,c] +-- +#include +#include +#include + +int main (int argc, char **argv) +{ + struct tracefs_hist_data *hdata; + const struct tracefs_hist_bucket_key *key; + const struct tracefs_hist_bucket_val *val; + char buf[BUFSIZ]; + const char *buffer; + char *content = NULL; + char *file; + char *err; + char **key_names; + char **value_names; + int key_idx; + int val_idx; + FILE *fp; + size_t r; + bool done = false; + int buffer_size = 0; + int c; + int i; + + for (;;) { + c = getopt(argc, argv, "hf:"); + if (c == -1) + break; + + switch(c) { + case 'h': + fprintf(stderr, "usage: %s [-f file]\n", argv[0]); + exit(0); + case 'f': + file = optarg; + break; + } + } + + if (file) { + if (!strcmp(file, "-")) + fp = stdin; + else + fp = fopen(file, "r"); + if (!fp) { + perror(file); + exit(-1); + } + while ((r = fread(buf, 1, BUFSIZ, fp)) > 0) { + content = realloc(content, buffer_size + r + 1); + strncpy(content + buffer_size, buf, r); + buffer_size += r; + } + fclose(fp); + if (buffer_size) + content[buffer_size] = '\0'; + } else if (argc == optind) { + fprintf(stderr, "usage: %s [-f file]\n", argv[0]); + exit(-1); + } else { + for (i = optind; i < argc; i++) { + r = strlen(argv[i]); + content = realloc(content, buffer_size + r + 2); + if (i != optind) + content[buffer_size++] = ' '; + strcpy(content + buffer_size, argv[i]); + buffer_size += r; + } + } + + buffer = content; + hdata = tracefs_hist_data_parse(buffer, &buffer, &err); + printf("hdata = %p\n", hdata); + if (!hdata && err) { + printf("%s\n", err); + exit(-1); + } + + key_names = tracefs_hist_data_key_names(hdata); + if (!key_names) { + perror("key_names"); + exit(-1); + } + + value_names = tracefs_hist_data_value_names(hdata); + if (!value_names) { + perror("value_names"); + exit(-1); + } + + do { + bool first = true; + key = tracefs_hist_data_keys(hdata); + val = tracefs_hist_data_values(hdata); + key_idx = 0; + val_idx = 0; + + if (!key || !val) { + perror("keys or vals"); + exit(-1); + } + + while (key) { + if (!first) + printf(","); + first = false; + if (key_names[key_idx]) + printf("%s:", key_names[key_idx++]); + else + printf("(\?\?):"); + if (key->flags & TRACEFS_BUCKET_KEY_FL_UNDEF) { + fprintf(stderr, "bad key type?"); + exit (-1); + } else if (key->flags & TRACEFS_BUCKET_KEY_FL_SINGLE) { + + if (key->flags & + ((1 << TRACEFS_HIST_KEY_SYM) | + (1 << TRACEFS_HIST_KEY_SYM_OFFSET) | + (1 << TRACEFS_HIST_KEY_SYSCALL) | + (1 << TRACEFS_HIST_KEY_EXECNAME))) + printf("%s [ %lld ]", + key->single.sym, + key->single.val); + else + printf("%s", key->single.sym); + + } else if (key->flags & TRACEFS_BUCKET_KEY_FL_RANGE) + printf("%lld - %lld", + key->range.start, + key->range.end); + key = key->next; + } + printf(":"); + first = true; + while (val) { + if (!first) + printf(","); + first = false; + if (value_names[val_idx]) + printf("%s:", value_names[val_idx++]); + else + printf("(\?\?):"); + printf("%lld", val->val); + val = val->next; + } + printf("\n"); + if (tracefs_hist_data_next_bucket(hdata)) + done = true; + } while (!done); + + tracefs_list_free(key_names); + tracefs_list_free(value_names); + tracefs_hist_data_free(hdata); + + return 0; +} +-- + +BUGS +---- +There are some known values that the histograms can produce that will break +the parsing. Those are any string value that contains a comma (,) or a +colon (:) may cause the parse to misinterpret the parsing and fail to parse. +This may be fixed in the future. + +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)_, +_tracefs_hist_data_parse(3)_ +_tracefs_hist_data_read(3)_ +_tracefs_hist_data_free(3)_ +_tracefs_hist_data_free_list(3)_ +_tracefs_hist_alloc(3)_, +_tracefs_hist_free(3)_, +_tracefs_hist_add_key(3)_, +_tracefs_hist_add_value(3)_, +_tracefs_hist_add_name(3)_, +_tracefs_hist_start(3)_, +_tracefs_hist_destory(3)_, +_tracefs_hist_add_sort_key(3)_, +_tracefs_hist_sort_key_direction(3)_ + +AUTHOR +------ +[verse] +-- +*Steven Rostedt* +*Tzvetomir Stoyanov* +*sameeruddin shaik* +-- +REPORTING BUGS +-------------- +Report bugs to + +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-hist-data.txt b/Documentation/libtracefs-hist-data.txt new file mode 100644 index 000000000000..1890eabb7cd1 --- /dev/null +++ b/Documentation/libtracefs-hist-data.txt @@ -0,0 +1,294 @@ +libtracefs(3) +============= + +NAME +---- +tracefs_hist_data_parse, tracefs_hist_data_read, tracefs_hist_data_free, tracefs_hist_data_free_list - Read and parse hist format files + +SYNOPSIS +-------- +[verse] +-- +*#include * + +struct tracefs_hist_data pass:[*]tracefs_hist_data_parse(const char pass:[*]buffer, + const char pass:[**]next_buffer, + char pass:[**]err); + +struct tracefs_hist_data pass:[**]tracefs_hist_data_read(struct tracefs_instance pass:[*]instance, + const char pass:[*]system, + const char pass:[*]event, + char pass:[**]err); + +void tracefs_hist_data_free(struct tracefs_hist_data pass:[*]hdata); +void tracefs_hist_data_free_list(struct tracefs_hist_data pass:[**]hdata_list); +-- + +DESCRIPTION +----------- +The _hist_ trigger for trace events will create a histogram that can be read in +the trace event's _hist_ file. The file is human readable ASCII format, but that +makes it difficult to process in programs. The *tracefs_hist_data_*pass:[*]() +functions convert the histogram ASCII format into structures that can be processed +and converted into tables. + +*tracefs_hist_data_parse*() will read a string buffer that contains the contents +of a trace_event hist file in _buffer_, and allocate and create a _tracefs_hist_data_ +descriptor. If there are more than one histograms in _buffer_, and _next_buffer_ is +not NULL, it will then be set to the location of _buffer_ that contains the next +histogram. _next_buffer_ may be a pointer to _buffer_ as it will not be updated +until after the histogram is fully parsed. The _tracefs_trace_data_ returned must +be freed with *tracefs_hist_data_free*(). + +*tracefs_hist_data_read*() will read the "hist" file of the given trace event +that is located in the _instance_ directory or the top level directory if _instance_ is NULL. +The trace event is found with the _system_ and _event_ names, where _system_ can be +NULL, and the first trace event with _event_ as its name will be used. +It returns an array of _tracefs_hist_data_ structures or NULL on error. The +array ends with a pointer to NULL. The reason for the array is because _hist_ files +may contain more than one histogram, and this will return an array that has all the +histograms in the _hist_ file parsed. The array can be freed with *tracefs_hist_data_free_list*() +or each individual _tracefs_hist_data_ may be freed with *tracefs_hist_data_free*() and the +array itself freed with *free*(). + +*tracefs_hist_data_free*() frees a _tracefs_hist_data_ descriptor that was created +with *tracefs_hist_data_parse*(). + +*tracefs_hist_data_free_list*() frees an array of _tracefs_hist_data_ descriptors that was created +with *tracefs_hist_data_read*(). + +RETURN VALUE +------------ +*tracefs_hist_data_parse*() returns an allocated _tracefs_hist_data_ descriptor. Or +NULL on error, and if it was a parsing error and _err_ is not NULL, it will be set to +an allocated string describing the error. _err_ must be freed with *free*(). + +*tracefs_hist_data_read*() returns an allocated array of allocated _tracefs_hist_data_ +descriptors. Or NULL on error, and if it was a parsing error and _err_ is not NULL, +it will be set to an allocated string describing the error. _err_ must be freed with *free*(). + +EXAMPLE +------- +[source,c] +-- +#include +#include +#include + +int main (int argc, char **argv) +{ + struct tracefs_hist_data *hdata; + const struct tracefs_hist_bucket_key *key; + const struct tracefs_hist_bucket_val *val; + char buf[BUFSIZ]; + const char *buffer; + char *content = NULL; + char *file; + char *err; + char **key_names; + char **value_names; + int key_idx; + int val_idx; + FILE *fp; + size_t r; + bool done = false; + int buffer_size = 0; + int c; + int i; + + for (;;) { + c = getopt(argc, argv, "hf:"); + if (c == -1) + break; + + switch(c) { + case 'h': + fprintf(stderr, "usage: %s [-f file]\n", argv[0]); + exit(0); + case 'f': + file = optarg; + break; + } + } + + if (file) { + if (!strcmp(file, "-")) + fp = stdin; + else + fp = fopen(file, "r"); + if (!fp) { + perror(file); + exit(-1); + } + while ((r = fread(buf, 1, BUFSIZ, fp)) > 0) { + content = realloc(content, buffer_size + r + 1); + strncpy(content + buffer_size, buf, r); + buffer_size += r; + } + fclose(fp); + if (buffer_size) + content[buffer_size] = '\0'; + } else if (argc == optind) { + fprintf(stderr, "usage: %s [-f file]\n", argv[0]); + exit(-1); + } else { + for (i = optind; i < argc; i++) { + r = strlen(argv[i]); + content = realloc(content, buffer_size + r + 2); + if (i != optind) + content[buffer_size++] = ' '; + strcpy(content + buffer_size, argv[i]); + buffer_size += r; + } + } + + buffer = content; + hdata = tracefs_hist_data_parse(buffer, &buffer, &err); + printf("hdata = %p\n", hdata); + if (!hdata && err) { + printf("%s\n", err); + exit(-1); + } + + key_names = tracefs_hist_data_key_names(hdata); + if (!key_names) { + perror("key_names"); + exit(-1); + } + + value_names = tracefs_hist_data_value_names(hdata); + if (!value_names) { + perror("value_names"); + exit(-1); + } + + do { + bool first = true; + key = tracefs_hist_data_keys(hdata); + val = tracefs_hist_data_values(hdata); + key_idx = 0; + val_idx = 0; + + if (!key || !val) { + perror("keys or vals"); + exit(-1); + } + + while (key) { + if (!first) + printf(","); + first = false; + if (key_names[key_idx]) + printf("%s:", key_names[key_idx++]); + else + printf("(\?\?):"); + if (key->flags & TRACEFS_BUCKET_KEY_FL_UNDEF) { + fprintf(stderr, "bad key type?"); + exit (-1); + } else if (key->flags & TRACEFS_BUCKET_KEY_FL_SINGLE) { + + if (key->flags & + ((1 << TRACEFS_HIST_KEY_SYM) | + (1 << TRACEFS_HIST_KEY_SYM_OFFSET) | + (1 << TRACEFS_HIST_KEY_SYSCALL) | + (1 << TRACEFS_HIST_KEY_EXECNAME))) + printf("%s [ %lld ]", + key->single.sym, + key->single.val); + else + printf("%s", key->single.sym); + + } else if (key->flags & TRACEFS_BUCKET_KEY_FL_RANGE) + printf("%lld - %lld", + key->range.start, + key->range.end); + key = key->next; + } + printf(":"); + first = true; + while (val) { + if (!first) + printf(","); + first = false; + if (value_names[val_idx]) + printf("%s:", value_names[val_idx++]); + else + printf("(\?\?):"); + printf("%lld", val->val); + val = val->next; + } + printf("\n"); + if (tracefs_hist_data_next_bucket(hdata)) + done = true; + } while (!done); + + tracefs_list_free(key_names); + tracefs_list_free(value_names); + tracefs_hist_data_free(hdata); + + return 0; +} +-- + +BUGS +---- +There are some known values that the histograms can produce that will break +the parsing. Those are any string value that contains a comma (,) or a +colon (:) may cause the parse to misinterpret the parsing and fail to parse. +This may be fixed in the future. + +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)_, +_tracefs_hist_data_key_names(3)_ +_tracefs_hist_data_value_names(3)_ +_tracefs_hist_data_keys(3)_ +_tracefs_hist_data_values(3)_ +_tracefs_hist_data_next_bucket(3)_ +_tracefs_hist_data_first_bucket(3)_ +_tracefs_hist_alloc(3)_, +_tracefs_hist_free(3)_, +_tracefs_hist_add_key(3)_, +_tracefs_hist_add_value(3)_, +_tracefs_hist_add_name(3)_, +_tracefs_hist_start(3)_, +_tracefs_hist_destory(3)_, +_tracefs_hist_add_sort_key(3)_, +_tracefs_hist_sort_key_direction(3)_ + +AUTHOR +------ +[verse] +-- +*Steven Rostedt* +*Tzvetomir Stoyanov* +*sameeruddin shaik* +-- +REPORTING BUGS +-------------- +Report bugs to + +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).