From: "Steven Rostedt (VMware)" <rostedt@xxxxxxxxxxx> 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) <rostedt@xxxxxxxxxxx> --- 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; -- 2.30.2