65
65
#define CNTR_NOT_SUPPORTED "<not supported>"
66
66
#define CNTR_NOT_COUNTED "<not counted>"
67
67
68
+ static void print_stat (int argc , const char * * argv );
69
+ static void print_counter_aggr (struct perf_evsel * counter , char * prefix );
70
+ static void print_counter (struct perf_evsel * counter , char * prefix );
71
+
68
72
static struct perf_evlist * evsel_list ;
69
73
70
74
static struct perf_target target = {
@@ -87,13 +91,37 @@ static FILE *output = NULL;
87
91
static const char * pre_cmd = NULL ;
88
92
static const char * post_cmd = NULL ;
89
93
static bool sync_run = false;
94
+ static unsigned int interval = 0 ;
95
+ static struct timespec ref_time ;
90
96
91
97
static volatile int done = 0 ;
92
98
93
99
struct perf_stat {
94
100
struct stats res_stats [3 ];
95
101
};
96
102
103
+ static inline void diff_timespec (struct timespec * r , struct timespec * a ,
104
+ struct timespec * b )
105
+ {
106
+ r -> tv_sec = a -> tv_sec - b -> tv_sec ;
107
+ if (a -> tv_nsec < b -> tv_nsec ) {
108
+ r -> tv_nsec = a -> tv_nsec + 1000000000L - b -> tv_nsec ;
109
+ r -> tv_sec -- ;
110
+ } else {
111
+ r -> tv_nsec = a -> tv_nsec - b -> tv_nsec ;
112
+ }
113
+ }
114
+
115
+ static inline struct cpu_map * perf_evsel__cpus (struct perf_evsel * evsel )
116
+ {
117
+ return (evsel -> cpus && !target .cpu_list ) ? evsel -> cpus : evsel_list -> cpus ;
118
+ }
119
+
120
+ static inline int perf_evsel__nr_cpus (struct perf_evsel * evsel )
121
+ {
122
+ return perf_evsel__cpus (evsel )-> nr ;
123
+ }
124
+
97
125
static int perf_evsel__alloc_stat_priv (struct perf_evsel * evsel )
98
126
{
99
127
evsel -> priv = zalloc (sizeof (struct perf_stat ));
@@ -106,14 +134,27 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
106
134
evsel -> priv = NULL ;
107
135
}
108
136
109
- static inline struct cpu_map * perf_evsel__cpus (struct perf_evsel * evsel )
137
+ static int perf_evsel__alloc_prev_raw_counts (struct perf_evsel * evsel )
110
138
{
111
- return (evsel -> cpus && !target .cpu_list ) ? evsel -> cpus : evsel_list -> cpus ;
139
+ void * addr ;
140
+ size_t sz ;
141
+
142
+ sz = sizeof (* evsel -> counts ) +
143
+ (perf_evsel__nr_cpus (evsel ) * sizeof (struct perf_counts_values ));
144
+
145
+ addr = zalloc (sz );
146
+ if (!addr )
147
+ return - ENOMEM ;
148
+
149
+ evsel -> prev_raw_counts = addr ;
150
+
151
+ return 0 ;
112
152
}
113
153
114
- static inline int perf_evsel__nr_cpus (struct perf_evsel * evsel )
154
+ static void perf_evsel__free_prev_raw_counts (struct perf_evsel * evsel )
115
155
{
116
- return perf_evsel__cpus (evsel )-> nr ;
156
+ free (evsel -> prev_raw_counts );
157
+ evsel -> prev_raw_counts = NULL ;
117
158
}
118
159
119
160
static struct stats runtime_nsecs_stats [MAX_NR_CPUS ];
@@ -245,16 +286,69 @@ static int read_counter(struct perf_evsel *counter)
245
286
return 0 ;
246
287
}
247
288
289
+ static void print_interval (void )
290
+ {
291
+ static int num_print_interval ;
292
+ struct perf_evsel * counter ;
293
+ struct perf_stat * ps ;
294
+ struct timespec ts , rs ;
295
+ char prefix [64 ];
296
+
297
+ if (no_aggr ) {
298
+ list_for_each_entry (counter , & evsel_list -> entries , node ) {
299
+ ps = counter -> priv ;
300
+ memset (ps -> res_stats , 0 , sizeof (ps -> res_stats ));
301
+ read_counter (counter );
302
+ }
303
+ } else {
304
+ list_for_each_entry (counter , & evsel_list -> entries , node ) {
305
+ ps = counter -> priv ;
306
+ memset (ps -> res_stats , 0 , sizeof (ps -> res_stats ));
307
+ read_counter_aggr (counter );
308
+ }
309
+ }
310
+ clock_gettime (CLOCK_MONOTONIC , & ts );
311
+ diff_timespec (& rs , & ts , & ref_time );
312
+ sprintf (prefix , "%6lu.%09lu%s" , rs .tv_sec , rs .tv_nsec , csv_sep );
313
+
314
+ if (num_print_interval == 0 && !csv_output ) {
315
+ if (no_aggr )
316
+ fprintf (output , "# time CPU counts events\n" );
317
+ else
318
+ fprintf (output , "# time counts events\n" );
319
+ }
320
+
321
+ if (++ num_print_interval == 25 )
322
+ num_print_interval = 0 ;
323
+
324
+ if (no_aggr ) {
325
+ list_for_each_entry (counter , & evsel_list -> entries , node )
326
+ print_counter (counter , prefix );
327
+ } else {
328
+ list_for_each_entry (counter , & evsel_list -> entries , node )
329
+ print_counter_aggr (counter , prefix );
330
+ }
331
+ }
332
+
248
333
static int __run_perf_stat (int argc __maybe_unused , const char * * argv )
249
334
{
250
335
char msg [512 ];
251
336
unsigned long long t0 , t1 ;
252
337
struct perf_evsel * counter ;
338
+ struct timespec ts ;
253
339
int status = 0 ;
254
340
int child_ready_pipe [2 ], go_pipe [2 ];
255
341
const bool forks = (argc > 0 );
256
342
char buf ;
257
343
344
+ if (interval ) {
345
+ ts .tv_sec = interval / 1000 ;
346
+ ts .tv_nsec = (interval % 1000 ) * 1000000 ;
347
+ } else {
348
+ ts .tv_sec = 1 ;
349
+ ts .tv_nsec = 0 ;
350
+ }
351
+
258
352
if (forks && (pipe (child_ready_pipe ) < 0 || pipe (go_pipe ) < 0 )) {
259
353
perror ("failed to create pipes" );
260
354
return -1 ;
@@ -347,14 +441,25 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
347
441
* Enable counters and exec the command:
348
442
*/
349
443
t0 = rdclock ();
444
+ clock_gettime (CLOCK_MONOTONIC , & ref_time );
350
445
351
446
if (forks ) {
352
447
close (go_pipe [1 ]);
448
+ if (interval ) {
449
+ while (!waitpid (child_pid , & status , WNOHANG )) {
450
+ nanosleep (& ts , NULL );
451
+ print_interval ();
452
+ }
453
+ }
353
454
wait (& status );
354
455
if (WIFSIGNALED (status ))
355
456
psignal (WTERMSIG (status ), argv [0 ]);
356
457
} else {
357
- while (!done ) sleep (1 );
458
+ while (!done ) {
459
+ nanosleep (& ts , NULL );
460
+ if (interval )
461
+ print_interval ();
462
+ }
358
463
}
359
464
360
465
t1 = rdclock ();
@@ -440,7 +545,7 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
440
545
if (evsel -> cgrp )
441
546
fprintf (output , "%s%s" , csv_sep , evsel -> cgrp -> name );
442
547
443
- if (csv_output )
548
+ if (csv_output || interval )
444
549
return ;
445
550
446
551
if (perf_evsel__match (evsel , SOFTWARE , SW_TASK_CLOCK ))
@@ -654,12 +759,11 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
654
759
if (evsel -> cgrp )
655
760
fprintf (output , "%s%s" , csv_sep , evsel -> cgrp -> name );
656
761
657
- if (csv_output )
762
+ if (csv_output || interval )
658
763
return ;
659
764
660
765
if (perf_evsel__match (evsel , HARDWARE , HW_INSTRUCTIONS )) {
661
766
total = avg_stats (& runtime_cycles_stats [cpu ]);
662
-
663
767
if (total )
664
768
ratio = avg / total ;
665
769
@@ -753,12 +857,15 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
753
857
* Print out the results of a single counter:
754
858
* aggregated counts in system-wide mode
755
859
*/
756
- static void print_counter_aggr (struct perf_evsel * counter )
860
+ static void print_counter_aggr (struct perf_evsel * counter , char * prefix )
757
861
{
758
862
struct perf_stat * ps = counter -> priv ;
759
863
double avg = avg_stats (& ps -> res_stats [0 ]);
760
864
int scaled = counter -> counts -> scaled ;
761
865
866
+ if (prefix )
867
+ fprintf (output , "%s" , prefix );
868
+
762
869
if (scaled == -1 ) {
763
870
fprintf (output , "%*s%s%*s" ,
764
871
csv_output ? 0 : 18 ,
@@ -801,7 +908,7 @@ static void print_counter_aggr(struct perf_evsel *counter)
801
908
* Print out the results of a single counter:
802
909
* does not use aggregated count in system-wide
803
910
*/
804
- static void print_counter (struct perf_evsel * counter )
911
+ static void print_counter (struct perf_evsel * counter , char * prefix )
805
912
{
806
913
u64 ena , run , val ;
807
914
int cpu ;
@@ -810,6 +917,10 @@ static void print_counter(struct perf_evsel *counter)
810
917
val = counter -> counts -> cpu [cpu ].val ;
811
918
ena = counter -> counts -> cpu [cpu ].ena ;
812
919
run = counter -> counts -> cpu [cpu ].run ;
920
+
921
+ if (prefix )
922
+ fprintf (output , "%s" , prefix );
923
+
813
924
if (run == 0 || ena == 0 ) {
814
925
fprintf (output , "CPU%*d%s%*s%s%*s" ,
815
926
csv_output ? 0 : -4 ,
@@ -871,10 +982,10 @@ static void print_stat(int argc, const char **argv)
871
982
872
983
if (no_aggr ) {
873
984
list_for_each_entry (counter , & evsel_list -> entries , node )
874
- print_counter (counter );
985
+ print_counter (counter , NULL );
875
986
} else {
876
987
list_for_each_entry (counter , & evsel_list -> entries , node )
877
- print_counter_aggr (counter );
988
+ print_counter_aggr (counter , NULL );
878
989
}
879
990
880
991
if (!csv_output ) {
@@ -895,7 +1006,7 @@ static volatile int signr = -1;
895
1006
896
1007
static void skip_signal (int signo )
897
1008
{
898
- if ( child_pid == -1 )
1009
+ if (( child_pid == -1 ) || interval )
899
1010
done = 1 ;
900
1011
901
1012
signr = signo ;
@@ -1115,6 +1226,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1115
1226
"command to run prior to the measured command" ),
1116
1227
OPT_STRING (0 , "post" , & post_cmd , "command" ,
1117
1228
"command to run after to the measured command" ),
1229
+ OPT_UINTEGER ('I' , "interval-print" , & interval ,
1230
+ "print counts at regular interval in ms (>= 100)" ),
1118
1231
OPT_END ()
1119
1232
};
1120
1233
const char * const stat_usage [] = {
@@ -1215,12 +1328,23 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1215
1328
usage_with_options (stat_usage , options );
1216
1329
return -1 ;
1217
1330
}
1331
+ if (interval && interval < 100 ) {
1332
+ pr_err ("print interval must be >= 100ms\n" );
1333
+ usage_with_options (stat_usage , options );
1334
+ return -1 ;
1335
+ }
1218
1336
1219
1337
list_for_each_entry (pos , & evsel_list -> entries , node ) {
1220
1338
if (perf_evsel__alloc_stat_priv (pos ) < 0 ||
1221
1339
perf_evsel__alloc_counts (pos , perf_evsel__nr_cpus (pos )) < 0 )
1222
1340
goto out_free_fd ;
1223
1341
}
1342
+ if (interval ) {
1343
+ list_for_each_entry (pos , & evsel_list -> entries , node ) {
1344
+ if (perf_evsel__alloc_prev_raw_counts (pos ) < 0 )
1345
+ goto out_free_fd ;
1346
+ }
1347
+ }
1224
1348
1225
1349
/*
1226
1350
* We dont want to block the signals - that would cause
@@ -1230,6 +1354,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1230
1354
*/
1231
1355
atexit (sig_atexit );
1232
1356
signal (SIGINT , skip_signal );
1357
+ signal (SIGCHLD , skip_signal );
1233
1358
signal (SIGALRM , skip_signal );
1234
1359
signal (SIGABRT , skip_signal );
1235
1360
@@ -1242,11 +1367,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1242
1367
status = run_perf_stat (argc , argv );
1243
1368
}
1244
1369
1245
- if (status != -1 )
1370
+ if (status != -1 && ! interval )
1246
1371
print_stat (argc , argv );
1247
1372
out_free_fd :
1248
- list_for_each_entry (pos , & evsel_list -> entries , node )
1373
+ list_for_each_entry (pos , & evsel_list -> entries , node ) {
1249
1374
perf_evsel__free_stat_priv (pos );
1375
+ perf_evsel__free_prev_raw_counts (pos );
1376
+ }
1250
1377
perf_evlist__delete_maps (evsel_list );
1251
1378
out :
1252
1379
perf_evlist__delete (evsel_list );
0 commit comments