@@ -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;