rbbcc 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/README.md +4 -0
- data/docs/README.md +2 -0
- data/docs/answers/01-hello-world.rb +16 -0
- data/docs/answers/02-sys_sync.rb +18 -0
- data/docs/answers/03-hello_fields.rb +33 -0
- data/docs/answers/04-sync_timing.rb +46 -0
- data/docs/answers/05-sync_count.rb +54 -0
- data/docs/answers/06-disksnoop.rb +71 -0
- data/docs/answers/07-hello_perf_output.rb +59 -0
- data/docs/answers/08-sync_perf_output.rb +60 -0
- data/docs/answers/09-bitehist.rb +32 -0
- data/docs/answers/10-disklatency.rb +51 -0
- data/docs/answers/11-vfsreadlat.c +46 -0
- data/docs/answers/11-vfsreadlat.rb +66 -0
- data/docs/answers/12-urandomread.rb +38 -0
- data/docs/answers/13-disksnoop_fixed.rb +108 -0
- data/docs/answers/14-strlen_count.rb +46 -0
- data/docs/answers/15-nodejs_http_server.rb +44 -0
- data/docs/answers/16-task_switch.c +23 -0
- data/docs/answers/16-task_switch.rb +17 -0
- data/docs/answers/node-server.js +11 -0
- data/docs/projects_using_rbbcc.md +43 -0
- data/docs/tutorial_bcc_ruby_developer.md +772 -0
- data/lib/rbbcc/bcc.rb +41 -13
- data/lib/rbbcc/clib.rb +1 -0
- data/lib/rbbcc/table.rb +16 -22
- data/lib/rbbcc/version.rb +1 -1
- data/rbbcc.gemspec +1 -1
- metadata +25 -4
@@ -0,0 +1,108 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# disksnoop_fixed.rb Trace block device I/O: basic version of iosnoop.
|
4
|
+
# For Linux, uses BCC, eBPF. Embedded C.
|
5
|
+
# This is ported from original disksnoop.py
|
6
|
+
#
|
7
|
+
# Written as a basic example of tracing latency.
|
8
|
+
#
|
9
|
+
# Licensed under the Apache License, Version 2.0 (the "License")
|
10
|
+
#
|
11
|
+
# 11-Aug-2015 Brendan Gregg Created disksnoop.py
|
12
|
+
|
13
|
+
=begin
|
14
|
+
name: block_rq_issue
|
15
|
+
ID: 1093
|
16
|
+
format:
|
17
|
+
field:unsigned short common_type; offset:0; size:2; signed:0;
|
18
|
+
field:unsigned char common_flags; offset:2; size:1; signed:0;
|
19
|
+
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
|
20
|
+
field:int common_pid; offset:4; size:4; signed:1;
|
21
|
+
|
22
|
+
field:dev_t dev; offset:8; size:4; signed:0;
|
23
|
+
field:sector_t sector; offset:16; size:8; signed:0;
|
24
|
+
field:unsigned int nr_sector; offset:24; size:4; signed:0;
|
25
|
+
field:unsigned int bytes; offset:28; size:4; signed:0;
|
26
|
+
field:char rwbs[8]; offset:32; size:8; signed:1;
|
27
|
+
field:char comm[16]; offset:40; size:16; signed:1;
|
28
|
+
field:__data_loc char[] cmd; offset:56; size:4; signed:1;
|
29
|
+
|
30
|
+
print fmt: "%d,%d %s %u (%s) %llu + %u [%s]", ((unsigned int) ((REC->dev) >> 20)), ((unsigned int) ((REC->dev) & ((1U << 20) - 1))), REC->rwbs, REC->bytes, __get_str(cmd), (unsigned long long)REC->sector, REC->nr_sector, REC->comm
|
31
|
+
|
32
|
+
name: block_rq_complete
|
33
|
+
ID: 1095
|
34
|
+
format:
|
35
|
+
field:unsigned short common_type; offset:0; size:2; signed:0;
|
36
|
+
field:unsigned char common_flags; offset:2; size:1; signed:0;
|
37
|
+
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
|
38
|
+
field:int common_pid; offset:4; size:4; signed:1;
|
39
|
+
|
40
|
+
field:dev_t dev; offset:8; size:4; signed:0;
|
41
|
+
field:sector_t sector; offset:16; size:8; signed:0;
|
42
|
+
field:unsigned int nr_sector; offset:24; size:4; signed:0;
|
43
|
+
field:int error; offset:28; size:4; signed:1;
|
44
|
+
field:char rwbs[8]; offset:32; size:8; signed:1;
|
45
|
+
field:__data_loc char[] cmd; offset:40; size:4; signed:1;
|
46
|
+
|
47
|
+
print fmt: "%d,%d %s (%s) %llu + %u [%d]", ((unsigned int) ((REC->dev) >> 20)), ((unsigned int) ((REC->dev) & ((1U << 20) - 1))), REC->rwbs, __get_str(cmd), (unsigned long long)REC->sector, REC->nr_sector, REC->error
|
48
|
+
|
49
|
+
in kernel 5.0.
|
50
|
+
This implementation shows the count of sector.
|
51
|
+
=end
|
52
|
+
|
53
|
+
require 'rbbcc'
|
54
|
+
include RbBCC
|
55
|
+
|
56
|
+
# load BPF program
|
57
|
+
b = BCC.new(text: <<CLANG)
|
58
|
+
#include <uapi/linux/ptrace.h>
|
59
|
+
#include <linux/blkdev.h>
|
60
|
+
|
61
|
+
BPF_HASH(start, u32);
|
62
|
+
|
63
|
+
TRACEPOINT_PROBE(block, block_rq_issue) {
|
64
|
+
// stash start timestamp by request ptr
|
65
|
+
u64 ts = bpf_ktime_get_ns();
|
66
|
+
u32 tid = bpf_get_current_pid_tgid();
|
67
|
+
|
68
|
+
start.update(&tid, &ts);
|
69
|
+
return 0;
|
70
|
+
}
|
71
|
+
|
72
|
+
TRACEPOINT_PROBE(block, block_rq_complete) {
|
73
|
+
u64 *tsp, delta;
|
74
|
+
u32 tid = bpf_get_current_pid_tgid();
|
75
|
+
|
76
|
+
tsp = start.lookup(&tid);
|
77
|
+
if (tsp != 0) {
|
78
|
+
char dst[8];
|
79
|
+
int i;
|
80
|
+
delta = bpf_ktime_get_ns() - *tsp;
|
81
|
+
if (bpf_probe_read_str(dst, sizeof(dst), args->rwbs) < 0) {
|
82
|
+
dst[0] = '?';
|
83
|
+
for(i = 1; i < sizeof(dst); ++i)
|
84
|
+
dst[i] = 0;
|
85
|
+
}
|
86
|
+
bpf_trace_printk("%d %s %d\\n", args->nr_sector,
|
87
|
+
dst, delta / 1000);
|
88
|
+
start.delete(&tid);
|
89
|
+
}
|
90
|
+
return 0;
|
91
|
+
}
|
92
|
+
CLANG
|
93
|
+
|
94
|
+
# header
|
95
|
+
puts("%-18s %-8s %-7s %8s" % ["TIME(s)", "RWBS", "SECTORS", "LAT(ms)"])
|
96
|
+
|
97
|
+
# format output
|
98
|
+
loop do
|
99
|
+
begin
|
100
|
+
task, pid, cpu, flags, ts, msg = b.trace_fields
|
101
|
+
sector_s, rwbs, us_s = msg.split
|
102
|
+
ms = us_s.to_i.to_f / 1000
|
103
|
+
|
104
|
+
puts("%-18.9f %-8s %-7s %8.2f" % [ts, rwbs, sector_s, ms])
|
105
|
+
rescue Interrupt
|
106
|
+
exit
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rbbcc'
|
2
|
+
include RbBCC
|
3
|
+
|
4
|
+
# load BPF program
|
5
|
+
b = BCC.new(text: <<BPF)
|
6
|
+
#include <uapi/linux/ptrace.h>
|
7
|
+
|
8
|
+
struct key_t {
|
9
|
+
char c[80];
|
10
|
+
};
|
11
|
+
BPF_HASH(counts, struct key_t);
|
12
|
+
|
13
|
+
int count(struct pt_regs *ctx) {
|
14
|
+
if (!PT_REGS_PARM1(ctx))
|
15
|
+
return 0;
|
16
|
+
|
17
|
+
struct key_t key = {};
|
18
|
+
u64 zero = 0, *val;
|
19
|
+
|
20
|
+
bpf_probe_read(&key.c, sizeof(key.c), (void *)PT_REGS_PARM1(ctx));
|
21
|
+
// could also use `counts.increment(key)`
|
22
|
+
val = counts.lookup_or_try_init(&key, &zero);
|
23
|
+
if (val) {
|
24
|
+
(*val)++;
|
25
|
+
}
|
26
|
+
return 0;
|
27
|
+
};
|
28
|
+
BPF
|
29
|
+
b.attach_uprobe(name: "c", sym: "strlen", fn_name: "count")
|
30
|
+
|
31
|
+
# header
|
32
|
+
print("Tracing strlen()... Hit Ctrl-C to end.")
|
33
|
+
|
34
|
+
# sleep until Ctrl-C
|
35
|
+
begin
|
36
|
+
sleep(99999999)
|
37
|
+
rescue Interrupt
|
38
|
+
puts
|
39
|
+
end
|
40
|
+
|
41
|
+
# print output
|
42
|
+
puts("%10s %s" % ["COUNT", "STRING"])
|
43
|
+
counts = b.get_table("counts")
|
44
|
+
counts.items.sort_by{|k, v| v.to_bcc_value }.each do |k, v|
|
45
|
+
puts("%10d %s" % [v.to_bcc_value, k[0, k.size].unpack("Z*")[0]])
|
46
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rbbcc'
|
2
|
+
include RbBCC
|
3
|
+
|
4
|
+
if ARGV.size != 1
|
5
|
+
print("USAGE: #{$0} PID")
|
6
|
+
exit()
|
7
|
+
end
|
8
|
+
pid = ARGV[0]
|
9
|
+
debug = !!ENV['DEBUG']
|
10
|
+
|
11
|
+
# load BPF program
|
12
|
+
bpf_text = <<BPF
|
13
|
+
#include <uapi/linux/ptrace.h>
|
14
|
+
int do_trace(struct pt_regs *ctx) {
|
15
|
+
uint64_t addr;
|
16
|
+
char path[128]={0};
|
17
|
+
bpf_usdt_readarg(6, ctx, &addr);
|
18
|
+
bpf_probe_read(&path, sizeof(path), (void *)addr);
|
19
|
+
bpf_trace_printk("path:%s\\n", path);
|
20
|
+
return 0;
|
21
|
+
};
|
22
|
+
BPF
|
23
|
+
|
24
|
+
# enable USDT probe from given PID
|
25
|
+
u = USDT.new(pid: pid.to_i)
|
26
|
+
u.enable_probe(probe: "http__server__request", fn_name: "do_trace")
|
27
|
+
if debug
|
28
|
+
puts(u.get_text)
|
29
|
+
puts(bpf_text)
|
30
|
+
end
|
31
|
+
|
32
|
+
# initialize BPF
|
33
|
+
b = BCC.new(text: bpf_text, usdt_contexts: [u])
|
34
|
+
|
35
|
+
puts("%-18s %-16s %-6s %s" % ["TIME(s)", "COMM", "PID", "ARGS"])
|
36
|
+
loop do
|
37
|
+
begin
|
38
|
+
b.trace_fields do |task, pid, cpu, flags, ts, msg|
|
39
|
+
puts("%-18.9f %-16s %-6d %s" % [ts, task, pid, msg])
|
40
|
+
end
|
41
|
+
rescue Interrupt
|
42
|
+
exit
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#include <uapi/linux/ptrace.h>
|
2
|
+
#include <linux/sched.h>
|
3
|
+
|
4
|
+
struct key_t {
|
5
|
+
u32 prev_pid;
|
6
|
+
u32 curr_pid;
|
7
|
+
};
|
8
|
+
|
9
|
+
BPF_HASH(stats, struct key_t, u64, 1024);
|
10
|
+
int count_sched(struct pt_regs *ctx, struct task_struct *prev) {
|
11
|
+
struct key_t key = {};
|
12
|
+
u64 zero = 0, *val;
|
13
|
+
|
14
|
+
key.curr_pid = bpf_get_current_pid_tgid();
|
15
|
+
key.prev_pid = prev->pid;
|
16
|
+
|
17
|
+
// could also use `stats.increment(key);`
|
18
|
+
val = stats.lookup_or_try_init(&key, &zero);
|
19
|
+
if (val) {
|
20
|
+
(*val)++;
|
21
|
+
}
|
22
|
+
return 0;
|
23
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Original task_switch.rb Copyright (c) PLUMgrid, Inc.
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License")
|
4
|
+
|
5
|
+
require 'rbbcc'
|
6
|
+
include RbBCC
|
7
|
+
|
8
|
+
b = BCC.new(src_file: "16-task_switch.c")
|
9
|
+
b.attach_kprobe(event: "finish_task_switch", fn_name: "count_sched")
|
10
|
+
|
11
|
+
# generate many schedule events
|
12
|
+
100.times { sleep 0.01 }
|
13
|
+
|
14
|
+
b["stats"].each do |_k, v|
|
15
|
+
k = _k[0, 8].unpack("i! i!") # Handling pointer without type!!
|
16
|
+
puts("task_switch[%5d->%5d]=%u" % [k[0], k[1], v.to_bcc_value])
|
17
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
var http = require("http");
|
2
|
+
|
3
|
+
var server = http.createServer(function (req, res) {
|
4
|
+
res.writeHead(200, {"Content-Type": "text/plain"});
|
5
|
+
res.end("Sample node.js server, returns contents in any path.\n");
|
6
|
+
});
|
7
|
+
|
8
|
+
var port = process.env.PORT || 8081;
|
9
|
+
server.listen(port, function() {
|
10
|
+
console.log("Do curl http://localhost:" + port);
|
11
|
+
});
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Projects Using RbBCC
|
2
|
+
|
3
|
+
## bpfql
|
4
|
+
|
5
|
+
[bpfql](https://github.com/udzura/bpfql) is a tool to run an eBPF tracing query, using YAML or Ruby DSL.
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
BPFQL do
|
9
|
+
select "*"
|
10
|
+
from "tracepoint:random:urandom_read"
|
11
|
+
where "comm", is: "ruby"
|
12
|
+
end
|
13
|
+
```
|
14
|
+
|
15
|
+
```console
|
16
|
+
$ sudo bundle exec bpfql examples/random.rb
|
17
|
+
Found fnc: tracepoint__random__urandom_read
|
18
|
+
Attach: random:urandom_read
|
19
|
+
TS COMM PID GOT_BITS POOL_LEFT INPUT_LEFT
|
20
|
+
0.000000000 ruby 32485 128 0 2451
|
21
|
+
0.002465663 ruby 32485 128 0 2451
|
22
|
+
^CExiting bpfql...
|
23
|
+
```
|
24
|
+
|
25
|
+
See [its repo](https://github.com/udzura/bpfql) for more details.
|
26
|
+
|
27
|
+
## rack-ebpf and rack application tracing
|
28
|
+
|
29
|
+
[rack-ebpf](https://github.com/udzura/rack-ebpf) is a rack middleware that invoke USDT probes every time start/end the requests.
|
30
|
+
|
31
|
+
Combine this rack middleware and `rack-ebpf-run` command, we can trace and analyze system stats per request.
|
32
|
+
|
33
|
+
e.g.
|
34
|
+
|
35
|
+
* Count of syscall invocations(like read, write) per request
|
36
|
+
* Consumed time for syscall ops(like read, write) per request
|
37
|
+
* Created Ruby objects per request, using Ruby itself's USDT (this requires ruby itself as `--enable-dtrace` build)
|
38
|
+
|
39
|
+
For detailed usage, see [rack-ebpf's repo](https://github.com/udzura/rack-ebpf)
|
40
|
+
|
41
|
+
----
|
42
|
+
|
43
|
+
Also we're going to prepare some BCC tools made with Ruby. TBA!
|