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