rbbcc 0.3.1 → 0.4.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.
@@ -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
+ }
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ # Original task_switch.rb Copyright (c) PLUMgrid, Inc.
3
+ # Licensed under the Apache License, Version 2.0 (the "License")
4
+
5
+ require 'rbbcc'
6
+ include RbBCC
7
+
8
+ b = BCC.new(src_file: "16-task_switch.c")
9
+ b.attach_kprobe(event: "finish_task_switch", fn_name: "count_sched")
10
+
11
+ # generate many schedule events
12
+ 100.times { sleep 0.01 }
13
+
14
+ b["stats"].each do |_k, v|
15
+ k = _k[0, 8].unpack("i! i!") # Handling pointer without type!!
16
+ puts("task_switch[%5d->%5d]=%u" % [k[0], k[1], v.to_bcc_value])
17
+ end
@@ -0,0 +1,11 @@
1
+ var http = require("http");
2
+
3
+ var server = http.createServer(function (req, res) {
4
+ res.writeHead(200, {"Content-Type": "text/plain"});
5
+ res.end("Sample node.js server, returns contents in any path.\n");
6
+ });
7
+
8
+ var port = process.env.PORT || 8081;
9
+ server.listen(port, function() {
10
+ console.log("Do curl http://localhost:" + port);
11
+ });
@@ -0,0 +1,43 @@
1
+ # Projects Using RbBCC
2
+
3
+ ## bpfql
4
+
5
+ [bpfql](https://github.com/udzura/bpfql) is a tool to run an eBPF tracing query, using YAML or Ruby DSL.
6
+
7
+ ```ruby
8
+ BPFQL do
9
+ select "*"
10
+ from "tracepoint:random:urandom_read"
11
+ where "comm", is: "ruby"
12
+ end
13
+ ```
14
+
15
+ ```console
16
+ $ sudo bundle exec bpfql examples/random.rb
17
+ Found fnc: tracepoint__random__urandom_read
18
+ Attach: random:urandom_read
19
+ TS COMM PID GOT_BITS POOL_LEFT INPUT_LEFT
20
+ 0.000000000 ruby 32485 128 0 2451
21
+ 0.002465663 ruby 32485 128 0 2451
22
+ ^CExiting bpfql...
23
+ ```
24
+
25
+ See [its repo](https://github.com/udzura/bpfql) for more details.
26
+
27
+ ## rack-ebpf and rack application tracing
28
+
29
+ [rack-ebpf](https://github.com/udzura/rack-ebpf) is a rack middleware that invoke USDT probes every time start/end the requests.
30
+
31
+ Combine this rack middleware and `rack-ebpf-run` command, we can trace and analyze system stats per request.
32
+
33
+ e.g.
34
+
35
+ * Count of syscall invocations(like read, write) per request
36
+ * Consumed time for syscall ops(like read, write) per request
37
+ * Created Ruby objects per request, using Ruby itself's USDT (this requires ruby itself as `--enable-dtrace` build)
38
+
39
+ For detailed usage, see [rack-ebpf's repo](https://github.com/udzura/rack-ebpf)
40
+
41
+ ----
42
+
43
+ Also we're going to prepare some BCC tools made with Ruby. TBA!