Skip to content

Commit

Permalink
Allow arbitrary hashtable increments. Fixes iovisor#1742 (iovisor#1897)
Browse files Browse the repository at this point in the history
* Allow arbitrary hashtable increments. Fixes iovisor#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
  • Loading branch information
javierhonduco authored and yonghong-song committed Jul 27, 2018
1 parent bfecc24 commit 230c9c0
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 16 deletions.
6 changes: 3 additions & 3 deletions docs/reference_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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),
Expand Down
6 changes: 3 additions & 3 deletions docs/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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.

Expand Down
14 changes: 7 additions & 7 deletions docs/tutorial_bcc_python_developer.md
Original file line number Diff line number Diff line change
Expand Up @@ -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!
[...]
Expand Down Expand Up @@ -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!
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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!
Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 " "
Expand Down
2 changes: 1 addition & 1 deletion src/cc/export/helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; \
Expand Down
12 changes: 10 additions & 2 deletions src/cc/frontends/clang/b_frontend_action.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 += "})";
Expand Down
13 changes: 13 additions & 0 deletions tests/python/test_clang.py
Original file line number Diff line number Diff line change
Expand Up @@ -1212,5 +1212,18 @@ def test_probe_read_array_accesses8(self):
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()

0 comments on commit 230c9c0

Please sign in to comment.