@@ -77,6 +77,22 @@ struct sched_atom {
77
77
78
78
#define TASK_STATE_TO_CHAR_STR "RSDTtZXxKWP"
79
79
80
+ /* task state bitmask, copied from include/linux/sched.h */
81
+ #define TASK_RUNNING 0
82
+ #define TASK_INTERRUPTIBLE 1
83
+ #define TASK_UNINTERRUPTIBLE 2
84
+ #define __TASK_STOPPED 4
85
+ #define __TASK_TRACED 8
86
+ /* in tsk->exit_state */
87
+ #define EXIT_DEAD 16
88
+ #define EXIT_ZOMBIE 32
89
+ #define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD)
90
+ /* in tsk->state again */
91
+ #define TASK_DEAD 64
92
+ #define TASK_WAKEKILL 128
93
+ #define TASK_WAKING 256
94
+ #define TASK_PARKED 512
95
+
80
96
enum thread_state {
81
97
THREAD_SLEEPING = 0 ,
82
98
THREAD_WAIT_CPU ,
@@ -206,6 +222,7 @@ struct perf_sched {
206
222
bool show_cpu_visual ;
207
223
bool show_wakeups ;
208
224
bool show_migrations ;
225
+ bool show_state ;
209
226
u64 skipped_samples ;
210
227
const char * time_str ;
211
228
struct perf_time_interval ptime ;
@@ -216,13 +233,20 @@ struct perf_sched {
216
233
struct thread_runtime {
217
234
u64 last_time ; /* time of previous sched in/out event */
218
235
u64 dt_run ; /* run time */
219
- u64 dt_wait ; /* time between CPU access (off cpu) */
236
+ u64 dt_sleep ; /* time between CPU access by sleep (off cpu) */
237
+ u64 dt_iowait ; /* time between CPU access by iowait (off cpu) */
238
+ u64 dt_preempt ; /* time between CPU access by preempt (off cpu) */
220
239
u64 dt_delay ; /* time between wakeup and sched-in */
221
240
u64 ready_to_run ; /* time of wakeup */
222
241
223
242
struct stats run_stats ;
224
243
u64 total_run_time ;
244
+ u64 total_sleep_time ;
245
+ u64 total_iowait_time ;
246
+ u64 total_preempt_time ;
247
+ u64 total_delay_time ;
225
248
249
+ int last_state ;
226
250
u64 migrations ;
227
251
};
228
252
@@ -1821,6 +1845,9 @@ static void timehist_header(struct perf_sched *sched)
1821
1845
printf (" %-*s %9s %9s %9s" , comm_width ,
1822
1846
"task name" , "wait time" , "sch delay" , "run time" );
1823
1847
1848
+ if (sched -> show_state )
1849
+ printf (" %s" , "state" );
1850
+
1824
1851
printf ("\n" );
1825
1852
1826
1853
/*
@@ -1831,9 +1858,14 @@ static void timehist_header(struct perf_sched *sched)
1831
1858
if (sched -> show_cpu_visual )
1832
1859
printf (" %*s " , ncpus , "" );
1833
1860
1834
- printf (" %-*s %9s %9s %9s\n " , comm_width ,
1861
+ printf (" %-*s %9s %9s %9s" , comm_width ,
1835
1862
"[tid/pid]" , "(msec)" , "(msec)" , "(msec)" );
1836
1863
1864
+ if (sched -> show_state )
1865
+ printf (" %5s" , "" );
1866
+
1867
+ printf ("\n" );
1868
+
1837
1869
/*
1838
1870
* separator
1839
1871
*/
@@ -1846,18 +1878,34 @@ static void timehist_header(struct perf_sched *sched)
1846
1878
graph_dotted_line , graph_dotted_line , graph_dotted_line ,
1847
1879
graph_dotted_line );
1848
1880
1881
+ if (sched -> show_state )
1882
+ printf (" %.5s" , graph_dotted_line );
1883
+
1849
1884
printf ("\n" );
1850
1885
}
1851
1886
1887
+ static char task_state_char (struct thread * thread , int state )
1888
+ {
1889
+ static const char state_to_char [] = TASK_STATE_TO_CHAR_STR ;
1890
+ unsigned bit = state ? ffs (state ) : 0 ;
1891
+
1892
+ /* 'I' for idle */
1893
+ if (thread -> tid == 0 )
1894
+ return 'I' ;
1895
+
1896
+ return bit < sizeof (state_to_char ) - 1 ? state_to_char [bit ] : '?' ;
1897
+ }
1898
+
1852
1899
static void timehist_print_sample (struct perf_sched * sched ,
1853
1900
struct perf_sample * sample ,
1854
1901
struct addr_location * al ,
1855
1902
struct thread * thread ,
1856
- u64 t )
1903
+ u64 t , int state )
1857
1904
{
1858
1905
struct thread_runtime * tr = thread__priv (thread );
1859
1906
u32 max_cpus = sched -> max_cpu + 1 ;
1860
1907
char tstr [64 ];
1908
+ u64 wait_time ;
1861
1909
1862
1910
timestamp__scnprintf_usec (t , tstr , sizeof (tstr ));
1863
1911
printf ("%15s [%04d] " , tstr , sample -> cpu );
@@ -1880,10 +1928,15 @@ static void timehist_print_sample(struct perf_sched *sched,
1880
1928
1881
1929
printf (" %-*s " , comm_width , timehist_get_commstr (thread ));
1882
1930
1883
- print_sched_time (tr -> dt_wait , 6 );
1931
+ wait_time = tr -> dt_sleep + tr -> dt_iowait + tr -> dt_preempt ;
1932
+ print_sched_time (wait_time , 6 );
1933
+
1884
1934
print_sched_time (tr -> dt_delay , 6 );
1885
1935
print_sched_time (tr -> dt_run , 6 );
1886
1936
1937
+ if (sched -> show_state )
1938
+ printf (" %5c " , task_state_char (thread , state ));
1939
+
1887
1940
if (sched -> show_wakeups )
1888
1941
printf (" %-*s" , comm_width , "" );
1889
1942
@@ -1930,8 +1983,11 @@ static void timehist_update_runtime_stats(struct thread_runtime *r,
1930
1983
u64 t , u64 tprev )
1931
1984
{
1932
1985
r -> dt_delay = 0 ;
1933
- r -> dt_wait = 0 ;
1986
+ r -> dt_sleep = 0 ;
1987
+ r -> dt_iowait = 0 ;
1988
+ r -> dt_preempt = 0 ;
1934
1989
r -> dt_run = 0 ;
1990
+
1935
1991
if (tprev ) {
1936
1992
r -> dt_run = t - tprev ;
1937
1993
if (r -> ready_to_run ) {
@@ -1943,12 +1999,25 @@ static void timehist_update_runtime_stats(struct thread_runtime *r,
1943
1999
1944
2000
if (r -> last_time > tprev )
1945
2001
pr_debug ("time travel: last sched out time for task > previous sched_switch event\n" );
1946
- else if (r -> last_time )
1947
- r -> dt_wait = tprev - r -> last_time ;
2002
+ else if (r -> last_time ) {
2003
+ u64 dt_wait = tprev - r -> last_time ;
2004
+
2005
+ if (r -> last_state == TASK_RUNNING )
2006
+ r -> dt_preempt = dt_wait ;
2007
+ else if (r -> last_state == TASK_UNINTERRUPTIBLE )
2008
+ r -> dt_iowait = dt_wait ;
2009
+ else
2010
+ r -> dt_sleep = dt_wait ;
2011
+ }
1948
2012
}
1949
2013
1950
2014
update_stats (& r -> run_stats , r -> dt_run );
1951
- r -> total_run_time += r -> dt_run ;
2015
+
2016
+ r -> total_run_time += r -> dt_run ;
2017
+ r -> total_delay_time += r -> dt_delay ;
2018
+ r -> total_sleep_time += r -> dt_sleep ;
2019
+ r -> total_iowait_time += r -> dt_iowait ;
2020
+ r -> total_preempt_time += r -> dt_preempt ;
1952
2021
}
1953
2022
1954
2023
static bool is_idle_sample (struct perf_sample * sample ,
@@ -2373,6 +2442,8 @@ static int timehist_sched_change_event(struct perf_tool *tool,
2373
2442
struct thread_runtime * tr = NULL ;
2374
2443
u64 tprev , t = sample -> time ;
2375
2444
int rc = 0 ;
2445
+ int state = perf_evsel__intval (evsel , sample , "prev_state" );
2446
+
2376
2447
2377
2448
if (machine__resolve (machine , & al , sample ) < 0 ) {
2378
2449
pr_err ("problem processing %d event. skipping it\n" ,
@@ -2447,8 +2518,10 @@ static int timehist_sched_change_event(struct perf_tool *tool,
2447
2518
* time. we only care total run time and run stat.
2448
2519
*/
2449
2520
last_tr -> dt_run = 0 ;
2450
- last_tr -> dt_wait = 0 ;
2451
2521
last_tr -> dt_delay = 0 ;
2522
+ last_tr -> dt_sleep = 0 ;
2523
+ last_tr -> dt_iowait = 0 ;
2524
+ last_tr -> dt_preempt = 0 ;
2452
2525
2453
2526
if (itr -> cursor .nr )
2454
2527
callchain_append (& itr -> callchain , & itr -> cursor , t - tprev );
@@ -2458,7 +2531,7 @@ static int timehist_sched_change_event(struct perf_tool *tool,
2458
2531
}
2459
2532
2460
2533
if (!sched -> summary_only )
2461
- timehist_print_sample (sched , sample , & al , thread , t );
2534
+ timehist_print_sample (sched , sample , & al , thread , t , state );
2462
2535
2463
2536
out :
2464
2537
if (sched -> hist_time .start == 0 && t >= ptime -> start )
@@ -2470,6 +2543,9 @@ static int timehist_sched_change_event(struct perf_tool *tool,
2470
2543
/* time of this sched_switch event becomes last time task seen */
2471
2544
tr -> last_time = sample -> time ;
2472
2545
2546
+ /* last state is used to determine where to account wait time */
2547
+ tr -> last_state = state ;
2548
+
2473
2549
/* sched out event for task so reset ready to run time */
2474
2550
tr -> ready_to_run = 0 ;
2475
2551
}
@@ -2526,7 +2602,26 @@ static void print_thread_runtime(struct thread *t,
2526
2602
printf ("\n" );
2527
2603
}
2528
2604
2605
+ static void print_thread_waittime (struct thread * t ,
2606
+ struct thread_runtime * r )
2607
+ {
2608
+ printf ("%*s %5d %9" PRIu64 " " ,
2609
+ comm_width , timehist_get_commstr (t ), t -> ppid ,
2610
+ (u64 ) r -> run_stats .n );
2611
+
2612
+ print_sched_time (r -> total_run_time , 8 );
2613
+ print_sched_time (r -> total_sleep_time , 6 );
2614
+ printf (" " );
2615
+ print_sched_time (r -> total_iowait_time , 6 );
2616
+ printf (" " );
2617
+ print_sched_time (r -> total_preempt_time , 6 );
2618
+ printf (" " );
2619
+ print_sched_time (r -> total_delay_time , 6 );
2620
+ printf ("\n" );
2621
+ }
2622
+
2529
2623
struct total_run_stats {
2624
+ struct perf_sched * sched ;
2530
2625
u64 sched_count ;
2531
2626
u64 task_count ;
2532
2627
u64 total_run_time ;
@@ -2545,7 +2640,11 @@ static int __show_thread_runtime(struct thread *t, void *priv)
2545
2640
stats -> task_count ++ ;
2546
2641
stats -> sched_count += r -> run_stats .n ;
2547
2642
stats -> total_run_time += r -> total_run_time ;
2548
- print_thread_runtime (t , r );
2643
+
2644
+ if (stats -> sched -> show_state )
2645
+ print_thread_waittime (t , r );
2646
+ else
2647
+ print_thread_runtime (t , r );
2549
2648
}
2550
2649
2551
2650
return 0 ;
@@ -2633,18 +2732,24 @@ static void timehist_print_summary(struct perf_sched *sched,
2633
2732
u64 hist_time = sched -> hist_time .end - sched -> hist_time .start ;
2634
2733
2635
2734
memset (& totals , 0 , sizeof (totals ));
2735
+ totals .sched = sched ;
2636
2736
2637
2737
if (sched -> idle_hist ) {
2638
2738
printf ("\nIdle-time summary\n" );
2639
2739
printf ("%*s parent sched-out " , comm_width , "comm" );
2640
2740
printf (" idle-time min-idle avg-idle max-idle stddev migrations\n" );
2741
+ } else if (sched -> show_state ) {
2742
+ printf ("\nWait-time summary\n" );
2743
+ printf ("%*s parent sched-in " , comm_width , "comm" );
2744
+ printf (" run-time sleep iowait preempt delay\n" );
2641
2745
} else {
2642
2746
printf ("\nRuntime summary\n" );
2643
2747
printf ("%*s parent sched-in " , comm_width , "comm" );
2644
2748
printf (" run-time min-run avg-run max-run stddev migrations\n" );
2645
2749
}
2646
2750
printf ("%*s (count) " , comm_width , "" );
2647
- printf (" (msec) (msec) (msec) (msec) %%\n" );
2751
+ printf (" (msec) (msec) (msec) (msec) %s\n" ,
2752
+ sched -> show_state ? "(msec)" : "%" );
2648
2753
printf ("%.117s\n" , graph_dotted_line );
2649
2754
2650
2755
machine__for_each_thread (m , show_thread_runtime , & totals );
@@ -3240,6 +3345,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
3240
3345
OPT_BOOLEAN ('I' , "idle-hist" , & sched .idle_hist , "Show idle events only" ),
3241
3346
OPT_STRING (0 , "time" , & sched .time_str , "str" ,
3242
3347
"Time span for analysis (start,stop)" ),
3348
+ OPT_BOOLEAN (0 , "state" , & sched .show_state , "Show task state when sched-out" ),
3243
3349
OPT_PARENT (sched_options )
3244
3350
};
3245
3351
0 commit comments