Skip to content

Commit

Permalink
tracing: Add support for dynamic strings to synthetic events
Browse files Browse the repository at this point in the history
Currently, sythetic events only support static string fields such as:

  # echo 'test_latency u64 lat; char somename[32]' > /sys/kernel/debug/tracing/synthetic_events

Which is fine, but wastes a lot of space in the event.

It also prevents the most commonly-defined strings in the existing
trace events e.g. those defined using __string(), from being passed to
synthetic events via the trace() action.

With this change, synthetic events with dynamic fields can be defined:

  # echo 'test_latency u64 lat; char somename[]' > /sys/kernel/debug/tracing/synthetic_events

And the trace() action can be used to generate events using either
dynamic or static strings:

  # echo 'hist:keys=name:lat=common_timestamp.usecs-$ts0:onmatch(sys.event).test_latency($lat,name)' > /sys/kernel/debug/tracing/events

The synthetic event dynamic strings are implemented in the same way as
the existing __data_loc strings and appear as such in the format file.

[ <rostedt@goodmis.org>: added __set_synth_event_print_fmt() changes:

  I added the following to make it work with trace-cmd. Dynamic strings
  must have __get_str() for events in the print_fmt otherwise it can't be
  parsed correctly. ]

Link: https://lore.kernel.org/r/cover.1601588066.git.zanussi@kernel.org
Link: https://lkml.kernel.org/r/3ed35b6d0e390f5b94cb4a9ba1cc18f5982ab277.1601848695.git.zanussi@kernel.org

Tested-by: Axel Rasmussen <axelrasmussen@google.com>
Signed-off-by: Tom Zanussi <zanussi@kernel.org>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
  • Loading branch information
Tom Zanussi authored and rostedt committed Oct 5, 2020
1 parent 63a1e5d commit bd82631
Show file tree
Hide file tree
Showing 6 changed files with 272 additions and 40 deletions.
15 changes: 13 additions & 2 deletions Documentation/trace/events.rst
Original file line number Diff line number Diff line change
Expand Up @@ -589,8 +589,19 @@ name::
{ .type = "int", .name = "my_int_field" },
};

See synth_field_size() for available types. If field_name contains [n]
the field is considered to be an array.
See synth_field_size() for available types.

If field_name contains [n], the field is considered to be a static array.

If field_names contains[] (no subscript), the field is considered to
be a dynamic array, which will only take as much space in the event as
is required to hold the array.

Because space for an event is reserved before assigning field values
to the event, using dynamic arrays implies that the piecewise
in-kernel API described below can't be used with dynamic arrays. The
other non-piecewise in-kernel APIs can, however, be used with dynamic
arrays.

If the event is created from within a module, a pointer to the module
must be passed to synth_event_create(). This will ensure that the
Expand Down
18 changes: 18 additions & 0 deletions Documentation/trace/histogram.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1776,6 +1776,24 @@ consisting of the name of the new event along with one or more
variables and their types, which can be any valid field type,
separated by semicolons, to the tracing/synthetic_events file.

See synth_field_size() for available types.

If field_name contains [n], the field is considered to be a static array.

If field_names contains[] (no subscript), the field is considered to
be a dynamic array, which will only take as much space in the event as
is required to hold the array.

A string field can be specified using either the static notation:

char name[32];

Or the dynamic:

char name[];

The size limit for either is 256.

For instance, the following creates a new event named 'wakeup_latency'
with 3 fields: lat, pid, and prio. Each of those fields is simply a
variable reference to a variable on another event::
Expand Down
18 changes: 12 additions & 6 deletions kernel/trace/synth_event_gen_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,9 +242,11 @@ static struct synth_field_desc create_synth_test_fields[] = {
{ .type = "pid_t", .name = "next_pid_field" },
{ .type = "char[16]", .name = "next_comm_field" },
{ .type = "u64", .name = "ts_ns" },
{ .type = "char[]", .name = "dynstring_field_1" },
{ .type = "u64", .name = "ts_ms" },
{ .type = "unsigned int", .name = "cpu" },
{ .type = "char[64]", .name = "my_string_field" },
{ .type = "char[]", .name = "dynstring_field_2" },
{ .type = "int", .name = "my_int_field" },
};

Expand All @@ -254,7 +256,7 @@ static struct synth_field_desc create_synth_test_fields[] = {
*/
static int __init test_create_synth_event(void)
{
u64 vals[7];
u64 vals[9];
int ret;

/* Create the create_synth_test event with the fields above */
Expand Down Expand Up @@ -292,10 +294,12 @@ static int __init test_create_synth_event(void)
vals[0] = 777; /* next_pid_field */
vals[1] = (u64)(long)"tiddlywinks"; /* next_comm_field */
vals[2] = 1000000; /* ts_ns */
vals[3] = 1000; /* ts_ms */
vals[4] = raw_smp_processor_id(); /* cpu */
vals[5] = (u64)(long)"thneed"; /* my_string_field */
vals[6] = 398; /* my_int_field */
vals[3] = (u64)(long)"xrayspecs"; /* dynstring_field_1 */
vals[4] = 1000; /* ts_ms */
vals[5] = raw_smp_processor_id(); /* cpu */
vals[6] = (u64)(long)"thneed"; /* my_string_field */
vals[7] = (u64)(long)"kerplunk"; /* dynstring_field_2 */
vals[8] = 398; /* my_int_field */

/* Now generate a create_synth_test event */
ret = synth_event_trace_array(create_synth_test, vals, ARRAY_SIZE(vals));
Expand Down Expand Up @@ -422,13 +426,15 @@ static int __init test_trace_synth_event(void)
int ret;

/* Trace some bogus values just for testing */
ret = synth_event_trace(create_synth_test, 7, /* number of values */
ret = synth_event_trace(create_synth_test, 9, /* number of values */
(u64)444, /* next_pid_field */
(u64)(long)"clackers", /* next_comm_field */
(u64)1000000, /* ts_ns */
(u64)(long)"viewmaster",/* dynstring_field_1 */
(u64)1000, /* ts_ms */
(u64)raw_smp_processor_id(), /* cpu */
(u64)(long)"Thneed", /* my_string_field */
(u64)(long)"yoyos", /* dynstring_field_2 */
(u64)999); /* my_int_field */
return ret;
}
Expand Down
9 changes: 9 additions & 0 deletions kernel/trace/trace_events_hist.c
Original file line number Diff line number Diff line change
Expand Up @@ -3289,6 +3289,15 @@ static int check_synth_field(struct synth_event *event,

field = event->fields[field_pos];

/*
* A dynamic string synth field can accept static or
* dynamic. A static string synth field can only accept a
* same-sized static string, which is checked for later.
*/
if (strstr(hist_field->type, "char[") && field->is_string
&& field->is_dynamic)
return 0;

if (strcmp(field->type, hist_field->type) != 0) {
if (field->size != hist_field->size ||
field->is_signed != hist_field->is_signed)
Expand Down
Loading

0 comments on commit bd82631

Please sign in to comment.