1616#include "trace_helpers.h"
1717
1818static struct env {
19- pid_t pid ;
20- pid_t tid ;
19+ pid_t pids [ MAX_PID_NR ] ;
20+ pid_t tids [ MAX_TID_NR ] ;
2121 bool user_threads_only ;
2222 bool kernel_threads_only ;
2323 int stack_storage_size ;
@@ -28,8 +28,6 @@ static struct env {
2828 int duration ;
2929 bool verbose ;
3030} env = {
31- .pid = -1 ,
32- .tid = -1 ,
3331 .stack_storage_size = 1024 ,
3432 .perf_max_stack_depth = 127 ,
3533 .min_block_time = 1 ,
@@ -82,9 +80,31 @@ static const struct argp_option opts[] = {
8280 {},
8381};
8482
83+ static int split_pidstr (char * s , char * sep , int max_split , pid_t * pids )
84+ {
85+ char * pid ;
86+ int nr = 0 ;
87+
88+ errno = 0 ;
89+ pid = strtok (s , sep );
90+ while (pid ) {
91+ if (nr >= max_split )
92+ return - ENOBUFS ;
93+
94+ pids [nr ++ ] = strtol (pid , NULL , 10 );
95+ if (errno )
96+ return - errno ;
97+
98+ pid = strtok (NULL , "," );
99+ }
100+
101+ return 0 ;
102+ }
103+
85104static error_t parse_arg (int key , char * arg , struct argp_state * state )
86105{
87106 static int pos_args ;
107+ int ret ;
88108
89109 switch (key ) {
90110 case 'h' :
@@ -94,18 +114,26 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
94114 env .verbose = true;
95115 break ;
96116 case 'p' :
97- errno = 0 ;
98- env .pid = strtol (arg , NULL , 10 );
99- if (errno ) {
100- fprintf (stderr , "invalid PID: %s\n" , arg );
117+ ret = split_pidstr (strdup (arg ), "," , MAX_PID_NR , env .pids );
118+ if (ret ) {
119+ if (ret == - ENOBUFS )
120+ fprintf (stderr , "the number of pid is too big, please "
121+ "increase MAX_PID_NR's value and recompile\n" );
122+ else
123+ fprintf (stderr , "invalid PID: %s\n" , arg );
124+
101125 argp_usage (state );
102126 }
103127 break ;
104128 case 't' :
105- errno = 0 ;
106- env .tid = strtol (arg , NULL , 10 );
107- if (errno || env .tid <= 0 ) {
108- fprintf (stderr , "Invalid TID: %s\n" , arg );
129+ ret = split_pidstr (strdup (arg ), "," , MAX_TID_NR , env .tids );
130+ if (ret ) {
131+ if (ret == - ENOBUFS )
132+ fprintf (stderr , "the number of tid is too big, please "
133+ "increase MAX_TID_NR's value and recompile\n" );
134+ else
135+ fprintf (stderr , "invalid TID: %s\n" , arg );
136+
109137 argp_usage (state );
110138 }
111139 break ;
@@ -281,6 +309,30 @@ static void print_map(struct ksyms *ksyms, struct syms_cache *syms_cache,
281309 free (ip );
282310}
283311
312+ static void print_headers ()
313+ {
314+ int i ;
315+
316+ printf ("Tracing off-CPU time (us) of" );
317+
318+ if (env .pids [0 ]) {
319+ printf (" PID [" );
320+ for (i = 0 ; i < MAX_PID_NR && env .pids [i ]; i ++ )
321+ printf ("%d%s" , env .pids [i ], (i < MAX_PID_NR - 1 && env .pids [i + 1 ]) ? ", " : "]" );
322+ } else if (env .tids [0 ]) {
323+ printf (" TID [" );
324+ for (i = 0 ; i < MAX_TID_NR && env .tids [i ]; i ++ )
325+ printf ("%d%s" , env .tids [i ], (i < MAX_TID_NR - 1 && env .tids [i + 1 ]) ? ", " : "]" );
326+ } else {
327+ printf (" all threads" );
328+ }
329+
330+ if (env .duration < 99999999 )
331+ printf (" for %d secs.\n" , env .duration );
332+ else
333+ printf ("... Hit Ctrl-C to end.\n" );
334+ }
335+
284336int main (int argc , char * * argv )
285337{
286338 static const struct argp argp = {
@@ -291,7 +343,9 @@ int main(int argc, char **argv)
291343 struct syms_cache * syms_cache = NULL ;
292344 struct ksyms * ksyms = NULL ;
293345 struct offcputime_bpf * obj ;
294- int err ;
346+ int pids_fd , tids_fd ;
347+ int err , i ;
348+ __u8 val = 0 ;
295349
296350 err = argp_parse (& argp , argc , argv , 0 , NULL , NULL );
297351 if (err )
@@ -314,14 +368,18 @@ int main(int argc, char **argv)
314368 }
315369
316370 /* initialize global data (filtering options) */
317- obj -> rodata -> targ_tgid = env .pid ;
318- obj -> rodata -> targ_pid = env .tid ;
319371 obj -> rodata -> user_threads_only = env .user_threads_only ;
320372 obj -> rodata -> kernel_threads_only = env .kernel_threads_only ;
321373 obj -> rodata -> state = env .state ;
322374 obj -> rodata -> min_block_ns = env .min_block_time ;
323375 obj -> rodata -> max_block_ns = env .max_block_time ;
324376
377+ /* User space PID and TID correspond to TGID and PID in the kernel, respectively */
378+ if (env .pids [0 ])
379+ obj -> rodata -> filter_by_tgid = true;
380+ else if (env .tids [0 ])
381+ obj -> rodata -> filter_by_pid = true;
382+
325383 bpf_map__set_value_size (obj -> maps .stackmap ,
326384 env .perf_max_stack_depth * sizeof (unsigned long ));
327385 bpf_map__set_max_entries (obj -> maps .stackmap , env .stack_storage_size );
@@ -331,6 +389,28 @@ int main(int argc, char **argv)
331389 fprintf (stderr , "failed to load BPF programs\n" );
332390 goto cleanup ;
333391 }
392+
393+ if (env .pids [0 ]) {
394+ /* User pids_fd points to the tgids map in the BPF program */
395+ pids_fd = bpf_map__fd (obj -> maps .tgids );
396+ for (i = 0 ; i < MAX_PID_NR && env .pids [i ]; i ++ ) {
397+ if (bpf_map_update_elem (pids_fd , & (env .pids [i ]), & val , BPF_ANY ) != 0 ) {
398+ fprintf (stderr , "failed to init pids map: %s\n" , strerror (errno ));
399+ goto cleanup ;
400+ }
401+ }
402+ }
403+ else if (env .tids [0 ]) {
404+ /* User tids_fd points to the pids map in the BPF program */
405+ tids_fd = bpf_map__fd (obj -> maps .pids );
406+ for (i = 0 ; i < MAX_TID_NR && env .tids [i ]; i ++ ) {
407+ if (bpf_map_update_elem (tids_fd , & (env .tids [i ]), & val , BPF_ANY ) != 0 ) {
408+ fprintf (stderr , "failed to init tids map: %s\n" , strerror (errno ));
409+ goto cleanup ;
410+ }
411+ }
412+ }
413+
334414 ksyms = ksyms__load ();
335415 if (!ksyms ) {
336416 fprintf (stderr , "failed to load kallsyms\n" );
@@ -349,11 +429,8 @@ int main(int argc, char **argv)
349429
350430 signal (SIGINT , sig_handler );
351431
352- printf ("Tracing off-CPU time (us)" );
353- if (env .duration < 99999999 )
354- printf (" for %d secs.\n" , env .duration );
355- else
356- printf ("... Hit Ctrl-C to end.\n" );
432+ print_headers ();
433+
357434 /*
358435 * We'll get sleep interrupted when someone presses Ctrl-C (which will
359436 * be "handled" with noop by sig_handler).
0 commit comments