forked from iovisor/bcc
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request iovisor#1644 from iovisor/yhs_dev
add an example of accessing an externally created map in C++
- Loading branch information
Showing
2 changed files
with
138 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <stdint.h> | ||
#include <iostream> | ||
|
||
#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 <linux/sched.h> | ||
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<struct sched_switch_info, uint32_t>("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<ebpf::TableStorage> 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<uint32_t>("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; | ||
} |