@@ -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
------------------------
@@ -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,
@@ -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;
@@ -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, "[");
@@ -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;
}