aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Zanussi <tom.zanussi@linux.intel.com>2016-03-03 13:54:42 -0500
committerSteven Rostedt <rostedt@goodmis.org>2016-04-19 12:16:14 -0400
commit7ef224d1d0e3a1ade02d02c01ce1dcffb736d2c3 (patch)
tree8daaf516defeabaacade6e88af3c5974fa357626
parent3b772b96b8338bca2532839b2cd7802800e66037 (diff)
tracing: Add 'hist' event trigger command
'hist' triggers allow users to continually aggregate trace events, which can then be viewed afterwards by simply reading a 'hist' file containing the aggregation in a human-readable format. The basic idea is very simple and boils down to a mechanism whereby trace events, rather than being exhaustively dumped in raw form and viewed directly, are automatically 'compressed' into meaningful tables completely defined by the user. This is done strictly via single-line command-line commands and without the aid of any kind of programming language or interpreter. A surprising number of typical use cases can be accomplished by users via this simple mechanism. In fact, a large number of the tasks that users typically do using the more complicated script-based tracing tools, at least during the initial stages of an investigation, can be accomplished by simply specifying a set of keys and values to be used in the creation of a hash table. The Linux kernel trace event subsystem happens to provide an extensive list of keys and values ready-made for such a purpose in the form of the event format files associated with each trace event. By simply consulting the format file for field names of interest and by plugging them into the hist trigger command, users can create an endless number of useful aggregations to help with investigating various properties of the system. See Documentation/trace/events.txt for examples. hist triggers are implemented on top of the existing event trigger infrastructure, and as such are consistent with the existing triggers from a user's perspective as well. The basic syntax follows the existing trigger syntax. Users start an aggregation by writing a 'hist' trigger to the event of interest's trigger file: # echo hist:keys=xxx [ if filter] > event/trigger Once a hist trigger has been set up, by default it continually aggregates every matching event into a hash table using the event key and a value field named 'hitcount'. To view the aggregation at any point in time, simply read the 'hist' file in the same directory as the 'trigger' file: # cat event/hist The detailed syntax provides additional options for user control, and is described exhaustively in Documentation/trace/events.txt and in the virtual tracing/README file in the tracing subsystem. Link: http://lkml.kernel.org/r/72d263b5e1853fe9c314953b65833c3aa75479f2.1457029949.git.tom.zanussi@linux.intel.com Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com> Tested-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Reviewed-by: Namhyung Kim <namhyung@kernel.org> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--include/linux/trace_events.h1
-rw-r--r--kernel/trace/Kconfig16
-rw-r--r--kernel/trace/Makefile1
-rw-r--r--kernel/trace/trace.c17
-rw-r--r--kernel/trace/trace.h7
-rw-r--r--kernel/trace/trace_events.c4
-rw-r--r--kernel/trace/trace_events_hist.c849
-rw-r--r--kernel/trace/trace_events_trigger.c1
8 files changed, 896 insertions, 0 deletions
diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h
index 0810f81b6db2..404603720650 100644
--- a/include/linux/trace_events.h
+++ b/include/linux/trace_events.h
@@ -407,6 +407,7 @@ enum event_trigger_type {
407 ETT_SNAPSHOT = (1 << 1), 407 ETT_SNAPSHOT = (1 << 1),
408 ETT_STACKTRACE = (1 << 2), 408 ETT_STACKTRACE = (1 << 2),
409 ETT_EVENT_ENABLE = (1 << 3), 409 ETT_EVENT_ENABLE = (1 << 3),
410 ETT_EVENT_HIST = (1 << 4),
410}; 411};
411 412
412extern int filter_match_preds(struct event_filter *filter, void *rec); 413extern int filter_match_preds(struct event_filter *filter, void *rec);
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index d39556fd863a..fafeaf803bd0 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -538,6 +538,22 @@ config TRACING_MAP
538 generally used outside of that context, and is normally 538 generally used outside of that context, and is normally
539 selected by tracers that use it. 539 selected by tracers that use it.
540 540
541config HIST_TRIGGERS
542 bool "Histogram triggers"
543 depends on ARCH_HAVE_NMI_SAFE_CMPXCHG
544 select TRACING_MAP
545 default n
546 help
547 Hist triggers allow one or more arbitrary trace event fields
548 to be aggregated into hash tables and dumped to stdout by
549 reading a debugfs/tracefs file. They're useful for
550 gathering quick and dirty (though precise) summaries of
551 event activity as an initial guide for further investigation
552 using more advanced tools.
553
554 See Documentation/trace/events.txt.
555 If in doubt, say N.
556
541config MMIOTRACE_TEST 557config MMIOTRACE_TEST
542 tristate "Test module for mmiotrace" 558 tristate "Test module for mmiotrace"
543 depends on MMIOTRACE && m 559 depends on MMIOTRACE && m
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 4255c4057aaa..979e7bfbde7a 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_EVENT_TRACING) += trace_event_perf.o
54endif 54endif
55obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o 55obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o
56obj-$(CONFIG_EVENT_TRACING) += trace_events_trigger.o 56obj-$(CONFIG_EVENT_TRACING) += trace_events_trigger.o
57obj-$(CONFIG_HIST_TRIGGERS) += trace_events_hist.o
57obj-$(CONFIG_BPF_EVENTS) += bpf_trace.o 58obj-$(CONFIG_BPF_EVENTS) += bpf_trace.o
58obj-$(CONFIG_KPROBE_EVENT) += trace_kprobe.o 59obj-$(CONFIG_KPROBE_EVENT) += trace_kprobe.o
59obj-$(CONFIG_TRACEPOINTS) += power-traces.o 60obj-$(CONFIG_TRACEPOINTS) += power-traces.o
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 0d12dbde8399..6cf8fd03b028 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -3813,6 +3813,9 @@ static const char readme_msg[] =
3813#ifdef CONFIG_TRACER_SNAPSHOT 3813#ifdef CONFIG_TRACER_SNAPSHOT
3814 "\t\t snapshot\n" 3814 "\t\t snapshot\n"
3815#endif 3815#endif
3816#ifdef CONFIG_HIST_TRIGGERS
3817 "\t\t hist (see below)\n"
3818#endif
3816 "\t example: echo traceoff > events/block/block_unplug/trigger\n" 3819 "\t example: echo traceoff > events/block/block_unplug/trigger\n"
3817 "\t echo traceoff:3 > events/block/block_unplug/trigger\n" 3820 "\t echo traceoff:3 > events/block/block_unplug/trigger\n"
3818 "\t echo 'enable_event:kmem:kmalloc:3 if nr_rq > 1' > \\\n" 3821 "\t echo 'enable_event:kmem:kmalloc:3 if nr_rq > 1' > \\\n"
@@ -3828,6 +3831,20 @@ static const char readme_msg[] =
3828 "\t To remove a trigger with a count:\n" 3831 "\t To remove a trigger with a count:\n"
3829 "\t echo '!<trigger>:0 > <system>/<event>/trigger\n" 3832 "\t echo '!<trigger>:0 > <system>/<event>/trigger\n"
3830 "\t Filters can be ignored when removing a trigger.\n" 3833 "\t Filters can be ignored when removing a trigger.\n"
3834#ifdef CONFIG_HIST_TRIGGERS
3835 " hist trigger\t- If set, event hits are aggregated into a hash table\n"
3836 "\t Format: hist:keys=<field1>\n"
3837 "\t [:size=#entries]\n"
3838 "\t [if <filter>]\n\n"
3839 "\t When a matching event is hit, an entry is added to a hash\n"
3840 "\t table using the key named, and the value of a sum called\n"
3841 "\t 'hitcount' is incremented. Keys correspond to fields in the\n"
3842 "\t event's format description. Keys can be any field. The\n"
3843 "\t 'size' parameter can be used to specify more or fewer than\n"
3844 "\t the default 2048 entries for the hashtable size.\n\n"
3845 "\t Reading the 'hist' file for the event will dump the hash\n"
3846 "\t table in its entirety to stdout."
3847#endif
3831; 3848;
3832 3849
3833static ssize_t 3850static ssize_t
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 2525042760e6..505f8a45f426 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -1162,6 +1162,13 @@ extern struct mutex event_mutex;
1162extern struct list_head ftrace_events; 1162extern struct list_head ftrace_events;
1163 1163
1164extern const struct file_operations event_trigger_fops; 1164extern const struct file_operations event_trigger_fops;
1165extern const struct file_operations event_hist_fops;
1166
1167#ifdef CONFIG_HIST_TRIGGERS
1168extern int register_trigger_hist_cmd(void);
1169#else
1170static inline int register_trigger_hist_cmd(void) { return 0; }
1171#endif
1165 1172
1166extern int register_trigger_cmds(void); 1173extern int register_trigger_cmds(void);
1167extern void clear_event_triggers(struct trace_array *tr); 1174extern void clear_event_triggers(struct trace_array *tr);
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index add81dff7520..e7cb983ee93c 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -2141,6 +2141,10 @@ event_create_dir(struct dentry *parent, struct trace_event_file *file)
2141 trace_create_file("trigger", 0644, file->dir, file, 2141 trace_create_file("trigger", 0644, file->dir, file,
2142 &event_trigger_fops); 2142 &event_trigger_fops);
2143 2143
2144#ifdef CONFIG_HIST_TRIGGERS
2145 trace_create_file("hist", 0444, file->dir, file,
2146 &event_hist_fops);
2147#endif
2144 trace_create_file("format", 0444, file->dir, call, 2148 trace_create_file("format", 0444, file->dir, call,
2145 &ftrace_event_format_fops); 2149 &ftrace_event_format_fops);
2146 2150
diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
new file mode 100644
index 000000000000..23b45e462117
--- /dev/null
+++ b/kernel/trace/trace_events_hist.c
@@ -0,0 +1,849 @@
1/*
2 * trace_events_hist - trace event hist triggers
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * Copyright (C) 2015 Tom Zanussi <tom.zanussi@linux.intel.com>
15 */
16
17#include <linux/module.h>
18#include <linux/kallsyms.h>
19#include <linux/mutex.h>
20#include <linux/slab.h>
21#include <linux/stacktrace.h>
22
23#include "tracing_map.h"
24#include "trace.h"
25
26struct hist_field;
27
28typedef u64 (*hist_field_fn_t) (struct hist_field *field, void *event);
29
30struct hist_field {
31 struct ftrace_event_field *field;
32 unsigned long flags;
33 hist_field_fn_t fn;
34 unsigned int size;
35};
36
37static u64 hist_field_counter(struct hist_field *field, void *event)
38{
39 return 1;
40}
41
42static u64 hist_field_string(struct hist_field *hist_field, void *event)
43{
44 char *addr = (char *)(event + hist_field->field->offset);
45
46 return (u64)(unsigned long)addr;
47}
48
49#define DEFINE_HIST_FIELD_FN(type) \
50static u64 hist_field_##type(struct hist_field *hist_field, void *event)\
51{ \
52 type *addr = (type *)(event + hist_field->field->offset); \
53 \
54 return (u64)*addr; \
55}
56
57DEFINE_HIST_FIELD_FN(s64);
58DEFINE_HIST_FIELD_FN(u64);
59DEFINE_HIST_FIELD_FN(s32);
60DEFINE_HIST_FIELD_FN(u32);
61DEFINE_HIST_FIELD_FN(s16);
62DEFINE_HIST_FIELD_FN(u16);
63DEFINE_HIST_FIELD_FN(s8);
64DEFINE_HIST_FIELD_FN(u8);
65
66#define for_each_hist_field(i, hist_data) \
67 for ((i) = 0; (i) < (hist_data)->n_fields; (i)++)
68
69#define for_each_hist_val_field(i, hist_data) \
70 for ((i) = 0; (i) < (hist_data)->n_vals; (i)++)
71
72#define for_each_hist_key_field(i, hist_data) \
73 for ((i) = (hist_data)->n_vals; (i) < (hist_data)->n_fields; (i)++)
74
75#define HITCOUNT_IDX 0
76#define HIST_KEY_MAX 1
77#define HIST_KEY_SIZE_MAX MAX_FILTER_STR_VAL
78
79enum hist_field_flags {
80 HIST_FIELD_FL_HITCOUNT = 1,
81 HIST_FIELD_FL_KEY = 2,
82 HIST_FIELD_FL_STRING = 4,
83};
84
85struct hist_trigger_attrs {
86 char *keys_str;
87 unsigned int map_bits;
88};
89
90struct hist_trigger_data {
91 struct hist_field *fields[TRACING_MAP_FIELDS_MAX];
92 unsigned int n_vals;
93 unsigned int n_keys;
94 unsigned int n_fields;
95 unsigned int key_size;
96 struct tracing_map_sort_key sort_keys[TRACING_MAP_SORT_KEYS_MAX];
97 unsigned int n_sort_keys;
98 struct trace_event_file *event_file;
99 struct hist_trigger_attrs *attrs;
100 struct tracing_map *map;
101};
102
103static hist_field_fn_t select_value_fn(int field_size, int field_is_signed)
104{
105 hist_field_fn_t fn = NULL;
106
107 switch (field_size) {
108 case 8:
109 if (field_is_signed)
110 fn = hist_field_s64;
111 else
112 fn = hist_field_u64;
113 break;
114 case 4:
115 if (field_is_signed)
116 fn = hist_field_s32;
117 else
118 fn = hist_field_u32;
119 break;
120 case 2:
121 if (field_is_signed)
122 fn = hist_field_s16;
123 else
124 fn = hist_field_u16;
125 break;
126 case 1:
127 if (field_is_signed)
128 fn = hist_field_s8;
129 else
130 fn = hist_field_u8;
131 break;
132 }
133
134 return fn;
135}
136
137static int parse_map_size(char *str)
138{
139 unsigned long size, map_bits;
140 int ret;
141
142 strsep(&str, "=");
143 if (!str) {
144 ret = -EINVAL;
145 goto out;
146 }
147
148 ret = kstrtoul(str, 0, &size);
149 if (ret)
150 goto out;
151
152 map_bits = ilog2(roundup_pow_of_two(size));
153 if (map_bits < TRACING_MAP_BITS_MIN ||
154 map_bits > TRACING_MAP_BITS_MAX)
155 ret = -EINVAL;
156 else
157 ret = map_bits;
158 out:
159 return ret;
160}
161
162static void destroy_hist_trigger_attrs(struct hist_trigger_attrs *attrs)
163{
164 if (!attrs)
165 return;
166
167 kfree(attrs->keys_str);
168 kfree(attrs);
169}
170
171static struct hist_trigger_attrs *parse_hist_trigger_attrs(char *trigger_str)
172{
173 struct hist_trigger_attrs *attrs;
174 int ret = 0;
175
176 attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
177 if (!attrs)
178 return ERR_PTR(-ENOMEM);
179
180 while (trigger_str) {
181 char *str = strsep(&trigger_str, ":");
182
183 if ((strncmp(str, "key=", strlen("key=")) == 0) ||
184 (strncmp(str, "keys=", strlen("keys=")) == 0))
185 attrs->keys_str = kstrdup(str, GFP_KERNEL);
186 else if (strncmp(str, "size=", strlen("size=")) == 0) {
187 int map_bits = parse_map_size(str);
188
189 if (map_bits < 0) {
190 ret = map_bits;
191 goto free;
192 }
193 attrs->map_bits = map_bits;
194 } else {
195 ret = -EINVAL;
196 goto free;
197 }
198 }
199
200 if (!attrs->keys_str) {
201 ret = -EINVAL;
202 goto free;
203 }
204
205 return attrs;
206 free:
207 destroy_hist_trigger_attrs(attrs);
208
209 return ERR_PTR(ret);
210}
211
212static void destroy_hist_field(struct hist_field *hist_field)
213{
214 kfree(hist_field);
215}
216
217static struct hist_field *create_hist_field(struct ftrace_event_field *field,
218 unsigned long flags)
219{
220 struct hist_field *hist_field;
221
222 if (field && is_function_field(field))
223 return NULL;
224
225 hist_field = kzalloc(sizeof(struct hist_field), GFP_KERNEL);
226 if (!hist_field)
227 return NULL;
228
229 if (flags & HIST_FIELD_FL_HITCOUNT) {
230 hist_field->fn = hist_field_counter;
231 goto out;
232 }
233
234 if (is_string_field(field)) {
235 flags |= HIST_FIELD_FL_STRING;
236 hist_field->fn = hist_field_string;
237 } else {
238 hist_field->fn = select_value_fn(field->size,
239 field->is_signed);
240 if (!hist_field->fn) {
241 destroy_hist_field(hist_field);
242 return NULL;
243 }
244 }
245 out:
246 hist_field->field = field;
247 hist_field->flags = flags;
248
249 return hist_field;
250}
251
252static void destroy_hist_fields(struct hist_trigger_data *hist_data)
253{
254 unsigned int i;
255
256 for (i = 0; i < TRACING_MAP_FIELDS_MAX; i++) {
257 if (hist_data->fields[i]) {
258 destroy_hist_field(hist_data->fields[i]);
259 hist_data->fields[i] = NULL;
260 }
261 }
262}
263
264static int create_hitcount_val(struct hist_trigger_data *hist_data)
265{
266 hist_data->fields[HITCOUNT_IDX] =
267 create_hist_field(NULL, HIST_FIELD_FL_HITCOUNT);
268 if (!hist_data->fields[HITCOUNT_IDX])
269 return -ENOMEM;
270
271 hist_data->n_vals++;
272
273 if (WARN_ON(hist_data->n_vals > TRACING_MAP_VALS_MAX))
274 return -EINVAL;
275
276 return 0;
277}
278
279static int create_val_fields(struct hist_trigger_data *hist_data,
280 struct trace_event_file *file)
281{
282 int ret;
283
284 ret = create_hitcount_val(hist_data);
285
286 return ret;
287}
288
289static int create_key_field(struct hist_trigger_data *hist_data,
290 unsigned int key_idx,
291 struct trace_event_file *file,
292 char *field_str)
293{
294 struct ftrace_event_field *field = NULL;
295 unsigned long flags = 0;
296 unsigned int key_size;
297 int ret = 0;
298
299 if (WARN_ON(key_idx >= TRACING_MAP_FIELDS_MAX))
300 return -EINVAL;
301
302 flags |= HIST_FIELD_FL_KEY;
303
304 field = trace_find_event_field(file->event_call, field_str);
305 if (!field) {
306 ret = -EINVAL;
307 goto out;
308 }
309
310 key_size = field->size;
311
312 hist_data->fields[key_idx] = create_hist_field(field, flags);
313 if (!hist_data->fields[key_idx]) {
314 ret = -ENOMEM;
315 goto out;
316 }
317
318 key_size = ALIGN(key_size, sizeof(u64));
319 hist_data->fields[key_idx]->size = key_size;
320 hist_data->key_size = key_size;
321 if (hist_data->key_size > HIST_KEY_SIZE_MAX) {
322 ret = -EINVAL;
323 goto out;
324 }
325
326 hist_data->n_keys++;
327
328 if (WARN_ON(hist_data->n_keys > TRACING_MAP_KEYS_MAX))
329 return -EINVAL;
330
331 ret = key_size;
332 out:
333 return ret;
334}
335
336static int create_key_fields(struct hist_trigger_data *hist_data,
337 struct trace_event_file *file)
338{
339 unsigned int i, n_vals = hist_data->n_vals;
340 char *fields_str, *field_str;
341 int ret = -EINVAL;
342
343 fields_str = hist_data->attrs->keys_str;
344 if (!fields_str)
345 goto out;
346
347 strsep(&fields_str, "=");
348 if (!fields_str)
349 goto out;
350
351 for (i = n_vals; i < n_vals + HIST_KEY_MAX; i++) {
352 field_str = strsep(&fields_str, ",");
353 if (!field_str)
354 break;
355 ret = create_key_field(hist_data, i, file, field_str);
356 if (ret < 0)
357 goto out;
358 }
359 if (fields_str) {
360 ret = -EINVAL;
361 goto out;
362 }
363 ret = 0;
364 out:
365 return ret;
366}
367
368static int create_hist_fields(struct hist_trigger_data *hist_data,
369 struct trace_event_file *file)
370{
371 int ret;
372
373 ret = create_val_fields(hist_data, file);
374 if (ret)
375 goto out;
376
377 ret = create_key_fields(hist_data, file);
378 if (ret)
379 goto out;
380
381 hist_data->n_fields = hist_data->n_vals + hist_data->n_keys;
382 out:
383 return ret;
384}
385
386static int create_sort_keys(struct hist_trigger_data *hist_data)
387{
388 int ret = 0;
389
390 hist_data->n_sort_keys = 1; /* sort_keys[0] is always hitcount */
391
392 return ret;
393}
394
395static void destroy_hist_data(struct hist_trigger_data *hist_data)
396{
397 destroy_hist_trigger_attrs(hist_data->attrs);
398 destroy_hist_fields(hist_data);
399 tracing_map_destroy(hist_data->map);
400 kfree(hist_data);
401}
402
403static int create_tracing_map_fields(struct hist_trigger_data *hist_data)
404{
405 struct tracing_map *map = hist_data->map;
406 struct ftrace_event_field *field;
407 struct hist_field *hist_field;
408 unsigned int i, idx;
409
410 for_each_hist_field(i, hist_data) {
411 hist_field = hist_data->fields[i];
412 if (hist_field->flags & HIST_FIELD_FL_KEY) {
413 tracing_map_cmp_fn_t cmp_fn;
414
415 field = hist_field->field;
416
417 if (is_string_field(field))
418 cmp_fn = tracing_map_cmp_string;
419 else
420 cmp_fn = tracing_map_cmp_num(field->size,
421 field->is_signed);
422 idx = tracing_map_add_key_field(map, 0, cmp_fn);
423 } else
424 idx = tracing_map_add_sum_field(map);
425
426 if (idx < 0)
427 return idx;
428 }
429
430 return 0;
431}
432
433static struct hist_trigger_data *
434create_hist_data(unsigned int map_bits,
435 struct hist_trigger_attrs *attrs,
436 struct trace_event_file *file)
437{
438 struct hist_trigger_data *hist_data;
439 int ret = 0;
440
441 hist_data = kzalloc(sizeof(*hist_data), GFP_KERNEL);
442 if (!hist_data)
443 return ERR_PTR(-ENOMEM);
444
445 hist_data->attrs = attrs;
446
447 ret = create_hist_fields(hist_data, file);
448 if (ret)
449 goto free;
450
451 ret = create_sort_keys(hist_data);
452 if (ret)
453 goto free;
454
455 hist_data->map = tracing_map_create(map_bits, hist_data->key_size,
456 NULL, hist_data);
457 if (IS_ERR(hist_data->map)) {
458 ret = PTR_ERR(hist_data->map);
459 hist_data->map = NULL;
460 goto free;
461 }
462
463 ret = create_tracing_map_fields(hist_data);
464 if (ret)
465 goto free;
466
467 ret = tracing_map_init(hist_data->map);
468 if (ret)
469 goto free;
470
471 hist_data->event_file = file;
472 out:
473 return hist_data;
474 free:
475 hist_data->attrs = NULL;
476
477 destroy_hist_data(hist_data);
478
479 hist_data = ERR_PTR(ret);
480
481 goto out;
482}
483
484static void hist_trigger_elt_update(struct hist_trigger_data *hist_data,
485 struct tracing_map_elt *elt,
486 void *rec)
487{
488 struct hist_field *hist_field;
489 unsigned int i;
490 u64 hist_val;
491
492 for_each_hist_val_field(i, hist_data) {
493 hist_field = hist_data->fields[i];
494 hist_val = hist_field->fn(hist_field, rec);
495 tracing_map_update_sum(elt, i, hist_val);
496 }
497}
498
499static void event_hist_trigger(struct event_trigger_data *data, void *rec)
500{
501 struct hist_trigger_data *hist_data = data->private_data;
502 struct hist_field *key_field;
503 struct tracing_map_elt *elt;
504 u64 field_contents;
505 void *key = NULL;
506 unsigned int i;
507
508 for_each_hist_key_field(i, hist_data) {
509 key_field = hist_data->fields[i];
510
511 field_contents = key_field->fn(key_field, rec);
512 if (key_field->flags & HIST_FIELD_FL_STRING)
513 key = (void *)(unsigned long)field_contents;
514 else
515 key = (void *)&field_contents;
516 }
517
518 elt = tracing_map_insert(hist_data->map, key);
519 if (elt)
520 hist_trigger_elt_update(hist_data, elt, rec);
521}
522
523static void
524hist_trigger_entry_print(struct seq_file *m,
525 struct hist_trigger_data *hist_data, void *key,
526 struct tracing_map_elt *elt)
527{
528 struct hist_field *key_field;
529 unsigned int i;
530 u64 uval;
531
532 seq_puts(m, "{ ");
533
534 for_each_hist_key_field(i, hist_data) {
535 key_field = hist_data->fields[i];
536
537 if (i > hist_data->n_vals)
538 seq_puts(m, ", ");
539
540 if (key_field->flags & HIST_FIELD_FL_STRING) {
541 seq_printf(m, "%s: %-50s", key_field->field->name,
542 (char *)key);
543 } else {
544 uval = *(u64 *)key;
545 seq_printf(m, "%s: %10llu",
546 key_field->field->name, uval);
547 }
548 }
549
550 seq_puts(m, " }");
551
552 seq_printf(m, " hitcount: %10llu",
553 tracing_map_read_sum(elt, HITCOUNT_IDX));
554
555 seq_puts(m, "\n");
556}
557
558static int print_entries(struct seq_file *m,
559 struct hist_trigger_data *hist_data)
560{
561 struct tracing_map_sort_entry **sort_entries = NULL;
562 struct tracing_map *map = hist_data->map;
563 unsigned int i, n_entries;
564
565 n_entries = tracing_map_sort_entries(map, hist_data->sort_keys,
566 hist_data->n_sort_keys,
567 &sort_entries);
568 if (n_entries < 0)
569 return n_entries;
570
571 for (i = 0; i < n_entries; i++)
572 hist_trigger_entry_print(m, hist_data,
573 sort_entries[i]->key,
574 sort_entries[i]->elt);
575
576 tracing_map_destroy_sort_entries(sort_entries, n_entries);
577
578 return n_entries;
579}
580
581static int hist_show(struct seq_file *m, void *v)
582{
583 struct event_trigger_data *test, *data = NULL;
584 struct trace_event_file *event_file;
585 struct hist_trigger_data *hist_data;
586 int n_entries, ret = 0;
587
588 mutex_lock(&event_mutex);
589
590 event_file = event_file_data(m->private);
591 if (unlikely(!event_file)) {
592 ret = -ENODEV;
593 goto out_unlock;
594 }
595
596 list_for_each_entry_rcu(test, &event_file->triggers, list) {
597 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
598 data = test;
599 break;
600 }
601 }
602 if (!data)
603 goto out_unlock;
604
605 seq_puts(m, "# event histogram\n#\n# trigger info: ");
606 data->ops->print(m, data->ops, data);
607 seq_puts(m, "\n");
608
609 hist_data = data->private_data;
610 n_entries = print_entries(m, hist_data);
611 if (n_entries < 0) {
612 ret = n_entries;
613 n_entries = 0;
614 }
615
616 seq_printf(m, "\nTotals:\n Hits: %llu\n Entries: %u\n Dropped: %llu\n",
617 (u64)atomic64_read(&hist_data->map->hits),
618 n_entries, (u64)atomic64_read(&hist_data->map->drops));
619 out_unlock:
620 mutex_unlock(&event_mutex);
621
622 return ret;
623}
624
625static int event_hist_open(struct inode *inode, struct file *file)
626{
627 return single_open(file, hist_show, file);
628}
629
630const struct file_operations event_hist_fops = {
631 .open = event_hist_open,
632 .read = seq_read,
633 .llseek = seq_lseek,
634 .release = single_release,
635};
636
637static void hist_field_print(struct seq_file *m, struct hist_field *hist_field)
638{
639 seq_printf(m, "%s", hist_field->field->name);
640}
641
642static int event_hist_trigger_print(struct seq_file *m,
643 struct event_trigger_ops *ops,
644 struct event_trigger_data *data)
645{
646 struct hist_trigger_data *hist_data = data->private_data;
647 struct hist_field *key_field;
648 unsigned int i;
649
650 seq_puts(m, "hist:keys=");
651
652 for_each_hist_key_field(i, hist_data) {
653 key_field = hist_data->fields[i];
654
655 if (i > hist_data->n_vals)
656 seq_puts(m, ",");
657
658 hist_field_print(m, key_field);
659 }
660
661 seq_puts(m, ":vals=");
662 seq_puts(m, "hitcount");
663
664 seq_puts(m, ":sort=");
665 seq_puts(m, "hitcount");
666
667 seq_printf(m, ":size=%u", (1 << hist_data->map->map_bits));
668
669 if (data->filter_str)
670 seq_printf(m, " if %s", data->filter_str);
671
672 seq_puts(m, " [active]");
673
674 seq_putc(m, '\n');
675
676 return 0;
677}
678
679static void event_hist_trigger_free(struct event_trigger_ops *ops,
680 struct event_trigger_data *data)
681{
682 struct hist_trigger_data *hist_data = data->private_data;
683
684 if (WARN_ON_ONCE(data->ref <= 0))
685 return;
686
687 data->ref--;
688 if (!data->ref) {
689 trigger_data_free(data);
690 destroy_hist_data(hist_data);
691 }
692}
693
694static struct event_trigger_ops event_hist_trigger_ops = {
695 .func = event_hist_trigger,
696 .print = event_hist_trigger_print,
697 .init = event_trigger_init,
698 .free = event_hist_trigger_free,
699};
700
701static struct event_trigger_ops *event_hist_get_trigger_ops(char *cmd,
702 char *param)
703{
704 return &event_hist_trigger_ops;
705}
706
707static int hist_register_trigger(char *glob, struct event_trigger_ops *ops,
708 struct event_trigger_data *data,
709 struct trace_event_file *file)
710{
711 struct event_trigger_data *test;
712 int ret = 0;
713
714 list_for_each_entry_rcu(test, &file->triggers, list) {
715 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
716 ret = -EEXIST;
717 goto out;
718 }
719 }
720
721 if (data->ops->init) {
722 ret = data->ops->init(data->ops, data);
723 if (ret < 0)
724 goto out;
725 }
726
727 list_add_rcu(&data->list, &file->triggers);
728 ret++;
729
730 update_cond_flag(file);
731 if (trace_event_trigger_enable_disable(file, 1) < 0) {
732 list_del_rcu(&data->list);
733 update_cond_flag(file);
734 ret--;
735 }
736 out:
737 return ret;
738}
739
740static int event_hist_trigger_func(struct event_command *cmd_ops,
741 struct trace_event_file *file,
742 char *glob, char *cmd, char *param)
743{
744 unsigned int hist_trigger_bits = TRACING_MAP_BITS_DEFAULT;
745 struct event_trigger_data *trigger_data;
746 struct hist_trigger_attrs *attrs;
747 struct event_trigger_ops *trigger_ops;
748 struct hist_trigger_data *hist_data;
749 char *trigger;
750 int ret = 0;
751
752 if (!param)
753 return -EINVAL;
754
755 /* separate the trigger from the filter (k:v [if filter]) */
756 trigger = strsep(&param, " \t");
757 if (!trigger)
758 return -EINVAL;
759
760 attrs = parse_hist_trigger_attrs(trigger);
761 if (IS_ERR(attrs))
762 return PTR_ERR(attrs);
763
764 if (attrs->map_bits)
765 hist_trigger_bits = attrs->map_bits;
766
767 hist_data = create_hist_data(hist_trigger_bits, attrs, file);
768 if (IS_ERR(hist_data)) {
769 destroy_hist_trigger_attrs(attrs);
770 return PTR_ERR(hist_data);
771 }
772
773 trigger_ops = cmd_ops->get_trigger_ops(cmd, trigger);
774
775 ret = -ENOMEM;
776 trigger_data = kzalloc(sizeof(*trigger_data), GFP_KERNEL);
777 if (!trigger_data)
778 goto out_free;
779
780 trigger_data->count = -1;
781 trigger_data->ops = trigger_ops;
782 trigger_data->cmd_ops = cmd_ops;
783
784 INIT_LIST_HEAD(&trigger_data->list);
785 RCU_INIT_POINTER(trigger_data->filter, NULL);
786
787 trigger_data->private_data = hist_data;
788
789 if (glob[0] == '!') {
790 cmd_ops->unreg(glob+1, trigger_ops, trigger_data, file);
791 ret = 0;
792 goto out_free;
793 }
794
795 if (!param) /* if param is non-empty, it's supposed to be a filter */
796 goto out_reg;
797
798 if (!cmd_ops->set_filter)
799 goto out_reg;
800
801 ret = cmd_ops->set_filter(param, trigger_data, file);
802 if (ret < 0)
803 goto out_free;
804 out_reg:
805 ret = cmd_ops->reg(glob, trigger_ops, trigger_data, file);
806 /*
807 * The above returns on success the # of triggers registered,
808 * but if it didn't register any it returns zero. Consider no
809 * triggers registered a failure too.
810 */
811 if (!ret) {
812 ret = -ENOENT;
813 goto out_free;
814 } else if (ret < 0)
815 goto out_free;
816 /* Just return zero, not the number of registered triggers */
817 ret = 0;
818 out:
819 return ret;
820 out_free:
821 if (cmd_ops->set_filter)
822 cmd_ops->set_filter(NULL, trigger_data, NULL);
823
824 kfree(trigger_data);
825
826 destroy_hist_data(hist_data);
827 goto out;
828}
829
830static struct event_command trigger_hist_cmd = {
831 .name = "hist",
832 .trigger_type = ETT_EVENT_HIST,
833 .flags = EVENT_CMD_FL_NEEDS_REC,
834 .func = event_hist_trigger_func,
835 .reg = hist_register_trigger,
836 .unreg = unregister_trigger,
837 .get_trigger_ops = event_hist_get_trigger_ops,
838 .set_filter = set_trigger_filter,
839};
840
841__init int register_trigger_hist_cmd(void)
842{
843 int ret;
844
845 ret = register_event_command(&trigger_hist_cmd);
846 WARN_ON(ret < 0);
847
848 return ret;
849}
diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c
index d67992f3bb0e..d29092afe005 100644
--- a/kernel/trace/trace_events_trigger.c
+++ b/kernel/trace/trace_events_trigger.c
@@ -1447,6 +1447,7 @@ __init int register_trigger_cmds(void)
1447 register_trigger_snapshot_cmd(); 1447 register_trigger_snapshot_cmd();
1448 register_trigger_stacktrace_cmd(); 1448 register_trigger_stacktrace_cmd();
1449 register_trigger_enable_disable_cmds(); 1449 register_trigger_enable_disable_cmds();
1450 register_trigger_hist_cmd();
1450 1451
1451 return 0; 1452 return 0;
1452} 1453}