@@ -67,7 +67,9 @@ struct thread_trace {
6767 u64 entry_time ;
6868 u64 exit_time ;
6969 bool entry_pending ;
70+ unsigned long nr_events ;
7071 char * entry_str ;
72+ double runtime_ms ;
7173};
7274
7375static struct thread_trace * thread_trace__new (void )
@@ -77,16 +79,21 @@ static struct thread_trace *thread_trace__new(void)
7779
7880static struct thread_trace * thread__trace (struct thread * thread )
7981{
82+ struct thread_trace * ttrace ;
83+
8084 if (thread == NULL )
8185 goto fail ;
8286
8387 if (thread -> priv == NULL )
8488 thread -> priv = thread_trace__new ();
85-
89+
8690 if (thread -> priv == NULL )
8791 goto fail ;
8892
89- return thread -> priv ;
93+ ttrace = thread -> priv ;
94+ ++ ttrace -> nr_events ;
95+
96+ return ttrace ;
9097fail :
9198 color_fprintf (stdout , PERF_COLOR_RED ,
9299 "WARNING: not enough memory, dropping samples!\n" );
@@ -102,8 +109,11 @@ struct trace {
102109 struct perf_record_opts opts ;
103110 struct machine host ;
104111 u64 base_time ;
112+ unsigned long nr_events ;
113+ bool sched ;
105114 bool multiple_threads ;
106115 double duration_filter ;
116+ double runtime_ms ;
107117};
108118
109119static bool trace__filter_duration (struct trace * trace , double t )
@@ -382,11 +392,37 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
382392 return 0 ;
383393}
384394
395+ static int trace__sched_stat_runtime (struct trace * trace , struct perf_evsel * evsel ,
396+ struct perf_sample * sample )
397+ {
398+ u64 runtime = perf_evsel__intval (evsel , sample , "runtime" );
399+ double runtime_ms = (double )runtime / NSEC_PER_MSEC ;
400+ struct thread * thread = machine__findnew_thread (& trace -> host , sample -> tid );
401+ struct thread_trace * ttrace = thread__trace (thread );
402+
403+ if (ttrace == NULL )
404+ goto out_dump ;
405+
406+ ttrace -> runtime_ms += runtime_ms ;
407+ trace -> runtime_ms += runtime_ms ;
408+ return 0 ;
409+
410+ out_dump :
411+ printf ("%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n" ,
412+ evsel -> name ,
413+ perf_evsel__strval (evsel , sample , "comm" ),
414+ (pid_t )perf_evsel__intval (evsel , sample , "pid" ),
415+ runtime ,
416+ perf_evsel__intval (evsel , sample , "vruntime" ));
417+ return 0 ;
418+ }
419+
385420static int trace__run (struct trace * trace , int argc , const char * * argv )
386421{
387422 struct perf_evlist * evlist = perf_evlist__new (NULL , NULL );
388423 struct perf_evsel * evsel ;
389- int err = -1 , i , nr_events = 0 , before ;
424+ int err = -1 , i ;
425+ unsigned long before ;
390426 const bool forks = argc > 0 ;
391427
392428 if (evlist == NULL ) {
@@ -400,6 +436,13 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
400436 goto out_delete_evlist ;
401437 }
402438
439+ if (trace -> sched &&
440+ perf_evlist__add_newtp (evlist , "sched" , "sched_stat_runtime" ,
441+ trace__sched_stat_runtime )) {
442+ printf ("Couldn't read the sched_stat_runtime tracepoint information!\n" );
443+ goto out_delete_evlist ;
444+ }
445+
403446 err = perf_evlist__create_maps (evlist , & trace -> opts .target );
404447 if (err < 0 ) {
405448 printf ("Problems parsing the target to trace, check your options!\n" );
@@ -444,7 +487,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
444487
445488 trace -> multiple_threads = evlist -> threads -> map [0 ] == -1 || evlist -> threads -> nr > 1 ;
446489again :
447- before = nr_events ;
490+ before = trace -> nr_events ;
448491
449492 for (i = 0 ; i < evlist -> nr_mmaps ; i ++ ) {
450493 union perf_event * event ;
@@ -454,7 +497,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
454497 tracepoint_handler handler ;
455498 struct perf_sample sample ;
456499
457- ++ nr_events ;
500+ ++ trace -> nr_events ;
458501
459502 err = perf_evlist__parse_sample (evlist , event , & sample );
460503 if (err ) {
@@ -495,7 +538,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
495538 }
496539 }
497540
498- if (nr_events == before ) {
541+ if (trace -> nr_events == before ) {
499542 if (done )
500543 goto out_delete_evlist ;
501544
@@ -513,6 +556,51 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
513556 return err ;
514557}
515558
559+ static size_t trace__fprintf_threads_header (FILE * fp )
560+ {
561+ size_t printed ;
562+
563+ printed = fprintf (fp , "\n _____________________________________________________________________\n" );
564+ printed += fprintf (fp ," __) Summary of events (__\n\n" );
565+ printed += fprintf (fp ," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n" );
566+ printed += fprintf (fp ," _____________________________________________________________________\n\n" );
567+
568+ return printed ;
569+ }
570+
571+ static size_t trace__fprintf_thread_summary (struct trace * trace , FILE * fp )
572+ {
573+ size_t printed = trace__fprintf_threads_header (fp );
574+ struct rb_node * nd ;
575+
576+ for (nd = rb_first (& trace -> host .threads ); nd ; nd = rb_next (nd )) {
577+ struct thread * thread = rb_entry (nd , struct thread , rb_node );
578+ struct thread_trace * ttrace = thread -> priv ;
579+ const char * color ;
580+ double ratio ;
581+
582+ if (ttrace == NULL )
583+ continue ;
584+
585+ ratio = (double )ttrace -> nr_events / trace -> nr_events * 100.0 ;
586+
587+ color = PERF_COLOR_NORMAL ;
588+ if (ratio > 50.0 )
589+ color = PERF_COLOR_RED ;
590+ else if (ratio > 25.0 )
591+ color = PERF_COLOR_GREEN ;
592+ else if (ratio > 5.0 )
593+ color = PERF_COLOR_YELLOW ;
594+
595+ printed += color_fprintf (fp , color , "%20s" , thread -> comm );
596+ printed += fprintf (fp , " - %-5d :%11lu [" , thread -> pid , ttrace -> nr_events );
597+ printed += color_fprintf (fp , color , "%5.1f%%" , ratio );
598+ printed += fprintf (fp , " ] %10.3f ms\n" , ttrace -> runtime_ms );
599+ }
600+
601+ return printed ;
602+ }
603+
516604static int trace__set_duration (const struct option * opt , const char * str ,
517605 int unset __maybe_unused )
518606{
@@ -563,6 +651,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
563651 OPT_CALLBACK (0 , "duration" , & trace , "float" ,
564652 "show only events with duration > N.M ms" ,
565653 trace__set_duration ),
654+ OPT_BOOLEAN (0 , "sched" , & trace .sched , "show blocking scheduler events" ),
566655 OPT_END ()
567656 };
568657 int err ;
@@ -587,5 +676,10 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
587676 if (!argc && perf_target__none (& trace .opts .target ))
588677 trace .opts .target .system_wide = true;
589678
590- return trace__run (& trace , argc , argv );
679+ err = trace__run (& trace , argc , argv );
680+
681+ if (trace .sched && !err )
682+ trace__fprintf_thread_summary (& trace , stdout );
683+
684+ return err ;
591685}
0 commit comments