From: "Steven Rostedt (Google)" <rostedt@xxxxxxxxxxx> Now that the kernel can pass stacktraces from the start to end of a synthetic event, update the tracefs_sql() (and by doing so sqlhist) to handle stacktrace. A new keyword STACKTRACE is added, so the following will now work: sqlhist -e -n block_lat 'SELECT (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) AS delta,start.STACKTRACE AS stack FROM sched_switch AS start JOIN sched_switch AS end ON end.next_pid = start.prev_pid WHERE start.prev_state == 1 && start.prev_prio < 100' Signed-off-by: Steven Rostedt (Google) <rostedt@xxxxxxxxxxx> --- Documentation/libtracefs-sql.txt | 13 +++++++++++++ include/tracefs.h | 2 ++ src/tracefs-filter.c | 10 ++++++++++ src/tracefs-hist.c | 3 ++- src/tracefs-sqlhist.c | 5 ++++- 5 files changed, 31 insertions(+), 2 deletions(-) diff --git a/Documentation/libtracefs-sql.txt b/Documentation/libtracefs-sql.txt index 6d606db..62fd771 100644 --- a/Documentation/libtracefs-sql.txt +++ b/Documentation/libtracefs-sql.txt @@ -162,6 +162,19 @@ select start.pid, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) as lat from sche WHERE start.prio < 100 || end.prev_prio < 100 -- +If the kernel supports it, you can pass around a stacktrace between events. + +[source, c] +-- +select start.prev_pid as pid, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) as delta, start.STACKTRACE as stack + FROM sched_switch as start JOIN sched_switch as end ON start.prev_pid = end.next_pid + WHERE start.prev_state == 2 +-- + +The above will record a stacktrace when a task is in the UNINTERRUPTIBLE (blocked) state, and trigger +the synthetic event when it is scheduled back in, recording the time delta that it was blocked for. +It will record the stacktrace of where it was when it scheduled out along with the delta. + KEYWORDS AS EVENT FIELDS ------------------------ diff --git a/include/tracefs.h b/include/tracefs.h index 3547b5a..23b3f8c 100644 --- a/include/tracefs.h +++ b/include/tracefs.h @@ -553,6 +553,8 @@ int tracefs_event_verify_filter(struct tep_event *event, const char *filter, #define TRACEFS_TIMESTAMP "common_timestamp" #define TRACEFS_TIMESTAMP_USECS "common_timestamp.usecs" +#define TRACEFS_STACKTRACE "stacktrace" + enum tracefs_synth_handler { TRACEFS_SYNTH_HANDLE_NONE = 0, TRACEFS_SYNTH_HANDLE_MATCH, diff --git a/src/tracefs-filter.c b/src/tracefs-filter.c index a3dd77b..068329e 100644 --- a/src/tracefs-filter.c +++ b/src/tracefs-filter.c @@ -41,6 +41,13 @@ static const struct tep_format_field common_comm = { .size = 16, }; +static const struct tep_format_field stacktrace = { + .type = "unsigned long[]", + .name = "stacktrace", + .size = 4, + .flags = TEP_FIELD_IS_ARRAY | TEP_FIELD_IS_DYNAMIC, +}; + /* * This also must be able to accept fields that are OK via the histograms, * such as common_timestamp. @@ -56,6 +63,9 @@ static const struct tep_format_field *get_event_field(struct tep_event *event, if (!strcmp(field_name, TRACEFS_TIMESTAMP_USECS)) return &common_timestamp_usecs; + if (!strcmp(field_name, TRACEFS_STACKTRACE)) + return &stacktrace; + field = tep_find_any_field(event, field_name); if (!field && (!strcmp(field_name, "COMM") || !strcmp(field_name, "comm"))) return &common_comm; diff --git a/src/tracefs-hist.c b/src/tracefs-hist.c index fb6231e..1918670 100644 --- a/src/tracefs-hist.c +++ b/src/tracefs-hist.c @@ -915,7 +915,8 @@ static char *add_synth_field(const struct tep_format_field *field, bool sign; if (field->flags & TEP_FIELD_IS_ARRAY) { - str = strdup("char"); + str = strdup(field->type); + str = strtok(str, "["); str = append_string(str, " ", name); str = append_string(str, NULL, "["); diff --git a/src/tracefs-sqlhist.c b/src/tracefs-sqlhist.c index 3f571b7..0035922 100644 --- a/src/tracefs-sqlhist.c +++ b/src/tracefs-sqlhist.c @@ -566,7 +566,8 @@ static int test_field_exists(struct tep_handle *tep, return -1; if (!strcmp(field_name, TRACEFS_TIMESTAMP) || - !strcmp(field->field, TRACEFS_TIMESTAMP_USECS)) + !strcmp(field->field, TRACEFS_TIMESTAMP_USECS) || + !strcmp(field->field, TRACEFS_STACKTRACE)) tfield = (void *)1L; else tfield = tep_find_any_field(field->event, field_name); @@ -695,6 +696,8 @@ static int update_vars(struct tep_handle *tep, field->field = store_str(sb, TRACEFS_TIMESTAMP); if (!strcmp(field->field, "TIMESTAMP_USECS")) field->field = store_str(sb, TRACEFS_TIMESTAMP_USECS); + if (!strcmp(field->field, "STACKTRACE")) + field->field = store_str(sb, TRACEFS_STACKTRACE); if (test_field_exists(tep, sb, expr)) return -1; } -- 2.35.1