rbbcc 0.3.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -1
  3. data/.semaphore/semaphore.yml +19 -0
  4. data/Gemfile +5 -0
  5. data/Gemfile.lock +6 -4
  6. data/README.md +5 -1
  7. data/Rakefile +8 -1
  8. data/docs/README.md +2 -0
  9. data/docs/answers/01-hello-world.rb +16 -0
  10. data/docs/answers/02-sys_sync.rb +18 -0
  11. data/docs/answers/03-hello_fields.rb +33 -0
  12. data/docs/answers/04-sync_timing.rb +46 -0
  13. data/docs/answers/05-sync_count.rb +54 -0
  14. data/docs/answers/06-disksnoop.rb +71 -0
  15. data/docs/answers/07-hello_perf_output.rb +59 -0
  16. data/docs/answers/08-sync_perf_output.rb +60 -0
  17. data/docs/answers/09-bitehist.rb +32 -0
  18. data/docs/answers/10-disklatency.rb +51 -0
  19. data/docs/answers/11-vfsreadlat.c +46 -0
  20. data/docs/answers/11-vfsreadlat.rb +66 -0
  21. data/docs/answers/12-urandomread.rb +38 -0
  22. data/docs/answers/13-disksnoop_fixed.rb +108 -0
  23. data/docs/answers/14-strlen_count.rb +46 -0
  24. data/docs/answers/15-nodejs_http_server.rb +44 -0
  25. data/docs/answers/16-task_switch.c +23 -0
  26. data/docs/answers/16-task_switch.rb +17 -0
  27. data/docs/answers/node-server.js +11 -0
  28. data/docs/projects_using_rbbcc.md +43 -0
  29. data/docs/tutorial_bcc_ruby_developer.md +774 -0
  30. data/docs/tutorial_bcc_ruby_developer_japanese.md +770 -0
  31. data/examples/networking/http_filter/http-parse-simple.c +114 -0
  32. data/examples/networking/http_filter/http-parse-simple.rb +85 -0
  33. data/examples/ruby_usdt.rb +105 -0
  34. data/examples/sbrk_trace.rb +204 -0
  35. data/lib/rbbcc/bcc.rb +67 -20
  36. data/lib/rbbcc/clib.rb +23 -10
  37. data/lib/rbbcc/debug.rb +17 -0
  38. data/lib/rbbcc/table.rb +36 -16
  39. data/lib/rbbcc/usdt.rb +21 -4
  40. data/lib/rbbcc/version.rb +1 -1
  41. data/rbbcc.gemspec +1 -4
  42. data/semaphore.sh +73 -0
  43. metadata +34 -46
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a1911b0a6e9450e76b3fda2c56c45bfc17846638e1ca99e64e983d99f99dff64
4
- data.tar.gz: e4841d103a87ee45ced700ea7dff562a305e1cbf1172ef35da40be063d4ee698
3
+ metadata.gz: 7b09e8de1a9fb9b045fc7cd7b00bb6cd54e2af818c8c66caed5b82370f4db612
4
+ data.tar.gz: 02b6c61e958a72b7d69a892dfa856823d12078393327138c523653bfc3110779
5
5
  SHA512:
6
- metadata.gz: fd3aba48720c19d46efa02eac50fd758e883306616bb14068e13c4062f8d8efd4f9852b2b5d7f8eded678a9954e36070cb13f2be99c271b6983ab8ec75e53807
7
- data.tar.gz: 63170a77e06d0c15d5dac6eed68112232b475259fcce7a07f4c99ba21baf9df0e85faa307fa2c868afc4aea9888ac7b4779188f03e0cd40d0cbedfab28c41873
6
+ metadata.gz: 2fefae013cd7a13666ae61fe19284fae49fdad67ac30692e13ab445be71b9ce788177e261e0ac884bc15e491dce2e8895dd374c623256c2dec3dab3158dc583e
7
+ data.tar.gz: d879de7d56899578ae483d85d9fd073cca4d84fcc5adaa465e86dacb152585c395cbdb2e563b69612577abfae07c2f500acdecd4a515c0c8f833ff586afe7158
data/.gitignore CHANGED
@@ -10,4 +10,8 @@
10
10
 
11
11
  .ruby-version
12
12
 
13
- /examples/work/*
13
+ /examples/work/*
14
+
15
+ /bin
16
+ !/bin/setup
17
+ !/bin/console
@@ -0,0 +1,19 @@
1
+ version: v1.0
2
+ name: Ruby Test
3
+ agent:
4
+ machine:
5
+ type: e1-standard-2
6
+ os_image: ubuntu1804
7
+ blocks:
8
+ - name: Basic Test
9
+ task:
10
+ jobs:
11
+ - name: ruby test
12
+ matrix:
13
+ - env_var: LIBBCC_VERSION
14
+ values: [ "0.12.0", "0.11.0", "0.10.0" ]
15
+ commands:
16
+ - sem-version c 7
17
+ - sem-version ruby 2.6.5
18
+ - checkout
19
+ - ./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,25 +1,27 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rbbcc (0.2.0)
4
+ rbbcc (0.5.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  coderay (1.1.2)
10
10
  method_source (0.9.2)
11
+ minitest (5.14.0)
11
12
  pry (0.12.2)
12
13
  coderay (~> 1.1.0)
13
14
  method_source (~> 0.9.0)
14
- rake (10.5.0)
15
+ rake (13.0.1)
15
16
 
16
17
  PLATFORMS
17
18
  ruby
18
19
 
19
20
  DEPENDENCIES
20
21
  bundler (~> 2.0)
21
- pry
22
- rake (~> 10.0)
22
+ minitest (>= 5)
23
+ pry (~> 0.12)
24
+ rake (~> 13.0)
23
25
  rbbcc!
24
26
 
25
27
  BUNDLED WITH
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # RbBCC
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/rbbcc.svg)](https://badge.fury.io/rb/rbbcc)
3
+ [![Gem Version](https://badge.fury.io/rb/rbbcc.svg)](https://badge.fury.io/rb/rbbcc) [![CI status](https://udzura.semaphoreci.com/badges/rbbcc.svg)](https://udzura.semaphoreci.com/projects/rbbcc)
4
4
 
5
5
  RbBCC is a port of [BCC](https://github.com/iovisor/bcc) in MRI. See iovisor project page.
6
6
 
@@ -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/Rakefile CHANGED
@@ -1,2 +1,9 @@
1
1
  require "bundler/gem_tasks"
2
- task :default => :spec
2
+
3
+ require "rake/testtask"
4
+ Rake::TestTask.new do |t|
5
+ t.test_files = FileList['test/**/*_test.rb']
6
+ end
7
+ desc "Run tests"
8
+
9
+ task :default => :test
@@ -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