rbbcc 0.3.1 → 0.4.0

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