Skip to content

Commit 68d5ac5

Browse files
committed
libbpf-tools/offcputime: Add multi process/thread support
This is a test example. # ./offcputime -p 16,48 Tracing off-CPU time (us) of PID [16, 48]... Hit Ctrl-C to end. bpf_prog_a42aae11c0bc18f2_sched_switch bpf_prog_a42aae11c0bc18f2_sched_switch bpf_trace_run4 __traceiter_sched_switch __schedule schedule worker_thread kthread ret_from_fork ret_from_fork_asm - kworker/2:1 (48) 3353019 bpf_prog_a42aae11c0bc18f2_sched_switch bpf_prog_a42aae11c0bc18f2_sched_switch bpf_trace_run4 __traceiter_sched_switch __schedule schedule rcu_gp_kthread kthread ret_from_fork ret_from_fork_asm - rcu_preempt (16) 1720974
1 parent 9f3d0df commit 68d5ac5

File tree

3 files changed

+120
-24
lines changed

3 files changed

+120
-24
lines changed

libbpf-tools/offcputime.bpf.c

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ const volatile bool kernel_threads_only = false;
1414
const volatile bool user_threads_only = false;
1515
const volatile __u64 max_block_ns = -1;
1616
const volatile __u64 min_block_ns = 1;
17-
const volatile pid_t targ_tgid = -1;
18-
const volatile pid_t targ_pid = -1;
17+
const volatile bool filter_by_tgid = false;
18+
const volatile bool filter_by_pid = false;
1919
const volatile long state = -1;
2020

2121
struct internal_key {
@@ -42,11 +42,28 @@ struct {
4242
__uint(max_entries, MAX_ENTRIES);
4343
} info SEC(".maps");
4444

45+
struct {
46+
__uint(type, BPF_MAP_TYPE_HASH);
47+
__type(key, u32);
48+
__type(value, u8);
49+
__uint(max_entries, MAX_PID_NR);
50+
} tgids SEC(".maps");
51+
52+
struct {
53+
__uint(type, BPF_MAP_TYPE_HASH);
54+
__type(key, u32);
55+
__type(value, u8);
56+
__uint(max_entries, MAX_TID_NR);
57+
} pids SEC(".maps");
58+
4559
static bool allow_record(struct task_struct *t)
4660
{
47-
if (targ_tgid != -1 && targ_tgid != t->tgid)
61+
u32 tgid = t->tgid;
62+
u32 pid = t->pid;
63+
64+
if (filter_by_tgid && !bpf_map_lookup_elem(&tgids, &tgid))
4865
return false;
49-
if (targ_pid != -1 && targ_pid != t->pid)
66+
if (filter_by_pid && !bpf_map_lookup_elem(&pids, &pid))
5067
return false;
5168
if (user_threads_only && t->flags & PF_KTHREAD)
5269
return false;

libbpf-tools/offcputime.c

Lines changed: 97 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
#include "trace_helpers.h"
1717

1818
static 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+
85104
static 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+
284336
int 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).

libbpf-tools/offcputime.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#define __OFFCPUTIME_H
44

55
#define TASK_COMM_LEN 16
6+
#define MAX_PID_NR 30
7+
#define MAX_TID_NR 30
68

79
struct key_t {
810
__u32 pid;

0 commit comments

Comments
 (0)