xref: /aosp_15_r20/external/bcc/examples/cpp/TCPSendStack.cc (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1 /*
2  * TCPSendStack Summarize tcp_sendmsg() calling stack traces.
3  *              For Linux, uses BCC, eBPF. Embedded C.
4  *
5  * Basic example of BCC in-kernel stack trace dedup.
6  *
7  * USAGE: TCPSendStack [duration]
8  *
9  * Copyright (c) Facebook, Inc.
10  * Licensed under the Apache License, Version 2.0 (the "License")
11  */
12 
13 #include <unistd.h>
14 #include <algorithm>
15 #include <iostream>
16 
17 #include "BPF.h"
18 
19 const std::string BPF_PROGRAM = R"(
20 #include <linux/sched.h>
21 #include <uapi/linux/ptrace.h>
22 
23 struct stack_key_t {
24   int pid;
25   char name[16];
26   int user_stack;
27   int kernel_stack;
28 };
29 
30 BPF_STACK_TRACE(stack_traces, 16384);
31 BPF_HASH(counts, struct stack_key_t, uint64_t);
32 
33 int on_tcp_send(struct pt_regs *ctx) {
34   struct stack_key_t key = {};
35   key.pid = bpf_get_current_pid_tgid() >> 32;
36   bpf_get_current_comm(&key.name, sizeof(key.name));
37   key.kernel_stack = stack_traces.get_stackid(ctx, 0);
38   key.user_stack = stack_traces.get_stackid(ctx, BPF_F_USER_STACK);
39 
40   u64 zero = 0, *val;
41   val = counts.lookup_or_try_init(&key, &zero);
42   if (val) {
43     (*val)++;
44   }
45 
46   return 0;
47 }
48 )";
49 
50 // Define the same struct to use in user space.
51 struct stack_key_t {
52   int pid;
53   char name[16];
54   int user_stack;
55   int kernel_stack;
56 };
57 
main(int argc,char ** argv)58 int main(int argc, char** argv) {
59   ebpf::BPF bpf;
60   auto init_res = bpf.init(BPF_PROGRAM);
61   if (!init_res.ok()) {
62     std::cerr << init_res.msg() << std::endl;
63     return 1;
64   }
65 
66   auto attach_res = bpf.attach_kprobe("tcp_sendmsg", "on_tcp_send");
67   if (!attach_res.ok()) {
68     std::cerr << attach_res.msg() << std::endl;
69     return 1;
70   }
71 
72   int probe_time = 10;
73   if (argc == 2) {
74     probe_time = atoi(argv[1]);
75   }
76   std::cout << "Probing for " << probe_time << " seconds" << std::endl;
77   sleep(probe_time);
78 
79   auto detach_res = bpf.detach_kprobe("tcp_sendmsg");
80   if (!detach_res.ok()) {
81     std::cerr << detach_res.msg() << std::endl;
82     return 1;
83   }
84 
85   auto table =
86       bpf.get_hash_table<stack_key_t, uint64_t>("counts").get_table_offline();
87   std::sort(
88       table.begin(), table.end(),
89       [](std::pair<stack_key_t, uint64_t> a,
90          std::pair<stack_key_t, uint64_t> b) { return a.second < b.second; });
91   auto stacks = bpf.get_stack_table("stack_traces");
92 
93   int lost_stacks = 0;
94   for (auto it : table) {
95     std::cout << "PID: " << it.first.pid << " (" << it.first.name << ") "
96               << "made " << it.second
97               << " TCP sends on following stack: " << std::endl;
98     if (it.first.kernel_stack >= 0) {
99       std::cout << "  Kernel Stack:" << std::endl;
100       auto syms = stacks.get_stack_symbol(it.first.kernel_stack, -1);
101       for (auto sym : syms)
102         std::cout << "    " << sym << std::endl;
103     } else {
104       // -EFAULT normally means the stack is not available and not an error
105       if (it.first.kernel_stack != -EFAULT) {
106         lost_stacks++;
107         std::cout << "    [Lost Kernel Stack" << it.first.kernel_stack << "]"
108                   << std::endl;
109       }
110     }
111     if (it.first.user_stack >= 0) {
112       std::cout << "  User Stack:" << std::endl;
113       auto syms = stacks.get_stack_symbol(it.first.user_stack, it.first.pid);
114       for (auto sym : syms)
115         std::cout << "    " << sym << std::endl;
116     } else {
117       // -EFAULT normally means the stack is not available and not an error
118       if (it.first.user_stack != -EFAULT) {
119         lost_stacks++;
120         std::cout << "    [Lost User Stack " << it.first.user_stack << "]"
121                   << std::endl;
122       }
123     }
124   }
125 
126   if (lost_stacks > 0)
127     std::cout << "Total " << lost_stacks << " stack-traces lost due to "
128               << "hash collision or stack table full" << std::endl;
129 
130   return 0;
131 }
132