libbcc: add atomic_increment()
authorchenyuezhou <zcy.chenyue.zhou@gmail.com>
Fri, 18 Jun 2021 20:31:52 +0000 (16:31 -0400)
committeryonghong-song <ys114321@gmail.com>
Fri, 18 Jun 2021 16:33:11 +0000 (09:33 -0700)
docs/reference_guide.md
src/cc/export/helpers.h
src/cc/frontends/clang/b_frontend_action.cc
tests/python/test_clang.py
tests/python/test_histogram.py
tests/python/test_perf_event.py

index aa7db55e3a66e845a9339aabbbad92d129cff804..0c7ccfebf3440895fba2ad1e4ce4a7488d5b98cd 100644 (file)
@@ -1305,6 +1305,10 @@ Syntax: ```map.increment(key[, increment_amount])```
 
 Increments the key's value by `increment_amount`, which defaults to 1. Used for histograms.
 
+```map.increment()``` are not atomic. In the concurrency case. If you want more accurate results, use ```map.atomic_increment()``` instead of ```map.increment()```. The overhead of ```map.increment()``` and ```map.atomic_increment()``` is similar.
+
+Note. When using ```map.atomic_increment()``` to operate on a BPF map of type ```BPF_MAP_TYPE_HASH```, ```map.atomic_increment()``` does not guarantee the atomicity of the operation when the specified key does not exist.
+
 Examples in situ:
 [search /examples](https://github.com/iovisor/bcc/search?q=increment+path%3Aexamples&type=Code),
 [search /tools](https://github.com/iovisor/bcc/search?q=increment+path%3Atools&type=Code)
index 0be3572b1473d6d1a5f69f86fcdb6c779729771f..12072b06a975a8debe9a9b563e0192691055c477 100644 (file)
@@ -101,6 +101,7 @@ struct _name##_table_t { \
   int (*delete) (_key_type *); \
   void (*call) (void *, int index); \
   void (*increment) (_key_type, ...); \
+  void (*atomic_increment) (_key_type, ...); \
   int (*get_stackid) (void *, u64); \
   u32 max_entries; \
   int flags; \
index e78ceb3ced645da2d78c938edb528610e6ba4a0d..27b193609023f34b6b9389c7fd16eb02e56d0d9a 100644 (file)
@@ -899,7 +899,7 @@ bool BTypeVisitor::VisitCallExpr(CallExpr *Call) {
           }
           txt += "}";
           txt += "leaf;})";
-        } else if (memb_name == "increment") {
+        } else if (memb_name == "increment" || memb_name == "atomic_increment") {
           string name = string(Ref->getDecl()->getName());
           string arg0 = rewriter_.getRewrittenText(expansionRange(Call->getArg(0)->getSourceRange()));
 
@@ -913,8 +913,13 @@ bool BTypeVisitor::VisitCallExpr(CallExpr *Call) {
           string update = "bpf_map_update_elem_(bpf_pseudo_fd(1, " + fd + ")";
           txt  = "({ typeof(" + name + ".key) _key = " + arg0 + "; ";
           txt += "typeof(" + name + ".leaf) *_leaf = " + lookup + ", &_key); ";
+          txt += "if (_leaf) ";
 
-          txt += "if (_leaf) (*_leaf) += " + increment_value + ";";
+          if (memb_name == "atomic_increment") {
+            txt += "lock_xadd(_leaf, " + increment_value + ");";
+          } else {
+            txt += "(*_leaf) += " + increment_value + ";";
+          }
           if (desc->second.type == BPF_MAP_TYPE_HASH) {
             txt += "else { typeof(" + name + ".leaf) _zleaf; __builtin_memset(&_zleaf, 0, sizeof(_zleaf)); ";
             txt += "_zleaf += " + increment_value + ";";
index b1fb7e96082145f60fa9715115084d811e82b1c8..b62e905ac0bc527b817573aa42e53987f9fa83f6 100755 (executable)
@@ -1254,7 +1254,8 @@ int test(struct pt_regs *ctx, struct mm_struct *mm) {
 struct bpf_map;
 BPF_HASH(map);
 int map_delete(struct pt_regs *ctx, struct bpf_map *bpfmap, u64 *k) {
-    map.increment(42, 10);
+    map.increment(42, 5);
+    map.atomic_increment(42, 5);
     return 0;
 }
 """)
index ec7950c9d5a7b894da4dd716f57845e10509805b..cb878c6de883b44a1a61b3c3c7409dba285223c0 100755 (executable)
@@ -17,6 +17,7 @@ BPF_HISTOGRAM(hist1);
 BPF_HASH(stub);
 int kprobe__htab_map_delete_elem(struct pt_regs *ctx, struct bpf_map *map, u64 *k) {
     hist1.increment(bpf_log2l(*k));
+    hist1.atomic_increment(bpf_log2l(*k));
     return 0;
 }
 """)
@@ -43,6 +44,7 @@ BPF_HASH(stub1);
 BPF_HASH(stub2);
 int kprobe__htab_map_delete_elem(struct pt_regs *ctx, struct bpf_map *map, u64 *k) {
     hist1.increment((Key){map, bpf_log2l(*k)});
+    hist1.atomic_increment((Key){map, bpf_log2l(*k)});
     return 0;
 }
 """)
@@ -68,8 +70,10 @@ int kprobe__finish_task_switch(struct pt_regs *ctx, struct task_struct *prev) {
 #else
     Key k = {.slot = bpf_log2l(prev->start_boottime)};
 #endif
-    if (!bpf_get_current_comm(&k.name, sizeof(k.name)))
+    if (!bpf_get_current_comm(&k.name, sizeof(k.name))) {
         hist1.increment(k);
+        hist1.atomic_increment(k);
+    }
     return 0;
 }
 """)
index 3f78f5b38d919ba42ffb659c0181590c822162fe..882e71a1e437f0b00e20038ab306e26ab2d4c858 100755 (executable)
@@ -33,8 +33,10 @@ int do_ret_sys_getuid(void *ctx) {
         return 0;
 
     u64 *prevp = prev.lookup(&cpu);
-    if (prevp)
+    if (prevp) {
         dist.increment(bpf_log2l(val - *prevp));
+        dist.atomic_increment(bpf_log2l(val - *prevp));
+    }
     return 0;
 }
 """