-
Notifications
You must be signed in to change notification settings - Fork 3.8k
/
UseExternalMap.cc
134 lines (109 loc) · 3.84 KB
/
UseExternalMap.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
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;
}