1*387f9dfdSAndroid Build Coastguard Worker /*
2*387f9dfdSAndroid Build Coastguard Worker * FollyRequestContextSwitch Monitor RequestContext switch events for any binary
3*387f9dfdSAndroid Build Coastguard Worker * uses the class from [folly](http://bit.ly/2h6S1yx).
4*387f9dfdSAndroid Build Coastguard Worker * For Linux, uses BCC, eBPF. Embedded C.
5*387f9dfdSAndroid Build Coastguard Worker *
6*387f9dfdSAndroid Build Coastguard Worker * Basic example of using USDT with BCC.
7*387f9dfdSAndroid Build Coastguard Worker *
8*387f9dfdSAndroid Build Coastguard Worker * USAGE: FollyRequestContextSwitch PATH_TO_BINARY
9*387f9dfdSAndroid Build Coastguard Worker *
10*387f9dfdSAndroid Build Coastguard Worker * Copyright (c) Facebook, Inc.
11*387f9dfdSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License")
12*387f9dfdSAndroid Build Coastguard Worker */
13*387f9dfdSAndroid Build Coastguard Worker
14*387f9dfdSAndroid Build Coastguard Worker #include <signal.h>
15*387f9dfdSAndroid Build Coastguard Worker #include <functional>
16*387f9dfdSAndroid Build Coastguard Worker #include <iostream>
17*387f9dfdSAndroid Build Coastguard Worker #include <vector>
18*387f9dfdSAndroid Build Coastguard Worker
19*387f9dfdSAndroid Build Coastguard Worker #include "BPF.h"
20*387f9dfdSAndroid Build Coastguard Worker
21*387f9dfdSAndroid Build Coastguard Worker const std::string BPF_PROGRAM = R"(
22*387f9dfdSAndroid Build Coastguard Worker #include <linux/sched.h>
23*387f9dfdSAndroid Build Coastguard Worker #include <uapi/linux/ptrace.h>
24*387f9dfdSAndroid Build Coastguard Worker
25*387f9dfdSAndroid Build Coastguard Worker struct event_t {
26*387f9dfdSAndroid Build Coastguard Worker int pid;
27*387f9dfdSAndroid Build Coastguard Worker char name[16];
28*387f9dfdSAndroid Build Coastguard Worker uint64_t old_addr;
29*387f9dfdSAndroid Build Coastguard Worker uint64_t new_addr;
30*387f9dfdSAndroid Build Coastguard Worker };
31*387f9dfdSAndroid Build Coastguard Worker
32*387f9dfdSAndroid Build Coastguard Worker BPF_PERF_OUTPUT(events);
33*387f9dfdSAndroid Build Coastguard Worker
34*387f9dfdSAndroid Build Coastguard Worker int on_context_switch(struct pt_regs *ctx) {
35*387f9dfdSAndroid Build Coastguard Worker struct event_t event = {};
36*387f9dfdSAndroid Build Coastguard Worker
37*387f9dfdSAndroid Build Coastguard Worker event.pid = bpf_get_current_pid_tgid();
38*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&event.name, sizeof(event.name));
39*387f9dfdSAndroid Build Coastguard Worker
40*387f9dfdSAndroid Build Coastguard Worker bpf_usdt_readarg(1, ctx, &event.old_addr);
41*387f9dfdSAndroid Build Coastguard Worker bpf_usdt_readarg(2, ctx, &event.new_addr);
42*387f9dfdSAndroid Build Coastguard Worker
43*387f9dfdSAndroid Build Coastguard Worker events.perf_submit(ctx, &event, sizeof(event));
44*387f9dfdSAndroid Build Coastguard Worker return 0;
45*387f9dfdSAndroid Build Coastguard Worker }
46*387f9dfdSAndroid Build Coastguard Worker )";
47*387f9dfdSAndroid Build Coastguard Worker
48*387f9dfdSAndroid Build Coastguard Worker // Define the same struct to use in user space.
49*387f9dfdSAndroid Build Coastguard Worker struct event_t {
50*387f9dfdSAndroid Build Coastguard Worker int pid;
51*387f9dfdSAndroid Build Coastguard Worker char name[16];
52*387f9dfdSAndroid Build Coastguard Worker uint64_t old_addr;
53*387f9dfdSAndroid Build Coastguard Worker uint64_t new_addr;
54*387f9dfdSAndroid Build Coastguard Worker };
55*387f9dfdSAndroid Build Coastguard Worker
handle_output(void * cb_cookie,void * data,int data_size)56*387f9dfdSAndroid Build Coastguard Worker void handle_output(void* cb_cookie, void* data, int data_size) {
57*387f9dfdSAndroid Build Coastguard Worker auto event = static_cast<event_t*>(data);
58*387f9dfdSAndroid Build Coastguard Worker std::cout << "PID " << event->pid << " (" << event->name << ") ";
59*387f9dfdSAndroid Build Coastguard Worker std::cout << "folly::RequestContext switch from " << event->old_addr << " to "
60*387f9dfdSAndroid Build Coastguard Worker << event->new_addr << std::endl;
61*387f9dfdSAndroid Build Coastguard Worker }
62*387f9dfdSAndroid Build Coastguard Worker
63*387f9dfdSAndroid Build Coastguard Worker std::function<void(int)> shutdown_handler;
64*387f9dfdSAndroid Build Coastguard Worker
signal_handler(int s)65*387f9dfdSAndroid Build Coastguard Worker void signal_handler(int s) { shutdown_handler(s); }
66*387f9dfdSAndroid Build Coastguard Worker
main(int argc,char ** argv)67*387f9dfdSAndroid Build Coastguard Worker int main(int argc, char** argv) {
68*387f9dfdSAndroid Build Coastguard Worker std::string binary;
69*387f9dfdSAndroid Build Coastguard Worker pid_t pid = -1;
70*387f9dfdSAndroid Build Coastguard Worker for (int i = 0; i < argc; i++) {
71*387f9dfdSAndroid Build Coastguard Worker if (strncmp(argv[i], "--pid", 5) == 0) {
72*387f9dfdSAndroid Build Coastguard Worker pid = std::stoi(argv[i + 1]);
73*387f9dfdSAndroid Build Coastguard Worker i++;
74*387f9dfdSAndroid Build Coastguard Worker continue;
75*387f9dfdSAndroid Build Coastguard Worker }
76*387f9dfdSAndroid Build Coastguard Worker if (strncmp(argv[i], "--binary", 8) == 0) {
77*387f9dfdSAndroid Build Coastguard Worker binary = argv[i + 1];
78*387f9dfdSAndroid Build Coastguard Worker i++;
79*387f9dfdSAndroid Build Coastguard Worker continue;
80*387f9dfdSAndroid Build Coastguard Worker }
81*387f9dfdSAndroid Build Coastguard Worker }
82*387f9dfdSAndroid Build Coastguard Worker
83*387f9dfdSAndroid Build Coastguard Worker if (pid <= 0 && binary.empty()) {
84*387f9dfdSAndroid Build Coastguard Worker std::cout << "Must specify at least one of binary or PID:" << std::endl
85*387f9dfdSAndroid Build Coastguard Worker << "FollyRequestContextSwitch [--pid PID] [--binary BINARY]"
86*387f9dfdSAndroid Build Coastguard Worker << std::endl;
87*387f9dfdSAndroid Build Coastguard Worker exit(1);
88*387f9dfdSAndroid Build Coastguard Worker }
89*387f9dfdSAndroid Build Coastguard Worker
90*387f9dfdSAndroid Build Coastguard Worker ebpf::USDT u(binary, pid, "folly", "request_context_switch_before",
91*387f9dfdSAndroid Build Coastguard Worker "on_context_switch");
92*387f9dfdSAndroid Build Coastguard Worker
93*387f9dfdSAndroid Build Coastguard Worker ebpf::BPF* bpf = new ebpf::BPF();
94*387f9dfdSAndroid Build Coastguard Worker
95*387f9dfdSAndroid Build Coastguard Worker auto init_res = bpf->init(BPF_PROGRAM, {}, {u});
96*387f9dfdSAndroid Build Coastguard Worker if (!init_res.ok()) {
97*387f9dfdSAndroid Build Coastguard Worker std::cerr << init_res.msg() << std::endl;
98*387f9dfdSAndroid Build Coastguard Worker return 1;
99*387f9dfdSAndroid Build Coastguard Worker }
100*387f9dfdSAndroid Build Coastguard Worker
101*387f9dfdSAndroid Build Coastguard Worker auto attach_res = bpf->attach_usdt_all();
102*387f9dfdSAndroid Build Coastguard Worker if (!attach_res.ok()) {
103*387f9dfdSAndroid Build Coastguard Worker std::cerr << attach_res.msg() << std::endl;
104*387f9dfdSAndroid Build Coastguard Worker return 1;
105*387f9dfdSAndroid Build Coastguard Worker } else {
106*387f9dfdSAndroid Build Coastguard Worker std::cout << "Attached to USDT " << u;
107*387f9dfdSAndroid Build Coastguard Worker }
108*387f9dfdSAndroid Build Coastguard Worker
109*387f9dfdSAndroid Build Coastguard Worker auto open_res = bpf->open_perf_buffer("events", &handle_output);
110*387f9dfdSAndroid Build Coastguard Worker if (!open_res.ok()) {
111*387f9dfdSAndroid Build Coastguard Worker std::cerr << open_res.msg() << std::endl;
112*387f9dfdSAndroid Build Coastguard Worker return 1;
113*387f9dfdSAndroid Build Coastguard Worker }
114*387f9dfdSAndroid Build Coastguard Worker
115*387f9dfdSAndroid Build Coastguard Worker shutdown_handler = [&](int s) {
116*387f9dfdSAndroid Build Coastguard Worker std::cerr << "Terminating..." << std::endl;
117*387f9dfdSAndroid Build Coastguard Worker bpf->detach_usdt_all();
118*387f9dfdSAndroid Build Coastguard Worker delete bpf;
119*387f9dfdSAndroid Build Coastguard Worker exit(0);
120*387f9dfdSAndroid Build Coastguard Worker };
121*387f9dfdSAndroid Build Coastguard Worker signal(SIGINT, signal_handler);
122*387f9dfdSAndroid Build Coastguard Worker
123*387f9dfdSAndroid Build Coastguard Worker std::cout << "Started tracing, hit Ctrl-C to terminate." << std::endl;
124*387f9dfdSAndroid Build Coastguard Worker auto perf_buffer = bpf->get_perf_buffer("events");
125*387f9dfdSAndroid Build Coastguard Worker if (perf_buffer)
126*387f9dfdSAndroid Build Coastguard Worker while (true)
127*387f9dfdSAndroid Build Coastguard Worker // 100ms timeout
128*387f9dfdSAndroid Build Coastguard Worker perf_buffer->poll(100);
129*387f9dfdSAndroid Build Coastguard Worker
130*387f9dfdSAndroid Build Coastguard Worker return 0;
131*387f9dfdSAndroid Build Coastguard Worker }
132