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
@@ -0,0 +1,32 @@
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
+ #include <linux/blkdev.h>
11
+
12
+ BPF_HISTOGRAM(dist);
13
+
14
+ int kprobe__blk_account_io_completion(struct pt_regs *ctx, struct request *req)
15
+ {
16
+ dist.increment(bpf_log2l(req->__data_len / 1024));
17
+ return 0;
18
+ }
19
+ BPF
20
+
21
+ # header
22
+ puts("Tracing... Hit Ctrl-C to end.")
23
+
24
+ # trace until Ctrl-C
25
+ begin
26
+ loop { sleep 0.1 }
27
+ rescue Interrupt
28
+ puts
29
+ end
30
+
31
+ # output
32
+ b["dist"].print_log2_hist("kbytes")
@@ -0,0 +1,51 @@
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
+ b = BCC.new(text: <<BPF)
8
+ #include <uapi/linux/ptrace.h>
9
+ #include <linux/blkdev.h>
10
+
11
+ BPF_HASH(start, struct request *);
12
+ BPF_HISTOGRAM(dist);
13
+
14
+ // note this program mixes R/W
15
+ // For next step, handle req->cmd_flags and prepare hist hash per op.
16
+
17
+ void trace_start(struct pt_regs *ctx, struct request *req) {
18
+ // stash start timestamp by request ptr
19
+ u64 ts = bpf_ktime_get_ns();
20
+
21
+ start.update(&req, &ts);
22
+ }
23
+
24
+ void trace_completion(struct pt_regs *ctx, struct request *req) {
25
+ u64 *tsp, delta;
26
+
27
+ tsp = start.lookup(&req);
28
+ if (tsp != 0) {
29
+ delta = bpf_ktime_get_ns() - *tsp;
30
+ dist.increment(bpf_log2l(delta / 1000)); // us
31
+ start.delete(&req);
32
+ }
33
+ }
34
+ BPF
35
+
36
+ b.attach_kprobe(event: "blk_start_request", fn_name: "trace_start") if BCC.get_kprobe_functions('blk_start_request')
37
+ b.attach_kprobe(event: "blk_mq_start_request", fn_name: "trace_start")
38
+ b.attach_kprobe(event: "blk_account_io_completion", fn_name: "trace_completion")
39
+
40
+ # header
41
+ puts("Tracing... Hit Ctrl-C to end.")
42
+
43
+ # trace until Ctrl-C
44
+ begin
45
+ loop { sleep 0.1 }
46
+ rescue Interrupt
47
+ puts
48
+ end
49
+
50
+ # output
51
+ b["dist"].print_log2_hist("usec")
@@ -0,0 +1,46 @@
1
+ /*
2
+ * From: https://github.com/iovisor/bcc/blob/master/examples/tracing/vfsreadlat.c
3
+ *
4
+ * vfsreadlat.c VFS read latency distribution.
5
+ * For Linux, uses BCC, eBPF. See .py/.rb file.
6
+ *
7
+ * Copyright (c) 2013-2015 PLUMgrid, http://plumgrid.com
8
+ * This program is free software; you can redistribute it and/or
9
+ * modify it under the terms of version 2 of the GNU General Public
10
+ * License as published by the Free Software Foundation.
11
+ *
12
+ * 15-Aug-2015 Brendan Gregg Created this.
13
+ */
14
+
15
+ #include <uapi/linux/ptrace.h>
16
+
17
+ BPF_HASH(start, u32);
18
+ BPF_HISTOGRAM(dist);
19
+
20
+ int do_entry(struct pt_regs *ctx)
21
+ {
22
+ u32 pid;
23
+ u64 ts, *val;
24
+
25
+ pid = bpf_get_current_pid_tgid();
26
+ ts = bpf_ktime_get_ns();
27
+ start.update(&pid, &ts);
28
+ return 0;
29
+ }
30
+
31
+ int do_return(struct pt_regs *ctx)
32
+ {
33
+ u32 pid;
34
+ u64 *tsp, delta;
35
+
36
+ pid = bpf_get_current_pid_tgid();
37
+ tsp = start.lookup(&pid);
38
+
39
+ if (tsp != 0) {
40
+ delta = bpf_ktime_get_ns() - *tsp;
41
+ dist.increment(bpf_log2l(delta / 1000));
42
+ start.delete(&pid);
43
+ }
44
+
45
+ return 0;
46
+ }
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Original: from vfsreadlat.py
4
+ # Copyright (c) 2015 Brendan Gregg.
5
+ # Licensed under the Apache License, Version 2.0 (the "License")
6
+ # Ruby version follows.
7
+ #
8
+ # vfsreadlat.rb VFS read latency distribution.
9
+ # For Linux, uses BCC, eBPF. See .c file.
10
+ #
11
+ # Written as a basic example of a function latency distribution histogram.
12
+ #
13
+ # USAGE: vfsreadlat.rb [interval [count]]
14
+ #
15
+ # The default interval is 5 seconds. A Ctrl-C will print the partially
16
+ # gathered histogram then exit.
17
+
18
+ require "rbbcc"
19
+ include RbBCC
20
+
21
+ def usage
22
+ puts("USAGE: %s [interval [count]]" % $0)
23
+ exit
24
+ end
25
+
26
+ # arguments
27
+ interval = 5
28
+ count = -1
29
+ if ARGV.size > 0
30
+ begin
31
+ interval = ARGV[0].to_i
32
+ raise if interval == 0
33
+ count = ARGV[1].to_i if ARGV[1]
34
+ rescue => e # also catches -h, --help
35
+ usage()
36
+ end
37
+ end
38
+
39
+ # load BPF program
40
+ b = BCC.new(src_file: "11-vfsreadlat.c")
41
+ b.attach_kprobe(event: "vfs_read", fn_name: "do_entry")
42
+ b.attach_kretprobe(event: "vfs_read", fn_name: "do_return")
43
+
44
+ # header
45
+ print("Tracing... Hit Ctrl-C to end.")
46
+
47
+ # output
48
+ cycle = 0
49
+ do_exit = false
50
+ loop do
51
+ if count > 0
52
+ cycle += 1
53
+ exit if cycle > count
54
+ end
55
+
56
+ begin
57
+ sleep(interval)
58
+ rescue Interrupt
59
+ do_exit = true
60
+ end
61
+
62
+ puts
63
+ b["dist"].print_log2_hist("usecs")
64
+ b["dist"].clear
65
+ exit if do_exit
66
+ end
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # urandomread.rb Example of instrumenting a kernel tracepoint.
4
+ # For Linux, uses BCC, BPF. Embedded C.
5
+ #
6
+ # REQUIRES: Linux 4.7+ (BPF_PROG_TYPE_TRACEPOINT support).
7
+ #
8
+ # Test by running this, then in another shell, run:
9
+ # dd if=/dev/urandom of=/dev/null bs=1k count=5
10
+ #
11
+ # Original urandomread.py Copyright 2016 Netflix, Inc.
12
+ # Licensed under the Apache License, Version 2.0 (the "License")
13
+ # Ruby version follows.
14
+
15
+ require 'rbbcc'
16
+ include RbBCC
17
+
18
+ b = BCC.new(text: <<BPF)
19
+ TRACEPOINT_PROBE(random, urandom_read) {
20
+ // args is from /sys/kernel/debug/tracing/events/random/urandom_read/format
21
+ bpf_trace_printk("%d\\n", args->got_bits);
22
+ return 0;
23
+ }
24
+ BPF
25
+
26
+ # header
27
+ puts("%-18s %-16s %-6s %s" % ["TIME(s)", "COMM", "PID", "GOTBITS"])
28
+
29
+ # format output
30
+ loop do
31
+ begin
32
+ b.trace_fields do |task, pid, cpu, flags, ts, msg|
33
+ puts("%-18.9f %-16s %-6d %s" % [ts, task, pid, msg])
34
+ end
35
+ rescue Interrupt
36
+ exit
37
+ end
38
+ end
@@ -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
+ }