diff options
Diffstat (limited to 'src/tracefs-hist.c')
-rw-r--r-- | src/tracefs-hist.c | 225 |
1 files changed, 182 insertions, 43 deletions
diff --git a/src/tracefs-hist.c b/src/tracefs-hist.c index e688eb3..fb6231e 100644 --- a/src/tracefs-hist.c +++ b/src/tracefs-hist.c @@ -280,25 +280,11 @@ tracefs_hist_alloc_2d(struct tep_handle *tep, return tracefs_hist_alloc_nd(tep, system, event_name, axis); } -/** - * tracefs_hist_alloc_nd - Initialize N-dimensional histogram - * @tep: The tep handle that has the @system and @event. - * @system: The system the histogram event is in - * @event: The event that the histogram will be attached to - * @axes: An array of histogram axes, terminated by a {NULL, 0} entry - * - * Will initialize a histogram descriptor that will be attached to - * the @system/@event. This only initializes the descriptor with the given - * @axes keys as primaries. This only initializes the descriptor, it does - * not start the histogram in the kernel. - * - * Returns an initialized histogram on success. - * NULL on failure. - */ -struct tracefs_hist * -tracefs_hist_alloc_nd(struct tep_handle *tep, - const char *system, const char *event_name, - struct tracefs_hist_axis *axes) +static struct tracefs_hist * +hist_alloc_nd(struct tep_handle *tep, + const char *system, const char *event_name, + struct tracefs_hist_axis *axes, + struct tracefs_hist_axis_cnt *axes_cnt) { struct tep_event *event; struct tracefs_hist *hist; @@ -326,25 +312,75 @@ tracefs_hist_alloc_nd(struct tep_handle *tep, if (tracefs_hist_add_key(hist, axes->key, axes->type) < 0) goto fail; + for (; axes_cnt && axes_cnt->key; axes_cnt++) + if (tracefs_hist_add_key_cnt(hist, axes_cnt->key, axes_cnt->type, axes_cnt->cnt) < 0) + goto fail; + return hist; fail: tracefs_hist_free(hist); return NULL; } +/** + * tracefs_hist_alloc_nd - Initialize N-dimensional histogram + * @tep: The tep handle that has the @system and @event. + * @system: The system the histogram event is in + * @event: The event that the histogram will be attached to + * @axes: An array of histogram axes, terminated by a {NULL, 0} entry + * + * Will initialize a histogram descriptor that will be attached to + * the @system/@event. This only initializes the descriptor with the given + * @axes keys as primaries. This only initializes the descriptor, it does + * not start the histogram in the kernel. + * + * Returns an initialized histogram on success. + * NULL on failure. + */ +struct tracefs_hist * +tracefs_hist_alloc_nd(struct tep_handle *tep, + const char *system, const char *event_name, + struct tracefs_hist_axis *axes) +{ + return hist_alloc_nd(tep, system, event_name, axes, NULL); +} + +/** + * tracefs_hist_alloc_nd_cnt - Initialize N-dimensional histogram + * @tep: The tep handle that has the @system and @event. + * @system: The system the histogram event is in + * @event: The event that the histogram will be attached to + * @axes: An array of histogram axes, terminated by a {NULL, 0} entry + * + * Will initialize a histogram descriptor that will be attached to + * the @system/@event. This only initializes the descriptor with the given + * @axes keys as primaries. This only initializes the descriptor, it does + * not start the histogram in the kernel. + * + * Returns an initialized histogram on success. + * NULL on failure. + */ +struct tracefs_hist * +tracefs_hist_alloc_nd_cnt(struct tep_handle *tep, + const char *system, const char *event_name, + struct tracefs_hist_axis_cnt *axes) +{ + return hist_alloc_nd(tep, system, event_name, NULL, axes); +} /** * tracefs_hist_add_key - add to a key to a histogram * @hist: The histogram to add the key to. * @key: The name of the key field. * @type: The type of the key format. + * @cnt: Some types require a counter, for those, this is used * * This adds a secondary or tertiary key to the histogram. * * Returns 0 on success, -1 on error. */ -int tracefs_hist_add_key(struct tracefs_hist *hist, const char *key, - enum tracefs_hist_key_type type) +int tracefs_hist_add_key_cnt(struct tracefs_hist *hist, const char *key, + enum tracefs_hist_key_type type, int cnt) { bool use_key = false; char *key_type = NULL; @@ -377,6 +413,9 @@ int tracefs_hist_add_key(struct tracefs_hist *hist, const char *key, case TRACEFS_HIST_KEY_USECS: ret = asprintf(&key_type, "%s.usecs", key); break; + case TRACEFS_HIST_KEY_BUCKETS: + ret = asprintf(&key_type, "%s.buckets=%d", key, cnt); + break; case TRACEFS_HIST_KEY_MAX: /* error */ break; @@ -396,6 +435,22 @@ int tracefs_hist_add_key(struct tracefs_hist *hist, const char *key, } /** + * tracefs_hist_add_key - add to a key to a histogram + * @hist: The histogram to add the key to. + * @key: The name of the key field. + * @type: The type of the key format. + * + * This adds a secondary or tertiary key to the histogram. + * + * Returns 0 on success, -1 on error. + */ +int tracefs_hist_add_key(struct tracefs_hist *hist, const char *key, + enum tracefs_hist_key_type type) +{ + return tracefs_hist_add_key_cnt(hist, key, type, 0); +} + +/** * tracefs_hist_add_value - add to a value to a histogram * @hist: The histogram to add the value to. * @key: The name of the value field. @@ -654,6 +709,12 @@ struct action { char *save; }; +struct name_hash { + struct name_hash *next; + char *name; + char *hash; +}; + /* * @name: name of the synthetic event * @start_system: system of the starting event @@ -684,6 +745,7 @@ struct tracefs_synth { struct action *actions; struct action **next_action; struct tracefs_dynevent *dyn_event; + struct name_hash *name_hash[1 << HASH_BITS]; char *start_hist; char *end_hist; char *name; @@ -724,6 +786,21 @@ static void action_free(struct action *action) free(action); } +static void free_name_hash(struct name_hash **hash) +{ + struct name_hash *item; + int i; + + for (i = 0; i < 1 << HASH_BITS; i++) { + while ((item = hash[i])) { + hash[i] = item->next; + free(item->name); + free(item->hash); + free(item); + } + } +} + /** * tracefs_synth_free - free the resources alloced to a synth * @synth: The tracefs_synth descriptor @@ -750,6 +827,7 @@ void tracefs_synth_free(struct tracefs_synth *synth) tracefs_list_free(synth->end_keys); tracefs_list_free(synth->start_vars); tracefs_list_free(synth->end_vars); + free_name_hash(synth->name_hash); free(synth->start_filter); free(synth->end_filter); free(synth->start_type); @@ -773,6 +851,7 @@ static bool verify_event_fields(struct tep_event *start_event, { const struct tep_format_field *start_field; const struct tep_format_field *end_field; + int start_flags, end_flags; if (!trace_verify_event_field(start_event, start_field_name, &start_field)) @@ -783,7 +862,11 @@ static bool verify_event_fields(struct tep_event *start_event, &end_field)) return false; - if (start_field->flags != end_field->flags || + /* A pointer can still match a long */ + start_flags = start_field->flags & ~TEP_FIELD_IS_POINTER; + end_flags = end_field->flags & ~TEP_FIELD_IS_POINTER; + + if (start_flags != end_flags || start_field->size != end_field->size) { errno = EBADE; return false; @@ -1068,9 +1151,8 @@ struct tracefs_synth *tracefs_synth_alloc(struct tep_handle *tep, if (!synth->name || !synth->start_keys || !synth->end_keys || ret) { tracefs_synth_free(synth); synth = NULL; - } - - synth->new_format = has_new_format(); + } else + synth->new_format = has_new_format(); return synth; } @@ -1096,7 +1178,7 @@ static int add_synth_fields(struct tracefs_synth *synth, return -1; synth->synthetic_fields = list; - ret = asprintf(&str, "$%s", name); + ret = asprintf(&str, "$%s", var ? : name); if (ret < 0) { trace_list_pop(synth->synthetic_fields); return -1; @@ -1196,7 +1278,7 @@ static unsigned int make_rand(void) return((unsigned)(seed/65536) % 32768); } -static char *new_arg(struct tracefs_synth *synth) +static char *new_name(struct tracefs_synth *synth, const char *name) { int cnt = synth->arg_cnt + 1; char *arg; @@ -1205,9 +1287,9 @@ static char *new_arg(struct tracefs_synth *synth) /* Create a unique argument name */ if (!synth->arg_name[0]) { /* make_rand() returns at most 32768 (total 13 bytes in use) */ - sprintf(synth->arg_name, "__arg_%u_", make_rand()); + sprintf(synth->arg_name, "%u", make_rand()); } - ret = asprintf(&arg, "%s%d", synth->arg_name, cnt); + ret = asprintf(&arg, "__%s_%s_%d", name, synth->arg_name, cnt); if (ret < 0) return NULL; @@ -1215,6 +1297,55 @@ static char *new_arg(struct tracefs_synth *synth) return arg; } +static struct name_hash *find_name(struct tracefs_synth *synth, const char *name) +{ + unsigned int key = quick_hash(name); + struct name_hash *hash = synth->name_hash[key]; + + for (; hash; hash = hash->next) { + if (!strcmp(hash->name, name)) + return hash; + } + return NULL; +} + +static const char *hash_name(struct tracefs_synth *synth, const char *name) +{ + struct name_hash *hash; + int key; + + hash = find_name(synth, name); + if (hash) + return hash->hash; + + hash = malloc(sizeof(*hash)); + if (!hash) + return name; + + hash->hash = new_name(synth, name); + if (!hash->hash) { + free(hash); + return name; + } + + key = quick_hash(name); + hash->next = synth->name_hash[key]; + synth->name_hash[key] = hash; + + hash->name = strdup(name); + if (!hash->name) { + free(hash->hash); + free(hash); + return name; + } + return hash->hash; +} + +static char *new_arg(struct tracefs_synth *synth) +{ + return new_name(synth, "arg"); +} + /** * tracefs_synth_add_compare_field - add a comparison between start and end * @synth: The tracefs_synth descriptor @@ -1245,6 +1376,7 @@ int tracefs_synth_add_compare_field(struct tracefs_synth *synth, const char *name) { const struct tep_format_field *start_field; + const char *hname; char *start_arg; char *compare; int ret; @@ -1296,11 +1428,12 @@ int tracefs_synth_add_compare_field(struct tracefs_synth *synth, if (ret < 0) return -1; - ret = add_var(&synth->end_vars, name, compare, false); + hname = hash_name(synth, name); + ret = add_var(&synth->end_vars, hname, compare, false); if (ret < 0) goto out_free; - ret = add_synth_fields(synth, start_field, name, NULL); + ret = add_synth_fields(synth, start_field, name, hname); if (ret < 0) goto out_free; @@ -1313,9 +1446,10 @@ int tracefs_synth_add_compare_field(struct tracefs_synth *synth, __hidden int synth_add_start_field(struct tracefs_synth *synth, const char *start_field, const char *name, - enum tracefs_hist_key_type type) + enum tracefs_hist_key_type type, int count) { const struct tep_format_field *field; + const char *var; char *start_arg; char **tmp; int *types; @@ -1330,6 +1464,8 @@ __hidden int synth_add_start_field(struct tracefs_synth *synth, if (!name) name = start_field; + var = hash_name(synth, name); + if (!trace_verify_event_field(synth->start_event, start_field, &field)) return -1; @@ -1341,11 +1477,11 @@ __hidden int synth_add_start_field(struct tracefs_synth *synth, if (ret) goto out_free; - ret = add_var(&synth->end_vars, name, start_arg, true); + ret = add_var(&synth->end_vars, var, start_arg, true); if (ret) goto out_free; - ret = add_synth_fields(synth, field, name, NULL); + ret = add_synth_fields(synth, field, name, var); if (ret) goto out_free; @@ -1394,7 +1530,7 @@ int tracefs_synth_add_start_field(struct tracefs_synth *synth, const char *start_field, const char *name) { - return synth_add_start_field(synth, start_field, name, 0); + return synth_add_start_field(synth, start_field, name, 0, 0); } /** @@ -1417,6 +1553,7 @@ int tracefs_synth_add_end_field(struct tracefs_synth *synth, const char *name) { const struct tep_format_field *field; + const char *hname = NULL; char *tmp_var = NULL; int ret; @@ -1425,17 +1562,24 @@ int tracefs_synth_add_end_field(struct tracefs_synth *synth, return -1; } + if (name) { + if (strncmp(name, "__arg", 5) != 0) + hname = hash_name(synth, name); + else + hname = name; + } + if (!name) tmp_var = new_arg(synth); if (!trace_verify_event_field(synth->end_event, end_field, &field)) return -1; - ret = add_var(&synth->end_vars, name ? : tmp_var, end_field, false); + ret = add_var(&synth->end_vars, name ? hname : tmp_var, end_field, false); if (ret) goto out; - ret = add_synth_fields(synth, field, name, tmp_var); + ret = add_synth_fields(synth, field, name, hname ? : tmp_var); free(tmp_var); out: return ret; @@ -2194,7 +2338,7 @@ int tracefs_synth_echo_cmd(struct trace_seq *seq, new_event = true; } - path = trace_find_tracing_dir(); + path = trace_find_tracing_dir(false); if (!path) goto out_free; @@ -2227,11 +2371,6 @@ int tracefs_synth_echo_cmd(struct trace_seq *seq, hist, path, synth->end_event->system, synth->end_event->name); - if (new_event) { - tracefs_dynevent_free(synth->dyn_event); - synth->dyn_event = NULL; - } - ret = 0; out_free: free(hist); |