rbbcc 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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!
|