Skip to content

Commit

Permalink
Examples of using BCC C++ API
Browse files Browse the repository at this point in the history
  • Loading branch information
palmtenor committed Nov 24, 2016
1 parent 335cbe4 commit 284dd8e
Show file tree
Hide file tree
Showing 7 changed files with 491 additions and 1 deletion.
3 changes: 2 additions & 1 deletion examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
set(EXAMPLE_PROGRAMS hello_world.py)
install(PROGRAMS ${EXAMPLE_PROGRAMS} DESTINATION share/bcc/examples)

add_subdirectory(cpp)
add_subdirectory(lua)
add_subdirectory(networking)
add_subdirectory(tracing)
add_subdirectory(lua)
24 changes: 24 additions & 0 deletions examples/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright (c) Facebook, Inc.
# Licensed under the Apache License, Version 2.0 (the "License")

include_directories(${CMAKE_SOURCE_DIR}/src/cc)

add_executable(HelloWorld HelloWorld.cc)
target_link_libraries(HelloWorld bcc-static)
install (TARGETS HelloWorld DESTINATION share/bcc/examples/cpp)

add_executable(CPUDistribution CPUDistribution.cc)
target_link_libraries(CPUDistribution bcc-static)
install (TARGETS CPUDistribution DESTINATION share/bcc/examples/cpp)

add_executable(RecordMySQLQuery RecordMySQLQuery.cc)
target_link_libraries(RecordMySQLQuery bcc-static)
install (TARGETS RecordMySQLQuery DESTINATION share/bcc/examples/cpp)

add_executable(TCPSendStack TCPSendStack.cc)
target_link_libraries(TCPSendStack bcc-static)
install (TARGETS TCPSendStack DESTINATION share/bcc/examples/cpp)

add_executable(RandomRead RandomRead.cc)
target_link_libraries(RandomRead bcc-static)
install (TARGETS RandomRead DESTINATION share/bcc/examples/cpp)
97 changes: 97 additions & 0 deletions examples/cpp/CPUDistribution.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* CPUDistribution Show load distribution across CPU cores during a period of
* time. For Linux, uses BCC, eBPF. Embedded C.
*
* Basic example of BCC and kprobes.
*
* USAGE: CPUDistribution [duration]
*
* Copyright (c) Facebook, Inc.
* Licensed under the Apache License, Version 2.0 (the "License")
*/

#include <unistd.h>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <string>

#include "BPF.h"

const std::string BPF_PROGRAM = R"(
#include <linux/sched.h>
#include <uapi/linux/ptrace.h>
BPF_HASH(pid_to_cpu, pid_t, int);
BPF_HASH(pid_to_ts, pid_t, uint64_t);
BPF_HASH(cpu_time, int, uint64_t);
int task_switch_event(struct pt_regs *ctx, struct task_struct *prev) {
pid_t prev_pid = prev->pid;
int* prev_cpu = pid_to_cpu.lookup(&prev_pid);
uint64_t* prev_ts = pid_to_ts.lookup(&prev_pid);
pid_t cur_pid = bpf_get_current_pid_tgid();
int cur_cpu = bpf_get_smp_processor_id();
uint64_t cur_ts = bpf_ktime_get_ns();
uint64_t this_cpu_time = 0;
if (prev_ts) {
pid_to_ts.delete(&prev_pid);
this_cpu_time = (cur_ts - *prev_ts);
}
if (prev_cpu) {
pid_to_cpu.delete(&prev_pid);
if (this_cpu_time > 0) {
int cpu_key = *prev_cpu;
uint64_t* history_time = cpu_time.lookup(&cpu_key);
if (history_time)
this_cpu_time += *history_time;
cpu_time.update(&cpu_key, &this_cpu_time);
}
}
pid_to_cpu.update(&cur_pid, &cur_cpu);
pid_to_ts.update(&cur_pid, &cur_ts);
return 0;
}
)";

