libbcc: add atomic_increment()
diff --git a/docs/reference_guide.md b/docs/reference_guide.md
index aa7db55..0c7ccfe 100644
--- a/docs/reference_guide.md
+++ b/docs/reference_guide.md
@@ -1305,6 +1305,10 @@
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)
diff --git a/src/cc/export/helpers.h b/src/cc/export/helpers.h
index 0be3572..12072b0 100644
--- a/src/cc/export/helpers.h
+++ b/src/cc/export/helpers.h
@@ -101,6 +101,7 @@
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; \
diff --git a/src/cc/frontends/clang/b_frontend_action.cc b/src/cc/frontends/clang/b_frontend_action.cc
index e78ceb3..27b1936 100644
--- a/src/cc/frontends/clang/b_frontend_action.cc
+++ b/src/cc/frontends/clang/b_frontend_action.cc
@@ -899,7 +899,7 @@
}
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 @@
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 + ";";
diff --git a/tests/python/test_clang.py b/tests/python/test_clang.py
index b1fb7e9..b62e905 100755
--- a/tests/python/test_clang.py
+++ b/tests/python/test_clang.py
@@ -1254,7 +1254,8 @@
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;
}
""")
diff --git a/tests/python/test_histogram.py b/tests/python/test_histogram.py
index ec7950c..cb878c6 100755
--- a/tests/python/test_histogram.py
+++ b/tests/python/test_histogram.py
@@ -17,6 +17,7 @@
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(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 @@
#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;
}
""")
diff --git a/tests/python/test_perf_event.py b/tests/python/test_perf_event.py
index 3f78f5b..882e71a 100755
--- a/tests/python/test_perf_event.py
+++ b/tests/python/test_perf_event.py
@@ -33,8 +33,10 @@
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;
}
"""