File: UseExternalMap.cc

package info (click to toggle)
bpfcc 0.18.0%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 12,368 kB
  • sloc: ansic: 132,727; python: 36,226; cpp: 26,973; sh: 710; yacc: 525; makefile: 141; lex: 94
file content (136 lines) | stat: -rw-r--r-- 3,957 bytes parent folder | download | duplicates (5)
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
135
136
/*
 * 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 bcc_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_try_init(&key, &zero);
  if (val) {
    (*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 bcc_create_map, bcc knows nothing about this map.
  ctrl_map_fd = bcc_create_map(BPF_MAP_TYPE_ARRAY, "control", sizeof(uint32_t),
                               sizeof(uint32_t), 1, 0);
  CHECK(ctrl_map_fd < 0, "bcc_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;
}