Commit db7b8eb0 authored by Yonghong Song's avatar Yonghong Song

add a BPFModule API to disable rw_engine sscanf/snprintf functions

Currently, for every table of a module, corresponding
key/value sscanf/snprintf functions will be generated.
These functions are mostly used for python API to
facilitate passing keys between python and C++.

It is a known issue that these sscanf/snprintf functions
can consume a lot of system resources esp. memory for
large arrays. Commit 22eae8c6 ("Use late-binding to
finalize snprintf/sscanf") avoids unnecessary code
generation for snprintf/sscanf until they are called.
Even with this commit, however, the overhead can still
be significant for large arrays.

For example, the following large array,
  #define TCP6_RXMIT_BUCKET_BITS 18
  struct tcp6_rxmit_tbl {
    __u64 buckets[1 << TCP6_RXMIT_BUCKET_BITS];
  };
  BPF_ARRAY(rxmit_marking_map, struct tcp6_rxmit_tbl, 1);
is used inside Facebook.
If it is added to examples/cpp/HelloWorld.cpp,
the HelloWorld RSS memory will increase from 7MB to
370MB.

This patch add a BPFModule API and a C++ API to
disable rw_engine sscanf/snprintf function through additional
constructor parameters. rw_engine support for Python is not affected.
Signed-off-by: default avatarYonghong Song <yhs@fb.com>
parent 40fd6692
...@@ -45,8 +45,9 @@ class BPF { ...@@ -45,8 +45,9 @@ class BPF {
public: public:
static const int BPF_MAX_STACK_DEPTH = 127; static const int BPF_MAX_STACK_DEPTH = 127;
explicit BPF(unsigned int flag = 0, TableStorage* ts = nullptr) explicit BPF(unsigned int flag = 0, TableStorage* ts = nullptr,
: flag_(flag), bpf_module_(new BPFModule(flag, ts)) {} bool rw_engine_enabled = true)
: flag_(flag), bpf_module_(new BPFModule(flag, ts, rw_engine_enabled)) {}
StatusTuple init(const std::string& bpf_program, StatusTuple init(const std::string& bpf_program,
const std::vector<std::string>& cflags = {}, const std::vector<std::string>& cflags = {},
const std::vector<USDT>& usdt = {}); const std::vector<USDT>& usdt = {});
......
...@@ -99,8 +99,9 @@ class MyMemoryManager : public SectionMemoryManager { ...@@ -99,8 +99,9 @@ class MyMemoryManager : public SectionMemoryManager {
map<string, tuple<uint8_t *, uintptr_t>> *sections_; map<string, tuple<uint8_t *, uintptr_t>> *sections_;
}; };
BPFModule::BPFModule(unsigned flags, TableStorage *ts) BPFModule::BPFModule(unsigned flags, TableStorage *ts, bool rw_engine_enabled)
: flags_(flags), : flags_(flags),
rw_engine_enabled_(rw_engine_enabled),
used_b_loader_(false), used_b_loader_(false),
ctx_(new LLVMContext), ctx_(new LLVMContext),
id_(std::to_string((uintptr_t)this)), id_(std::to_string((uintptr_t)this)),
...@@ -530,6 +531,8 @@ int BPFModule::annotate() { ...@@ -530,6 +531,8 @@ int BPFModule::annotate() {
} }
StatusTuple BPFModule::sscanf(string fn_name, const char *str, void *val) { StatusTuple BPFModule::sscanf(string fn_name, const char *str, void *val) {
if (!rw_engine_enabled_)
return StatusTuple(-1, "rw_engine not enabled");
auto fn = auto fn =
(int (*)(const char *, void *))rw_engine_->getFunctionAddress(fn_name); (int (*)(const char *, void *))rw_engine_->getFunctionAddress(fn_name);
if (!fn) if (!fn)
...@@ -542,6 +545,8 @@ StatusTuple BPFModule::sscanf(string fn_name, const char *str, void *val) { ...@@ -542,6 +545,8 @@ StatusTuple BPFModule::sscanf(string fn_name, const char *str, void *val) {
StatusTuple BPFModule::snprintf(string fn_name, char *str, size_t sz, StatusTuple BPFModule::snprintf(string fn_name, char *str, size_t sz,
const void *val) { const void *val) {
if (!rw_engine_enabled_)
return StatusTuple(-1, "rw_engine not enabled");
auto fn = (int (*)(char *, size_t, auto fn = (int (*)(char *, size_t,
const void *))rw_engine_->getFunctionAddress(fn_name); const void *))rw_engine_->getFunctionAddress(fn_name);
if (!fn) if (!fn)
...@@ -937,8 +942,10 @@ int BPFModule::load_b(const string &filename, const string &proto_filename) { ...@@ -937,8 +942,10 @@ int BPFModule::load_b(const string &filename, const string &proto_filename) {
used_b_loader_ = true; used_b_loader_ = true;
if (int rc = b_loader.parse(&*mod_, filename, proto_filename, *ts_, id_)) if (int rc = b_loader.parse(&*mod_, filename, proto_filename, *ts_, id_))
return rc; return rc;
if (int rc = annotate()) if (rw_engine_enabled_) {
return rc; if (int rc = annotate())
return rc;
}
if (int rc = finalize()) if (int rc = finalize())
return rc; return rc;
return 0; return 0;
...@@ -956,8 +963,10 @@ int BPFModule::load_c(const string &filename, const char *cflags[], int ncflags) ...@@ -956,8 +963,10 @@ int BPFModule::load_c(const string &filename, const char *cflags[], int ncflags)
} }
if (int rc = load_cfile(filename, false, cflags, ncflags)) if (int rc = load_cfile(filename, false, cflags, ncflags))
return rc; return rc;
if (int rc = annotate()) if (rw_engine_enabled_) {
return rc; if (int rc = annotate())
return rc;
}
if (int rc = finalize()) if (int rc = finalize())
return rc; return rc;
return 0; return 0;
...@@ -971,8 +980,10 @@ int BPFModule::load_string(const string &text, const char *cflags[], int ncflags ...@@ -971,8 +980,10 @@ int BPFModule::load_string(const string &text, const char *cflags[], int ncflags
} }
if (int rc = load_cfile(text, true, cflags, ncflags)) if (int rc = load_cfile(text, true, cflags, ncflags))
return rc; return rc;
if (int rc = annotate()) if (rw_engine_enabled_) {
return rc; if (int rc = annotate())
return rc;
}
if (int rc = finalize()) if (int rc = finalize())
return rc; return rc;
......
...@@ -75,7 +75,7 @@ class BPFModule { ...@@ -75,7 +75,7 @@ class BPFModule {
const void *val); const void *val);
public: public:
BPFModule(unsigned flags, TableStorage *ts = nullptr); BPFModule(unsigned flags, TableStorage *ts = nullptr, bool rw_engine_enabled = true);
~BPFModule(); ~BPFModule();
int load_b(const std::string &filename, const std::string &proto_filename); int load_b(const std::string &filename, const std::string &proto_filename);
int load_c(const std::string &filename, const char *cflags[], int ncflags); int load_c(const std::string &filename, const char *cflags[], int ncflags);
...@@ -120,6 +120,7 @@ class BPFModule { ...@@ -120,6 +120,7 @@ class BPFModule {
private: private:
unsigned flags_; // 0x1 for printing unsigned flags_; // 0x1 for printing
bool rw_engine_enabled_;
bool used_b_loader_; bool used_b_loader_;
std::string filename_; std::string filename_;
std::string proto_filename_; std::string proto_filename_;
......
...@@ -27,7 +27,8 @@ TEST_CASE("test array table", "[array_table]") { ...@@ -27,7 +27,8 @@ TEST_CASE("test array table", "[array_table]") {
BPF_TABLE("array", int, int, myarray, 128); BPF_TABLE("array", int, int, myarray, 128);
)"; )";
ebpf::BPF bpf; // turn off the rw_engine
ebpf::BPF bpf(0, nullptr, false);
ebpf::StatusTuple res(0); ebpf::StatusTuple res(0);
res = bpf.init(BPF_PROGRAM); res = bpf.init(BPF_PROGRAM);
REQUIRE(res.code() == 0); REQUIRE(res.code() == 0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment