@@ -35,6 +35,11 @@ struct hist_field {
35
35
unsigned int offset ;
36
36
};
37
37
38
+ static u64 hist_field_none (struct hist_field * field , void * event )
39
+ {
40
+ return 0 ;
41
+ }
42
+
38
43
static u64 hist_field_counter (struct hist_field * field , void * event )
39
44
{
40
45
return 1 ;
@@ -73,8 +78,12 @@ DEFINE_HIST_FIELD_FN(u8);
73
78
#define for_each_hist_key_field (i , hist_data ) \
74
79
for ((i) = (hist_data)->n_vals; (i) < (hist_data)->n_fields; (i)++)
75
80
81
+ #define HIST_STACKTRACE_DEPTH 16
82
+ #define HIST_STACKTRACE_SIZE (HIST_STACKTRACE_DEPTH * sizeof(unsigned long))
83
+ #define HIST_STACKTRACE_SKIP 5
84
+
76
85
#define HITCOUNT_IDX 0
77
- #define HIST_KEY_SIZE_MAX (MAX_FILTER_STR_VAL + sizeof(u64) )
86
+ #define HIST_KEY_SIZE_MAX (MAX_FILTER_STR_VAL + HIST_STACKTRACE_SIZE )
78
87
79
88
enum hist_field_flags {
80
89
HIST_FIELD_FL_HITCOUNT = 1 ,
@@ -85,6 +94,7 @@ enum hist_field_flags {
85
94
HIST_FIELD_FL_SYM_OFFSET = 32 ,
86
95
HIST_FIELD_FL_EXECNAME = 64 ,
87
96
HIST_FIELD_FL_SYSCALL = 128 ,
97
+ HIST_FIELD_FL_STACKTRACE = 256 ,
88
98
};
89
99
90
100
struct hist_trigger_attrs {
@@ -323,6 +333,11 @@ static struct hist_field *create_hist_field(struct ftrace_event_field *field,
323
333
goto out ;
324
334
}
325
335
336
+ if (flags & HIST_FIELD_FL_STACKTRACE ) {
337
+ hist_field -> fn = hist_field_none ;
338
+ goto out ;
339
+ }
340
+
326
341
if (is_string_field (field )) {
327
342
flags |= HIST_FIELD_FL_STRING ;
328
343
hist_field -> fn = hist_field_string ;
@@ -456,41 +471,46 @@ static int create_key_field(struct hist_trigger_data *hist_data,
456
471
struct ftrace_event_field * field = NULL ;
457
472
unsigned long flags = 0 ;
458
473
unsigned int key_size ;
459
- char * field_name ;
460
474
int ret = 0 ;
461
475
462
476
if (WARN_ON (key_idx >= TRACING_MAP_FIELDS_MAX ))
463
477
return - EINVAL ;
464
478
465
479
flags |= HIST_FIELD_FL_KEY ;
466
480
467
- field_name = strsep (& field_str , "." );
468
- if (field_str ) {
469
- if (strcmp (field_str , "hex" ) == 0 )
470
- flags |= HIST_FIELD_FL_HEX ;
471
- else if (strcmp (field_str , "sym" ) == 0 )
472
- flags |= HIST_FIELD_FL_SYM ;
473
- else if (strcmp (field_str , "sym-offset" ) == 0 )
474
- flags |= HIST_FIELD_FL_SYM_OFFSET ;
475
- else if ((strcmp (field_str , "execname" ) == 0 ) &&
476
- (strcmp (field_name , "common_pid" ) == 0 ))
477
- flags |= HIST_FIELD_FL_EXECNAME ;
478
- else if (strcmp (field_str , "syscall" ) == 0 )
479
- flags |= HIST_FIELD_FL_SYSCALL ;
480
- else {
481
+ if (strcmp (field_str , "stacktrace" ) == 0 ) {
482
+ flags |= HIST_FIELD_FL_STACKTRACE ;
483
+ key_size = sizeof (unsigned long ) * HIST_STACKTRACE_DEPTH ;
484
+ } else {
485
+ char * field_name = strsep (& field_str , "." );
486
+
487
+ if (field_str ) {
488
+ if (strcmp (field_str , "hex" ) == 0 )
489
+ flags |= HIST_FIELD_FL_HEX ;
490
+ else if (strcmp (field_str , "sym" ) == 0 )
491
+ flags |= HIST_FIELD_FL_SYM ;
492
+ else if (strcmp (field_str , "sym-offset" ) == 0 )
493
+ flags |= HIST_FIELD_FL_SYM_OFFSET ;
494
+ else if ((strcmp (field_str , "execname" ) == 0 ) &&
495
+ (strcmp (field_name , "common_pid" ) == 0 ))
496
+ flags |= HIST_FIELD_FL_EXECNAME ;
497
+ else if (strcmp (field_str , "syscall" ) == 0 )
498
+ flags |= HIST_FIELD_FL_SYSCALL ;
499
+ else {
500
+ ret = - EINVAL ;
501
+ goto out ;
502
+ }
503
+ }
504
+
505
+ field = trace_find_event_field (file -> event_call , field_name );
506
+ if (!field ) {
481
507
ret = - EINVAL ;
482
508
goto out ;
483
509
}
484
- }
485
510
486
- field = trace_find_event_field (file -> event_call , field_name );
487
- if (!field ) {
488
- ret = - EINVAL ;
489
- goto out ;
511
+ key_size = field -> size ;
490
512
}
491
513
492
- key_size = field -> size ;
493
-
494
514
hist_data -> fields [key_idx ] = create_hist_field (field , flags );
495
515
if (!hist_data -> fields [key_idx ]) {
496
516
ret = - ENOMEM ;
@@ -679,7 +699,9 @@ static int create_tracing_map_fields(struct hist_trigger_data *hist_data)
679
699
680
700
field = hist_field -> field ;
681
701
682
- if (is_string_field (field ))
702
+ if (hist_field -> flags & HIST_FIELD_FL_STACKTRACE )
703
+ cmp_fn = tracing_map_cmp_none ;
704
+ else if (is_string_field (field ))
683
705
cmp_fn = tracing_map_cmp_string ;
684
706
else
685
707
cmp_fn = tracing_map_cmp_num (field -> size ,
@@ -786,7 +808,9 @@ static void hist_trigger_elt_update(struct hist_trigger_data *hist_data,
786
808
static void event_hist_trigger (struct event_trigger_data * data , void * rec )
787
809
{
788
810
struct hist_trigger_data * hist_data = data -> private_data ;
811
+ unsigned long entries [HIST_STACKTRACE_DEPTH ];
789
812
char compound_key [HIST_KEY_SIZE_MAX ];
813
+ struct stack_trace stacktrace ;
790
814
struct hist_field * key_field ;
791
815
struct tracing_map_elt * elt ;
792
816
u64 field_contents ;
@@ -799,15 +823,27 @@ static void event_hist_trigger(struct event_trigger_data *data, void *rec)
799
823
for_each_hist_key_field (i , hist_data ) {
800
824
key_field = hist_data -> fields [i ];
801
825
802
- field_contents = key_field -> fn ( key_field , rec );
803
- if ( key_field -> flags & HIST_FIELD_FL_STRING )
804
- key = ( void * )( unsigned long ) field_contents ;
805
- else
806
- key = ( void * ) & field_contents ;
826
+ if ( key_field -> flags & HIST_FIELD_FL_STACKTRACE ) {
827
+ stacktrace . max_entries = HIST_STACKTRACE_DEPTH ;
828
+ stacktrace . entries = entries ;
829
+ stacktrace . nr_entries = 0 ;
830
+ stacktrace . skip = HIST_STACKTRACE_SKIP ;
807
831
808
- if (hist_data -> n_keys > 1 ) {
809
- memcpy (compound_key + key_field -> offset , key ,
810
- key_field -> size );
832
+ memset (stacktrace .entries , 0 , HIST_STACKTRACE_SIZE );
833
+ save_stack_trace (& stacktrace );
834
+
835
+ key = entries ;
836
+ } else {
837
+ field_contents = key_field -> fn (key_field , rec );
838
+ if (key_field -> flags & HIST_FIELD_FL_STRING )
839
+ key = (void * )(unsigned long )field_contents ;
840
+ else
841
+ key = (void * )& field_contents ;
842
+
843
+ if (hist_data -> n_keys > 1 ) {
844
+ memcpy (compound_key + key_field -> offset , key ,
845
+ key_field -> size );
846
+ }
811
847
}
812
848
}
813
849
@@ -819,13 +855,32 @@ static void event_hist_trigger(struct event_trigger_data *data, void *rec)
819
855
hist_trigger_elt_update (hist_data , elt , rec );
820
856
}
821
857
858
+ static void hist_trigger_stacktrace_print (struct seq_file * m ,
859
+ unsigned long * stacktrace_entries ,
860
+ unsigned int max_entries )
861
+ {
862
+ char str [KSYM_SYMBOL_LEN ];
863
+ unsigned int spaces = 8 ;
864
+ unsigned int i ;
865
+
866
+ for (i = 0 ; i < max_entries ; i ++ ) {
867
+ if (stacktrace_entries [i ] == ULONG_MAX )
868
+ return ;
869
+
870
+ seq_printf (m , "%*c" , 1 + spaces , ' ' );
871
+ sprint_symbol (str , stacktrace_entries [i ]);
872
+ seq_printf (m , "%s\n" , str );
873
+ }
874
+ }
875
+
822
876
static void
823
877
hist_trigger_entry_print (struct seq_file * m ,
824
878
struct hist_trigger_data * hist_data , void * key ,
825
879
struct tracing_map_elt * elt )
826
880
{
827
881
struct hist_field * key_field ;
828
882
char str [KSYM_SYMBOL_LEN ];
883
+ bool multiline = false;
829
884
unsigned int i ;
830
885
u64 uval ;
831
886
@@ -867,6 +922,12 @@ hist_trigger_entry_print(struct seq_file *m,
867
922
868
923
seq_printf (m , "%s: %-30s[%3llu]" ,
869
924
key_field -> field -> name , syscall_name , uval );
925
+ } else if (key_field -> flags & HIST_FIELD_FL_STACKTRACE ) {
926
+ seq_puts (m , "stacktrace:\n" );
927
+ hist_trigger_stacktrace_print (m ,
928
+ key + key_field -> offset ,
929
+ HIST_STACKTRACE_DEPTH );
930
+ multiline = true;
870
931
} else if (key_field -> flags & HIST_FIELD_FL_STRING ) {
871
932
seq_printf (m , "%s: %-50s" , key_field -> field -> name ,
872
933
(char * )(key + key_field -> offset ));
@@ -877,7 +938,10 @@ hist_trigger_entry_print(struct seq_file *m,
877
938
}
878
939
}
879
940
880
- seq_puts (m , " }" );
941
+ if (!multiline )
942
+ seq_puts (m , " " );
943
+
944
+ seq_puts (m , "}" );
881
945
882
946
seq_printf (m , " hitcount: %10llu" ,
883
947
tracing_map_read_sum (elt , HITCOUNT_IDX ));
@@ -1021,7 +1085,10 @@ static int event_hist_trigger_print(struct seq_file *m,
1021
1085
if (i > hist_data -> n_vals )
1022
1086
seq_puts (m , "," );
1023
1087
1024
- hist_field_print (m , key_field );
1088
+ if (key_field -> flags & HIST_FIELD_FL_STACKTRACE )
1089
+ seq_puts (m , "stacktrace" );
1090
+ else
1091
+ hist_field_print (m , key_field );
1025
1092
}
1026
1093
1027
1094
seq_puts (m , ":vals=" );
0 commit comments