rbbcc 0.3.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.semaphore/semaphore.yml +3 -1
- data/Gemfile +5 -0
- data/Gemfile.lock +6 -6
- 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 +774 -0
- data/docs/tutorial_bcc_ruby_developer_japanese.md +770 -0
- data/examples/networking/http_filter/http-parse-simple.c +114 -0
- data/examples/networking/http_filter/http-parse-simple.rb +85 -0
- data/examples/ruby_usdt.rb +105 -0
- data/examples/sbrk_trace.rb +204 -0
- data/examples/tools/bashreadline.rb +83 -0
- data/lib/rbbcc/bcc.rb +73 -20
- data/lib/rbbcc/clib.rb +7 -2
- data/lib/rbbcc/debug.rb +17 -0
- data/lib/rbbcc/table.rb +16 -22
- data/lib/rbbcc/usdt.rb +21 -4
- data/lib/rbbcc/version.rb +1 -1
- data/rbbcc.gemspec +1 -5
- metadata +34 -61
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4bfc5d3f19fd4dbfa744a6380055103b5c45a0a72d956ced238154472ae4d7b5
|
4
|
+
data.tar.gz: 160c2a313f7181c6a9dab665c265fe2760d743ecbcab4797cc25e920e00d7f11
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e2f72abd18698c9dca81342474a38e10a2e65d88e4acc7d0bbb3d924d9019d7204639f407a14418664d49ef4eb0666729fda06e3a06f2066dd0c8bfa0cf6701
|
7
|
+
data.tar.gz: e651213860bacc705b8b3f8c51c962aba9f5f1d67cb041eab850eee64b1c8ab6d7fe71a6bd630cddc224bea2af465323c3b4ef728995d124c954f194e9cd6714
|
data/.semaphore/semaphore.yml
CHANGED
@@ -10,10 +10,12 @@ blocks:
|
|
10
10
|
jobs:
|
11
11
|
- name: ruby test
|
12
12
|
matrix:
|
13
|
+
- env_var: RUBY_VERSION
|
14
|
+
values: [ "2.6.5", "2.6.6", "2.7.1" ]
|
13
15
|
- env_var: LIBBCC_VERSION
|
14
16
|
values: [ "0.12.0", "0.11.0", "0.10.0" ]
|
15
17
|
commands:
|
16
18
|
- sem-version c 7
|
17
|
-
- sem-version ruby
|
19
|
+
- sem-version ruby $RUBY_VERSION
|
18
20
|
- checkout
|
19
21
|
- ./semaphore.sh
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rbbcc (0.
|
4
|
+
rbbcc (0.6.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -12,17 +12,17 @@ GEM
|
|
12
12
|
pry (0.12.2)
|
13
13
|
coderay (~> 1.1.0)
|
14
14
|
method_source (~> 0.9.0)
|
15
|
-
rake (
|
15
|
+
rake (13.0.1)
|
16
16
|
|
17
17
|
PLATFORMS
|
18
18
|
ruby
|
19
19
|
|
20
20
|
DEPENDENCIES
|
21
21
|
bundler (~> 2.0)
|
22
|
-
minitest
|
23
|
-
pry
|
24
|
-
rake (~>
|
22
|
+
minitest (>= 5)
|
23
|
+
pry (~> 0.12)
|
24
|
+
rake (~> 13.0)
|
25
25
|
rbbcc!
|
26
26
|
|
27
27
|
BUNDLED WITH
|
28
|
-
2.1.
|
28
|
+
2.1.4
|
data/README.md
CHANGED
@@ -94,6 +94,10 @@ $ docker run --privileged \
|
|
94
94
|
runc-5025 [003] d... 1237.797464: : Hello, World!
|
95
95
|
```
|
96
96
|
|
97
|
+
## Documents
|
98
|
+
|
99
|
+
See [docs/](docs/) for getting started and tutorial.
|
100
|
+
|
97
101
|
## Development
|
98
102
|
|
99
103
|
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/docs/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# RbBCC Docs
|
2
2
|
|
3
3
|
* [Getting Started](getting_started.md)
|
4
|
+
* [Ruby Tutorial](tutorial_bcc_ruby_developer.md)
|
5
|
+
* [Projects Using RbBCC](projects_using_rbbcc.md)
|
4
6
|
|
5
7
|
**Please see also [BCC itself's README](https://github.com/iovisor/bcc/#readme) and [docs](https://github.com/iovisor/bcc/tree/master/docs).**
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Original hello_world.py:
|
3
|
+
# Copyright (c) PLUMgrid, Inc.
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License")
|
5
|
+
#
|
6
|
+
# This Ruby version follows the Apache License 2.0
|
7
|
+
|
8
|
+
# run in project examples directory with:
|
9
|
+
# sudo ./hello_world.rb"
|
10
|
+
# see trace_fields.rb for a longer example
|
11
|
+
|
12
|
+
require "rbbcc"
|
13
|
+
include RbBCC
|
14
|
+
|
15
|
+
# This may not work for 4.17 on x64, you need replace kprobe__sys_clone with kprobe____x64_sys_clone
|
16
|
+
BCC.new(text: 'int kprobe__sys_clone(void *ctx) { bpf_trace_printk("Hello, World!\\n"); return 0; }').trace_print
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License")
|
3
|
+
|
4
|
+
require "rbbcc"
|
5
|
+
include RbBCC
|
6
|
+
|
7
|
+
puts "Tracing sys_sync()... Ctrl-C to end."
|
8
|
+
begin
|
9
|
+
BCC.new(text: <<~BPF).trace_print
|
10
|
+
int kprobe__sys_sync(void *ctx) {
|
11
|
+
bpf_trace_printk("sys_sync() called\\n");
|
12
|
+
return 0;
|
13
|
+
}
|
14
|
+
BPF
|
15
|
+
rescue Interrupt
|
16
|
+
puts
|
17
|
+
puts "Done"
|
18
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License")
|
3
|
+
|
4
|
+
require "rbbcc"
|
5
|
+
include RbBCC
|
6
|
+
|
7
|
+
# define BPF program
|
8
|
+
prog = <<BPF
|
9
|
+
int hello(void *ctx) {
|
10
|
+
bpf_trace_printk("Hello, World!\\n");
|
11
|
+
return 0;
|
12
|
+
}
|
13
|
+
BPF
|
14
|
+
|
15
|
+
# load BPF program
|
16
|
+
b = BCC.new(text: prog)
|
17
|
+
b.attach_kprobe(event: b.get_syscall_fnname("clone"), fn_name: "hello")
|
18
|
+
|
19
|
+
# header
|
20
|
+
puts("%-18s %-16s %-6s %s" % ["TIME(s)", "COMM", "PID", "MESSAGE"])
|
21
|
+
|
22
|
+
# format output
|
23
|
+
begin
|
24
|
+
b.trace_fields do |task, pid, cpu, flags, ts, msg|
|
25
|
+
print("%-18.9f %-16s %-6d %s" % [ts, task, pid, msg])
|
26
|
+
end
|
27
|
+
rescue Interrupt
|
28
|
+
puts
|
29
|
+
puts "Done"
|
30
|
+
rescue => e
|
31
|
+
p e
|
32
|
+
retry
|
33
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Original sync_timing.py:
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License")
|
4
|
+
#
|
5
|
+
# This Ruby version follows the Apache License 2.0
|
6
|
+
|
7
|
+
require "rbbcc"
|
8
|
+
include RbBCC
|
9
|
+
|
10
|
+
# load BPF program
|
11
|
+
b = BCC.new(text: <<BPF)
|
12
|
+
#include <uapi/linux/ptrace.h>
|
13
|
+
|
14
|
+
BPF_HASH(last);
|
15
|
+
|
16
|
+
int do_trace(struct pt_regs *ctx) {
|
17
|
+
u64 ts, *tsp, delta, key = 0;
|
18
|
+
|
19
|
+
// attempt to read stored timestamp
|
20
|
+
tsp = last.lookup(&key);
|
21
|
+
if (tsp != 0) {
|
22
|
+
delta = bpf_ktime_get_ns() - *tsp;
|
23
|
+
if (delta < 1000000000) {
|
24
|
+
// output if time is less than 1 second
|
25
|
+
bpf_trace_printk("%d\\n", delta / 1000000);
|
26
|
+
}
|
27
|
+
last.delete(&key);
|
28
|
+
}
|
29
|
+
|
30
|
+
// update stored timestamp
|
31
|
+
ts = bpf_ktime_get_ns();
|
32
|
+
last.update(&key, &ts);
|
33
|
+
return 0;
|
34
|
+
}
|
35
|
+
BPF
|
36
|
+
|
37
|
+
b.attach_kprobe(event: b.get_syscall_fnname("sync"), fn_name: "do_trace")
|
38
|
+
puts("Tracing for quick sync's... Ctrl-C to end")
|
39
|
+
|
40
|
+
# format output
|
41
|
+
start = 0
|
42
|
+
b.trace_fields do |task, pid, cpu, flags, ts, ms|
|
43
|
+
start = ts.to_f if start.zero?
|
44
|
+
ts = ts.to_f - start
|
45
|
+
puts("At time %.2f s: multiple syncs detected, last %s ms ago" % [ts, ms.chomp])
|
46
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License")
|
3
|
+
|
4
|
+
require "rbbcc"
|
5
|
+
include RbBCC
|
6
|
+
|
7
|
+
# load BPF program
|
8
|
+
b = BCC.new(text: <<BPF)
|
9
|
+
#include <uapi/linux/ptrace.h>
|
10
|
+
|
11
|
+
BPF_HASH(last);
|
12
|
+
|
13
|
+
int do_trace(struct pt_regs *ctx) {
|
14
|
+
u64 ts, *tsp, delta, key = 0, counter_key = 1, zero = 0;
|
15
|
+
|
16
|
+
// initialize counter key
|
17
|
+
if (last.lookup_or_try_init(&counter_key, &zero))
|
18
|
+
last.increment(counter_key);
|
19
|
+
|
20
|
+
// attempt to read stored timestamp
|
21
|
+
tsp = last.lookup(&key);
|
22
|
+
if (tsp != 0) {
|
23
|
+
delta = bpf_ktime_get_ns() - *tsp;
|
24
|
+
if (delta < 1000000000) {
|
25
|
+
// output if time is less than 1 second
|
26
|
+
bpf_trace_printk("%d\\n", delta / 1000000);
|
27
|
+
}
|
28
|
+
last.delete(&key);
|
29
|
+
}
|
30
|
+
|
31
|
+
// update stored timestamp
|
32
|
+
ts = bpf_ktime_get_ns();
|
33
|
+
last.update(&key, &ts);
|
34
|
+
return 0;
|
35
|
+
}
|
36
|
+
BPF
|
37
|
+
|
38
|
+
COUNTER_KEY = 1
|
39
|
+
|
40
|
+
b.attach_kprobe(event: b.get_syscall_fnname("sync"), fn_name: "do_trace")
|
41
|
+
puts("Tracing for quick sync's... Ctrl-C to end")
|
42
|
+
|
43
|
+
# format output
|
44
|
+
start = 0
|
45
|
+
begin
|
46
|
+
b.trace_fields do |task, pid, cpu, flags, ts, ms|
|
47
|
+
start = ts.to_f if start.zero?
|
48
|
+
ts = ts.to_f - start
|
49
|
+
puts("At time %.2f s: multiple syncs detected, last %s ms ago" % [ts, ms.chomp])
|
50
|
+
end
|
51
|
+
rescue Interrupt
|
52
|
+
table = b["last"]
|
53
|
+
puts "Count of sys_sync: %d" % table[COUNTER_KEY].to_bcc_value
|
54
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# disksnoop.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
|
+
require 'rbbcc'
|
14
|
+
include RbBCC
|
15
|
+
|
16
|
+
REQ_WRITE = 1 # from include/linux/blk_types.h
|
17
|
+
|
18
|
+
# load BPF program
|
19
|
+
b = BCC.new(text: <<CLANG)
|
20
|
+
#include <uapi/linux/ptrace.h>
|
21
|
+
#include <linux/blkdev.h>
|
22
|
+
|
23
|
+
BPF_HASH(start, struct request *);
|
24
|
+
|
25
|
+
void trace_start(struct pt_regs *ctx, struct request *req) {
|
26
|
+
// stash start timestamp by request ptr
|
27
|
+
u64 ts = bpf_ktime_get_ns();
|
28
|
+
|
29
|
+
start.update(&req, &ts);
|
30
|
+
}
|
31
|
+
|
32
|
+
void trace_completion(struct pt_regs *ctx, struct request *req) {
|
33
|
+
u64 *tsp, delta;
|
34
|
+
|
35
|
+
tsp = start.lookup(&req);
|
36
|
+
if (tsp != 0) {
|
37
|
+
delta = bpf_ktime_get_ns() - *tsp;
|
38
|
+
bpf_trace_printk("%d %x %d\\n", req->__data_len,
|
39
|
+
req->cmd_flags, delta / 1000);
|
40
|
+
start.delete(&req);
|
41
|
+
}
|
42
|
+
}
|
43
|
+
CLANG
|
44
|
+
|
45
|
+
b.attach_kprobe(event: "blk_start_request", fn_name: "trace_start") if BCC.get_kprobe_functions('blk_start_request')
|
46
|
+
b.attach_kprobe(event: "blk_mq_start_request", fn_name: "trace_start")
|
47
|
+
b.attach_kprobe(event: "blk_account_io_completion", fn_name: "trace_completion")
|
48
|
+
|
49
|
+
# header
|
50
|
+
puts("%-18s %-2s %-7s %8s" % ["TIME(s)", "T", "BYTES", "LAT(ms)"])
|
51
|
+
|
52
|
+
# format output
|
53
|
+
loop do
|
54
|
+
begin
|
55
|
+
task, pid, cpu, flags, ts, msg = b.trace_fields
|
56
|
+
bytes_s, bflags_s, us_s = msg.split
|
57
|
+
|
58
|
+
if (bflags_s.to_i(16) & REQ_WRITE).nonzero?
|
59
|
+
type_s = "W"
|
60
|
+
elsif bytes_s == "0" # see blk_fill_rwbs() for logic
|
61
|
+
type_s = "M"
|
62
|
+
else
|
63
|
+
type_s = "R"
|
64
|
+
end
|
65
|
+
ms = us_s.to_i.to_f / 1000
|
66
|
+
|
67
|
+
puts("%-18.9f %-2s %-7s %8.2f" % [ts, type_s, bytes_s, ms])
|
68
|
+
rescue Interrupt
|
69
|
+
exit
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This is a Hello World example that uses BPF_PERF_OUTPUT.
|
4
|
+
# Ported from hello_perf_output.py
|
5
|
+
|
6
|
+
require 'rbbcc'
|
7
|
+
include RbBCC
|
8
|
+
|
9
|
+
# define BPF program
|
10
|
+
prog = """
|
11
|
+
#include <linux/sched.h>
|
12
|
+
|
13
|
+
// define output data structure in C
|
14
|
+
struct data_t {
|
15
|
+
u32 pid;
|
16
|
+
u64 ts;
|
17
|
+
char comm[TASK_COMM_LEN];
|
18
|
+
};
|
19
|
+
BPF_PERF_OUTPUT(events);
|
20
|
+
|
21
|
+
int hello(struct pt_regs *ctx) {
|
22
|
+
struct data_t data = {};
|
23
|
+
|
24
|
+
data.pid = bpf_get_current_pid_tgid();
|
25
|
+
data.ts = bpf_ktime_get_ns();
|
26
|
+
bpf_get_current_comm(&data.comm, sizeof(data.comm));
|
27
|
+
|
28
|
+
events.perf_submit(ctx, &data, sizeof(data));
|
29
|
+
|
30
|
+
return 0;
|
31
|
+
}
|
32
|
+
"""
|
33
|
+
|
34
|
+
# load BPF program
|
35
|
+
b = BCC.new(text: prog)
|
36
|
+
b.attach_kprobe(event: b.get_syscall_fnname("clone"), fn_name: "hello")
|
37
|
+
|
38
|
+
# header
|
39
|
+
puts("%-18s %-16s %-6s %s" % ["TIME(s)", "COMM", "PID", "MESSAGE"])
|
40
|
+
|
41
|
+
# process event
|
42
|
+
start = 0
|
43
|
+
print_event = lambda { |cpu, data, size|
|
44
|
+
event = b["events"].event(data)
|
45
|
+
if start == 0
|
46
|
+
start = event.ts
|
47
|
+
end
|
48
|
+
|
49
|
+
time_s = ((event.ts - start).to_f) / 1000000000
|
50
|
+
puts("%-18.9f %-16s %-6d %s" % [time_s, event.comm, event.pid,
|
51
|
+
"Hello, perf_output!"])
|
52
|
+
}
|
53
|
+
|
54
|
+
# loop with callback to print_event
|
55
|
+
b["events"].open_perf_buffer(&print_event)
|
56
|
+
|
57
|
+
loop do
|
58
|
+
b.perf_buffer_poll()
|
59
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License")
|
3
|
+
|
4
|
+
require "rbbcc"
|
5
|
+
include RbBCC
|
6
|
+
|
7
|
+
# load BPF program
|
8
|
+
b = BCC.new(text: <<BPF)
|
9
|
+
#include <uapi/linux/ptrace.h>
|
10
|
+
|
11
|
+
struct data_t {
|
12
|
+
u32 pid;
|
13
|
+
u64 ts;
|
14
|
+
u64 delta;
|
15
|
+
};
|
16
|
+
BPF_PERF_OUTPUT(events);
|
17
|
+
BPF_HASH(last);
|
18
|
+
|
19
|
+
int do_trace(struct pt_regs *ctx) {
|
20
|
+
u64 ts, *tsp, delta, key = 0;
|
21
|
+
|
22
|
+
// attempt to read stored timestamp
|
23
|
+
tsp = last.lookup(&key);
|
24
|
+
if (tsp != 0) {
|
25
|
+
struct data_t data = {};
|
26
|
+
delta = bpf_ktime_get_ns() - *tsp;
|
27
|
+
if (delta < 1000000000) {
|
28
|
+
data.pid = bpf_get_current_pid_tgid();
|
29
|
+
data.ts = bpf_ktime_get_ns();
|
30
|
+
data.delta = delta;
|
31
|
+
events.perf_submit(ctx, &data, sizeof(data));
|
32
|
+
}
|
33
|
+
last.delete(&key);
|
34
|
+
}
|
35
|
+
|
36
|
+
// update stored timestamp
|
37
|
+
ts = bpf_ktime_get_ns();
|
38
|
+
last.update(&key, &ts);
|
39
|
+
return 0;
|
40
|
+
}
|
41
|
+
BPF
|
42
|
+
|
43
|
+
b.attach_kprobe(event: b.get_syscall_fnname("sync"), fn_name: "do_trace")
|
44
|
+
puts("Tracing for quick sync's... Ctrl-C to end")
|
45
|
+
|
46
|
+
# format output
|
47
|
+
start = 0
|
48
|
+
b["events"].open_perf_buffer do |_, data, _|
|
49
|
+
event = b["events"].event(data)
|
50
|
+
if start == 0
|
51
|
+
start = event.ts
|
52
|
+
end
|
53
|
+
|
54
|
+
time_s = ((event.ts - start).to_f) / 1_000_000_000
|
55
|
+
puts("At time %.2f s: multiple syncs detected, last %s ms ago" % [time_s, event.delta / 1_000_000])
|
56
|
+
end
|
57
|
+
|
58
|
+
loop do
|
59
|
+
b.perf_buffer_poll()
|
60
|
+
end
|