rbbcc 0.3.1 → 0.6.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.semaphore/semaphore.yml +3 -1
  3. data/Gemfile +5 -0
  4. data/Gemfile.lock +6 -6
  5. data/README.md +4 -0
  6. data/docs/README.md +2 -0
  7. data/docs/answers/01-hello-world.rb +16 -0
  8. data/docs/answers/02-sys_sync.rb +18 -0
  9. data/docs/answers/03-hello_fields.rb +33 -0
  10. data/docs/answers/04-sync_timing.rb +46 -0
  11. data/docs/answers/05-sync_count.rb +54 -0
  12. data/docs/answers/06-disksnoop.rb +71 -0
  13. data/docs/answers/07-hello_perf_output.rb +59 -0
  14. data/docs/answers/08-sync_perf_output.rb +60 -0
  15. data/docs/answers/09-bitehist.rb +32 -0
  16. data/docs/answers/10-disklatency.rb +51 -0
  17. data/docs/answers/11-vfsreadlat.c +46 -0
  18. data/docs/answers/11-vfsreadlat.rb +66 -0
  19. data/docs/answers/12-urandomread.rb +38 -0
  20. data/docs/answers/13-disksnoop_fixed.rb +108 -0
  21. data/docs/answers/14-strlen_count.rb +46 -0
  22. data/docs/answers/15-nodejs_http_server.rb +44 -0
  23. data/docs/answers/16-task_switch.c +23 -0
  24. data/docs/answers/16-task_switch.rb +17 -0
  25. data/docs/answers/node-server.js +11 -0
  26. data/docs/projects_using_rbbcc.md +43 -0
  27. data/docs/tutorial_bcc_ruby_developer.md +774 -0
  28. data/docs/tutorial_bcc_ruby_developer_japanese.md +770 -0
  29. data/examples/networking/http_filter/http-parse-simple.c +114 -0
  30. data/examples/networking/http_filter/http-parse-simple.rb +85 -0
  31. data/examples/ruby_usdt.rb +105 -0
  32. data/examples/sbrk_trace.rb +204 -0
  33. data/examples/tools/bashreadline.rb +83 -0
  34. data/lib/rbbcc/bcc.rb +73 -20
  35. data/lib/rbbcc/clib.rb +7 -2
  36. data/lib/rbbcc/debug.rb +17 -0
  37. data/lib/rbbcc/table.rb +16 -22
  38. data/lib/rbbcc/usdt.rb +21 -4
  39. data/lib/rbbcc/version.rb +1 -1
  40. data/rbbcc.gemspec +1 -5
  41. metadata +34 -61
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 162758633aea60cbe4979dd77f61603a7f2032d624594b523f990d703d9fc0e6
4
- data.tar.gz: 39b9b0b9fd390f45a5a242d6182197d9e39de0fb0444f06c94872a42b5dd4d5a
3
+ metadata.gz: 4bfc5d3f19fd4dbfa744a6380055103b5c45a0a72d956ced238154472ae4d7b5
4
+ data.tar.gz: 160c2a313f7181c6a9dab665c265fe2760d743ecbcab4797cc25e920e00d7f11
5
5
  SHA512:
6
- metadata.gz: e807d4903cbd8683eb58b073700a24993824e23027de3445d2729728e9cbe7d556a7948a15efaf5c5e7462521675854ec40e32e9776d64c637778fcbad4ad79c
7
- data.tar.gz: fcecb00f5eb34f247987b445c59daa221b99ed477ffcd5355e965ac20c97cbe748b3650f2066de1b6575e4ffaf97c7cf21bf9751a7e55ec02cfb0a1837f3e7be
6
+ metadata.gz: 9e2f72abd18698c9dca81342474a38e10a2e65d88e4acc7d0bbb3d924d9019d7204639f407a14418664d49ef4eb0666729fda06e3a06f2066dd0c8bfa0cf6701
7
+ data.tar.gz: e651213860bacc705b8b3f8c51c962aba9f5f1d67cb041eab850eee64b1c8ab6d7fe71a6bd630cddc224bea2af465323c3b4ef728995d124c954f194e9cd6714
@@ -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 2.6.5
19
+ - sem-version ruby $RUBY_VERSION
18
20
  - checkout
19
21
  - ./semaphore.sh
data/Gemfile CHANGED
@@ -2,3 +2,8 @@ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in rbbcc.gemspec
4
4
  gemspec
5
+
6
+ gem "bundler", "~> 2.0"
7
+ gem "rake", "~> 13.0"
8
+ gem "pry", "~> 0.12"
9
+ gem "minitest", ">= 5"
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rbbcc (0.3.1)
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 (10.5.0)
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 (~> 10.0)
22
+ minitest (>= 5)
23
+ pry (~> 0.12)
24
+ rake (~> 13.0)
25
25
  rbbcc!
26
26
 
27
27
  BUNDLED WITH
28
- 2.1.0
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.
@@ -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