blob: 183529ef04521ea6e1371cac793353e0bd0794c0 [file] [log] [blame]
Teng Qin284dd8e2016-11-23 12:23:03 -08001/*
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
19const std::string BPF_PROGRAM = R"(
20#include <linux/sched.h>
21#include <uapi/linux/ptrace.h>
22
23struct stack_key_t {
24 int pid;
25 char name[16];
26 int user_stack;
27 int kernel_stack;
28};
29
Teng Qince657b12018-04-27 12:51:46 -070030BPF_STACK_TRACE(stack_traces, 16384);
Teng Qin284dd8e2016-11-23 12:23:03 -080031BPF_HASH(counts, struct stack_key_t, uint64_t);
32
33int on_tcp_send(struct pt_regs *ctx) {
34 struct stack_key_t key = {};
Teng Qine69aaa82017-05-20 22:44:32 -070035 key.pid = bpf_get_current_pid_tgid() >> 32;
Teng Qin284dd8e2016-11-23 12:23:03 -080036 bpf_get_current_comm(&key.name, sizeof(key.name));
Teng Qince657b12018-04-27 12:51:46 -070037 key.kernel_stack = stack_traces.get_stackid(ctx, 0);
38 key.user_stack = stack_traces.get_stackid(ctx, BPF_F_USER_STACK);
Teng Qin284dd8e2016-11-23 12:23:03 -080039
40 u64 zero = 0, *val;
41 val = counts.lookup_or_init(&key, &zero);
42 (*val)++;
43
44 return 0;
45}
46)";
47
48// Define the same struct to use in user space.
49struct stack_key_t {
50 int pid;
51 char name[16];
52 int user_stack;
53 int kernel_stack;
54};
55
56int main(int argc, char** argv) {
57 ebpf::BPF bpf;
58 auto init_res = bpf.init(BPF_PROGRAM);
Teng Qin13ebe8e2016-11-29 16:29:08 -080059 if (init_res.code() != 0) {
60 std::cerr << init_res.msg() << std::endl;
Teng Qin284dd8e2016-11-23 12:23:03 -080061 return 1;
62 }
63
64 auto attach_res = bpf.attach_kprobe("tcp_sendmsg", "on_tcp_send");
Teng Qin13ebe8e2016-11-29 16:29:08 -080065 if (attach_res.code() != 0) {
66 std::cerr << attach_res.msg() << std::endl;
Teng Qin284dd8e2016-11-23 12:23:03 -080067 return 1;
68 }
69
70 int probe_time = 10;
71 if (argc == 2) {
72 probe_time = atoi(argv[1]);
73 }
74 std::cout << "Probing for " << probe_time << " seconds" << std::endl;
75 sleep(probe_time);
76
Teng Qince657b12018-04-27 12:51:46 -070077 auto detach_res = bpf.detach_kprobe("tcp_sendmsg");
78 if (detach_res.code() != 0) {
79 std::cerr << detach_res.msg() << std::endl;
80 return 1;
81 }
82
Teng Qin284dd8e2016-11-23 12:23:03 -080083 auto table =
84 bpf.get_hash_table<stack_key_t, uint64_t>("counts").get_table_offline();
Teng Qin5cf87882018-04-27 12:36:58 -070085 std::sort(
86 table.begin(), table.end(),
87 [](std::pair<stack_key_t, uint64_t> a,
88 std::pair<stack_key_t, uint64_t> b) { return a.second < b.second; });
Teng Qin284dd8e2016-11-23 12:23:03 -080089 auto stacks = bpf.get_stack_table("stack_traces");
90
Teng Qince657b12018-04-27 12:51:46 -070091 int lost_stacks = 0;
Teng Qin284dd8e2016-11-23 12:23:03 -080092 for (auto it : table) {
93 std::cout << "PID: " << it.first.pid << " (" << it.first.name << ") "
94 << "made " << it.second
95 << " TCP sends on following stack: " << std::endl;
Teng Qin284dd8e2016-11-23 12:23:03 -080096 if (it.first.kernel_stack >= 0) {
Teng Qince657b12018-04-27 12:51:46 -070097 std::cout << " Kernel Stack:" << std::endl;
Teng Qin284dd8e2016-11-23 12:23:03 -080098 auto syms = stacks.get_stack_symbol(it.first.kernel_stack, -1);
99 for (auto sym : syms)
100 std::cout << " " << sym << std::endl;
Teng Qince657b12018-04-27 12:51:46 -0700101 } else {
102 // -EFAULT normally means the stack is not availiable and not an error
103 if (it.first.kernel_stack != -EFAULT) {
104 lost_stacks++;
105 std::cout << " [Lost Kernel Stack" << it.first.kernel_stack << "]"
106 << std::endl;
107 }
108 }
Teng Qin284dd8e2016-11-23 12:23:03 -0800109 if (it.first.user_stack >= 0) {
Teng Qince657b12018-04-27 12:51:46 -0700110 std::cout << " User Stack:" << std::endl;
Teng Qin284dd8e2016-11-23 12:23:03 -0800111 auto syms = stacks.get_stack_symbol(it.first.user_stack, it.first.pid);
112 for (auto sym : syms)
113 std::cout << " " << sym << std::endl;
Teng Qince657b12018-04-27 12:51:46 -0700114 } else {
115 // -EFAULT normally means the stack is not availiable and not an error
116 if (it.first.user_stack != -EFAULT) {
117 lost_stacks++;
118 std::cout << " [Lost User Stack " << it.first.user_stack << "]"
119 << std::endl;
120 }
121 }
Teng Qin284dd8e2016-11-23 12:23:03 -0800122 }
123
Teng Qince657b12018-04-27 12:51:46 -0700124 if (lost_stacks > 0)
125 std::cout << "Total " << lost_stacks << " stack-traces lost due to "
126 << "hash collision or stack table full" << std::endl;
Teng Qin284dd8e2016-11-23 12:23:03 -0800127
128 return 0;
129}