int main(int argc, char** argv) {
ebpf::BPF bpf;
auto init_res = bpf.init(BPF_PROGRAM);
if (std::get<0>(init_res) != 0) {
std::cerr << std::get<1>(init_res) << std::endl;
return 1;
}

auto attach_res =
bpf.attach_kprobe("finish_task_switch", "task_switch_event");
if (std::get<0>(attach_res) != 0) {
std::cerr << std::get<1>(attach_res) << std::endl;
return 1;
}

int probe_time = 10;
if (argc == 2) {
probe_time = atoi(argv[1]);
}
std::cout << "Probing for " << probe_time << " seconds" << std::endl;
sleep(probe_time);

auto table = bpf.get_hash_table<int, uint64_t>("cpu_time");
auto num_cores = sysconf(_SC_NPROCESSORS_ONLN);
for (int i = 0; i < num_cores; i++) {
std::cout << "CPU " << std::setw(2) << i << " worked for ";
std::cout << (table[i] / 1000000.0) << " ms." << std::endl;
}

auto detach_res = bpf.detach_kprobe("finish_task_switch");
if (std::get<0>(detach_res) != 0) {
std::cerr << std::get<1>(detach_res) << std::endl;
return 1;
}

return 0;
}
54 changes: 54 additions & 0 deletions examples/cpp/HelloWorld.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (c) Facebook, Inc.
* Licensed under the Apache License, Version 2.0 (the "License")
*/

#include <unistd.h>
#include <fstream>
#include <iostream>
#include <string>

#include "BPF.h"

const std::string BPF_PROGRAM = R"(
int on_sys_clone(void *ctx) {
bpf_trace_printk("Hello, World! Here I did a sys_clone call!\n");
return 0;
}
)";

int main() {
ebpf::BPF bpf;
auto init_res = bpf.init(BPF_PROGRAM);
if (std::get<0>(init_res) != 0) {
std::cerr << std::get<1>(init_res) << std::endl;
return 1;
}

std::ifstream pipe("/sys/kernel/debug/tracing/trace_pipe");
std::string line;

auto attach_res = bpf.attach_kprobe("sys_clone", "on_sys_clone");
if (std::get<0>(attach_res) != 0) {
std::cerr << std::get<1>(attach_res) << std::endl;
return 1;
}

while (true) {
if (std::getline(pipe, line)) {
std::cout << line << std::endl;
// Detach the probe if we got at least one line.
auto detach_res = bpf.detach_kprobe("sys_clone");
if (std::get<0>(detach_res) != 0) {
std::cerr << std::get<1>(detach_res) << std::endl;
return 1;
}
break;
} else {
std::cout << "Waiting for a sys_clone event" << std::endl;
sleep(1);
}
}

return 0;
}
97 changes: 97 additions & 0 deletions examples/cpp/RandomRead.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* RandomRead Monitor random number read events.
* For Linux, uses BCC, eBPF. Embedded C.
*
* Basic example of BCC Tracepoint and perf buffer.
*
* USAGE: RandomRead
*
* Copyright (c) Facebook, Inc.
* Licensed under the Apache License, Version 2.0 (the "License")
*/

#include <signal.h>
#include <iostream>

#include "BPF.h"

const std::string BPF_PROGRAM = R"(
#include <linux/sched.h>
#include <uapi/linux/ptrace.h>
struct urandom_read_args {
// See /sys/kernel/debug/tracing/events/random/urandom_read/format
uint64_t common__unused;
int got_bits;
int pool_left;
int input_left;
};
struct event_t {
int pid;
char comm[16];
int got_bits;
};
BPF_PERF_OUTPUT(events);
int on_urandom_read(struct urandom_read_args* attr) {
struct event_t event = {};
event.pid = bpf_get_current_pid_tgid();
bpf_get_current_comm(&event.comm, sizeof(event.comm));
event.got_bits = attr->got_bits;
events.perf_submit(attr, &event, sizeof(event));
return 0;
}
)";

// Define the same struct to use in user space.
struct event_t {
int pid;
char comm[16];
int got_bits;
};

void handle_output(void* cb_cookie, void* data, int data_size) {
auto event = static_cast<event_t*>(data);
std::cout << "PID: " << event->pid << " (" << event->comm << ") "
<< "Read " << event->got_bits << " bits" << std::endl;
}

ebpf::BPF* bpf;

