From 914a78f6255cb1d0280757f19277f8a14b5ee2e9 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 20 Mar 2018 16:26:46 -0700 Subject: [PATCH] add an example of accessing an externally created map in C++ Some application may need to access a pinned map which is not created by bcc. This example shows how to incorporate such maps with C++ APIs. Basically, the application needs to create a TableStorage and pre-populate it with pinned map before calling BPF constructor. The bpf program defines this pinned map as an "extern" map. Signed-off-by: Yonghong Song --- examples/cpp/CMakeLists.txt | 4 + examples/cpp/UseExternalMap.cc | 134 +++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 examples/cpp/UseExternalMap.cc diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt index 7d6ccee258e9..9d5e5d43e843 100644 --- a/examples/cpp/CMakeLists.txt +++ b/examples/cpp/CMakeLists.txt @@ -27,6 +27,9 @@ target_link_libraries(LLCStat bcc-static) add_executable(FollyRequestContextSwitch FollyRequestContextSwitch.cc) target_link_libraries(FollyRequestContextSwitch bcc-static) +add_executable(UseExternalMap UseExternalMap.cc) +target_link_libraries(UseExternalMap bcc-static) + if(INSTALL_CPP_EXAMPLES) install (TARGETS HelloWorld DESTINATION share/bcc/examples/cpp) install (TARGETS CPUDistribution DESTINATION share/bcc/examples/cpp) @@ -35,4 +38,5 @@ if(INSTALL_CPP_EXAMPLES) install (TARGETS RandomRead DESTINATION share/bcc/examples/cpp) install (TARGETS LLCStat DESTINATION share/bcc/examples/cpp) install (TARGETS FollyRequestContextSwitch DESTINATION share/bcc/examples/cpp) + install (TARGETS UseExternalMap DESTINATION share/bcc/examples/cpp) endif(INSTALL_CPP_EXAMPLES) diff --git a/examples/cpp/UseExternalMap.cc b/examples/cpp/UseExternalMap.cc new file mode 100644 index 000000000000..3d4d759dc3c1 --- /dev/null +++ b/examples/cpp/UseExternalMap.cc @@ -0,0 +1,134 @@ +/* + * UseExternalMap shows how to access an external map through + * C++ interface. The external map could be a pinned map. + * This example simulates the pinned map through a locally + * created map by calling libbpf bpf_create_map. + * + * Copyright (c) Facebook, Inc. + * Licensed under the Apache License, Version 2.0 (the "License") + */ + +#include +#include + +#include "BPF.h" + +// Used by C++ get hash_table +struct sched_switch_info { + int prev_pid; + int next_pid; + char prev_comm[16]; + char next_comm[16]; +}; + +#define CHECK(condition, msg) \ + ({ \ + if (condition) { \ + std::cerr << msg << std::endl; \ + return 1; \ + } \ + }) + +const std::string BPF_PROGRAM = R"( +#include + +struct sched_switch_info { + int prev_pid; + int next_pid; + char prev_comm[16]; + char next_comm[16]; +}; + +BPF_TABLE("extern", u32, u32, control, 1); +BPF_HASH(counts, struct sched_switch_info, u32); +int on_sched_switch(struct tracepoint__sched__sched_switch *args) { + struct sched_switch_info key = {}; + u32 zero = 0, *val; + + /* only do something when control is on */ + val = control.lookup(&zero); + if (!val || *val == 0) + return 0; + + /* record sched_switch info in counts table */ + key.prev_pid = args->prev_pid; + key.next_pid = args->next_pid; + __builtin_memcpy(&key.prev_comm, args->prev_comm, 16); + __builtin_memcpy(&key.next_comm, args->next_comm, 16); + val = counts.lookup_or_init(&key, &zero); + (*val)++; + + return 0; +} +)"; + +static void print_counts(ebpf::BPF *bpfp, std::string msg) { + auto counts_table_hdl = + bpfp->get_hash_table("counts"); + printf("%s\n", msg.c_str()); + printf("%-8s %-16s %-8s %-16s %-4s\n", "PREV_PID", "PREV_COMM", + "CURR_PID", "CURR_COMM", "CNT"); + for (auto it : counts_table_hdl.get_table_offline()) { + printf("%-8d (%-16s) ==> %-8d (%-16s): %-4d\n", it.first.prev_pid, + it.first.prev_comm, it.first.next_pid, it.first.next_comm, + it.second); + } +} + +int main() { + int ctrl_map_fd; + uint32_t val; + + // create a map through bpf_create_map, bcc knows nothing about this map. + ctrl_map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, "control", sizeof(uint32_t), + sizeof(uint32_t), 1, 0); + CHECK(ctrl_map_fd < 0, "bpf_create_map failure"); + + // populate control map into TableStorage + std::unique_ptr local_ts = + ebpf::createSharedTableStorage(); + ebpf::Path global_path({"control"}); + ebpf::TableDesc table_desc("control", ebpf::FileDesc(ctrl_map_fd), + BPF_MAP_TYPE_ARRAY, sizeof(uint32_t), + sizeof(uint32_t), 1, 0); + local_ts->Insert(global_path, std::move(table_desc)); + + // constructor with the pre-populated table storage + ebpf::BPF bpf(0, &*local_ts); + auto res = bpf.init(BPF_PROGRAM); + CHECK(res.code(), res.msg()); + + // attach to the tracepoint sched:sched_switch + res = bpf.attach_tracepoint("sched:sched_switch", "on_sched_switch"); + CHECK(res.code(), res.msg()); + + // wait for some scheduling events + sleep(1); + + auto control_table_hdl = bpf.get_array_table("control"); + res = control_table_hdl.get_value(0, val); + CHECK(res.code() || val != 0, res.msg()); + + // we should not see any events here + print_counts(&bpf, "events with control off:"); + + printf("\n"); + + // change the control to on so bpf program starts to count events + val = 1; + res = control_table_hdl.update_value(0, val); + CHECK(res.code(), res.msg()); + + // verify we get the control on back + val = 0; + res = control_table_hdl.get_value(0, val); + CHECK(res.code() || val != 1, res.msg()); + + // wait for some scheduling events + sleep(1); + + // we should see a bunch of events here + print_counts(&bpf, "events with control on:"); + + return 0; +}