xref: /aosp_15_r20/external/bcc/examples/cpp/TaskIterator.cc (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1 /*
2  * Copyright (c) Facebook, Inc.
3  * Licensed under the Apache License, Version 2.0 (the "License")
4  *
5  * Usage:
6  *   ./TaskIterator
7  *
8  * BPF task iterator is available since linux 5.8.
9  * This example shows how to dump all threads in the system with
10  * bpf iterator. An example output likes below:
11  *   tid     comm
12  *   1       systemd
13  *   2       kthreadd
14  *   3       rcu_gp
15  *   4       rcu_par_gp
16  *   6       kworker/0:0H
17  *   ...
18  *   2613386 sleep
19  *   2613474 GetCountersCPU6
20  *   2613587 GetCountersCPU7
21  *   2613621 CPUThreadPool69
22  *   2613906 GetCountersCPU5
23  *   2614140 GetCountersCPU2
24  *   2614193 CfgrExtension56
25  *   2614449 ruby-timer-thr
26  *   2614529 chef-client
27  *   2615122 systemd-hostnam
28  *   ...
29  *   2608477 sudo
30  *   2608478 TaskIterator
31  */
32 
33 #include <unistd.h>
34 #include <fstream>
35 #include <iostream>
36 #include <string>
37 
38 #include "bcc_version.h"
39 #include "BPF.h"
40 
41 const std::string BPF_PROGRAM = R"(
42 #include <linux/bpf.h>
43 #include <linux/seq_file.h>
44 #include <linux/sched.h>
45 
46 /* the structure is defined in .c file, so explicitly define
47  * the structure here.
48  */
49 struct bpf_iter__task {
50   union {
51     struct bpf_iter_meta *meta;
52   };
53   union {
54     struct task_struct *task;
55   };
56 };
57 
58 struct info_t {
59   int tid;
60   char comm[TASK_COMM_LEN];
61 };
62 
63 BPF_ITER(task) {
64   struct seq_file *seq = ctx->meta->seq;
65   struct task_struct *task = ctx->task;
66   struct info_t info = {};
67 
68   if (task == (void *)0)
69     return 0;
70 
71   info.tid = task->pid;
72   __builtin_memcpy(&info.comm, task->comm, sizeof(info.comm));
73   bpf_seq_write(seq, &info, sizeof(info));
74 
75   return 0;
76 }
77 )";
78 
79 // linux/sched.h
80 #define TASK_COMM_LEN	16
81 
82 struct info_t {
83   int tid;
84   char comm[TASK_COMM_LEN];
85 };
86 
main()87 int main() {
88   ebpf::BPF bpf;
89   auto res = bpf.init(BPF_PROGRAM);
90   if (!res.ok()) {
91     std::cerr << res.msg() << std::endl;
92     return 1;
93   }
94 
95   int prog_fd;
96   res = bpf.load_func("bpf_iter__task", BPF_PROG_TYPE_TRACING, prog_fd);
97   if (!res.ok()) {
98     std::cerr << res.msg() << std::endl;
99     return 1;
100   }
101 
102   int link_fd = bcc_iter_attach(prog_fd, NULL, 0);
103   if (link_fd < 0) {
104     std::cerr << "bcc_iter_attach failed: " << link_fd << std::endl;
105     return 1;
106   }
107 
108   int iter_fd = bcc_iter_create(link_fd);
109   if (iter_fd < 0) {
110     std::cerr << "bcc_iter_create failed: " << iter_fd << std::endl;
111     close(link_fd);
112     return 1;
113   }
114 
115   // Header.
116   printf("tid\tcomm\n");
117 
118   struct info_t info[20];
119   int len, leftover = 0, info_size = 20 * sizeof(struct info_t);
120   while ((len = read(iter_fd, (char *)info + leftover, info_size - leftover))) {
121     if (len < 0) {
122       if (len == -EAGAIN)
123 	continue;
124       std::cerr << "read failed: " << len << std::endl;
125       break;
126     }
127 
128     int num_info = len / sizeof(struct info_t);
129     for (int i = 0; i < num_info; i++) {
130       printf("%d\t%s\n", info[i].tid, info[i].comm);
131     }
132 
133     leftover = len % sizeof(struct info_t);
134     if (num_info > 0)
135       memcpy(info, (void *)&info[num_info], leftover);
136   }
137 
138   close(iter_fd);
139   close(link_fd);
140   return 0;
141 }
142