From: Steven Rostedt <rostedt@goodmis.org>
To: linux-kernel@vger.kernel.org
Cc: Ingo Molnar <mingo@kernel.org>,
Andrew Morton <akpm@linux-foundation.org>,
Tom Zanussi <tom.zanussi@linux.intel.com>
Subject: [for-next][PATCH 19/29] tracing: Add hist trigger snapshot() action
Date: Wed, 20 Feb 2019 13:37:56 -0500 [thread overview]
Message-ID: <20190220183806.761427626@goodmis.org> (raw)
In-Reply-To: 20190220183737.034634614@goodmis.org
From: Tom Zanussi <tom.zanussi@linux.intel.com>
Add support for hist:handlerXXX($var).snapshot(), which will take a
snapshot of the current trace buffer whenever handlerXXX is hit.
As a first user, this also adds snapshot() action support for the
onmax() handler i.e. hist:onmax($var).snapshot().
Also, the hist trigger key printing is moved into a separate function
so the snapshot() action can print a histogram key outside the
histogram display - add and use hist_trigger_print_key() for that
purpose.
Link: http://lkml.kernel.org/r/2f1a952c0dcd8aca8702ce81269581a692396d45.1550100284.git.tom.zanussi@linux.intel.com
Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
kernel/trace/trace.c | 3 +
kernel/trace/trace_events_hist.c | 266 +++++++++++++++++++++++++++++--
2 files changed, 259 insertions(+), 10 deletions(-)
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 9f4d56f74b46..dd60c14a0fb0 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4919,6 +4919,9 @@ static const char readme_msg[] =
"\t The available actions are:\n\n"
"\t <synthetic_event>(param list) - generate synthetic event\n"
"\t save(field,...) - save current event fields\n"
+#ifdef CONFIG_TRACER_SNAPSHOT
+ "\t snapshot() - snapshot the trace buffer\n"
+#endif
#endif
;
diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
index 0515229e5f95..571937a268a3 100644
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -396,6 +396,7 @@ enum handler_id {
enum action_id {
ACTION_SAVE = 1,
ACTION_TRACE,
+ ACTION_SNAPSHOT,
};
struct action_data {
@@ -454,6 +455,83 @@ struct action_data {
};
};
+struct track_data {
+ u64 track_val;
+ bool updated;
+
+ unsigned int key_len;
+ void *key;
+ struct tracing_map_elt elt;
+
+ struct action_data *action_data;
+ struct hist_trigger_data *hist_data;
+};
+
+struct hist_elt_data {
+ char *comm;
+ u64 *var_ref_vals;
+ char *field_var_str[SYNTH_FIELDS_MAX];
+};
+
+struct snapshot_context {
+ struct tracing_map_elt *elt;
+ void *key;
+};
+
+static void track_data_free(struct track_data *track_data)
+{
+ struct hist_elt_data *elt_data;
+
+ if (!track_data)
+ return;
+
+ kfree(track_data->key);
+
+ elt_data = track_data->elt.private_data;
+ if (elt_data) {
+ kfree(elt_data->comm);
+ kfree(elt_data);
+ }
+
+ kfree(track_data);
+}
+
+static struct track_data *track_data_alloc(unsigned int key_len,
+ struct action_data *action_data,
+ struct hist_trigger_data *hist_data)
+{
+ struct track_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
+ struct hist_elt_data *elt_data;
+
+ if (!data)
+ return ERR_PTR(-ENOMEM);
+
+ data->key = kzalloc(key_len, GFP_KERNEL);
+ if (!data->key) {
+ track_data_free(data);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ data->key_len = key_len;
+ data->action_data = action_data;
+ data->hist_data = hist_data;
+
+ elt_data = kzalloc(sizeof(*elt_data), GFP_KERNEL);
+ if (!elt_data) {
+ track_data_free(data);
+ return ERR_PTR(-ENOMEM);
+ }
+ data->elt.private_data = elt_data;
+
+ elt_data->comm = kzalloc(TASK_COMM_LEN, GFP_KERNEL);
+ if (!elt_data->comm) {
+ track_data_free(data);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ return data;
+}
+
static char last_hist_cmd[MAX_FILTER_STR_VAL];
static char hist_err_str[MAX_FILTER_STR_VAL];
@@ -1726,12 +1804,6 @@ static struct hist_field *find_event_var(struct hist_trigger_data *hist_data,
return hist_field;
}
-struct hist_elt_data {
- char *comm;
- u64 *var_ref_vals;
- char *field_var_str[SYNTH_FIELDS_MAX];
-};
-
static u64 hist_field_var_ref(struct hist_field *hist_field,
struct tracing_map_elt *elt,
struct ring_buffer_event *rbe,
@@ -3452,6 +3524,112 @@ static bool check_track_val(struct tracing_map_elt *elt,
return data->track_data.check_val(track_val, var_val);
}
+#ifdef CONFIG_TRACER_SNAPSHOT
+static bool cond_snapshot_update(struct trace_array *tr, void *cond_data)
+{
+ /* called with tr->max_lock held */
+ struct track_data *track_data = tr->cond_snapshot->cond_data;
+ struct hist_elt_data *elt_data, *track_elt_data;
+ struct snapshot_context *context = cond_data;
+ u64 track_val;
+
+ if (!track_data)
+ return false;
+
+ track_val = get_track_val(track_data->hist_data, context->elt,
+ track_data->action_data);
+
+ track_data->track_val = track_val;
+ memcpy(track_data->key, context->key, track_data->key_len);
+
+ elt_data = context->elt->private_data;
+ track_elt_data = track_data->elt.private_data;
+ if (elt_data->comm)
+ memcpy(track_elt_data->comm, elt_data->comm, TASK_COMM_LEN);
+
+ track_data->updated = true;
+
+ return true;
+}
+
+static void save_track_data_snapshot(struct hist_trigger_data *hist_data,
+ struct tracing_map_elt *elt, void *rec,
+ struct ring_buffer_event *rbe, void *key,
+ struct action_data *data,
+ u64 *var_ref_vals)
+{
+ struct trace_event_file *file = hist_data->event_file;
+ struct snapshot_context context;
+
+ context.elt = elt;
+ context.key = key;
+
+ tracing_snapshot_cond(file->tr, &context);
+}
+
+static void hist_trigger_print_key(struct seq_file *m,
+ struct hist_trigger_data *hist_data,
+ void *key,
+ struct tracing_map_elt *elt);
+
+static struct action_data *snapshot_action(struct hist_trigger_data *hist_data)
+{
+ unsigned int i;
+
+ if (!hist_data->n_actions)
+ return NULL;
+
+ for (i = 0; i < hist_data->n_actions; i++) {
+ struct action_data *data = hist_data->actions[i];
+
+ if (data->action == ACTION_SNAPSHOT)
+ return data;
+ }
+
+ return NULL;
+}
+
+static void track_data_snapshot_print(struct seq_file *m,
+ struct hist_trigger_data *hist_data)
+{
+ struct trace_event_file *file = hist_data->event_file;
+ struct track_data *track_data;
+ struct action_data *action;
+
+ track_data = tracing_cond_snapshot_data(file->tr);
+ if (!track_data)
+ return;
+
+ if (!track_data->updated)
+ return;
+
+ action = snapshot_action(hist_data);
+ if (!action)
+ return;
+
+ seq_puts(m, "\nSnapshot taken (see tracing/snapshot). Details:\n");
+ seq_printf(m, "\ttriggering value { %s(%s) }: %10llu",
+ action->handler == HANDLER_ONMAX ? "onmax" : "onchange",
+ action->track_data.var_str, track_data->track_val);
+
+ seq_puts(m, "\ttriggered by event with key: ");
+ hist_trigger_print_key(m, hist_data, track_data->key, &track_data->elt);
+ seq_putc(m, '\n');
+}
+#else
+static bool cond_snapshot_update(struct trace_array *tr, void *cond_data)
+{
+ return false;
+}
+static void save_track_data_snapshot(struct hist_trigger_data *hist_data,
+ struct tracing_map_elt *elt, void *rec,
+ struct ring_buffer_event *rbe, void *key,
+ struct action_data *data,
+ u64 *var_ref_vals) {}
+static void track_data_snapshot_print(struct seq_file *m,
+ struct hist_trigger_data *hist_data) {}
+#endif /* CONFIG_TRACER_SNAPSHOT */
+
static void track_data_print(struct seq_file *m,
struct hist_trigger_data *hist_data,
struct tracing_map_elt *elt,
@@ -3463,6 +3641,9 @@ static void track_data_print(struct seq_file *m,
if (data->handler == HANDLER_ONMAX)
seq_printf(m, "\n\tmax: %10llu", track_val);
+ if (data->action == ACTION_SNAPSHOT)
+ return;
+
for (i = 0; i < hist_data->n_save_vars; i++) {
struct hist_field *save_val = hist_data->save_vars[i]->val;
struct hist_field *save_var = hist_data->save_vars[i]->var;
@@ -3513,9 +3694,21 @@ static void action_data_destroy(struct action_data *data)
static void track_data_destroy(struct hist_trigger_data *hist_data,
struct action_data *data)
{
+ struct trace_event_file *file = hist_data->event_file;
+
destroy_hist_field(data->track_data.track_var, 0);
destroy_hist_field(data->track_data.var_ref, 0);
+ if (data->action == ACTION_SNAPSHOT) {
+ struct track_data *track_data;
+
+ track_data = tracing_cond_snapshot_data(file->tr);
+ if (track_data && track_data->hist_data == hist_data) {
+ tracing_snapshot_cond_disable(file->tr);
+ track_data_free(track_data);
+ }
+ }
+
kfree(data->track_data.var_str);
action_data_destroy(data);
@@ -3646,6 +3839,26 @@ static int action_parse(char *str, struct action_data *data,
data->track_data.save_data = save_track_data_vars;
data->fn = ontrack_action;
data->action = ACTION_SAVE;
+ } else if (str_has_prefix(action_name, "snapshot")) {
+ char *params = strsep(&str, ")");
+
+ if (!str) {
+ hist_err("action parsing: No closing paren found: %s", params);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (handler == HANDLER_ONMAX)
+ data->track_data.check_val = check_track_val_max;
+ else {
+ hist_err("action parsing: Handler doesn't support action: ", action_name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ data->track_data.save_data = save_track_data_snapshot;
+ data->fn = ontrack_action;
+ data->action = ACTION_SNAPSHOT;
} else {
char *params = strsep(&str, ")");
@@ -3942,6 +4155,8 @@ static int trace_action_create(struct hist_trigger_data *hist_data,
static int action_create(struct hist_trigger_data *hist_data,
struct action_data *data)
{
+ struct trace_event_file *file = hist_data->event_file;
+ struct track_data *track_data;
struct field_var *field_var;
unsigned int i;
char *param;
@@ -3950,6 +4165,21 @@ static int action_create(struct hist_trigger_data *hist_data,
if (data->action == ACTION_TRACE)
return trace_action_create(hist_data, data);
+ if (data->action == ACTION_SNAPSHOT) {
+ track_data = track_data_alloc(hist_data->key_size, data, hist_data);
+ if (IS_ERR(track_data)) {
+ ret = PTR_ERR(track_data);
+ goto out;
+ }
+
+ ret = tracing_snapshot_cond_enable(file->tr, track_data,
+ cond_snapshot_update);
+ if (ret)
+ track_data_free(track_data);
+
+ goto out;
+ }
+
if (data->action == ACTION_SAVE) {
if (hist_data->n_save_vars) {
ret = -EEXIST;
@@ -4552,6 +4782,9 @@ static void print_actions(struct seq_file *m,
for (i = 0; i < hist_data->n_actions; i++) {
struct action_data *data = hist_data->actions[i];
+ if (data->action == ACTION_SNAPSHOT)
+ continue;
+
if (data->handler == HANDLER_ONMAX)
track_data_print(m, hist_data, elt, data);
}
@@ -4946,10 +5179,10 @@ static void hist_trigger_stacktrace_print(struct seq_file *m,
}
}
-static void
-hist_trigger_entry_print(struct seq_file *m,
- struct hist_trigger_data *hist_data, void *key,
- struct tracing_map_elt *elt)
+static void hist_trigger_print_key(struct seq_file *m,
+ struct hist_trigger_data *hist_data,
+ void *key,
+ struct tracing_map_elt *elt)
{
struct hist_field *key_field;
char str[KSYM_SYMBOL_LEN];
@@ -5025,6 +5258,17 @@ hist_trigger_entry_print(struct seq_file *m,
seq_puts(m, " ");
seq_puts(m, "}");
+}
+
+static void hist_trigger_entry_print(struct seq_file *m,
+ struct hist_trigger_data *hist_data,
+ void *key,
+ struct tracing_map_elt *elt)
+{
+ const char *field_name;
+ unsigned int i;
+
+ hist_trigger_print_key(m, hist_data, key, elt);
seq_printf(m, " hitcount: %10llu",
tracing_map_read_sum(elt, HITCOUNT_IDX));
@@ -5091,6 +5335,8 @@ static void hist_trigger_show(struct seq_file *m,
if (n_entries < 0)
n_entries = 0;
+ track_data_snapshot_print(m, hist_data);
+
seq_printf(m, "\nTotals:\n Hits: %llu\n Entries: %u\n Dropped: %llu\n",
(u64)atomic64_read(&hist_data->map->hits),
n_entries, (u64)atomic64_read(&hist_data->map->drops));
--
2.20.1
next prev parent reply other threads:[~2019-02-20 18:39 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-02-20 18:37 [for-next][PATCH 00/29] tracing: Updates for 5.1 Steven Rostedt
2019-02-20 18:37 ` [for-next][PATCH 01/29] function_graph: Support displaying relative timestamp Steven Rostedt
2019-02-20 18:37 ` [for-next][PATCH 02/29] tracing: Annotate implicit fall through in parse_probe_arg() Steven Rostedt
2019-02-20 18:37 ` [for-next][PATCH 03/29] tracing: Annotate implicit fall through in predicate_parse() Steven Rostedt
2019-02-20 18:37 ` [for-next][PATCH 04/29] tracing: Add comment to predicate_parse() about "&&" or "||" Steven Rostedt
2019-02-20 18:37 ` [for-next][PATCH 05/29] tracing: Show more info for funcgraph wakeup tracers Steven Rostedt
2019-02-20 18:37 ` [for-next][PATCH 06/29] tracing: Put a margin between flags and duration for " Steven Rostedt
2019-02-20 18:37 ` [for-next][PATCH 07/29] tracing/doc: Add latency tracer funcgraph example Steven Rostedt
2019-02-20 18:37 ` [for-next][PATCH 08/29] tracing: Show stacktrace for wakeup tracers Steven Rostedt
2019-02-20 18:37 ` [for-next][PATCH 09/29] ring-buffer: Remove unused function ring_buffer_page_len() Steven Rostedt
2019-02-20 18:37 ` [for-next][PATCH 10/29] tracing: Change the function format to display function names by perf Steven Rostedt
2019-02-20 18:37 ` [for-next][PATCH 11/29] ftrace: Allow enabling of filters via index of available_filter_functions Steven Rostedt
2019-02-20 18:37 ` [for-next][PATCH 12/29] uprobes: convert uprobe.ref to refcount_t Steven Rostedt
2019-02-20 18:37 ` [for-next][PATCH 13/29] tracing: No need to free iter->trace in fail path of tracing_open_pipe() Steven Rostedt
2019-02-20 18:46 ` Steven Rostedt
2019-02-20 18:50 ` Steven Rostedt
2019-02-20 18:37 ` [for-next][PATCH 14/29] tracing: Refactor hist trigger action code Steven Rostedt
2019-02-20 18:37 ` [for-next][PATCH 15/29] tracing: Make hist trigger Documentation better reflect actions/handlers Steven Rostedt
2019-02-20 18:37 ` [for-next][PATCH 16/29] tracing: Split up onmatch action data Steven Rostedt
2019-02-20 18:37 ` [for-next][PATCH 17/29] tracing: Generalize hist trigger onmax and save action Steven Rostedt
2019-02-20 18:37 ` [for-next][PATCH 18/29] tracing: Add conditional snapshot Steven Rostedt
2019-02-20 18:37 ` Steven Rostedt [this message]
2019-02-20 18:37 ` [for-next][PATCH 20/29] tracing: Add hist trigger snapshot() action Documentation Steven Rostedt
2019-02-20 18:37 ` [for-next][PATCH 21/29] tracing: Add hist trigger onchange() handler Steven Rostedt
2019-02-20 18:37 ` [for-next][PATCH 22/29] tracing: Add hist trigger onchange() handler Documentation Steven Rostedt
2019-02-20 18:38 ` [for-next][PATCH 23/29] tracing: Add alternative synthetic event trace action syntax Steven Rostedt
2019-02-20 18:38 ` [for-next][PATCH 24/29] tracing: Add SPDX license GPL-2.0 license identifier to inter-event testcases Steven Rostedt
2019-02-20 18:38 ` [for-next][PATCH 25/29] tracing: Add hist trigger snapshot() action test case Steven Rostedt
2019-02-20 18:38 ` [for-next][PATCH 26/29] tracing: Add hist trigger onchange() handler " Steven Rostedt
2019-02-20 18:38 ` [for-next][PATCH 27/29] tracing: Add alternative synthetic event trace action " Steven Rostedt
2019-02-20 18:38 ` [for-next][PATCH 28/29] tracing: Add hist trigger action expected fail " Steven Rostedt
2019-02-20 18:38 ` [for-next][PATCH 29/29] tracing: Comment why cond_snapshot is checked outside of max_lock protection Steven Rostedt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190220183806.761427626@goodmis.org \
--to=rostedt@goodmis.org \
--cc=akpm@linux-foundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@kernel.org \
--cc=tom.zanussi@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.