ruby-dtrace 0.0.1
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.
- data/History.txt +3 -0
- data/Manifest.txt +28 -0
- data/README.txt +60 -0
- data/Rakefile +30 -0
- data/ext/dtrace_aggregate.c +150 -0
- data/ext/dtrace_api.c +69 -0
- data/ext/dtrace_api.h +53 -0
- data/ext/dtrace_hdl.c +280 -0
- data/ext/dtrace_probe.c +78 -0
- data/ext/dtrace_program.c +57 -0
- data/ext/dtrace_programinfo.c +60 -0
- data/ext/dtrace_recdesc.c +38 -0
- data/ext/extconf.rb +4 -0
- data/lib/dtrace.rb +11 -0
- data/plugin/dtrace/README +4 -0
- data/plugin/dtrace/Rakefile +22 -0
- data/plugin/dtrace/bin/dtracer.rb +24 -0
- data/plugin/dtrace/init.rb +7 -0
- data/plugin/dtrace/lib/dtrace_helper.rb +2 -0
- data/plugin/dtrace/lib/dtrace_report.rb +47 -0
- data/plugin/dtrace/lib/dtrace_tracer.rb +34 -0
- data/plugin/dtrace/lib/dtracer.rb +43 -0
- data/plugin/dtrace/lib/dtracer_client.rb +18 -0
- data/plugin/dtrace/public/stylesheets/dtrace.css +48 -0
- data/plugin/dtrace/tasks/dtrace.rake +52 -0
- data/plugin/dtrace/test/dtrace_test.rb +8 -0
- data/plugin/dtrace/views/dtrace/_report.rhtml +11 -0
- data/test/test_dtrace.rb +415 -0
- metadata +85 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'drb'
|
2
|
+
|
3
|
+
class DtracerClient
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
DRb.start_service
|
7
|
+
@tracer = DRbObject.new(nil, 'druby://localhost:2999')
|
8
|
+
end
|
9
|
+
|
10
|
+
def start_dtrace(pid)
|
11
|
+
@tracer.start_dtrace(pid)
|
12
|
+
end
|
13
|
+
|
14
|
+
def end_dtrace
|
15
|
+
@tracer.end_dtrace
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
body {
|
2
|
+
margin-bottom:25px;
|
3
|
+
}
|
4
|
+
|
5
|
+
#dtrace {
|
6
|
+
width:100%;
|
7
|
+
}
|
8
|
+
|
9
|
+
#dtrace td, #dtrace th, #dtrace div, #dtrace p {
|
10
|
+
text-align:left;
|
11
|
+
}
|
12
|
+
|
13
|
+
#dtrace a,
|
14
|
+
#dtrace a:visited {
|
15
|
+
color:#005;
|
16
|
+
text-decoration:none;
|
17
|
+
}
|
18
|
+
|
19
|
+
#dtrace a:hover,
|
20
|
+
#dtrace a:active {
|
21
|
+
text-decoration:underline;
|
22
|
+
}
|
23
|
+
|
24
|
+
#dtrace .dtrace-tab {
|
25
|
+
background-color:#fff;
|
26
|
+
padding:1em;
|
27
|
+
margin:0;
|
28
|
+
}
|
29
|
+
|
30
|
+
#dtrace-tabs {
|
31
|
+
width:100%;
|
32
|
+
height:25px;
|
33
|
+
margin:0; padding:0;
|
34
|
+
list-style-type:none;
|
35
|
+
background:#000;
|
36
|
+
}
|
37
|
+
|
38
|
+
#dtrace-tabs li {
|
39
|
+
float:left;
|
40
|
+
}
|
41
|
+
|
42
|
+
#dtrace-tabs li a,
|
43
|
+
#dtrace-tabs li a:visited {
|
44
|
+
display:block;
|
45
|
+
line-height:25px;
|
46
|
+
margin:0 1em;
|
47
|
+
color:#fff;
|
48
|
+
}
|
@@ -0,0 +1,52 @@
|
|
1
|
+
namespace :dtrace do
|
2
|
+
|
3
|
+
desc 'Set up dtrace in your rails application'
|
4
|
+
task :setup do
|
5
|
+
['dtracer'].each do |script|
|
6
|
+
script_dest = "#{RAILS_ROOT}/script/#{script}"
|
7
|
+
script_src = File.dirname(__FILE__) + "/../bin/#{script}.rb"
|
8
|
+
|
9
|
+
FileUtils.chmod 0774, script_src
|
10
|
+
|
11
|
+
unless File.exists?(script_dest)
|
12
|
+
puts "Copying acts_as_encrypted script #{script}.rb to #{script_dest}"
|
13
|
+
FileUtils.cp_r(script_src, script_dest)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
['stylesheets/dtrace.css'].each do |asset|
|
18
|
+
asset_dest = "#{RAILS_ROOT}/public/#{asset}"
|
19
|
+
asset_src = File.dirname(__FILE__) + "/../public/#{asset}"
|
20
|
+
|
21
|
+
FileUtils.chmod 0774, asset_src
|
22
|
+
|
23
|
+
unless File.exists?(asset_dest)
|
24
|
+
puts "Copying acts_as_encrypted asset #{asset} to #{asset_dest}"
|
25
|
+
FileUtils.cp_r(asset_src, asset_dest)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
desc 'Remove dtrace from your rails application'
|
31
|
+
task :remove do
|
32
|
+
['dtracer'].each do |script|
|
33
|
+
script_dest = "#{RAILS_ROOT}/script/#{script}"
|
34
|
+
|
35
|
+
if File.exists?(script_dest)
|
36
|
+
puts "Removing #{script_dest} ..."
|
37
|
+
FileUtils.rm(script_dest, :force => true)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
['stylesheets/dtrace.css'].each do |asset|
|
42
|
+
asset_dest = "#{RAILS_ROOT}/public/#{asset}"
|
43
|
+
|
44
|
+
if File.exists?(asset_dest)
|
45
|
+
puts "Removing #{asset_dest} ..."
|
46
|
+
FileUtils.rm(asset_dest, :force => true)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
data/test/test_dtrace.rb
ADDED
@@ -0,0 +1,415 @@
|
|
1
|
+
#
|
2
|
+
# Ruby-Dtrace
|
3
|
+
# (c) 2007 Chris Andrews <chris@nodnol.org>
|
4
|
+
#
|
5
|
+
|
6
|
+
require 'dtrace'
|
7
|
+
require 'test/unit'
|
8
|
+
|
9
|
+
class TestDtrace < Test::Unit::TestCase
|
10
|
+
def test_dtrace
|
11
|
+
t = Dtrace.new
|
12
|
+
assert_equal Object, Dtrace.superclass
|
13
|
+
assert_equal Dtrace, t.class
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_list_probes
|
17
|
+
t = Dtrace.new
|
18
|
+
probe_count = 0
|
19
|
+
t.each_probe do |probe|
|
20
|
+
assert probe.provider
|
21
|
+
assert probe.mod
|
22
|
+
assert probe.func
|
23
|
+
assert probe.name
|
24
|
+
probe_count += 1
|
25
|
+
end
|
26
|
+
assert probe_count
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_compile
|
30
|
+
t = Dtrace.new
|
31
|
+
|
32
|
+
progtext = "syscall:::entry
|
33
|
+
{
|
34
|
+
@calls[execname] = count();
|
35
|
+
@fcalls[probefunc] = count();
|
36
|
+
}"
|
37
|
+
|
38
|
+
prog = t.compile progtext
|
39
|
+
assert prog
|
40
|
+
prog.execute
|
41
|
+
|
42
|
+
info = prog.info
|
43
|
+
assert info
|
44
|
+
assert info.aggregates_count
|
45
|
+
assert_equal 0, info.speculations_count
|
46
|
+
assert info.recgens_count
|
47
|
+
assert info.matches_count
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_compile_with_args
|
51
|
+
t = Dtrace.new
|
52
|
+
|
53
|
+
progtext = "syscall:::entry
|
54
|
+
/pid == $1/
|
55
|
+
{
|
56
|
+
@calls[execname] = count();
|
57
|
+
@fcalls[probefunc] = count();
|
58
|
+
}"
|
59
|
+
|
60
|
+
prog = t.compile(progtext, $$.to_s)
|
61
|
+
assert prog
|
62
|
+
prog.execute
|
63
|
+
|
64
|
+
info = prog.info
|
65
|
+
assert info
|
66
|
+
assert_equal 2, info.aggregates_count
|
67
|
+
assert_equal 0, info.speculations_count
|
68
|
+
assert_equal 4, info.recgens_count
|
69
|
+
|
70
|
+
# matches_count is platform dependent
|
71
|
+
assert info.matches_count
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_run
|
75
|
+
t = Dtrace.new
|
76
|
+
|
77
|
+
t.setopt("aggsize", "4m")
|
78
|
+
t.setopt("bufsize", "4m")
|
79
|
+
|
80
|
+
progtext = "syscall:::entry
|
81
|
+
{
|
82
|
+
@calls[execname] = count();
|
83
|
+
@fcalls[probefunc] = count();
|
84
|
+
}"
|
85
|
+
|
86
|
+
prog = t.compile progtext
|
87
|
+
assert prog
|
88
|
+
prog.execute
|
89
|
+
assert_equal 0, t.status # none
|
90
|
+
|
91
|
+
t.go
|
92
|
+
|
93
|
+
assert_equal 1, t.status # ok
|
94
|
+
sleep 1
|
95
|
+
assert_equal 1, t.status # ok
|
96
|
+
t.stop
|
97
|
+
assert_equal 4, t.status # stopped
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_aggregate_print
|
101
|
+
t = Dtrace.new
|
102
|
+
|
103
|
+
t.setopt("aggsize", "4m")
|
104
|
+
t.setopt("bufsize", "4m")
|
105
|
+
|
106
|
+
progtext = "syscall:::entry
|
107
|
+
{
|
108
|
+
@calls[execname] = count();
|
109
|
+
@fcalls[probefunc] = count();
|
110
|
+
}"
|
111
|
+
|
112
|
+
prog = t.compile progtext
|
113
|
+
assert prog
|
114
|
+
prog.execute
|
115
|
+
|
116
|
+
t.go
|
117
|
+
sleep 1
|
118
|
+
t.stop
|
119
|
+
|
120
|
+
t.aggregate_snap
|
121
|
+
t.aggregate_print
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_aggregate_walk
|
125
|
+
t = Dtrace.new
|
126
|
+
|
127
|
+
t.setopt("aggsize", "4m")
|
128
|
+
t.setopt("bufsize", "4m")
|
129
|
+
|
130
|
+
progtext = "syscall:::entry
|
131
|
+
{
|
132
|
+
@fcalls[probefunc] = count();
|
133
|
+
@calls[execname] = count();
|
134
|
+
}"
|
135
|
+
|
136
|
+
prog = t.compile progtext
|
137
|
+
assert prog
|
138
|
+
prog.execute
|
139
|
+
|
140
|
+
t.go
|
141
|
+
sleep 1
|
142
|
+
t.stop
|
143
|
+
|
144
|
+
t.aggregate_snap
|
145
|
+
|
146
|
+
t.each_aggregate do |agg|
|
147
|
+
agg.each_record do |rec|
|
148
|
+
assert rec
|
149
|
+
assert rec.data
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_aggregate_record_array
|
155
|
+
t = Dtrace.new
|
156
|
+
|
157
|
+
t.setopt("aggsize", "4m")
|
158
|
+
t.setopt("bufsize", "4m")
|
159
|
+
|
160
|
+
progtext = "syscall:::entry
|
161
|
+
{
|
162
|
+
@calls[execname] = count();
|
163
|
+
}"
|
164
|
+
|
165
|
+
prog = t.compile progtext
|
166
|
+
assert prog
|
167
|
+
prog.execute
|
168
|
+
|
169
|
+
t.go
|
170
|
+
sleep 1
|
171
|
+
t.stop
|
172
|
+
|
173
|
+
t.aggregate_snap
|
174
|
+
|
175
|
+
t.each_aggregate do |agg|
|
176
|
+
assert agg
|
177
|
+
assert agg.num_records
|
178
|
+
(0..(agg.num_records - 1)).each do |i|
|
179
|
+
rec = agg[i]
|
180
|
+
assert rec.data
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def test_aggregate_record_array_continuous
|
186
|
+
t = Dtrace.new
|
187
|
+
|
188
|
+
t.setopt("aggsize", "4m")
|
189
|
+
t.setopt("bufsize", "4m")
|
190
|
+
|
191
|
+
progtext = "syscall:::entry
|
192
|
+
{
|
193
|
+
@calls[execname] = count();
|
194
|
+
}"
|
195
|
+
|
196
|
+
prog = t.compile progtext
|
197
|
+
assert prog
|
198
|
+
prog.execute
|
199
|
+
|
200
|
+
t.go
|
201
|
+
|
202
|
+
(1..10).each do
|
203
|
+
sleep 1
|
204
|
+
t.aggregate_snap
|
205
|
+
|
206
|
+
t.each_aggregate do |agg|
|
207
|
+
assert agg
|
208
|
+
assert agg.num_records
|
209
|
+
(0..(agg.num_records - 1)).each do |i|
|
210
|
+
rec = agg[i]
|
211
|
+
assert rec.data
|
212
|
+
end
|
213
|
+
end
|
214
|
+
t.aggregate_clear
|
215
|
+
end
|
216
|
+
|
217
|
+
t.stop
|
218
|
+
end
|
219
|
+
|
220
|
+
def test_bad_program
|
221
|
+
t = Dtrace.new
|
222
|
+
progtext = "blah blahb albhacasfas"
|
223
|
+
e = assert_raise DtraceException do
|
224
|
+
prog = t.compile progtext
|
225
|
+
end
|
226
|
+
assert_equal "probe description :::blah does not match any probes", e.message
|
227
|
+
end
|
228
|
+
|
229
|
+
def test_rubys_own_dtrace
|
230
|
+
t = Dtrace.new
|
231
|
+
|
232
|
+
t.setopt("aggsize", "4m")
|
233
|
+
t.setopt("bufsize", "4m")
|
234
|
+
|
235
|
+
progtext = "ruby*:::function-entry{ @[copyinstr(arg1)] = count(); }"
|
236
|
+
|
237
|
+
prog = t.compile progtext
|
238
|
+
assert prog
|
239
|
+
prog.execute
|
240
|
+
|
241
|
+
t.go
|
242
|
+
|
243
|
+
foo = 0
|
244
|
+
(1..1000).each do |i|
|
245
|
+
foo = foo + i
|
246
|
+
end
|
247
|
+
|
248
|
+
t.stop
|
249
|
+
t.aggregate_snap
|
250
|
+
|
251
|
+
t.each_aggregate do |agg|
|
252
|
+
assert agg
|
253
|
+
assert agg.num_records
|
254
|
+
(0..(agg.num_records - 1)).each do |i|
|
255
|
+
rec = agg[i]
|
256
|
+
assert rec.data
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def test_multiple_programs
|
262
|
+
t = Dtrace.new
|
263
|
+
|
264
|
+
t.setopt("aggsize", "4m")
|
265
|
+
t.setopt("bufsize", "4m")
|
266
|
+
|
267
|
+
progtext = "syscall:::entry
|
268
|
+
{
|
269
|
+
@calls[execname] = count();
|
270
|
+
}"
|
271
|
+
|
272
|
+
prog1 = t.compile progtext
|
273
|
+
assert prog1
|
274
|
+
|
275
|
+
progtext = "syscall:::entry
|
276
|
+
{
|
277
|
+
@fcalls[probefunc] = count();
|
278
|
+
}"
|
279
|
+
|
280
|
+
prog2 = t.compile progtext
|
281
|
+
assert prog2
|
282
|
+
|
283
|
+
prog1.execute
|
284
|
+
prog2.execute
|
285
|
+
|
286
|
+
info1 = prog1.info
|
287
|
+
assert info1
|
288
|
+
assert_equal 1, info1.aggregates_count
|
289
|
+
assert_equal 0, info1.speculations_count
|
290
|
+
assert_equal 2, info1.recgens_count
|
291
|
+
assert info1.matches_count
|
292
|
+
|
293
|
+
info2 = prog2.info
|
294
|
+
assert info2
|
295
|
+
assert_equal 1, info2.aggregates_count
|
296
|
+
assert_equal 0, info2.speculations_count
|
297
|
+
assert_equal 2, info2.recgens_count
|
298
|
+
assert info2.matches_count
|
299
|
+
|
300
|
+
t.go
|
301
|
+
sleep 2
|
302
|
+
t.stop
|
303
|
+
t.aggregate_snap
|
304
|
+
|
305
|
+
t.each_aggregate do |agg|
|
306
|
+
assert agg
|
307
|
+
assert agg.num_records
|
308
|
+
(0..(agg.num_records - 1)).each do |i|
|
309
|
+
rec = agg[i]
|
310
|
+
assert rec.data
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
def test_multiple_runs
|
316
|
+
t = Dtrace.new
|
317
|
+
t.setopt("aggsize", "4m")
|
318
|
+
t.setopt("bufsize", "4m")
|
319
|
+
|
320
|
+
progtext = "ruby*:::function-entry{ @[copyinstr(arg1)] = count(); }"
|
321
|
+
|
322
|
+
prog = t.compile progtext
|
323
|
+
assert prog
|
324
|
+
prog.execute
|
325
|
+
|
326
|
+
t.go
|
327
|
+
|
328
|
+
foo = 0
|
329
|
+
(1..1000).each do |i|
|
330
|
+
foo = foo + i
|
331
|
+
end
|
332
|
+
|
333
|
+
t.stop
|
334
|
+
t.aggregate_snap
|
335
|
+
|
336
|
+
t.each_aggregate do |agg|
|
337
|
+
assert agg
|
338
|
+
assert agg.num_records
|
339
|
+
(0..(agg.num_records - 1)).each do |i|
|
340
|
+
rec = agg[i]
|
341
|
+
assert rec.data
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
t = Dtrace.new
|
346
|
+
t.setopt("aggsize", "4m")
|
347
|
+
t.setopt("bufsize", "4m")
|
348
|
+
|
349
|
+
prog = t.compile progtext
|
350
|
+
assert prog
|
351
|
+
|
352
|
+
prog.execute
|
353
|
+
|
354
|
+
t.go
|
355
|
+
|
356
|
+
foo = 0
|
357
|
+
(1..1000).each do |i|
|
358
|
+
foo = foo + i
|
359
|
+
end
|
360
|
+
|
361
|
+
t.stop
|
362
|
+
t.aggregate_snap
|
363
|
+
|
364
|
+
t.each_aggregate do |agg|
|
365
|
+
assert agg
|
366
|
+
assert agg.num_records
|
367
|
+
(0..(agg.num_records - 1)).each do |i|
|
368
|
+
rec = agg[i]
|
369
|
+
assert rec.data
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
end
|
374
|
+
|
375
|
+
def test_aggdata_probe
|
376
|
+
t = Dtrace.new
|
377
|
+
|
378
|
+
t.setopt("aggsize", "4m")
|
379
|
+
t.setopt("bufsize", "4m")
|
380
|
+
|
381
|
+
progtext = "ruby*:::function-entry{ @[copyinstr(arg1)] = count(); }"
|
382
|
+
|
383
|
+
prog = t.compile progtext
|
384
|
+
assert prog
|
385
|
+
prog.execute
|
386
|
+
|
387
|
+
t.go
|
388
|
+
|
389
|
+
foo = 0
|
390
|
+
(1..1000).each do |i|
|
391
|
+
foo = foo + i
|
392
|
+
end
|
393
|
+
|
394
|
+
t.stop
|
395
|
+
|
396
|
+
t.aggregate_snap
|
397
|
+
|
398
|
+
t.each_aggregate do |agg|
|
399
|
+
|
400
|
+
probe = agg.probe
|
401
|
+
assert probe.provider
|
402
|
+
assert probe.mod
|
403
|
+
assert probe.func
|
404
|
+
assert probe.name
|
405
|
+
|
406
|
+
agg.each_record do |rec|
|
407
|
+
assert rec
|
408
|
+
assert rec.data
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
|
413
|
+
end
|
414
|
+
|
415
|
+
end
|