From: "Steven Rostedt (VMware)" <rostedt@xxxxxxxxxxx> Use the CAST() command of SQL to define which items in the select should be cast as values and not keys. By casting the field as the special value _COUNTER_, it will turn the selection item into a value. For example: SELECT common_pid, CAST(bytes_req AS _COUNTER_) FROM kmalloc Will create: echo 'hist:keys=common_pid:vals=bytes_req' > events/kmem/kmalloc/trigger Signed-off-by: Steven Rostedt (VMware) <rostedt@xxxxxxxxxxx> --- Documentation/libtracefs-sql.txt | 24 ++++++++++++++++++++++++ include/tracefs-local.h | 2 ++ include/tracefs.h | 3 +++ src/tracefs-hist.c | 28 ++++++++++++++++++++++++++-- src/tracefs-sqlhist.c | 23 +++++++++++++++++++++++ 5 files changed, 78 insertions(+), 2 deletions(-) diff --git a/Documentation/libtracefs-sql.txt b/Documentation/libtracefs-sql.txt index 314f607fa84e..7b616fa27d23 100644 --- a/Documentation/libtracefs-sql.txt +++ b/Documentation/libtracefs-sql.txt @@ -238,6 +238,30 @@ name of the process. *LOG* or *LOG2* - bucket the key values in a log 2 values (1, 2, 3-4, 5-8, 9-16, 17-32, ...) +The above fields are not case sensitive, and "LOG2" works as good as "log". + +A special CAST to _COUNTER_ or __COUNTER__ will make the field a value and not +a key. For example: + +[source,c] +-- + SELECT common_pid, CAST(bytes_req AS _COUNTER_) FROM kmalloc +-- + +Which will create + +[source,c] +-- + echo 'hist:keys=common_pid:vals=bytes_req' > events/kmem/kmalloc/trigger + + cat events/kmem/kmalloc/hist + +{ common_pid: 1812 } hitcount: 1 bytes_req: 32 +{ common_pid: 9111 } hitcount: 2 bytes_req: 272 +{ common_pid: 1768 } hitcount: 3 bytes_req: 1112 +{ common_pid: 0 } hitcount: 4 bytes_req: 512 +{ common_pid: 18297 } hitcount: 11 bytes_req: 2004 +-- RETURN VALUE ------------ diff --git a/include/tracefs-local.h b/include/tracefs-local.h index 07d40b2fae4f..684eccffafee 100644 --- a/include/tracefs-local.h +++ b/include/tracefs-local.h @@ -88,6 +88,8 @@ int trace_append_filter(char **filter, unsigned int *state, struct tracefs_synth *synth_init_from(struct tep_handle *tep, const char *start_system, const char *start_event); + +#define HIST_COUNTER_TYPE (TRACEFS_HIST_KEY_MAX + 100) int synth_add_start_field(struct tracefs_synth *synth, const char *start_field, const char *name, diff --git a/include/tracefs.h b/include/tracefs.h index 219adba4b0ce..17020de0108a 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -264,6 +264,7 @@ enum tracefs_hist_key_type { TRACEFS_HIST_KEY_EXECNAME, TRACEFS_HIST_KEY_LOG, TRACEFS_HIST_KEY_USECS, + TRACEFS_HIST_KEY_MAX }; enum tracefs_hist_sort_direction { @@ -275,6 +276,8 @@ enum tracefs_hist_sort_direction { #define TRACEFS_HIST_TIMESTAMP_USECS "common_timestamp.usecs" #define TRACEFS_HIST_CPU "cpu" +#define TRACEFS_HIST_COUNTER "__COUNTER__" + #define TRACEFS_HIST_HITCOUNT "hitcount" struct tracefs_hist; diff --git a/src/tracefs-hist.c b/src/tracefs-hist.c index d62422399552..c3aecf9a8fef 100644 --- a/src/tracefs-hist.c +++ b/src/tracefs-hist.c @@ -256,7 +256,7 @@ int tracefs_hist_add_key(struct tracefs_hist *hist, const char *key, bool use_key = false; char *key_type = NULL; char **new_list; - int ret; + int ret = -1; switch (type) { case TRACEFS_HIST_KEY_NORMAL: @@ -284,6 +284,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_MAX: + /* error */ + break; } if (ret < 0) @@ -1450,6 +1453,9 @@ tracefs_synth_get_start_hist(struct tracefs_synth *synth) for (i = 0; keys[i]; i++) { int type = types ? types[i] : 0; + if (type == HIST_COUNTER_TYPE) + continue; + key = keys[i]; if (i) { @@ -1466,7 +1472,25 @@ tracefs_synth_get_start_hist(struct tracefs_synth *synth) } } - if (hist && synth->start_filter) { + if (!hist) + return NULL; + + for (i = 0; keys[i]; i++) { + int type = types ? types[i] : 0; + + if (type != HIST_COUNTER_TYPE) + continue; + + key = keys[i]; + + ret = tracefs_hist_add_value(hist, key); + if (ret < 0) { + tracefs_hist_free(hist); + return NULL; + } + } + + if (synth->start_filter) { hist->filter = strdup(synth->start_filter); if (!hist->filter) { tracefs_hist_free(hist); diff --git a/src/tracefs-sqlhist.c b/src/tracefs-sqlhist.c index 88563e98f298..1a3cf37c84ba 100644 --- a/src/tracefs-sqlhist.c +++ b/src/tracefs-sqlhist.c @@ -1253,6 +1253,17 @@ static int verify_field_type(struct tep_handle *tep, if (!type) return -1; + if (!strcmp(type, TRACEFS_HIST_COUNTER) || + !strcmp(type, "_COUNTER_")) { + ret = HIST_COUNTER_TYPE; + if (tfield->flags & (TEP_FIELD_IS_STRING | TEP_FIELD_IS_ARRAY)) { + parse_error(sb, field->raw, + "'%s' is a string, and counters may only be used with numbers\n"); + ret = -1; + } + goto out; + } + for (i = 0; type[i]; i++) type[i] = tolower(type[i]); @@ -1292,6 +1303,7 @@ static int verify_field_type(struct tep_handle *tep, field->raw, type); ret = -1; } + out: free(type); return ret; fail_type: @@ -1319,6 +1331,7 @@ static struct tracefs_synth *build_synth(struct tep_handle *tep, const char *end_match; bool started_start = false; bool started_end = false; + bool non_val = false; int ret; if (!table->from) @@ -1396,6 +1409,8 @@ static struct tracefs_synth *build_synth(struct tep_handle *tep, type = verify_field_type(tep, table->sb, expr); if (type < 0) goto free; + if (type != HIST_COUNTER_TYPE) + non_val = true; ret = synth_add_start_field(synth, field->field, field->label, type); @@ -1426,6 +1441,14 @@ static struct tracefs_synth *build_synth(struct tep_handle *tep, } } + if (!non_val && !table->to) { + table->sb->line_no = 0; + table->sb->line_idx = 10; + parse_error(table->sb, "CAST", + "Not all SELECT items can be of type _COUNTER_\n"); + goto free; + } + for (expr = table->where; expr; expr = expr->next) { const char *filter_system = NULL; const char *filter_event = NULL; -- 2.30.2