rbbcc 0.3.1 → 0.6.0

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