Commit 230c9c00 authored by Javier Honduvilla Coto's avatar Javier Honduvilla Coto Committed by yonghong-song

Allow arbitrary hashtable increments. Fixes #1742 (#1897)

* Allow arbitrary hashtable increments. Fixes #1742

Right now incrementing some datastructure's values like maps or histograms can
be done with some boilerplate[1] or with `increment` which increments a value
by 1.

This patch allows a second optional parameter to use as the increment.

- [1]:
```
u64 zero = 0, *val;
val = map.lookup_or_init(&key, &zero);
(*val) += inc;
```

Notes:
- Some lines in the documentation where changed because of trailing spaces
deletion
- The test is quite simple right now
- Will update the tools to use `increment` in another PR

* CR changes
parent bfecc243
......@@ -413,7 +413,7 @@ Return: 0 on success
When used in a program attached to a function entry kprobe, causes the
execution of the function to be skipped, immediately returning `rc` instead.
This is used for targeted error injection.
This is used for targeted error injection.
bpf_override_return will only work when the kprobed function is whitelisted to
allow error injections. Whitelisting entails tagging a function with
......@@ -756,9 +756,9 @@ Examples in situ:
### 17. map.increment()
Syntax: ```map.increment(key)```
Syntax: ```map.increment(key[, increment_amount])```
Increments the key's value by one. Used for histograms.
Increments the key's value by `increment_amount`, which defaults to 1. Used for histograms.
Examples in situ:
[search /examples](https://github.com/iovisor/bcc/search?q=increment+path%3Aexamples&type=Code),
......
......@@ -214,7 +214,7 @@ More [examples](../tools/tcpaccept_example.txt).
#### 1.9. tcpretrans
```
# ./tcpretrans
# ./tcpretrans
TIME PID IP LADDR:LPORT T> RADDR:RPORT STATE
01:55:05 0 4 10.153.223.157:22 R> 69.53.245.40:34619 ESTABLISHED
01:55:05 0 4 10.153.223.157:22 R> 69.53.245.40:34619 ESTABLISHED
......@@ -231,7 +231,7 @@ More [examples](../tools/tcpretrans_example.txt).
#### 1.10. runqlat
```
# ./runqlat
# ./runqlat
Tracing run queue latency... Hit Ctrl-C to end.
^C
usecs : count distribution
......@@ -300,7 +300,7 @@ Sampling at 49 Hertz of all threads by user + kernel stack... Hit Ctrl-C to end.
75
```
profile is a CPU profiler, which takes samples of stack traces at timed intervals, and prints a summary of unique stack traces and a count of their occurrence.
profile is a CPU profiler, which takes samples of stack traces at timed intervals, and prints a summary of unique stack traces and a count of their occurrence.
Use this tool to understand the code paths that are consuming CPU resources.
......
......@@ -13,7 +13,7 @@ This observability tutorial contains 17 lessons, and 46 enumerated things to lea
Start by running [examples/hello_world.py](../examples/hello_world.py), while running some commands (eg, "ls") in another session. It should print "Hello, World!" for new processes. If not, start by fixing bcc: see [INSTALL.md](../INSTALL.md).
```
# ./examples/hello_world.py
# ./examples/hello_world.py
bash-13364 [002] d... 24573433.052937: : Hello, World!
bash-13364 [003] d... 24573436.642808: : Hello, World!
[...]
......@@ -51,7 +51,7 @@ Improve it by printing "Tracing sys_sync()... Ctrl-C to end." when the program f
This program is in [examples/tracing/hello_fields.py](../examples/tracing/trace_fields.py). Sample output (run commands in another session):
```
# ./examples/tracing/hello_fields.py
# ./examples/tracing/hello_fields.py
TIME(s) COMM PID MESSAGE
24585001.174885999 sshd 1432 Hello, World!
24585001.195710000 sshd 15780 Hello, World!
......@@ -175,7 +175,7 @@ Modify the sync_timing.py program (prior lesson) to store the count of all sys_s
Browse the [examples/tracing/disksnoop.py](../examples/tracing/disksnoop.py) program to see what is new. Here is some sample output:
```
# ./disksnoop.py
# ./disksnoop.py
TIME(s) T BYTES LAT(ms)
16458043.436012 W 4096 3.13
16458043.437326 W 4096 4.44
......@@ -237,7 +237,7 @@ This is a pretty interesting program, and if you can understand all the code, yo
Let's finally stop using bpf_trace_printk() and use the proper BPF_PERF_OUTPUT() interface. This will also mean we stop getting the free trace_field() members like PID and timestamp, and will need to fetch them directly. Sample output while commands are run in another session:
```
# ./hello_perf_output.py
# ./hello_perf_output.py
TIME(s) COMM PID MESSAGE
0.000000000 bash 22986 Hello, perf_output!
0.021080275 systemd-udevd 484 Hello, perf_output!
......@@ -388,7 +388,7 @@ A recap from earlier lessons:
New things to learn:
1. ```BPF_HISTOGRAM(dist)```: Defines a BPF map object that is a histogram, and names it "dist".
1. ```dist.increment()```: Increments the histogram bucket index provided as an argument by one.
1. ```dist.increment()```: Increments the histogram bucket index provided as first argument by one by default. Optionally, custom increments can be passed as the second argument.
1. ```bpf_log2l()```: Returns the log-2 of the provided value. This becomes the index of our histogram, so that we're constructing a power-of-2 histogram.
1. ```b["dist"].print_log2_hist("kbytes")```: Prints the "dist" histogram as power-of-2, with a column header of "kbytes". The only data transferred from kernel to user space is the bucket counts, making this efficient.
......@@ -449,7 +449,7 @@ Browse the code in [examples/tracing/vfsreadlat.py](../examples/tracing/vfsreadl
Tracing while a ```dd if=/dev/urandom of=/dev/null bs=8k count=5``` is run:
```
# ./urandomread.py
# ./urandomread.py
TIME(s) COMM PID GOTBITS
24652832.956994001 smtp 24690 384
24652837.726500999 dd 24692 65536
......@@ -518,7 +518,7 @@ Convert disksnoop.py from a previous lesson to use the ```block:block_rq_issue``
This program instruments a user-level function, the ```strlen()``` library function, and frequency counts its string argument. Example output:
```
# ./strlen_count.py
# ./strlen_count.py
Tracing strlen()... Hit Ctrl-C to end.
^C COUNT STRING
1 " "
......
......@@ -49,7 +49,7 @@ struct _name##_table_t { \
int (*insert) (_key_type *, _leaf_type *); \
int (*delete) (_key_type *); \
void (*call) (void *, int index); \
void (*increment) (_key_type); \
void (*increment) (_key_type, ...); \
int (*get_stackid) (void *, u64); \
u32 max_entries; \
int flags; \
......
......@@ -780,14 +780,22 @@ bool BTypeVisitor::VisitCallExpr(CallExpr *Call) {
} else if (memb_name == "increment") {
string name = Ref->getDecl()->getName();
string arg0 = rewriter_.getRewrittenText(expansionRange(Call->getArg(0)->getSourceRange()));
string increment_value = "1";
if (Call->getNumArgs() == 2) {
increment_value = rewriter_.getRewrittenText(expansionRange(Call->getArg(1)->getSourceRange()));
}
string lookup = "bpf_map_lookup_elem_(bpf_pseudo_fd(1, " + fd + ")";
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) (*_leaf)++; ";
txt += "if (_leaf) (*_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++; ";
txt += "_zleaf += " + increment_value + ";";
txt += update + ", &_key, &_zleaf, BPF_NOEXIST); } ";
}
txt += "})";
......
......@@ -1212,5 +1212,18 @@ int test(struct pt_regs *ctx, struct mm_struct *mm) {
b = BPF(text=text)
fn = b.load_func("test", BPF.KPROBE)
def test_arbitrary_increment_simple(self):
b = BPF(text=b"""
#include <uapi/linux/ptrace.h>
struct bpf_map;
BPF_HASH(map);
int map_delete(struct pt_regs *ctx, struct bpf_map *bpfmap, u64 *k) {
map.increment(42, 10);
return 0;
}
""")
b.attach_kprobe(event=b"htab_map_delete_elem", fn_name=b"map_delete")
b.cleanup()
if __name__ == "__main__":
main()
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