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