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