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 ...@@ -413,7 +413,7 @@ Return: 0 on success
When used in a program attached to a function entry kprobe, causes the When used in a program attached to a function entry kprobe, causes the
execution of the function to be skipped, immediately returning `rc` instead. 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 bpf_override_return will only work when the kprobed function is whitelisted to
allow error injections. Whitelisting entails tagging a function with allow error injections. Whitelisting entails tagging a function with
...@@ -756,9 +756,9 @@ Examples in situ: ...@@ -756,9 +756,9 @@ Examples in situ:
### 17. map.increment() ### 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: Examples in situ:
[search /examples](https://github.com/iovisor/bcc/search?q=increment+path%3Aexamples&type=Code), [search /examples](https://github.com/iovisor/bcc/search?q=increment+path%3Aexamples&type=Code),
......
...@@ -214,7 +214,7 @@ More [examples](../tools/tcpaccept_example.txt). ...@@ -214,7 +214,7 @@ More [examples](../tools/tcpaccept_example.txt).
#### 1.9. tcpretrans #### 1.9. tcpretrans
``` ```
# ./tcpretrans # ./tcpretrans
TIME PID IP LADDR:LPORT T> RADDR:RPORT STATE 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
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). ...@@ -231,7 +231,7 @@ More [examples](../tools/tcpretrans_example.txt).
#### 1.10. runqlat #### 1.10. runqlat
``` ```
# ./runqlat # ./runqlat
Tracing run queue latency... Hit Ctrl-C to end. Tracing run queue latency... Hit Ctrl-C to end.
^C ^C
usecs : count distribution usecs : count distribution
...@@ -300,7 +300,7 @@ Sampling at 49 Hertz of all threads by user + kernel stack... Hit Ctrl-C to end. ...@@ -300,7 +300,7 @@ Sampling at 49 Hertz of all threads by user + kernel stack... Hit Ctrl-C to end.
75 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. 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 ...@@ -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). 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 [002] d... 24573433.052937: : Hello, World!
bash-13364 [003] d... 24573436.642808: : 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 ...@@ -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): 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 TIME(s) COMM PID MESSAGE
24585001.174885999 sshd 1432 Hello, World! 24585001.174885999 sshd 1432 Hello, World!
24585001.195710000 sshd 15780 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 ...@@ -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: 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) TIME(s) T BYTES LAT(ms)
16458043.436012 W 4096 3.13 16458043.436012 W 4096 3.13
16458043.437326 W 4096 4.44 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 ...@@ -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: 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 TIME(s) COMM PID MESSAGE
0.000000000 bash 22986 Hello, perf_output! 0.000000000 bash 22986 Hello, perf_output!
0.021080275 systemd-udevd 484 Hello, perf_output! 0.021080275 systemd-udevd 484 Hello, perf_output!
...@@ -388,7 +388,7 @@ A recap from earlier lessons: ...@@ -388,7 +388,7 @@ A recap from earlier lessons:
New things to learn: New things to learn:
1. ```BPF_HISTOGRAM(dist)```: Defines a BPF map object that is a histogram, and names it "dist". 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. ```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. 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 ...@@ -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: 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 TIME(s) COMM PID GOTBITS
24652832.956994001 smtp 24690 384 24652832.956994001 smtp 24690 384
24652837.726500999 dd 24692 65536 24652837.726500999 dd 24692 65536
...@@ -518,7 +518,7 @@ Convert disksnoop.py from a previous lesson to use the ```block:block_rq_issue`` ...@@ -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: 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. Tracing strlen()... Hit Ctrl-C to end.
^C COUNT STRING ^C COUNT STRING
1 " " 1 " "
......
...@@ -49,7 +49,7 @@ struct _name##_table_t { \ ...@@ -49,7 +49,7 @@ struct _name##_table_t { \
int (*insert) (_key_type *, _leaf_type *); \ int (*insert) (_key_type *, _leaf_type *); \
int (*delete) (_key_type *); \ int (*delete) (_key_type *); \
void (*call) (void *, int index); \ void (*call) (void *, int index); \
void (*increment) (_key_type); \ void (*increment) (_key_type, ...); \
int (*get_stackid) (void *, u64); \ int (*get_stackid) (void *, u64); \
u32 max_entries; \ u32 max_entries; \
int flags; \ int flags; \
......
...@@ -780,14 +780,22 @@ bool BTypeVisitor::VisitCallExpr(CallExpr *Call) { ...@@ -780,14 +780,22 @@ bool BTypeVisitor::VisitCallExpr(CallExpr *Call) {
} else if (memb_name == "increment") { } else if (memb_name == "increment") {
string name = Ref->getDecl()->getName(); string name = Ref->getDecl()->getName();
string arg0 = rewriter_.getRewrittenText(expansionRange(Call->getArg(0)->getSourceRange())); 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 lookup = "bpf_map_lookup_elem_(bpf_pseudo_fd(1, " + fd + ")";
string update = "bpf_map_update_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 + ".key) _key = " + arg0 + "; ";
txt += "typeof(" + name + ".leaf) *_leaf = " + lookup + ", &_key); "; 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) { if (desc->second.type == BPF_MAP_TYPE_HASH) {
txt += "else { typeof(" + name + ".leaf) _zleaf; __builtin_memset(&_zleaf, 0, sizeof(_zleaf)); "; 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 += update + ", &_key, &_zleaf, BPF_NOEXIST); } ";
} }
txt += "})"; txt += "})";
......
...@@ -1212,5 +1212,18 @@ int test(struct pt_regs *ctx, struct mm_struct *mm) { ...@@ -1212,5 +1212,18 @@ int test(struct pt_regs *ctx, struct mm_struct *mm) {
b = BPF(text=text) b = BPF(text=text)
fn = b.load_func("test", BPF.KPROBE) 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__": if __name__ == "__main__":
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