tracing: Add hist trigger 'sym' and 'sym-offset' modifiers
[linux-2.6-block.git] / kernel / trace / trace_events_hist.c
CommitLineData
7ef224d1
TZ
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;
76a3b0c8 35 unsigned int offset;
7ef224d1
TZ
36};
37
38static u64 hist_field_counter(struct hist_field *field, void *event)
39{
40 return 1;
41}
42
43static u64 hist_field_string(struct hist_field *hist_field, void *event)
44{
45 char *addr = (char *)(event + hist_field->field->offset);
46
47 return (u64)(unsigned long)addr;
48}
49
50#define DEFINE_HIST_FIELD_FN(type) \
51static u64 hist_field_##type(struct hist_field *hist_field, void *event)\
52{ \
53 type *addr = (type *)(event + hist_field->field->offset); \
54 \
55 return (u64)*addr; \
56}
57
58DEFINE_HIST_FIELD_FN(s64);
59DEFINE_HIST_FIELD_FN(u64);
60DEFINE_HIST_FIELD_FN(s32);
61DEFINE_HIST_FIELD_FN(u32);
62DEFINE_HIST_FIELD_FN(s16);
63DEFINE_HIST_FIELD_FN(u16);
64DEFINE_HIST_FIELD_FN(s8);
65DEFINE_HIST_FIELD_FN(u8);
66
67#define for_each_hist_field(i, hist_data) \
68 for ((i) = 0; (i) < (hist_data)->n_fields; (i)++)
69
70#define for_each_hist_val_field(i, hist_data) \
71 for ((i) = 0; (i) < (hist_data)->n_vals; (i)++)
72
73#define for_each_hist_key_field(i, hist_data) \
74 for ((i) = (hist_data)->n_vals; (i) < (hist_data)->n_fields; (i)++)
75
76#define HITCOUNT_IDX 0
76a3b0c8 77#define HIST_KEY_SIZE_MAX (MAX_FILTER_STR_VAL + sizeof(u64))
7ef224d1
TZ
78
79enum hist_field_flags {
c6afad49
TZ
80 HIST_FIELD_FL_HITCOUNT = 1,
81 HIST_FIELD_FL_KEY = 2,
82 HIST_FIELD_FL_STRING = 4,
83 HIST_FIELD_FL_HEX = 8,
84 HIST_FIELD_FL_SYM = 16,
85 HIST_FIELD_FL_SYM_OFFSET = 32,
7ef224d1
TZ
86};
87
88struct hist_trigger_attrs {
89 char *keys_str;
f2606835 90 char *vals_str;
e62347d2 91 char *sort_key_str;
83e99914
TZ
92 bool pause;
93 bool cont;
e86ae9ba 94 bool clear;
7ef224d1
TZ
95 unsigned int map_bits;
96};
97
98struct hist_trigger_data {
99 struct hist_field *fields[TRACING_MAP_FIELDS_MAX];
100 unsigned int n_vals;
101 unsigned int n_keys;
102 unsigned int n_fields;
103 unsigned int key_size;
104 struct tracing_map_sort_key sort_keys[TRACING_MAP_SORT_KEYS_MAX];
105 unsigned int n_sort_keys;
106 struct trace_event_file *event_file;
107 struct hist_trigger_attrs *attrs;
108 struct tracing_map *map;
109};
110
111static hist_field_fn_t select_value_fn(int field_size, int field_is_signed)
112{
113 hist_field_fn_t fn = NULL;
114
115 switch (field_size) {
116 case 8:
117 if (field_is_signed)
118 fn = hist_field_s64;
119 else
120 fn = hist_field_u64;
121 break;
122 case 4:
123 if (field_is_signed)
124 fn = hist_field_s32;
125 else
126 fn = hist_field_u32;
127 break;
128 case 2:
129 if (field_is_signed)
130 fn = hist_field_s16;
131 else
132 fn = hist_field_u16;
133 break;
134 case 1:
135 if (field_is_signed)
136 fn = hist_field_s8;
137 else
138 fn = hist_field_u8;
139 break;
140 }
141
142 return fn;
143}
144
145static int parse_map_size(char *str)
146{
147 unsigned long size, map_bits;
148 int ret;
149
150 strsep(&str, "=");
151 if (!str) {
152 ret = -EINVAL;
153 goto out;
154 }
155
156 ret = kstrtoul(str, 0, &size);
157 if (ret)
158 goto out;
159
160 map_bits = ilog2(roundup_pow_of_two(size));
161 if (map_bits < TRACING_MAP_BITS_MIN ||
162 map_bits > TRACING_MAP_BITS_MAX)
163 ret = -EINVAL;
164 else
165 ret = map_bits;
166 out:
167 return ret;
168}
169
170static void destroy_hist_trigger_attrs(struct hist_trigger_attrs *attrs)
171{
172 if (!attrs)
173 return;
174
e62347d2 175 kfree(attrs->sort_key_str);
7ef224d1 176 kfree(attrs->keys_str);
f2606835 177 kfree(attrs->vals_str);
7ef224d1
TZ
178 kfree(attrs);
179}
180
181static struct hist_trigger_attrs *parse_hist_trigger_attrs(char *trigger_str)
182{
183 struct hist_trigger_attrs *attrs;
184 int ret = 0;
185
186 attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
187 if (!attrs)
188 return ERR_PTR(-ENOMEM);
189
190 while (trigger_str) {
191 char *str = strsep(&trigger_str, ":");
192
193 if ((strncmp(str, "key=", strlen("key=")) == 0) ||
194 (strncmp(str, "keys=", strlen("keys=")) == 0))
195 attrs->keys_str = kstrdup(str, GFP_KERNEL);
f2606835
TZ
196 else if ((strncmp(str, "val=", strlen("val=")) == 0) ||
197 (strncmp(str, "vals=", strlen("vals=")) == 0) ||
198 (strncmp(str, "values=", strlen("values=")) == 0))
199 attrs->vals_str = kstrdup(str, GFP_KERNEL);
e62347d2
TZ
200 else if (strncmp(str, "sort=", strlen("sort=")) == 0)
201 attrs->sort_key_str = kstrdup(str, GFP_KERNEL);
83e99914
TZ
202 else if (strcmp(str, "pause") == 0)
203 attrs->pause = true;
204 else if ((strcmp(str, "cont") == 0) ||
205 (strcmp(str, "continue") == 0))
206 attrs->cont = true;
e86ae9ba
TZ
207 else if (strcmp(str, "clear") == 0)
208 attrs->clear = true;
7ef224d1
TZ
209 else if (strncmp(str, "size=", strlen("size=")) == 0) {
210 int map_bits = parse_map_size(str);
211
212 if (map_bits < 0) {
213 ret = map_bits;
214 goto free;
215 }
216 attrs->map_bits = map_bits;
217 } else {
218 ret = -EINVAL;
219 goto free;
220 }
221 }
222
223 if (!attrs->keys_str) {
224 ret = -EINVAL;
225 goto free;
226 }
227
228 return attrs;
229 free:
230 destroy_hist_trigger_attrs(attrs);
231
232 return ERR_PTR(ret);
233}
234
235static void destroy_hist_field(struct hist_field *hist_field)
236{
237 kfree(hist_field);
238}
239
240static struct hist_field *create_hist_field(struct ftrace_event_field *field,
241 unsigned long flags)
242{
243 struct hist_field *hist_field;
244
245 if (field && is_function_field(field))
246 return NULL;
247
248 hist_field = kzalloc(sizeof(struct hist_field), GFP_KERNEL);
249 if (!hist_field)
250 return NULL;
251
252 if (flags & HIST_FIELD_FL_HITCOUNT) {
253 hist_field->fn = hist_field_counter;
254 goto out;
255 }
256
257 if (is_string_field(field)) {
258 flags |= HIST_FIELD_FL_STRING;
259 hist_field->fn = hist_field_string;
260 } else {
261 hist_field->fn = select_value_fn(field->size,
262 field->is_signed);
263 if (!hist_field->fn) {
264 destroy_hist_field(hist_field);
265 return NULL;
266 }
267 }
268 out:
269 hist_field->field = field;
270 hist_field->flags = flags;
271
272 return hist_field;
273}
274
275static void destroy_hist_fields(struct hist_trigger_data *hist_data)
276{
277 unsigned int i;
278
279 for (i = 0; i < TRACING_MAP_FIELDS_MAX; i++) {
280 if (hist_data->fields[i]) {
281 destroy_hist_field(hist_data->fields[i]);
282 hist_data->fields[i] = NULL;
283 }
284 }
285}
286
287static int create_hitcount_val(struct hist_trigger_data *hist_data)
288{
289 hist_data->fields[HITCOUNT_IDX] =
290 create_hist_field(NULL, HIST_FIELD_FL_HITCOUNT);
291 if (!hist_data->fields[HITCOUNT_IDX])
292 return -ENOMEM;
293
294 hist_data->n_vals++;
295
296 if (WARN_ON(hist_data->n_vals > TRACING_MAP_VALS_MAX))
297 return -EINVAL;
298
299 return 0;
300}
301
f2606835
TZ
302static int create_val_field(struct hist_trigger_data *hist_data,
303 unsigned int val_idx,
304 struct trace_event_file *file,
305 char *field_str)
306{
307 struct ftrace_event_field *field = NULL;
308 unsigned long flags = 0;
0c4a6b46 309 char *field_name;
f2606835
TZ
310 int ret = 0;
311
312 if (WARN_ON(val_idx >= TRACING_MAP_VALS_MAX))
313 return -EINVAL;
0c4a6b46
TZ
314
315 field_name = strsep(&field_str, ".");
316 if (field_str) {
317 if (strcmp(field_str, "hex") == 0)
318 flags |= HIST_FIELD_FL_HEX;
319 else {
320 ret = -EINVAL;
321 goto out;
322 }
323 }
324
325 field = trace_find_event_field(file->event_call, field_name);
f2606835
TZ
326 if (!field) {
327 ret = -EINVAL;
328 goto out;
329 }
330
331 hist_data->fields[val_idx] = create_hist_field(field, flags);
332 if (!hist_data->fields[val_idx]) {
333 ret = -ENOMEM;
334 goto out;
335 }
336
337 ++hist_data->n_vals;
338
339 if (WARN_ON(hist_data->n_vals > TRACING_MAP_VALS_MAX))
340 ret = -EINVAL;
341 out:
342 return ret;
343}
344
7ef224d1
TZ
345static int create_val_fields(struct hist_trigger_data *hist_data,
346 struct trace_event_file *file)
347{
f2606835
TZ
348 char *fields_str, *field_str;
349 unsigned int i, j;
7ef224d1
TZ
350 int ret;
351
352 ret = create_hitcount_val(hist_data);
f2606835
TZ
353 if (ret)
354 goto out;
7ef224d1 355
f2606835
TZ
356 fields_str = hist_data->attrs->vals_str;
357 if (!fields_str)
358 goto out;
359
360 strsep(&fields_str, "=");
361 if (!fields_str)
362 goto out;
363
364 for (i = 0, j = 1; i < TRACING_MAP_VALS_MAX &&
365 j < TRACING_MAP_VALS_MAX; i++) {
366 field_str = strsep(&fields_str, ",");
367 if (!field_str)
368 break;
369 if (strcmp(field_str, "hitcount") == 0)
370 continue;
371 ret = create_val_field(hist_data, j++, file, field_str);
372 if (ret)
373 goto out;
374 }
375 if (fields_str && (strcmp(fields_str, "hitcount") != 0))
376 ret = -EINVAL;
377 out:
7ef224d1
TZ
378 return ret;
379}
380
381static int create_key_field(struct hist_trigger_data *hist_data,
382 unsigned int key_idx,
76a3b0c8 383 unsigned int key_offset,
7ef224d1
TZ
384 struct trace_event_file *file,
385 char *field_str)
386{
387 struct ftrace_event_field *field = NULL;
388 unsigned long flags = 0;
389 unsigned int key_size;
0c4a6b46 390 char *field_name;
7ef224d1
TZ
391 int ret = 0;
392
393 if (WARN_ON(key_idx >= TRACING_MAP_FIELDS_MAX))
394 return -EINVAL;
395
396 flags |= HIST_FIELD_FL_KEY;
397
0c4a6b46
TZ
398 field_name = strsep(&field_str, ".");
399 if (field_str) {
400 if (strcmp(field_str, "hex") == 0)
401 flags |= HIST_FIELD_FL_HEX;
c6afad49
TZ
402 else if (strcmp(field_str, "sym") == 0)
403 flags |= HIST_FIELD_FL_SYM;
404 else if (strcmp(field_str, "sym-offset") == 0)
405 flags |= HIST_FIELD_FL_SYM_OFFSET;
0c4a6b46
TZ
406 else {
407 ret = -EINVAL;
408 goto out;
409 }
410 }
411
412 field = trace_find_event_field(file->event_call, field_name);
7ef224d1
TZ
413 if (!field) {
414 ret = -EINVAL;
415 goto out;
416 }
417
418 key_size = field->size;
419
420 hist_data->fields[key_idx] = create_hist_field(field, flags);
421 if (!hist_data->fields[key_idx]) {
422 ret = -ENOMEM;
423 goto out;
424 }
425
426 key_size = ALIGN(key_size, sizeof(u64));
427 hist_data->fields[key_idx]->size = key_size;
76a3b0c8
TZ
428 hist_data->fields[key_idx]->offset = key_offset;
429 hist_data->key_size += key_size;
7ef224d1
TZ
430 if (hist_data->key_size > HIST_KEY_SIZE_MAX) {
431 ret = -EINVAL;
432 goto out;
433 }
434
435 hist_data->n_keys++;
436
437 if (WARN_ON(hist_data->n_keys > TRACING_MAP_KEYS_MAX))
438 return -EINVAL;
439
440 ret = key_size;
441 out:
442 return ret;
443}
444
445static int create_key_fields(struct hist_trigger_data *hist_data,
446 struct trace_event_file *file)
447{
76a3b0c8 448 unsigned int i, key_offset = 0, n_vals = hist_data->n_vals;
7ef224d1
TZ
449 char *fields_str, *field_str;
450 int ret = -EINVAL;
451
452 fields_str = hist_data->attrs->keys_str;
453 if (!fields_str)
454 goto out;
455
456 strsep(&fields_str, "=");
457 if (!fields_str)
458 goto out;
459
76a3b0c8 460 for (i = n_vals; i < n_vals + TRACING_MAP_KEYS_MAX; i++) {
7ef224d1
TZ
461 field_str = strsep(&fields_str, ",");
462 if (!field_str)
463 break;
76a3b0c8
TZ
464 ret = create_key_field(hist_data, i, key_offset,
465 file, field_str);
7ef224d1
TZ
466 if (ret < 0)
467 goto out;
76a3b0c8 468 key_offset += ret;
7ef224d1
TZ
469 }
470 if (fields_str) {
471 ret = -EINVAL;
472 goto out;
473 }
474 ret = 0;
475 out:
476 return ret;
477}
478
479static int create_hist_fields(struct hist_trigger_data *hist_data,
480 struct trace_event_file *file)
481{
482 int ret;
483
484 ret = create_val_fields(hist_data, file);
485 if (ret)
486 goto out;
487
488 ret = create_key_fields(hist_data, file);
489 if (ret)
490 goto out;
491
492 hist_data->n_fields = hist_data->n_vals + hist_data->n_keys;
493 out:
494 return ret;
495}
496
e62347d2
TZ
497static int is_descending(const char *str)
498{
499 if (!str)
500 return 0;
501
502 if (strcmp(str, "descending") == 0)
503 return 1;
504
505 if (strcmp(str, "ascending") == 0)
506 return 0;
507
508 return -EINVAL;
509}
510
7ef224d1
TZ
511static int create_sort_keys(struct hist_trigger_data *hist_data)
512{
e62347d2
TZ
513 char *fields_str = hist_data->attrs->sort_key_str;
514 struct ftrace_event_field *field = NULL;
515 struct tracing_map_sort_key *sort_key;
516 int descending, ret = 0;
517 unsigned int i, j;
518
519 hist_data->n_sort_keys = 1; /* we always have at least one, hitcount */
520
521 if (!fields_str)
522 goto out;
523
524 strsep(&fields_str, "=");
525 if (!fields_str) {
526 ret = -EINVAL;
527 goto out;
528 }
529
530 for (i = 0; i < TRACING_MAP_SORT_KEYS_MAX; i++) {
531 char *field_str, *field_name;
532
533 sort_key = &hist_data->sort_keys[i];
534
535 field_str = strsep(&fields_str, ",");
536 if (!field_str) {
537 if (i == 0)
538 ret = -EINVAL;
539 break;
540 }
541
542 if ((i == TRACING_MAP_SORT_KEYS_MAX - 1) && fields_str) {
543 ret = -EINVAL;
544 break;
545 }
7ef224d1 546
e62347d2
TZ
547 field_name = strsep(&field_str, ".");
548 if (!field_name) {
549 ret = -EINVAL;
550 break;
551 }
552
553 if (strcmp(field_name, "hitcount") == 0) {
554 descending = is_descending(field_str);
555 if (descending < 0) {
556 ret = descending;
557 break;
558 }
559 sort_key->descending = descending;
560 continue;
561 }
7ef224d1 562
e62347d2
TZ
563 for (j = 1; j < hist_data->n_fields; j++) {
564 field = hist_data->fields[j]->field;
565 if (field && (strcmp(field_name, field->name) == 0)) {
566 sort_key->field_idx = j;
567 descending = is_descending(field_str);
568 if (descending < 0) {
569 ret = descending;
570 goto out;
571 }
572 sort_key->descending = descending;
573 break;
574 }
575 }
576 if (j == hist_data->n_fields) {
577 ret = -EINVAL;
578 break;
579 }
580 }
581 hist_data->n_sort_keys = i;
582 out:
7ef224d1
TZ
583 return ret;
584}
585
586static void destroy_hist_data(struct hist_trigger_data *hist_data)
587{
588 destroy_hist_trigger_attrs(hist_data->attrs);
589 destroy_hist_fields(hist_data);
590 tracing_map_destroy(hist_data->map);
591 kfree(hist_data);
592}
593
594static int create_tracing_map_fields(struct hist_trigger_data *hist_data)
595{
596 struct tracing_map *map = hist_data->map;
597 struct ftrace_event_field *field;
598 struct hist_field *hist_field;
599 unsigned int i, idx;
600
601 for_each_hist_field(i, hist_data) {
602 hist_field = hist_data->fields[i];
603 if (hist_field->flags & HIST_FIELD_FL_KEY) {
604 tracing_map_cmp_fn_t cmp_fn;
605
606 field = hist_field->field;
607
608 if (is_string_field(field))
609 cmp_fn = tracing_map_cmp_string;
610 else
611 cmp_fn = tracing_map_cmp_num(field->size,
612 field->is_signed);
76a3b0c8
TZ
613 idx = tracing_map_add_key_field(map,
614 hist_field->offset,
615 cmp_fn);
616
7ef224d1
TZ
617 } else
618 idx = tracing_map_add_sum_field(map);
619
620 if (idx < 0)
621 return idx;
622 }
623
624 return 0;
625}
626
627static struct hist_trigger_data *
628create_hist_data(unsigned int map_bits,
629 struct hist_trigger_attrs *attrs,
630 struct trace_event_file *file)
631{
632 struct hist_trigger_data *hist_data;
633 int ret = 0;
634
635 hist_data = kzalloc(sizeof(*hist_data), GFP_KERNEL);
636 if (!hist_data)
637 return ERR_PTR(-ENOMEM);
638
639 hist_data->attrs = attrs;
640
641 ret = create_hist_fields(hist_data, file);
642 if (ret)
643 goto free;
644
645 ret = create_sort_keys(hist_data);
646 if (ret)
647 goto free;
648
649 hist_data->map = tracing_map_create(map_bits, hist_data->key_size,
650 NULL, hist_data);
651 if (IS_ERR(hist_data->map)) {
652 ret = PTR_ERR(hist_data->map);
653 hist_data->map = NULL;
654 goto free;
655 }
656
657 ret = create_tracing_map_fields(hist_data);
658 if (ret)
659 goto free;
660
661 ret = tracing_map_init(hist_data->map);
662 if (ret)
663 goto free;
664
665 hist_data->event_file = file;
666 out:
667 return hist_data;
668 free:
669 hist_data->attrs = NULL;
670
671 destroy_hist_data(hist_data);
672
673 hist_data = ERR_PTR(ret);
674
675 goto out;
676}
677
678static void hist_trigger_elt_update(struct hist_trigger_data *hist_data,
679 struct tracing_map_elt *elt,
680 void *rec)
681{
682 struct hist_field *hist_field;
683 unsigned int i;
684 u64 hist_val;
685
686 for_each_hist_val_field(i, hist_data) {
687 hist_field = hist_data->fields[i];
688 hist_val = hist_field->fn(hist_field, rec);
689 tracing_map_update_sum(elt, i, hist_val);
690 }
691}
692
693static void event_hist_trigger(struct event_trigger_data *data, void *rec)
694{
695 struct hist_trigger_data *hist_data = data->private_data;
76a3b0c8 696 char compound_key[HIST_KEY_SIZE_MAX];
7ef224d1
TZ
697 struct hist_field *key_field;
698 struct tracing_map_elt *elt;
699 u64 field_contents;
700 void *key = NULL;
701 unsigned int i;
702
76a3b0c8
TZ
703 if (hist_data->n_keys > 1)
704 memset(compound_key, 0, hist_data->key_size);
705
7ef224d1
TZ
706 for_each_hist_key_field(i, hist_data) {
707 key_field = hist_data->fields[i];
708
709 field_contents = key_field->fn(key_field, rec);
710 if (key_field->flags & HIST_FIELD_FL_STRING)
711 key = (void *)(unsigned long)field_contents;
712 else
713 key = (void *)&field_contents;
76a3b0c8
TZ
714
715 if (hist_data->n_keys > 1) {
716 memcpy(compound_key + key_field->offset, key,
717 key_field->size);
718 }
7ef224d1
TZ
719 }
720
76a3b0c8
TZ
721 if (hist_data->n_keys > 1)
722 key = compound_key;
723
7ef224d1
TZ
724 elt = tracing_map_insert(hist_data->map, key);
725 if (elt)
726 hist_trigger_elt_update(hist_data, elt, rec);
727}
728
729static void
730hist_trigger_entry_print(struct seq_file *m,
731 struct hist_trigger_data *hist_data, void *key,
732 struct tracing_map_elt *elt)
733{
734 struct hist_field *key_field;
c6afad49 735 char str[KSYM_SYMBOL_LEN];
7ef224d1
TZ
736 unsigned int i;
737 u64 uval;
738
739 seq_puts(m, "{ ");
740
741 for_each_hist_key_field(i, hist_data) {
742 key_field = hist_data->fields[i];
743
744 if (i > hist_data->n_vals)
745 seq_puts(m, ", ");
746
0c4a6b46
TZ
747 if (key_field->flags & HIST_FIELD_FL_HEX) {
748 uval = *(u64 *)(key + key_field->offset);
749 seq_printf(m, "%s: %llx",
750 key_field->field->name, uval);
c6afad49
TZ
751 } else if (key_field->flags & HIST_FIELD_FL_SYM) {
752 uval = *(u64 *)(key + key_field->offset);
753 sprint_symbol_no_offset(str, uval);
754 seq_printf(m, "%s: [%llx] %-45s",
755 key_field->field->name, uval, str);
756 } else if (key_field->flags & HIST_FIELD_FL_SYM_OFFSET) {
757 uval = *(u64 *)(key + key_field->offset);
758 sprint_symbol(str, uval);
759 seq_printf(m, "%s: [%llx] %-55s",
760 key_field->field->name, uval, str);
0c4a6b46 761 } else if (key_field->flags & HIST_FIELD_FL_STRING) {
7ef224d1 762 seq_printf(m, "%s: %-50s", key_field->field->name,
76a3b0c8 763 (char *)(key + key_field->offset));
7ef224d1 764 } else {
76a3b0c8
TZ
765 uval = *(u64 *)(key + key_field->offset);
766 seq_printf(m, "%s: %10llu", key_field->field->name,
767 uval);
7ef224d1
TZ
768 }
769 }
770
771 seq_puts(m, " }");
772
773 seq_printf(m, " hitcount: %10llu",
774 tracing_map_read_sum(elt, HITCOUNT_IDX));
775
f2606835 776 for (i = 1; i < hist_data->n_vals; i++) {
0c4a6b46
TZ
777 if (hist_data->fields[i]->flags & HIST_FIELD_FL_HEX) {
778 seq_printf(m, " %s: %10llx",
779 hist_data->fields[i]->field->name,
780 tracing_map_read_sum(elt, i));
781 } else {
782 seq_printf(m, " %s: %10llu",
783 hist_data->fields[i]->field->name,
784 tracing_map_read_sum(elt, i));
785 }
f2606835
TZ
786 }
787
7ef224d1
TZ
788 seq_puts(m, "\n");
789}
790
791static int print_entries(struct seq_file *m,
792 struct hist_trigger_data *hist_data)
793{
794 struct tracing_map_sort_entry **sort_entries = NULL;
795 struct tracing_map *map = hist_data->map;
796 unsigned int i, n_entries;
797
798 n_entries = tracing_map_sort_entries(map, hist_data->sort_keys,
799 hist_data->n_sort_keys,
800 &sort_entries);
801 if (n_entries < 0)
802 return n_entries;
803
804 for (i = 0; i < n_entries; i++)
805 hist_trigger_entry_print(m, hist_data,
806 sort_entries[i]->key,
807 sort_entries[i]->elt);
808
809 tracing_map_destroy_sort_entries(sort_entries, n_entries);
810
811 return n_entries;
812}
813
814static int hist_show(struct seq_file *m, void *v)
815{
816 struct event_trigger_data *test, *data = NULL;
817 struct trace_event_file *event_file;
818 struct hist_trigger_data *hist_data;
819 int n_entries, ret = 0;
820
821 mutex_lock(&event_mutex);
822
823 event_file = event_file_data(m->private);
824 if (unlikely(!event_file)) {
825 ret = -ENODEV;
826 goto out_unlock;
827 }
828
829 list_for_each_entry_rcu(test, &event_file->triggers, list) {
830 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
831 data = test;
832 break;
833 }
834 }
835 if (!data)
836 goto out_unlock;
837
838 seq_puts(m, "# event histogram\n#\n# trigger info: ");
839 data->ops->print(m, data->ops, data);
840 seq_puts(m, "\n");
841
842 hist_data = data->private_data;
843 n_entries = print_entries(m, hist_data);
844 if (n_entries < 0) {
845 ret = n_entries;
846 n_entries = 0;
847 }
848
849 seq_printf(m, "\nTotals:\n Hits: %llu\n Entries: %u\n Dropped: %llu\n",
850 (u64)atomic64_read(&hist_data->map->hits),
851 n_entries, (u64)atomic64_read(&hist_data->map->drops));
852 out_unlock:
853 mutex_unlock(&event_mutex);
854
855 return ret;
856}
857
858static int event_hist_open(struct inode *inode, struct file *file)
859{
860 return single_open(file, hist_show, file);
861}
862
863const struct file_operations event_hist_fops = {
864 .open = event_hist_open,
865 .read = seq_read,
866 .llseek = seq_lseek,
867 .release = single_release,
868};
869
0c4a6b46
TZ
870static const char *get_hist_field_flags(struct hist_field *hist_field)
871{
872 const char *flags_str = NULL;
873
874 if (hist_field->flags & HIST_FIELD_FL_HEX)
875 flags_str = "hex";
c6afad49
TZ
876 else if (hist_field->flags & HIST_FIELD_FL_SYM)
877 flags_str = "sym";
878 else if (hist_field->flags & HIST_FIELD_FL_SYM_OFFSET)
879 flags_str = "sym-offset";
0c4a6b46
TZ
880
881 return flags_str;
882}
883
7ef224d1
TZ
884static void hist_field_print(struct seq_file *m, struct hist_field *hist_field)
885{
886 seq_printf(m, "%s", hist_field->field->name);
0c4a6b46
TZ
887 if (hist_field->flags) {
888 const char *flags_str = get_hist_field_flags(hist_field);
889
890 if (flags_str)
891 seq_printf(m, ".%s", flags_str);
892 }
7ef224d1
TZ
893}
894
895static int event_hist_trigger_print(struct seq_file *m,
896 struct event_trigger_ops *ops,
897 struct event_trigger_data *data)
898{
899 struct hist_trigger_data *hist_data = data->private_data;
900 struct hist_field *key_field;
901 unsigned int i;
902
903 seq_puts(m, "hist:keys=");
904
905 for_each_hist_key_field(i, hist_data) {
906 key_field = hist_data->fields[i];
907
908 if (i > hist_data->n_vals)
909 seq_puts(m, ",");
910
911 hist_field_print(m, key_field);
912 }
913
914 seq_puts(m, ":vals=");
f2606835
TZ
915
916 for_each_hist_val_field(i, hist_data) {
917 if (i == HITCOUNT_IDX)
918 seq_puts(m, "hitcount");
919 else {
920 seq_puts(m, ",");
921 hist_field_print(m, hist_data->fields[i]);
922 }
923 }
7ef224d1
TZ
924
925 seq_puts(m, ":sort=");
e62347d2
TZ
926
927 for (i = 0; i < hist_data->n_sort_keys; i++) {
928 struct tracing_map_sort_key *sort_key;
929
930 sort_key = &hist_data->sort_keys[i];
931
932 if (i > 0)
933 seq_puts(m, ",");
934
935 if (sort_key->field_idx == HITCOUNT_IDX)
936 seq_puts(m, "hitcount");
937 else {
938 unsigned int idx = sort_key->field_idx;
939
940 if (WARN_ON(idx >= TRACING_MAP_FIELDS_MAX))
941 return -EINVAL;
942
943 hist_field_print(m, hist_data->fields[idx]);
944 }
945
946 if (sort_key->descending)
947 seq_puts(m, ".descending");
948 }
7ef224d1
TZ
949
950 seq_printf(m, ":size=%u", (1 << hist_data->map->map_bits));
951
952 if (data->filter_str)
953 seq_printf(m, " if %s", data->filter_str);
954
83e99914
TZ
955 if (data->paused)
956 seq_puts(m, " [paused]");
957 else
958 seq_puts(m, " [active]");
7ef224d1
TZ
959
960 seq_putc(m, '\n');
961
962 return 0;
963}
964
965static void event_hist_trigger_free(struct event_trigger_ops *ops,
966 struct event_trigger_data *data)
967{
968 struct hist_trigger_data *hist_data = data->private_data;
969
970 if (WARN_ON_ONCE(data->ref <= 0))
971 return;
972
973 data->ref--;
974 if (!data->ref) {
975 trigger_data_free(data);
976 destroy_hist_data(hist_data);
977 }
978}
979
980static struct event_trigger_ops event_hist_trigger_ops = {
981 .func = event_hist_trigger,
982 .print = event_hist_trigger_print,
983 .init = event_trigger_init,
984 .free = event_hist_trigger_free,
985};
986
987static struct event_trigger_ops *event_hist_get_trigger_ops(char *cmd,
988 char *param)
989{
990 return &event_hist_trigger_ops;
991}
992
e86ae9ba
TZ
993static void hist_clear(struct event_trigger_data *data)
994{
995 struct hist_trigger_data *hist_data = data->private_data;
996 bool paused;
997
998 paused = data->paused;
999 data->paused = true;
1000
1001 synchronize_sched();
1002
1003 tracing_map_clear(hist_data->map);
1004
1005 data->paused = paused;
1006}
1007
7ef224d1
TZ
1008static int hist_register_trigger(char *glob, struct event_trigger_ops *ops,
1009 struct event_trigger_data *data,
1010 struct trace_event_file *file)
1011{
83e99914 1012 struct hist_trigger_data *hist_data = data->private_data;
7ef224d1
TZ
1013 struct event_trigger_data *test;
1014 int ret = 0;
1015
1016 list_for_each_entry_rcu(test, &file->triggers, list) {
1017 if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
83e99914
TZ
1018 if (hist_data->attrs->pause)
1019 test->paused = true;
1020 else if (hist_data->attrs->cont)
1021 test->paused = false;
e86ae9ba
TZ
1022 else if (hist_data->attrs->clear)
1023 hist_clear(test);
83e99914
TZ
1024 else
1025 ret = -EEXIST;
7ef224d1
TZ
1026 goto out;
1027 }
1028 }
1029
e86ae9ba 1030 if (hist_data->attrs->cont || hist_data->attrs->clear) {
83e99914
TZ
1031 ret = -ENOENT;
1032 goto out;
1033 }
1034
1035 if (hist_data->attrs->pause)
1036 data->paused = true;
1037
7ef224d1
TZ
1038 if (data->ops->init) {
1039 ret = data->ops->init(data->ops, data);
1040 if (ret < 0)
1041 goto out;
1042 }
1043
1044 list_add_rcu(&data->list, &file->triggers);
1045 ret++;
1046
1047 update_cond_flag(file);
1048 if (trace_event_trigger_enable_disable(file, 1) < 0) {
1049 list_del_rcu(&data->list);
1050 update_cond_flag(file);
1051 ret--;
1052 }
1053 out:
1054 return ret;
1055}
1056
1057static int event_hist_trigger_func(struct event_command *cmd_ops,
1058 struct trace_event_file *file,
1059 char *glob, char *cmd, char *param)
1060{
1061 unsigned int hist_trigger_bits = TRACING_MAP_BITS_DEFAULT;
1062 struct event_trigger_data *trigger_data;
1063 struct hist_trigger_attrs *attrs;
1064 struct event_trigger_ops *trigger_ops;
1065 struct hist_trigger_data *hist_data;
1066 char *trigger;
1067 int ret = 0;
1068
1069 if (!param)
1070 return -EINVAL;
1071
1072 /* separate the trigger from the filter (k:v [if filter]) */
1073 trigger = strsep(&param, " \t");
1074 if (!trigger)
1075 return -EINVAL;
1076
1077 attrs = parse_hist_trigger_attrs(trigger);
1078 if (IS_ERR(attrs))
1079 return PTR_ERR(attrs);
1080
1081 if (attrs->map_bits)
1082 hist_trigger_bits = attrs->map_bits;
1083
1084 hist_data = create_hist_data(hist_trigger_bits, attrs, file);
1085 if (IS_ERR(hist_data)) {
1086 destroy_hist_trigger_attrs(attrs);
1087 return PTR_ERR(hist_data);
1088 }
1089
1090 trigger_ops = cmd_ops->get_trigger_ops(cmd, trigger);
1091
1092 ret = -ENOMEM;
1093 trigger_data = kzalloc(sizeof(*trigger_data), GFP_KERNEL);
1094 if (!trigger_data)
1095 goto out_free;
1096
1097 trigger_data->count = -1;
1098 trigger_data->ops = trigger_ops;
1099 trigger_data->cmd_ops = cmd_ops;
1100
1101 INIT_LIST_HEAD(&trigger_data->list);
1102 RCU_INIT_POINTER(trigger_data->filter, NULL);
1103
1104 trigger_data->private_data = hist_data;
1105
1106 if (glob[0] == '!') {
1107 cmd_ops->unreg(glob+1, trigger_ops, trigger_data, file);
1108 ret = 0;
1109 goto out_free;
1110 }
1111
1112 if (!param) /* if param is non-empty, it's supposed to be a filter */
1113 goto out_reg;
1114
1115 if (!cmd_ops->set_filter)
1116 goto out_reg;
1117
1118 ret = cmd_ops->set_filter(param, trigger_data, file);
1119 if (ret < 0)
1120 goto out_free;
1121 out_reg:
1122 ret = cmd_ops->reg(glob, trigger_ops, trigger_data, file);
1123 /*
1124 * The above returns on success the # of triggers registered,
1125 * but if it didn't register any it returns zero. Consider no
1126 * triggers registered a failure too.
1127 */
1128 if (!ret) {
e86ae9ba 1129 if (!(attrs->pause || attrs->cont || attrs->clear))
83e99914 1130 ret = -ENOENT;
7ef224d1
TZ
1131 goto out_free;
1132 } else if (ret < 0)
1133 goto out_free;
1134 /* Just return zero, not the number of registered triggers */
1135 ret = 0;
1136 out:
1137 return ret;
1138 out_free:
1139 if (cmd_ops->set_filter)
1140 cmd_ops->set_filter(NULL, trigger_data, NULL);
1141
1142 kfree(trigger_data);
1143
1144 destroy_hist_data(hist_data);
1145 goto out;
1146}
1147
1148static struct event_command trigger_hist_cmd = {
1149 .name = "hist",
1150 .trigger_type = ETT_EVENT_HIST,
1151 .flags = EVENT_CMD_FL_NEEDS_REC,
1152 .func = event_hist_trigger_func,
1153 .reg = hist_register_trigger,
1154 .unreg = unregister_trigger,
1155 .get_trigger_ops = event_hist_get_trigger_ops,
1156 .set_filter = set_trigger_filter,
1157};
1158
1159__init int register_trigger_hist_cmd(void)
1160{
1161 int ret;
1162
1163 ret = register_event_command(&trigger_hist_cmd);
1164 WARN_ON(ret < 0);
1165
1166 return ret;
1167}