xref: /aosp_15_r20/external/bcc/examples/cpp/UseExternalMap.cc (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1 /*
2  * UseExternalMap shows how to access an external map through
3  * C++ interface. The external map could be a pinned map.
4  * This example simulates the pinned map through a locally
5  * created map by calling libbpf bcc_create_map.
6  *
7  * Copyright (c) Facebook, Inc.
8  * Licensed under the Apache License, Version 2.0 (the "License")
9  */
10 
11 #include <stdint.h>
12 #include <iostream>
13 
14 #include "BPF.h"
15 
16 // Used by C++ get hash_table
17 struct sched_switch_info {
18   int prev_pid;
19   int next_pid;
20   char prev_comm[16];
21   char next_comm[16];
22 };
23 
24 #define CHECK(condition, msg)        \
25   ({                                 \
26     if (condition) {                 \
27       std::cerr << msg << std::endl; \
28       return 1;                      \
29     }                                \
30   })
31 
32 const std::string BPF_PROGRAM = R"(
33 #include <linux/sched.h>
34 
35 struct sched_switch_info {
36   int prev_pid;
37   int next_pid;
38   char prev_comm[16];
39   char next_comm[16];
40 };
41 
42 BPF_TABLE("extern", u32, u32, control, 1);
43 BPF_HASH(counts, struct sched_switch_info, u32);
44 int on_sched_switch(struct tracepoint__sched__sched_switch *args) {
45   struct sched_switch_info key = {};
46   u32 zero = 0, *val;
47 
48   /* only do something when control is on */
49   val = control.lookup(&zero);
50   if (!val || *val == 0)
51     return 0;
52 
53   /* record sched_switch info in counts table */
54   key.prev_pid = args->prev_pid;
55   key.next_pid = args->next_pid;
56   __builtin_memcpy(&key.prev_comm, args->prev_comm, 16);
57   __builtin_memcpy(&key.next_comm, args->next_comm, 16);
58   val = counts.lookup_or_try_init(&key, &zero);
59   if (val) {
60     (*val)++;
61   }
62 
63   return 0;
64 }
65 )";
66 
print_counts(ebpf::BPF * bpfp,std::string msg)67 static void print_counts(ebpf::BPF *bpfp, std::string msg) {
68   auto counts_table_hdl =
69       bpfp->get_hash_table<struct sched_switch_info, uint32_t>("counts");
70   printf("%s\n", msg.c_str());
71   printf("%-8s  %-16s      %-8s  %-16s   %-4s\n", "PREV_PID", "PREV_COMM",
72          "CURR_PID", "CURR_COMM", "CNT");
73   for (auto it : counts_table_hdl.get_table_offline()) {
74     printf("%-8d (%-16s) ==> %-8d (%-16s): %-4d\n", it.first.prev_pid,
75            it.first.prev_comm, it.first.next_pid, it.first.next_comm,
76            it.second);
77   }
78 }
79 
main()80 int main() {
81   int ctrl_map_fd;
82   uint32_t val;
83 
84   // create a map through bcc_create_map, bcc knows nothing about this map.
85   ctrl_map_fd = bcc_create_map(BPF_MAP_TYPE_ARRAY, "control", sizeof(uint32_t),
86                                sizeof(uint32_t), 1, 0);
87   CHECK(ctrl_map_fd < 0, "bcc_create_map failure");
88 
89   // populate control map into TableStorage
90   std::unique_ptr<ebpf::TableStorage> local_ts =
91       ebpf::createSharedTableStorage();
92   ebpf::Path global_path({"control"});
93   ebpf::TableDesc table_desc("control", ebpf::FileDesc(ctrl_map_fd),
94                              BPF_MAP_TYPE_ARRAY, sizeof(uint32_t),
95                              sizeof(uint32_t), 1, 0);
96   local_ts->Insert(global_path, std::move(table_desc));
97 
98   // constructor with the pre-populated table storage
99   ebpf::BPF bpf(0, &*local_ts);
100   auto res = bpf.init(BPF_PROGRAM);
101   CHECK(res.code(), res.msg());
102 
103   // attach to the tracepoint sched:sched_switch
104   res = bpf.attach_tracepoint("sched:sched_switch", "on_sched_switch");
105   CHECK(res.code(), res.msg());
106 
107   // wait for some scheduling events
108   sleep(1);
109 
110   auto control_table_hdl = bpf.get_array_table<uint32_t>("control");
111   res = control_table_hdl.get_value(0, val);
112   CHECK(res.code() || val != 0, res.msg());
113 
114   // we should not see any events here
115   print_counts(&bpf, "events with control off:");
116 
117   printf("\n");
118 
119   // change the control to on so bpf program starts to count events
120   val = 1;
121   res = control_table_hdl.update_value(0, val);
122   CHECK(res.code(), res.msg());
123 
124   // verify we get the control on back
125   val = 0;
126   res = control_table_hdl.get_value(0, val);
127   CHECK(res.code() || val != 1, res.msg());
128 
129   // wait for some scheduling events
130   sleep(1);
131 
132   // we should see a bunch of events here
133   print_counts(&bpf, "events with control on:");
134 
135   return 0;
136 }
137