void signal_handler(int s) {
std::cerr << "Terminating..." << std::endl;
delete bpf;
exit(0);
}

int main(int argc, char** argv) {
bpf = new ebpf::BPF();
auto init_res = bpf->init(BPF_PROGRAM);
if (std::get<0>(init_res) != 0) {
std::cerr << std::get<1>(init_res) << std::endl;
return 1;
}

auto attach_res =
bpf->attach_tracepoint("random:urandom_read", "on_urandom_read");
if (std::get<0>(attach_res) != 0) {
std::cerr << std::get<1>(attach_res) << std::endl;
return 1;
}

auto open_res = bpf->open_perf_buffer("events", &handle_output);
if (std::get<0>(open_res) != 0) {
std::cerr << std::get<1>(open_res) << std::endl;
return 1;
}

signal(SIGINT, signal_handler);
std::cout << "Started tracing, hit Ctrl-C to terminate." << std::endl;
while (true)
bpf->poll_perf_buffer("events");

return 0;
}
103 changes: 103 additions & 0 deletions examples/cpp/RecordMySQLQuery.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* RecordMySQLQuery Record MySQL queries by probing the alloc_query() function
* in mysqld. For Linux, uses BCC, eBPF. Embedded C.
*
* Basic example of BCC and uprobes.
*
* Copyright (c) Facebook, Inc.
* Licensed under the Apache License, Version 2.0 (the "License")
*/

#include <unistd.h>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <string>

#include "BPF.h"

const std::string BPF_PROGRAM = R"(
#include <linux/ptrace.h>
struct query_probe_t {
uint64_t ts;
pid_t pid;
char query[100];
};
BPF_HASH(queries, struct query_probe_t, int);
int probe_mysql_query(struct pt_regs *ctx, void* thd, char* query, size_t len) {
if (query) {
struct query_probe_t key = {};
key.ts = bpf_ktime_get_ns();
key.pid = bpf_get_current_pid_tgid();
bpf_probe_read(&key.query, sizeof(key.query), query);
int one = 1;
queries.update(&key, &one);
}
return 0;
}
)";
const std::string ALLOC_QUERY_FUNC = "_Z11alloc_queryP3THDPKcj";

// Define the same struct to use in user space.
struct query_probe_t {
uint64_t ts;
pid_t pid;
char query[100];
};

int main(int argc, char** argv) {
if (argc < 2) {
std::cout << "USAGE: RecordMySQLQuery PATH_TO_MYSQLD [duration]"
<< std::endl;
exit(1);
}

std::string mysql_path(argv[1]);
std::cout << "Using mysqld path: " << mysql_path << std::endl;

ebpf::BPF bpf;
auto init_res = bpf.init(BPF_PROGRAM);
if (std::get<0>(init_res) != 0) {
std::cerr << std::get<1>(init_res) << std::endl;
return 1;
}

auto attach_res =
bpf.attach_uprobe(mysql_path, ALLOC_QUERY_FUNC, "probe_mysql_query");
if (std::get<0>(attach_res) != 0) {
std::cerr << std::get<1>(attach_res) << std::endl;
return 1;
}

int probe_time = 10;
if (argc >= 3)
probe_time = atoi(argv[2]);
std::cout << "Probing for " << probe_time << " seconds" << std::endl;
sleep(probe_time);

auto table_handle = bpf.get_hash_table<query_probe_t, int>("queries");
auto table = table_handle.get_table_offline();
std::sort(table.begin(), table.end(), [](std::pair<query_probe_t, int> a,
std::pair<query_probe_t, int> b) {
return a.first.ts < b.first.ts;
});
std::cout << table.size() << " queries recorded:" << std::endl;
for (auto it : table) {
std::cout << "Time: " << it.first.ts << " PID: " << it.first.pid
<< " Query: " << it.first.query << std::endl;
}

auto detach_res = bpf.detach_uprobe(mysql_path, ALLOC_QUERY_FUNC);
if (std::get<0>(detach_res) != 0) {
std::cerr << std::get<1>(detach_res) << std::endl;
return 1;
}

return 0;
}
Loading

0 comments on commit 284dd8e

Please sign in to comment.