ruby-prof 0.8.2 → 0.9.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.
- data/CHANGES +23 -13
- data/{README → README.rdoc} +118 -111
- data/Rakefile +14 -26
- data/bin/ruby-prof +16 -4
- data/examples/empty.png +0 -0
- data/examples/graph.dot +106 -0
- data/examples/graph.png +0 -0
- data/examples/minus.png +0 -0
- data/examples/multi.flat.txt +23 -0
- data/examples/multi.graph.html +906 -0
- data/examples/multi.grind.dat +194 -0
- data/examples/multi.stack.html +573 -0
- data/examples/plus.png +0 -0
- data/examples/stack.html +573 -0
- data/ext/ruby_prof/extconf.rb +0 -1
- data/ext/ruby_prof/measure_allocations.h +6 -6
- data/ext/ruby_prof/measure_cpu_time.h +5 -5
- data/ext/ruby_prof/measure_gc_runs.h +1 -1
- data/ext/ruby_prof/measure_gc_time.h +1 -1
- data/ext/ruby_prof/measure_memory.h +4 -4
- data/ext/ruby_prof/measure_process_time.h +1 -1
- data/ext/ruby_prof/measure_wall_time.h +1 -1
- data/ext/ruby_prof/ruby_prof.c +240 -167
- data/ext/ruby_prof/ruby_prof.h +12 -10
- data/ext/ruby_prof/version.h +3 -3
- data/lib/ruby-prof.rb +7 -1
- data/lib/ruby-prof/abstract_printer.rb +5 -5
- data/lib/ruby-prof/aggregate_call_info.rb +9 -3
- data/lib/ruby-prof/call_info.rb +66 -1
- data/lib/ruby-prof/call_stack_printer.rb +751 -0
- data/lib/ruby-prof/call_tree_printer.rb +2 -2
- data/lib/ruby-prof/dot_printer.rb +151 -0
- data/lib/ruby-prof/empty.png +0 -0
- data/lib/ruby-prof/flat_printer.rb +16 -16
- data/lib/ruby-prof/flat_printer_with_line_numbers.rb +13 -13
- data/lib/ruby-prof/graph_html_printer.rb +58 -36
- data/lib/ruby-prof/graph_printer.rb +30 -30
- data/lib/ruby-prof/method_info.rb +24 -4
- data/lib/ruby-prof/minus.png +0 -0
- data/lib/ruby-prof/multi_printer.rb +54 -0
- data/lib/ruby-prof/plus.png +0 -0
- data/lib/ruby-prof/rack.rb +28 -0
- data/lib/ruby-prof/result.rb +70 -0
- data/lib/ruby-prof/symbol_to_proc.rb +1 -1
- data/lib/ruby-prof/task.rb +19 -19
- data/lib/ruby-prof/test.rb +3 -3
- data/lib/ruby_prof.so +0 -0
- data/rails/environment/profile.rb +2 -2
- data/rails/example/example_test.rb +2 -2
- data/rails/profile_test_helper.rb +1 -1
- data/test/aggregate_test.rb +21 -6
- data/test/basic_test.rb +3 -3
- data/test/duplicate_names_test.rb +2 -2
- data/test/enumerable_test.rb +2 -2
- data/test/exceptions_test.rb +2 -2
- data/test/exclude_threads_test.rb +45 -45
- data/test/exec_test.rb +2 -2
- data/test/line_number_test.rb +11 -11
- data/test/measurement_test.rb +4 -3
- data/test/method_elimination_test.rb +74 -0
- data/test/module_test.rb +7 -7
- data/test/multi_printer_test.rb +81 -0
- data/test/no_method_class_test.rb +2 -2
- data/test/prime.rb +7 -10
- data/test/printers_test.rb +57 -47
- data/test/recursive_test.rb +23 -62
- data/test/singleton_test.rb +3 -2
- data/test/stack_printer_test.rb +74 -0
- data/test/stack_test.rb +1 -1
- data/test/start_stop_test.rb +2 -2
- data/test/test_suite.rb +9 -0
- data/test/thread_test.rb +17 -17
- data/test/unique_call_path_test.rb +4 -4
- metadata +29 -8
data/ext/ruby_prof/extconf.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
/* :nodoc:
|
1
|
+
/* :nodoc:
|
2
2
|
* Copyright (C) 2008 Shugo Maeda <shugo@ruby-lang.org>
|
3
3
|
* Charlie Savage <cfis@savagexi.com>
|
4
4
|
* All rights reserved.
|
@@ -28,17 +28,17 @@
|
|
28
28
|
|
29
29
|
#if defined(HAVE_RB_OS_ALLOCATED_OBJECTS)
|
30
30
|
#define MEASURE_ALLOCATIONS 3
|
31
|
-
|
31
|
+
|
32
32
|
static prof_measure_t
|
33
33
|
measure_allocations()
|
34
|
-
{
|
35
|
-
return rb_os_allocated_objects();
|
34
|
+
{
|
35
|
+
return rb_os_allocated_objects();
|
36
36
|
}
|
37
37
|
|
38
38
|
static double
|
39
39
|
convert_allocations(prof_measure_t c)
|
40
|
-
{
|
41
|
-
return c;
|
40
|
+
{
|
41
|
+
return c;
|
42
42
|
}
|
43
43
|
|
44
44
|
/* Document-method: prof_measure_allocations
|
@@ -1,4 +1,4 @@
|
|
1
|
-
/* :nodoc:
|
1
|
+
/* :nodoc:
|
2
2
|
* Copyright (C) 2008 Shugo Maeda <shugo@ruby-lang.org>
|
3
3
|
* Charlie Savage <cfis@savagexi.com>
|
4
4
|
* All rights reserved.
|
@@ -38,7 +38,7 @@ static unsigned LONG_LONG cpu_frequency;
|
|
38
38
|
static prof_measure_t
|
39
39
|
measure_cpu_time()
|
40
40
|
{
|
41
|
-
#if defined(__i386__) || defined(__x86_64__)
|
41
|
+
#if defined(__i386__) || defined(__x86_64__)
|
42
42
|
uint32_t a, d;
|
43
43
|
__asm__ volatile("rdtsc" : "=a" (a), "=d" (d));
|
44
44
|
return ((uint64_t)d << 32) + a;
|
@@ -46,7 +46,7 @@ measure_cpu_time()
|
|
46
46
|
unsigned long long x, y;
|
47
47
|
|
48
48
|
__asm__ __volatile__ ("\n\
|
49
|
-
1:
|
49
|
+
1: mftbu %1\n\
|
50
50
|
mftb %L0\n\
|
51
51
|
mftbu %0\n\
|
52
52
|
cmpw %0,%1\n\
|
@@ -128,7 +128,7 @@ prof_measure_cpu_time(VALUE self)
|
|
128
128
|
call-seq:
|
129
129
|
cpu_frequency -> int
|
130
130
|
|
131
|
-
Returns the cpu's frequency. This value is needed when
|
131
|
+
Returns the cpu's frequency. This value is needed when
|
132
132
|
RubyProf::measure_mode is set to CPU_TIME. */
|
133
133
|
static VALUE
|
134
134
|
prof_get_cpu_frequency(VALUE self)
|
@@ -140,7 +140,7 @@ prof_get_cpu_frequency(VALUE self)
|
|
140
140
|
call-seq:
|
141
141
|
cpu_frequency=value -> void
|
142
142
|
|
143
|
-
Sets the cpu's frequency. This value is needed when
|
143
|
+
Sets the cpu's frequency. This value is needed when
|
144
144
|
RubyProf::measure_mode is set to CPU_TIME. */
|
145
145
|
static VALUE
|
146
146
|
prof_set_cpu_frequency(VALUE self, VALUE val)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
/* :nodoc:
|
1
|
+
/* :nodoc:
|
2
2
|
* Copyright (C) 2008 Alexander Dymo <adymo@pluron.com>
|
3
3
|
*
|
4
4
|
* All rights reserved.
|
@@ -28,7 +28,7 @@
|
|
28
28
|
#if defined(HAVE_RB_GC_ALLOCATED_SIZE)
|
29
29
|
#define MEASURE_MEMORY 4
|
30
30
|
#define TOGGLE_GC_STATS 1
|
31
|
-
|
31
|
+
|
32
32
|
static prof_measure_t
|
33
33
|
measure_memory()
|
34
34
|
{
|
@@ -41,8 +41,8 @@ measure_memory()
|
|
41
41
|
|
42
42
|
static double
|
43
43
|
convert_memory(prof_measure_t c)
|
44
|
-
{
|
45
|
-
return (double) c / 1024;
|
44
|
+
{
|
45
|
+
return (double) c / 1024;
|
46
46
|
}
|
47
47
|
|
48
48
|
/* Document-method: prof_measure_memory
|
data/ext/ruby_prof/ruby_prof.c
CHANGED
@@ -29,22 +29,22 @@
|
|
29
29
|
The main players are:
|
30
30
|
|
31
31
|
prof_result_t - Its one field, values, contains the overall results
|
32
|
-
thread_data_t - Stores data about a single thread.
|
32
|
+
thread_data_t - Stores data about a single thread.
|
33
33
|
prof_stack_t - The method call stack in a particular thread
|
34
34
|
prof_method_t - Profiling information for each method
|
35
|
-
prof_call_info_t - Keeps track a method's callers and callees.
|
35
|
+
prof_call_info_t - Keeps track a method's callers and callees.
|
36
36
|
|
37
37
|
The final resulut is a hash table of thread_data_t, keyed on the thread
|
38
38
|
id. Each thread has an hash a table of prof_method_t, keyed on the
|
39
39
|
method id. A hash table is used for quick look up when doing a profile.
|
40
40
|
However, it is exposed to Ruby as an array.
|
41
|
-
|
41
|
+
|
42
42
|
Each prof_method_t has two hash tables, parent and children, of prof_call_info_t.
|
43
43
|
These objects keep track of a method's callers (who called the method) and its
|
44
44
|
callees (who the method called). These are keyed the method id, but once again,
|
45
45
|
are exposed to Ruby as arrays. Each prof_call_into_t maintains a pointer to the
|
46
|
-
caller or callee method, thereby making it easy to navigate through the call
|
47
|
-
hierarchy in ruby - which is very helpful for creating call graphs.
|
46
|
+
caller or callee method, thereby making it easy to navigate through the call
|
47
|
+
hierarchy in ruby - which is very helpful for creating call graphs.
|
48
48
|
*/
|
49
49
|
|
50
50
|
#include "ruby_prof.h"
|
@@ -92,7 +92,7 @@ figure_singleton_name(VALUE klass)
|
|
92
92
|
rb_str_append(result, rb_inspect(super));
|
93
93
|
rb_str_cat2(result, ">");
|
94
94
|
}
|
95
|
-
|
95
|
+
|
96
96
|
/* Ok, this could be other things like an array made put onto
|
97
97
|
a singleton object (yeah, it happens, see the singleton
|
98
98
|
objects test case). */
|
@@ -108,7 +108,7 @@ static VALUE
|
|
108
108
|
klass_name(VALUE klass)
|
109
109
|
{
|
110
110
|
VALUE result = Qnil;
|
111
|
-
|
111
|
+
|
112
112
|
if (klass == 0 || klass == Qnil)
|
113
113
|
{
|
114
114
|
result = rb_str_new2("Global");
|
@@ -135,34 +135,27 @@ klass_name(VALUE klass)
|
|
135
135
|
}
|
136
136
|
|
137
137
|
static VALUE
|
138
|
-
method_name(ID mid
|
138
|
+
method_name(ID mid)
|
139
139
|
{
|
140
140
|
VALUE result;
|
141
141
|
|
142
|
-
if (mid == ID_ALLOCATOR)
|
142
|
+
if (mid == ID_ALLOCATOR)
|
143
143
|
result = rb_str_new2("allocate");
|
144
144
|
else if (mid == 0)
|
145
145
|
result = rb_str_new2("[No method]");
|
146
146
|
else
|
147
147
|
result = rb_String(ID2SYM(mid));
|
148
|
-
|
149
|
-
if (depth > 0)
|
150
|
-
{
|
151
|
-
char buffer[65];
|
152
|
-
sprintf(buffer, "(d%i)", depth);
|
153
|
-
rb_str_cat2(result, buffer);
|
154
|
-
}
|
155
148
|
|
156
149
|
return result;
|
157
150
|
}
|
158
151
|
|
159
152
|
static VALUE
|
160
|
-
full_name(VALUE klass, ID mid
|
153
|
+
full_name(VALUE klass, ID mid)
|
161
154
|
{
|
162
155
|
VALUE result = klass_name(klass);
|
163
156
|
rb_str_cat2(result, "#");
|
164
|
-
rb_str_append(result, method_name(mid
|
165
|
-
|
157
|
+
rb_str_append(result, method_name(mid));
|
158
|
+
|
166
159
|
return result;
|
167
160
|
}
|
168
161
|
|
@@ -221,16 +214,14 @@ stack_peek(prof_stack_t *stack)
|
|
221
214
|
}
|
222
215
|
|
223
216
|
/* ================ Method Key =================*/
|
224
|
-
static int
|
225
|
-
method_table_cmp(prof_method_key_t *key1, prof_method_key_t *key2)
|
217
|
+
static int
|
218
|
+
method_table_cmp(prof_method_key_t *key1, prof_method_key_t *key2)
|
226
219
|
{
|
227
|
-
return (key1->klass != key2->klass) ||
|
228
|
-
(key1->mid != key2->mid) ||
|
229
|
-
(key1->depth != key2->depth);
|
220
|
+
return (key1->klass != key2->klass) || (key1->mid != key2->mid);
|
230
221
|
}
|
231
222
|
|
232
|
-
static
|
233
|
-
method_table_hash(prof_method_key_t *key)
|
223
|
+
static st_index_t
|
224
|
+
method_table_hash(prof_method_key_t *key)
|
234
225
|
{
|
235
226
|
return key->key;
|
236
227
|
}
|
@@ -241,12 +232,11 @@ static struct st_hash_type type_method_hash = {
|
|
241
232
|
};
|
242
233
|
|
243
234
|
static void
|
244
|
-
method_key(prof_method_key_t* key, VALUE klass, ID mid
|
235
|
+
method_key(prof_method_key_t* key, VALUE klass, ID mid)
|
245
236
|
{
|
246
237
|
key->klass = klass;
|
247
238
|
key->mid = mid;
|
248
|
-
key->
|
249
|
-
key->key = (klass << 4) + (mid << 2) + depth;
|
239
|
+
key->key = (klass << 4) + (mid << 2);
|
250
240
|
}
|
251
241
|
|
252
242
|
|
@@ -334,7 +324,7 @@ prof_call_info_mark(prof_call_info_t *call_info)
|
|
334
324
|
static void
|
335
325
|
prof_call_info_free(prof_call_info_t *call_info)
|
336
326
|
{
|
337
|
-
call_info_table_free(call_info->call_infos);
|
327
|
+
call_info_table_free(call_info->call_infos);
|
338
328
|
xfree(call_info);
|
339
329
|
}
|
340
330
|
|
@@ -370,7 +360,7 @@ prof_call_info_target(VALUE self)
|
|
370
360
|
/* Target is a pointer to a method_info - so we have to be careful
|
371
361
|
about the GC. We will wrap the method_info but provide no
|
372
362
|
free method so the underlying object is not freed twice! */
|
373
|
-
|
363
|
+
|
374
364
|
prof_call_info_t *result = prof_get_call_info_result(self);
|
375
365
|
return prof_method_wrap(result->target);
|
376
366
|
}
|
@@ -386,6 +376,18 @@ prof_call_info_called(VALUE self)
|
|
386
376
|
return INT2NUM(result->called);
|
387
377
|
}
|
388
378
|
|
379
|
+
/* call-seq:
|
380
|
+
called=n -> n
|
381
|
+
|
382
|
+
Sets the call count to n. */
|
383
|
+
static VALUE
|
384
|
+
prof_call_info_set_called(VALUE self, VALUE called)
|
385
|
+
{
|
386
|
+
prof_call_info_t *result = prof_get_call_info_result(self);
|
387
|
+
result->called = NUM2INT(called);
|
388
|
+
return called;
|
389
|
+
}
|
390
|
+
|
389
391
|
/* call-seq:
|
390
392
|
line_no -> int
|
391
393
|
|
@@ -408,6 +410,20 @@ prof_call_info_total_time(VALUE self)
|
|
408
410
|
return rb_float_new(convert_measurement(result->total_time));
|
409
411
|
}
|
410
412
|
|
413
|
+
/* call-seq:
|
414
|
+
add_total_time(call_info) -> nil
|
415
|
+
|
416
|
+
adds total time time from call_info to self. */
|
417
|
+
static VALUE
|
418
|
+
prof_call_info_add_total_time(VALUE self, VALUE other)
|
419
|
+
{
|
420
|
+
prof_call_info_t *result = prof_get_call_info_result(self);
|
421
|
+
prof_call_info_t *other_info = prof_get_call_info_result(other);
|
422
|
+
|
423
|
+
result->total_time += other_info->total_time;
|
424
|
+
return Qnil;
|
425
|
+
}
|
426
|
+
|
411
427
|
/* call-seq:
|
412
428
|
self_time -> float
|
413
429
|
|
@@ -420,6 +436,20 @@ prof_call_info_self_time(VALUE self)
|
|
420
436
|
return rb_float_new(convert_measurement(result->self_time));
|
421
437
|
}
|
422
438
|
|
439
|
+
/* call-seq:
|
440
|
+
add_self_time(call_info) -> nil
|
441
|
+
|
442
|
+
adds self time from call_info to self. */
|
443
|
+
static VALUE
|
444
|
+
prof_call_info_add_self_time(VALUE self, VALUE other)
|
445
|
+
{
|
446
|
+
prof_call_info_t *result = prof_get_call_info_result(self);
|
447
|
+
prof_call_info_t *other_info = prof_get_call_info_result(other);
|
448
|
+
|
449
|
+
result->self_time += other_info->self_time;
|
450
|
+
return Qnil;
|
451
|
+
}
|
452
|
+
|
423
453
|
/* call-seq:
|
424
454
|
wait_time -> float
|
425
455
|
|
@@ -432,6 +462,21 @@ prof_call_info_wait_time(VALUE self)
|
|
432
462
|
return rb_float_new(convert_measurement(result->wait_time));
|
433
463
|
}
|
434
464
|
|
465
|
+
/* call-seq:
|
466
|
+
add_wait_time(call_info) -> nil
|
467
|
+
|
468
|
+
adds wait time from call_info to self. */
|
469
|
+
|
470
|
+
static VALUE
|
471
|
+
prof_call_info_add_wait_time(VALUE self, VALUE other)
|
472
|
+
{
|
473
|
+
prof_call_info_t *result = prof_get_call_info_result(self);
|
474
|
+
prof_call_info_t *other_info = prof_get_call_info_result(other);
|
475
|
+
|
476
|
+
result->wait_time += other_info->wait_time;
|
477
|
+
return Qnil;
|
478
|
+
}
|
479
|
+
|
435
480
|
/* call-seq:
|
436
481
|
parent -> call_info
|
437
482
|
|
@@ -446,6 +491,21 @@ prof_call_info_parent(VALUE self)
|
|
446
491
|
return Qnil;
|
447
492
|
}
|
448
493
|
|
494
|
+
/* call-seq:
|
495
|
+
parent=new_parent -> new_parent
|
496
|
+
|
497
|
+
Changes the parent of self to new_parent and returns it.*/
|
498
|
+
static VALUE
|
499
|
+
prof_call_info_set_parent(VALUE self, VALUE new_parent)
|
500
|
+
{
|
501
|
+
prof_call_info_t *result = prof_get_call_info_result(self);
|
502
|
+
if (new_parent == Qnil)
|
503
|
+
result->parent = NULL;
|
504
|
+
else
|
505
|
+
result->parent = prof_get_call_info_result(new_parent);
|
506
|
+
return prof_call_info_parent(self);
|
507
|
+
}
|
508
|
+
|
449
509
|
static int
|
450
510
|
prof_call_info_collect_children(st_data_t key, st_data_t value, st_data_t result)
|
451
511
|
{
|
@@ -458,7 +518,7 @@ prof_call_info_collect_children(st_data_t key, st_data_t value, st_data_t result
|
|
458
518
|
/* call-seq:
|
459
519
|
children -> hash
|
460
520
|
|
461
|
-
Returns an array of call info objects of methods that this method
|
521
|
+
Returns an array of call info objects of methods that this method
|
462
522
|
called (ie, children).*/
|
463
523
|
static VALUE
|
464
524
|
prof_call_info_children(VALUE self)
|
@@ -539,24 +599,22 @@ prof_method_create(prof_method_key_t *key, const char* source_file, int line)
|
|
539
599
|
prof_method_t *result = ALLOC(prof_method_t);
|
540
600
|
result->object = Qnil;
|
541
601
|
result->key = ALLOC(prof_method_key_t);
|
542
|
-
method_key(result->key, key->klass, key->mid
|
602
|
+
method_key(result->key, key->klass, key->mid);
|
543
603
|
|
544
604
|
result->call_infos = prof_call_infos_create();
|
545
605
|
|
546
|
-
|
547
|
-
|
548
|
-
if (source_file != NULL)
|
606
|
+
if (source_file != NULL)
|
549
607
|
{
|
550
|
-
|
608
|
+
size_t len = strlen(source_file) + 1;
|
551
609
|
char *buffer = ALLOC_N(char, len);
|
552
610
|
|
553
611
|
MEMCPY(buffer, source_file, char, len);
|
554
612
|
result->source_file = buffer;
|
555
613
|
}
|
556
|
-
else
|
557
|
-
{
|
614
|
+
else
|
615
|
+
{
|
558
616
|
result->source_file = source_file;
|
559
|
-
}
|
617
|
+
}
|
560
618
|
result->line = line;
|
561
619
|
|
562
620
|
return result;
|
@@ -574,7 +632,7 @@ prof_method_free(prof_method_t *method)
|
|
574
632
|
{
|
575
633
|
if (method->source_file)
|
576
634
|
{
|
577
|
-
xfree((char*)method->source_file);
|
635
|
+
xfree((char*)method->source_file);
|
578
636
|
}
|
579
637
|
|
580
638
|
prof_call_infos_free(method->call_infos);
|
@@ -611,7 +669,7 @@ prof_method_line(VALUE self)
|
|
611
669
|
/* call-seq:
|
612
670
|
source_file => string
|
613
671
|
|
614
|
-
return the source file of the method
|
672
|
+
return the source file of the method
|
615
673
|
*/
|
616
674
|
static VALUE prof_method_source_file(VALUE self)
|
617
675
|
{
|
@@ -669,10 +727,10 @@ Returns the name of this method in the format Object#method. Singletons
|
|
669
727
|
methods will be returned in the format <Object::Object>#method.*/
|
670
728
|
|
671
729
|
static VALUE
|
672
|
-
prof_method_name(VALUE self
|
730
|
+
prof_method_name(VALUE self)
|
673
731
|
{
|
674
732
|
prof_method_t *method = get_prof_method(self);
|
675
|
-
return method_name(method->key->mid
|
733
|
+
return method_name(method->key->mid);
|
676
734
|
}
|
677
735
|
|
678
736
|
/* call-seq:
|
@@ -684,13 +742,13 @@ static VALUE
|
|
684
742
|
prof_full_name(VALUE self)
|
685
743
|
{
|
686
744
|
prof_method_t *method = get_prof_method(self);
|
687
|
-
return full_name(method->key->klass, method->key->mid
|
745
|
+
return full_name(method->key->klass, method->key->mid);
|
688
746
|
}
|
689
747
|
|
690
748
|
/* call-seq:
|
691
749
|
call_infos -> Array of call_info
|
692
750
|
|
693
|
-
Returns an array of call info objects that contain profiling information
|
751
|
+
Returns an array of call info objects that contain profiling information
|
694
752
|
about the current method.*/
|
695
753
|
static VALUE
|
696
754
|
prof_method_call_infos(VALUE self)
|
@@ -702,7 +760,7 @@ prof_method_call_infos(VALUE self)
|
|
702
760
|
static int
|
703
761
|
collect_methods(st_data_t key, st_data_t value, st_data_t result)
|
704
762
|
{
|
705
|
-
/* Called for each method stored in a thread's method table.
|
763
|
+
/* Called for each method stored in a thread's method table.
|
706
764
|
We want to store the method info information into an array.*/
|
707
765
|
VALUE methods = (VALUE) result;
|
708
766
|
prof_method_t *method = (prof_method_t *) value;
|
@@ -735,7 +793,7 @@ method_table_lookup(st_table *table, const prof_method_key_t* key)
|
|
735
793
|
{
|
736
794
|
return (prof_method_t *) val;
|
737
795
|
}
|
738
|
-
else
|
796
|
+
else
|
739
797
|
{
|
740
798
|
return NULL;
|
741
799
|
}
|
@@ -829,7 +887,7 @@ threads_table_free(st_table *table)
|
|
829
887
|
static int
|
830
888
|
collect_threads(st_data_t key, st_data_t value, st_data_t result)
|
831
889
|
{
|
832
|
-
/* Although threads are keyed on an id, that is actually a
|
890
|
+
/* Although threads are keyed on an id, that is actually a
|
833
891
|
pointer to the VALUE object of the thread. So its bogus.
|
834
892
|
However, in thread_data is the real thread id stored
|
835
893
|
as an int. */
|
@@ -841,7 +899,7 @@ collect_threads(st_data_t key, st_data_t value, st_data_t result)
|
|
841
899
|
/* Now collect an array of all the called methods */
|
842
900
|
st_table* method_table = thread_data->method_table;
|
843
901
|
st_foreach(method_table, collect_methods, methods);
|
844
|
-
|
902
|
+
|
845
903
|
/* Store the results in the threads hash keyed on the thread id. */
|
846
904
|
rb_hash_aset(threads_hash, thread_data->thread_id, methods);
|
847
905
|
|
@@ -850,9 +908,16 @@ collect_threads(st_data_t key, st_data_t value, st_data_t result)
|
|
850
908
|
|
851
909
|
|
852
910
|
/* ================ Profiling =================*/
|
853
|
-
|
854
|
-
|
855
|
-
|
911
|
+
|
912
|
+
/* support tracing ruby events from ruby-prof. useful for getting at
|
913
|
+
what actually happens inside the ruby interpreter (and ruby-prof).
|
914
|
+
set environment variable RUBY_PROF_TRACE to filename you want to
|
915
|
+
find the trace in.
|
916
|
+
*/
|
917
|
+
static FILE* trace_file = NULL;
|
918
|
+
|
919
|
+
/* Copied from eval.c (1.8.x) / thread.c (1.9.2) */
|
920
|
+
static const char *
|
856
921
|
get_event_name(rb_event_flag_t event)
|
857
922
|
{
|
858
923
|
switch (event) {
|
@@ -872,43 +937,43 @@ get_event_name(rb_event_flag_t event)
|
|
872
937
|
return "c-return";
|
873
938
|
case RUBY_EVENT_RAISE:
|
874
939
|
return "raise";
|
875
|
-
|
940
|
+
|
876
941
|
#ifdef RUBY_VM
|
877
942
|
case RUBY_EVENT_SWITCH:
|
878
943
|
return "thread-interrupt";
|
879
944
|
#endif
|
880
|
-
|
945
|
+
|
881
946
|
default:
|
882
947
|
return "unknown";
|
883
948
|
}
|
884
949
|
}
|
885
|
-
#endif
|
886
950
|
|
887
|
-
|
951
|
+
|
952
|
+
static prof_method_t*
|
888
953
|
#ifdef RUBY_VM
|
889
|
-
get_method(rb_event_flag_t event, VALUE klass, ID mid,
|
954
|
+
get_method(rb_event_flag_t event, VALUE klass, ID mid, st_table* method_table)
|
890
955
|
# else
|
891
|
-
get_method(rb_event_flag_t event, NODE *node, VALUE klass, ID mid,
|
892
|
-
#endif
|
956
|
+
get_method(rb_event_flag_t event, NODE *node, VALUE klass, ID mid, st_table* method_table)
|
957
|
+
#endif
|
893
958
|
{
|
894
959
|
prof_method_key_t key;
|
895
960
|
prof_method_t *method = NULL;
|
896
|
-
|
897
|
-
method_key(&key, klass, mid
|
961
|
+
|
962
|
+
method_key(&key, klass, mid);
|
898
963
|
method = method_table_lookup(method_table, &key);
|
899
964
|
|
900
965
|
if (!method)
|
901
966
|
{
|
902
967
|
const char* source_file = rb_sourcefile();
|
903
968
|
int line = rb_sourceline();
|
904
|
-
|
969
|
+
|
905
970
|
/* Line numbers are not accurate for c method calls */
|
906
971
|
if (event == RUBY_EVENT_C_CALL)
|
907
972
|
{
|
908
973
|
line = 0;
|
909
974
|
source_file = NULL;
|
910
975
|
}
|
911
|
-
|
976
|
+
|
912
977
|
method = prof_method_create(&key, source_file, line);
|
913
978
|
method_table_insert(method_table, method->key, method);
|
914
979
|
}
|
@@ -917,18 +982,18 @@ static prof_method_t*
|
|
917
982
|
|
918
983
|
static void
|
919
984
|
update_result(prof_measure_t total_time,
|
920
|
-
prof_frame_t *parent_frame,
|
985
|
+
prof_frame_t *parent_frame,
|
921
986
|
prof_frame_t *frame)
|
922
987
|
{
|
923
988
|
prof_measure_t self_time = total_time - frame->child_time - frame->wait_time;
|
924
989
|
prof_call_info_t *call_info = frame->call_info;
|
925
|
-
|
990
|
+
|
926
991
|
/* Update information about the current method */
|
927
992
|
call_info->called++;
|
928
993
|
call_info->total_time += total_time;
|
929
994
|
call_info->self_time += self_time;
|
930
995
|
call_info->wait_time += frame->wait_time;
|
931
|
-
|
996
|
+
|
932
997
|
/* Note where the current method was called from */
|
933
998
|
if (parent_frame)
|
934
999
|
call_info->line = parent_frame->line;
|
@@ -937,31 +1002,31 @@ update_result(prof_measure_t total_time,
|
|
937
1002
|
static thread_data_t *
|
938
1003
|
switch_thread(VALUE thread_id, prof_measure_t now)
|
939
1004
|
{
|
940
|
-
|
941
|
-
|
1005
|
+
prof_frame_t *frame = NULL;
|
1006
|
+
prof_measure_t wait_time = 0;
|
942
1007
|
/* Get new thread information. */
|
943
1008
|
thread_data_t *thread_data = threads_table_lookup(threads_tbl, thread_id);
|
944
1009
|
|
945
1010
|
/* How long has this thread been waiting? */
|
946
1011
|
wait_time = now - thread_data->last_switch;
|
947
|
-
|
1012
|
+
|
948
1013
|
thread_data->last_switch = now; // XXXX a test that fails if this is 0
|
949
1014
|
|
950
1015
|
/* Get the frame at the top of the stack. This may represent
|
951
1016
|
the current method (EVENT_LINE, EVENT_RETURN) or the
|
952
1017
|
previous method (EVENT_CALL).*/
|
953
1018
|
frame = stack_peek(thread_data->stack);
|
954
|
-
|
1019
|
+
|
955
1020
|
if (frame) {
|
956
1021
|
frame->wait_time += wait_time;
|
957
1022
|
}
|
958
|
-
|
1023
|
+
|
959
1024
|
/* Save on the last thread the time of the context switch
|
960
1025
|
and reset this thread's last context switch to 0.*/
|
961
1026
|
if (last_thread_data) {
|
962
|
-
last_thread_data->last_switch = now;
|
1027
|
+
last_thread_data->last_switch = now;
|
963
1028
|
}
|
964
|
-
|
1029
|
+
|
965
1030
|
last_thread_data = thread_data;
|
966
1031
|
return thread_data;
|
967
1032
|
}
|
@@ -983,20 +1048,17 @@ pop_frame(thread_data_t *thread_data, prof_measure_t now)
|
|
983
1048
|
/* Calculate the total time this method took */
|
984
1049
|
total_time = now - frame->start_time;
|
985
1050
|
|
986
|
-
/* Now deactivate the method */
|
987
|
-
frame->call_info->target->active = 0;
|
988
|
-
|
989
1051
|
parent_frame = stack_peek(thread_data->stack);
|
990
1052
|
if (parent_frame)
|
991
1053
|
{
|
992
|
-
|
1054
|
+
parent_frame->child_time += total_time;
|
993
1055
|
}
|
994
|
-
|
1056
|
+
|
995
1057
|
update_result(total_time, parent_frame, frame); // only time it's called
|
996
1058
|
return frame;
|
997
1059
|
}
|
998
1060
|
|
999
|
-
static int
|
1061
|
+
static int
|
1000
1062
|
pop_frames(st_data_t key, st_data_t value, st_data_t now_arg)
|
1001
1063
|
{
|
1002
1064
|
VALUE thread_id = (VALUE)key;
|
@@ -1011,11 +1073,11 @@ pop_frames(st_data_t key, st_data_t value, st_data_t now_arg)
|
|
1011
1073
|
while (pop_frame(thread_data, now))
|
1012
1074
|
{
|
1013
1075
|
}
|
1014
|
-
|
1076
|
+
|
1015
1077
|
return ST_CONTINUE;
|
1016
1078
|
}
|
1017
1079
|
|
1018
|
-
static void
|
1080
|
+
static void
|
1019
1081
|
prof_pop_threads()
|
1020
1082
|
{
|
1021
1083
|
/* Get current measurement */
|
@@ -1061,10 +1123,7 @@ prof_event_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE kla
|
|
1061
1123
|
/* Get current timestamp */
|
1062
1124
|
now = get_measurement();
|
1063
1125
|
|
1064
|
-
|
1065
|
-
/* This code is here for debug purposes - uncomment it out
|
1066
|
-
when debugging to see a print out of exactly what the
|
1067
|
-
profiler is tracing. */
|
1126
|
+
if (trace_file != NULL)
|
1068
1127
|
{
|
1069
1128
|
static VALUE last_thread_id = Qnil;
|
1070
1129
|
|
@@ -1075,7 +1134,7 @@ prof_event_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE kla
|
|
1075
1134
|
const char* source_file = rb_sourcefile();
|
1076
1135
|
unsigned int source_line = rb_sourceline();
|
1077
1136
|
|
1078
|
-
char* event_name = get_event_name(event);
|
1137
|
+
const char* event_name = get_event_name(event);
|
1079
1138
|
|
1080
1139
|
if (klass != 0)
|
1081
1140
|
klass = (BUILTIN_TYPE(klass) == T_ICLASS ? RBASIC(klass)->klass : klass);
|
@@ -1083,17 +1142,16 @@ prof_event_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE kla
|
|
1083
1142
|
class_name = rb_class2name(klass);
|
1084
1143
|
|
1085
1144
|
if (last_thread_id != thread_id) {
|
1086
|
-
|
1145
|
+
fprintf(trace_file, "\n");
|
1087
1146
|
}
|
1088
|
-
|
1089
|
-
|
1147
|
+
|
1148
|
+
fprintf(trace_file, "%2u:%2ums %-8s %s:%2d %s#%s\n",
|
1090
1149
|
(unsigned int) thread_id, (unsigned int) now, event_name, source_file, source_line, class_name, method_name);
|
1091
|
-
fflush(
|
1092
|
-
last_thread_id = thread_id;
|
1150
|
+
/* fflush(trace_file); */
|
1151
|
+
last_thread_id = thread_id;
|
1093
1152
|
}
|
1094
|
-
|
1095
|
-
|
1096
|
-
/* Special case - skip any methods from the mProf
|
1153
|
+
|
1154
|
+
/* Special case - skip any methods from the mProf
|
1097
1155
|
module, such as Prof.stop, since they clutter
|
1098
1156
|
the results but aren't important to them results. */
|
1099
1157
|
if (self == mProf) return;
|
@@ -1101,7 +1159,7 @@ prof_event_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE kla
|
|
1101
1159
|
/* Get the current thread information. */
|
1102
1160
|
thread = rb_thread_current();
|
1103
1161
|
thread_id = rb_obj_id(thread);
|
1104
|
-
|
1162
|
+
|
1105
1163
|
# if RUBY_VERSION == 191
|
1106
1164
|
/* ensure that new threads are hooked [sigh] (bug in core) */
|
1107
1165
|
prof_remove_hook();
|
@@ -1109,43 +1167,43 @@ prof_event_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE kla
|
|
1109
1167
|
# endif
|
1110
1168
|
|
1111
1169
|
if (exclude_threads_tbl &&
|
1112
|
-
st_lookup(exclude_threads_tbl, (st_data_t) thread_id, 0))
|
1170
|
+
st_lookup(exclude_threads_tbl, (st_data_t) thread_id, 0))
|
1113
1171
|
{
|
1114
1172
|
return;
|
1115
|
-
}
|
1116
|
-
|
1117
|
-
|
1173
|
+
}
|
1174
|
+
|
1175
|
+
|
1118
1176
|
/* Was there a context switch? */
|
1119
1177
|
if (!last_thread_data || last_thread_data->thread_id != thread_id)
|
1120
1178
|
thread_data = switch_thread(thread_id, now);
|
1121
1179
|
else
|
1122
1180
|
thread_data = last_thread_data;
|
1123
|
-
|
1124
|
-
|
1181
|
+
|
1182
|
+
|
1125
1183
|
switch (event) {
|
1126
1184
|
case RUBY_EVENT_LINE:
|
1127
1185
|
{
|
1128
1186
|
/* Keep track of the current line number in this method. When
|
1129
|
-
a new method is called, we know what line number it was
|
1187
|
+
a new method is called, we know what line number it was
|
1130
1188
|
called from. */
|
1131
|
-
|
1189
|
+
|
1132
1190
|
/* Get the current frame for the current thread. */
|
1133
1191
|
frame = stack_peek(thread_data->stack);
|
1134
1192
|
|
1135
1193
|
if (frame)
|
1136
1194
|
{
|
1137
|
-
frame->line = rb_sourceline();
|
1138
|
-
|
1195
|
+
frame->line = rb_sourceline();
|
1196
|
+
|
1139
1197
|
# if RUBY_VERSION == 191
|
1140
1198
|
// disabled it causes
|
1141
1199
|
// us to lose valuable frame information...maybe mid comes in wrong sometimes?
|
1142
1200
|
// walk_up_until_right_frame(frame, thread_data, mid, klass, now);
|
1143
1201
|
# endif
|
1144
|
-
|
1202
|
+
|
1145
1203
|
break;
|
1146
1204
|
}
|
1147
1205
|
|
1148
|
-
/* If we get here there was no frame, which means this is
|
1206
|
+
/* If we get here there was no frame, which means this is
|
1149
1207
|
the first method seen for this thread, so fall through
|
1150
1208
|
to below to create it. */
|
1151
1209
|
}
|
@@ -1161,27 +1219,15 @@ prof_event_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE kla
|
|
1161
1219
|
/* Is this an include for a module? If so get the actual
|
1162
1220
|
module class since we want to combine all profiling
|
1163
1221
|
results for that module. */
|
1164
|
-
|
1222
|
+
|
1165
1223
|
if (klass != 0)
|
1166
1224
|
klass = (BUILTIN_TYPE(klass) == T_ICLASS ? RBASIC(klass)->klass : klass);
|
1167
|
-
|
1168
|
-
/* Assume this is the first time we have called this method. */
|
1225
|
+
|
1169
1226
|
#ifdef RUBY_VM
|
1170
|
-
|
1227
|
+
method = get_method(event, klass, mid, thread_data->method_table);
|
1171
1228
|
#else
|
1172
|
-
|
1229
|
+
method = get_method(event, node, klass, mid, thread_data->method_table);
|
1173
1230
|
#endif
|
1174
|
-
/* Check for a recursive call */
|
1175
|
-
while (method->active) // it's while because we start at 0 and then inc. to the right recursive depth
|
1176
|
-
{
|
1177
|
-
/* Yes, this method is already active somewhere up the stack */
|
1178
|
-
#ifdef RUBY_VM
|
1179
|
-
method = get_method(event, klass, mid, method->key->depth + 1, thread_data->method_table);
|
1180
|
-
#else
|
1181
|
-
method = get_method(event, node, klass, mid, method->key->depth + 1, thread_data->method_table);
|
1182
|
-
#endif
|
1183
|
-
}
|
1184
|
-
method->active = 1;
|
1185
1231
|
|
1186
1232
|
if (!frame)
|
1187
1233
|
{
|
@@ -1211,9 +1257,9 @@ prof_event_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE kla
|
|
1211
1257
|
}
|
1212
1258
|
case RUBY_EVENT_RETURN:
|
1213
1259
|
case RUBY_EVENT_C_RETURN:
|
1214
|
-
{
|
1215
|
-
|
1216
|
-
|
1260
|
+
{
|
1261
|
+
frame = pop_frame(thread_data, now);
|
1262
|
+
|
1217
1263
|
# if RUBY_VERSION == 191
|
1218
1264
|
// we need to walk up the stack to find the right one [http://redmine.ruby-lang.org/issues/show/2610] (for now)
|
1219
1265
|
// sometimes frames don't have line and source somehow [like blank]
|
@@ -1221,7 +1267,7 @@ prof_event_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE kla
|
|
1221
1267
|
// or maybe we don't have one because we're at the top or something.
|
1222
1268
|
walk_up_until_right_frame(frame, thread_data, mid, klass, now);
|
1223
1269
|
# endif
|
1224
|
-
|
1270
|
+
|
1225
1271
|
break;
|
1226
1272
|
}
|
1227
1273
|
}
|
@@ -1240,7 +1286,7 @@ static inline void walk_up_until_right_frame(prof_frame_t *frame, thread_data_t*
|
|
1240
1286
|
/* ======== ProfResult ============== */
|
1241
1287
|
|
1242
1288
|
/* Document-class: RubyProf::Result
|
1243
|
-
The RubyProf::Result class is used to store the results of a
|
1289
|
+
The RubyProf::Result class is used to store the results of a
|
1244
1290
|
profiling run. And instace of the class is returned from
|
1245
1291
|
the methods RubyProf#stop and RubyProf#profile.
|
1246
1292
|
|
@@ -1296,7 +1342,7 @@ get_prof_result(VALUE obj)
|
|
1296
1342
|
Returns a hash table keyed on thread ID. For each thread id,
|
1297
1343
|
the hash table stores another hash table that contains profiling
|
1298
1344
|
information for each method called during the threads execution.
|
1299
|
-
That hash table is keyed on method name and contains
|
1345
|
+
That hash table is keyed on method name and contains
|
1300
1346
|
RubyProf::MethodInfo objects. */
|
1301
1347
|
static VALUE
|
1302
1348
|
prof_result_threads(VALUE self)
|
@@ -1309,12 +1355,12 @@ prof_result_threads(VALUE self)
|
|
1309
1355
|
|
1310
1356
|
/* call-seq:
|
1311
1357
|
measure_mode -> measure_mode
|
1312
|
-
|
1358
|
+
|
1313
1359
|
Returns what ruby-prof is measuring. Valid values include:
|
1314
|
-
|
1360
|
+
|
1315
1361
|
*RubyProf::PROCESS_TIME - Measure process time. This is default. It is implemented using the clock functions in the C Runtime library.
|
1316
1362
|
*RubyProf::WALL_TIME - Measure wall time using gettimeofday on Linx and GetLocalTime on Windows
|
1317
|
-
*RubyProf::CPU_TIME - Measure time using the CPU clock counter. This mode is only supported on Pentium or PowerPC platforms.
|
1363
|
+
*RubyProf::CPU_TIME - Measure time using the CPU clock counter. This mode is only supported on Pentium or PowerPC platforms.
|
1318
1364
|
*RubyProf::ALLOCATIONS - Measure object allocations. This requires a patched Ruby interpreter.
|
1319
1365
|
*RubyProf::MEMORY - Measure memory size. This requires a patched Ruby interpreter.
|
1320
1366
|
*RubyProf::GC_RUNS - Measure number of garbage collections. This requires a patched Ruby interpreter.
|
@@ -1327,12 +1373,12 @@ prof_get_measure_mode(VALUE self)
|
|
1327
1373
|
|
1328
1374
|
/* call-seq:
|
1329
1375
|
measure_mode=value -> void
|
1330
|
-
|
1376
|
+
|
1331
1377
|
Specifies what ruby-prof should measure. Valid values include:
|
1332
|
-
|
1378
|
+
|
1333
1379
|
*RubyProf::PROCESS_TIME - Measure process time. This is default. It is implemented using the clock functions in the C Runtime library.
|
1334
1380
|
*RubyProf::WALL_TIME - Measure wall time using gettimeofday on Linx and GetLocalTime on Windows
|
1335
|
-
*RubyProf::CPU_TIME - Measure time using the CPU clock counter. This mode is only supported on Pentium or PowerPC platforms.
|
1381
|
+
*RubyProf::CPU_TIME - Measure time using the CPU clock counter. This mode is only supported on Pentium or PowerPC platforms.
|
1336
1382
|
*RubyProf::ALLOCATIONS - Measure object allocations. This requires a patched Ruby interpreter.
|
1337
1383
|
*RubyProf::MEMORY - Measure memory size. This requires a patched Ruby interpreter.
|
1338
1384
|
*RubyProf::GC_RUNS - Measure number of garbage collections. This requires a patched Ruby interpreter.
|
@@ -1340,7 +1386,7 @@ prof_get_measure_mode(VALUE self)
|
|
1340
1386
|
static VALUE
|
1341
1387
|
prof_set_measure_mode(VALUE self, VALUE val)
|
1342
1388
|
{
|
1343
|
-
|
1389
|
+
int mode = NUM2INT(val);
|
1344
1390
|
|
1345
1391
|
if (threads_tbl)
|
1346
1392
|
{
|
@@ -1352,12 +1398,12 @@ prof_set_measure_mode(VALUE self, VALUE val)
|
|
1352
1398
|
get_measurement = measure_process_time;
|
1353
1399
|
convert_measurement = convert_process_time;
|
1354
1400
|
break;
|
1355
|
-
|
1401
|
+
|
1356
1402
|
case MEASURE_WALL_TIME:
|
1357
1403
|
get_measurement = measure_wall_time;
|
1358
1404
|
convert_measurement = convert_wall_time;
|
1359
1405
|
break;
|
1360
|
-
|
1406
|
+
|
1361
1407
|
#if defined(MEASURE_CPU_TIME)
|
1362
1408
|
case MEASURE_CPU_TIME:
|
1363
1409
|
if (cpu_frequency == 0)
|
@@ -1366,14 +1412,14 @@ prof_set_measure_mode(VALUE self, VALUE val)
|
|
1366
1412
|
convert_measurement = convert_cpu_time;
|
1367
1413
|
break;
|
1368
1414
|
#endif
|
1369
|
-
|
1415
|
+
|
1370
1416
|
#if defined(MEASURE_ALLOCATIONS)
|
1371
1417
|
case MEASURE_ALLOCATIONS:
|
1372
1418
|
get_measurement = measure_allocations;
|
1373
1419
|
convert_measurement = convert_allocations;
|
1374
1420
|
break;
|
1375
1421
|
#endif
|
1376
|
-
|
1422
|
+
|
1377
1423
|
#if defined(MEASURE_MEMORY)
|
1378
1424
|
case MEASURE_MEMORY:
|
1379
1425
|
get_measurement = measure_memory;
|
@@ -1396,10 +1442,10 @@ prof_set_measure_mode(VALUE self, VALUE val)
|
|
1396
1442
|
#endif
|
1397
1443
|
|
1398
1444
|
default:
|
1399
|
-
rb_raise(rb_eArgError, "invalid mode: %
|
1445
|
+
rb_raise(rb_eArgError, "invalid mode: %d", mode);
|
1400
1446
|
break;
|
1401
1447
|
}
|
1402
|
-
|
1448
|
+
|
1403
1449
|
measure_mode = mode;
|
1404
1450
|
return val;
|
1405
1451
|
}
|
@@ -1431,12 +1477,12 @@ prof_set_exclude_threads(VALUE self, VALUE threads)
|
|
1431
1477
|
Check_Type(threads, T_ARRAY);
|
1432
1478
|
exclude_threads_tbl = st_init_numtable();
|
1433
1479
|
|
1434
|
-
for (i=0; i < RARRAY_LEN(threads); ++i)
|
1480
|
+
for (i=0; i < RARRAY_LEN(threads); ++i)
|
1435
1481
|
{
|
1436
1482
|
VALUE thread = rb_ary_entry(threads, i);
|
1437
1483
|
st_insert(exclude_threads_tbl, (st_data_t) rb_obj_id(thread), 0);
|
1438
1484
|
}
|
1439
|
-
}
|
1485
|
+
}
|
1440
1486
|
return threads;
|
1441
1487
|
}
|
1442
1488
|
|
@@ -1448,12 +1494,12 @@ prof_install_hook()
|
|
1448
1494
|
#ifdef RUBY_VM
|
1449
1495
|
rb_add_event_hook(prof_event_hook,
|
1450
1496
|
RUBY_EVENT_CALL | RUBY_EVENT_RETURN |
|
1451
|
-
RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN
|
1497
|
+
RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN
|
1452
1498
|
| RUBY_EVENT_LINE, Qnil); // RUBY_EVENT_SWITCH
|
1453
1499
|
#else
|
1454
1500
|
rb_add_event_hook(prof_event_hook,
|
1455
1501
|
RUBY_EVENT_CALL | RUBY_EVENT_RETURN |
|
1456
|
-
RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN
|
1502
|
+
RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN
|
1457
1503
|
| RUBY_EVENT_LINE);
|
1458
1504
|
#endif
|
1459
1505
|
|
@@ -1477,7 +1523,7 @@ prof_remove_hook()
|
|
1477
1523
|
|
1478
1524
|
/* call-seq:
|
1479
1525
|
running? -> boolean
|
1480
|
-
|
1526
|
+
|
1481
1527
|
Returns whether a profile is currently running.*/
|
1482
1528
|
static VALUE
|
1483
1529
|
prof_running(VALUE self)
|
@@ -1490,7 +1536,7 @@ prof_running(VALUE self)
|
|
1490
1536
|
|
1491
1537
|
/* call-seq:
|
1492
1538
|
start -> RubyProf
|
1493
|
-
|
1539
|
+
|
1494
1540
|
Starts recording profile data.*/
|
1495
1541
|
static VALUE
|
1496
1542
|
prof_start(VALUE self)
|
@@ -1504,9 +1550,21 @@ prof_start(VALUE self)
|
|
1504
1550
|
last_thread_data = NULL;
|
1505
1551
|
threads_tbl = threads_table_create();
|
1506
1552
|
|
1507
|
-
|
1553
|
+
/* open trace file if environment wants it */
|
1554
|
+
char* trace_file_name = getenv("RUBY_PROF_TRACE");
|
1555
|
+
if (trace_file_name != NULL) {
|
1556
|
+
if (0==strcmp(trace_file_name, "stdout")) {
|
1557
|
+
trace_file = stdout;
|
1558
|
+
} else if (0==strcmp(trace_file_name, "stderr")) {
|
1559
|
+
trace_file = stderr;
|
1560
|
+
} else {
|
1561
|
+
trace_file = fopen(trace_file_name, "a");
|
1562
|
+
}
|
1563
|
+
}
|
1564
|
+
|
1565
|
+
prof_install_hook();
|
1508
1566
|
return self;
|
1509
|
-
}
|
1567
|
+
}
|
1510
1568
|
|
1511
1569
|
/* call-seq:
|
1512
1570
|
pause -> RubyProf
|
@@ -1526,20 +1584,20 @@ prof_pause(VALUE self)
|
|
1526
1584
|
|
1527
1585
|
/* call-seq:
|
1528
1586
|
resume {block} -> RubyProf
|
1529
|
-
|
1587
|
+
|
1530
1588
|
Resumes recording profile data.*/
|
1531
1589
|
static VALUE
|
1532
1590
|
prof_resume(VALUE self)
|
1533
1591
|
{
|
1534
1592
|
if (threads_tbl == NULL)
|
1535
|
-
{
|
1593
|
+
{
|
1536
1594
|
prof_start(self);
|
1537
1595
|
}
|
1538
1596
|
else
|
1539
|
-
{
|
1597
|
+
{
|
1540
1598
|
prof_install_hook();
|
1541
1599
|
}
|
1542
|
-
|
1600
|
+
|
1543
1601
|
if (rb_block_given_p())
|
1544
1602
|
{
|
1545
1603
|
rb_ensure(rb_yield, self, prof_pause, self);
|
@@ -1556,7 +1614,14 @@ static VALUE
|
|
1556
1614
|
prof_stop(VALUE self)
|
1557
1615
|
{
|
1558
1616
|
VALUE result = Qnil;
|
1559
|
-
|
1617
|
+
|
1618
|
+
/* close trace file if open */
|
1619
|
+
if (trace_file != NULL) {
|
1620
|
+
if (trace_file!=stderr && trace_file!=stdout)
|
1621
|
+
fclose(trace_file);
|
1622
|
+
trace_file = NULL;
|
1623
|
+
}
|
1624
|
+
|
1560
1625
|
prof_remove_hook();
|
1561
1626
|
|
1562
1627
|
prof_pop_threads();
|
@@ -1564,12 +1629,15 @@ prof_stop(VALUE self)
|
|
1564
1629
|
/* Create the result */
|
1565
1630
|
result = prof_result_new();
|
1566
1631
|
|
1567
|
-
/* Unset the last_thread_data (very important!)
|
1632
|
+
/* Unset the last_thread_data (very important!)
|
1568
1633
|
and the threads table */
|
1569
1634
|
last_thread_data = NULL;
|
1570
1635
|
threads_table_free(threads_tbl);
|
1571
1636
|
threads_tbl = NULL;
|
1572
1637
|
|
1638
|
+
/* compute minimality of call_infos */
|
1639
|
+
rb_funcall(result, rb_intern("compute_minimality") , 0);
|
1640
|
+
|
1573
1641
|
return result;
|
1574
1642
|
}
|
1575
1643
|
|
@@ -1581,7 +1649,7 @@ static VALUE
|
|
1581
1649
|
prof_profile(VALUE self)
|
1582
1650
|
{
|
1583
1651
|
int result;
|
1584
|
-
|
1652
|
+
|
1585
1653
|
if (!rb_block_given_p())
|
1586
1654
|
{
|
1587
1655
|
rb_raise(rb_eArgError, "A block must be provided to the profile method.");
|
@@ -1616,21 +1684,21 @@ Returns the cpu time.*/
|
|
1616
1684
|
call-seq:
|
1617
1685
|
cpu_frequency -> int
|
1618
1686
|
|
1619
|
-
Returns the cpu's frequency. This value is needed when
|
1687
|
+
Returns the cpu's frequency. This value is needed when
|
1620
1688
|
RubyProf::measure_mode is set to CPU_TIME. */
|
1621
1689
|
|
1622
1690
|
/* Document-method: cpu_frequency
|
1623
1691
|
call-seq:
|
1624
1692
|
cpu_frequency -> int
|
1625
1693
|
|
1626
|
-
Returns the cpu's frequency. This value is needed when
|
1694
|
+
Returns the cpu's frequency. This value is needed when
|
1627
1695
|
RubyProf::measure_mode is set to CPU_TIME. */
|
1628
1696
|
|
1629
1697
|
/* Document-method: cpu_frequency=
|
1630
1698
|
call-seq:
|
1631
1699
|
cpu_frequency = frequency
|
1632
1700
|
|
1633
|
-
Sets the cpu's frequency. This value is needed when
|
1701
|
+
Sets the cpu's frequency. This value is needed when
|
1634
1702
|
RubyProf::measure_mode is set to CPU_TIME. */
|
1635
1703
|
|
1636
1704
|
/* Document-method: measure_allocations
|
@@ -1659,7 +1727,7 @@ Returns the time spent doing garbage collections in microseconds.*/
|
|
1659
1727
|
|
1660
1728
|
|
1661
1729
|
#if defined(_WIN32)
|
1662
|
-
__declspec(dllexport)
|
1730
|
+
__declspec(dllexport)
|
1663
1731
|
#endif
|
1664
1732
|
void
|
1665
1733
|
|
@@ -1673,7 +1741,7 @@ Init_ruby_prof()
|
|
1673
1741
|
rb_define_module_function(mProf, "pause", prof_pause, 0);
|
1674
1742
|
rb_define_module_function(mProf, "running?", prof_running, 0);
|
1675
1743
|
rb_define_module_function(mProf, "profile", prof_profile, 0);
|
1676
|
-
|
1744
|
+
|
1677
1745
|
rb_define_singleton_method(mProf, "exclude_threads=", prof_set_exclude_threads, 1);
|
1678
1746
|
rb_define_singleton_method(mProf, "measure_mode", prof_get_measure_mode, 0);
|
1679
1747
|
rb_define_singleton_method(mProf, "measure_mode=", prof_set_measure_mode, 1);
|
@@ -1692,14 +1760,14 @@ Init_ruby_prof()
|
|
1692
1760
|
rb_define_singleton_method(mProf, "cpu_frequency", prof_get_cpu_frequency, 0); /* in measure_cpu_time.h */
|
1693
1761
|
rb_define_singleton_method(mProf, "cpu_frequency=", prof_set_cpu_frequency, 1); /* in measure_cpu_time.h */
|
1694
1762
|
#endif
|
1695
|
-
|
1763
|
+
|
1696
1764
|
#ifndef MEASURE_ALLOCATIONS
|
1697
1765
|
rb_define_const(mProf, "ALLOCATIONS", Qnil);
|
1698
1766
|
#else
|
1699
1767
|
rb_define_const(mProf, "ALLOCATIONS", INT2NUM(MEASURE_ALLOCATIONS));
|
1700
1768
|
rb_define_singleton_method(mProf, "measure_allocations", prof_measure_allocations, 0); /* in measure_allocations.h */
|
1701
1769
|
#endif
|
1702
|
-
|
1770
|
+
|
1703
1771
|
#ifndef MEASURE_MEMORY
|
1704
1772
|
rb_define_const(mProf, "MEMORY", Qnil);
|
1705
1773
|
#else
|
@@ -1728,13 +1796,13 @@ Init_ruby_prof()
|
|
1728
1796
|
/* MethodInfo */
|
1729
1797
|
cMethodInfo = rb_define_class_under(mProf, "MethodInfo", rb_cObject);
|
1730
1798
|
rb_undef_method(CLASS_OF(cMethodInfo), "new");
|
1731
|
-
|
1799
|
+
|
1732
1800
|
rb_define_method(cMethodInfo, "klass", prof_method_klass, 0);
|
1733
1801
|
rb_define_method(cMethodInfo, "klass_name", prof_klass_name, 0);
|
1734
1802
|
rb_define_method(cMethodInfo, "method_name", prof_method_name, 0);
|
1735
1803
|
rb_define_method(cMethodInfo, "full_name", prof_full_name, 0);
|
1736
1804
|
rb_define_method(cMethodInfo, "method_id", prof_method_id, 0);
|
1737
|
-
|
1805
|
+
|
1738
1806
|
rb_define_method(cMethodInfo, "source_file", prof_method_source_file,0);
|
1739
1807
|
rb_define_method(cMethodInfo, "line", prof_method_line, 0);
|
1740
1808
|
|
@@ -1744,11 +1812,16 @@ Init_ruby_prof()
|
|
1744
1812
|
cCallInfo = rb_define_class_under(mProf, "CallInfo", rb_cObject);
|
1745
1813
|
rb_undef_method(CLASS_OF(cCallInfo), "new");
|
1746
1814
|
rb_define_method(cCallInfo, "parent", prof_call_info_parent, 0);
|
1815
|
+
rb_define_method(cCallInfo, "parent=", prof_call_info_set_parent, 1);
|
1747
1816
|
rb_define_method(cCallInfo, "children", prof_call_info_children, 0);
|
1748
1817
|
rb_define_method(cCallInfo, "target", prof_call_info_target, 0);
|
1749
1818
|
rb_define_method(cCallInfo, "called", prof_call_info_called, 0);
|
1819
|
+
rb_define_method(cCallInfo, "called=", prof_call_info_set_called, 1);
|
1750
1820
|
rb_define_method(cCallInfo, "total_time", prof_call_info_total_time, 0);
|
1821
|
+
rb_define_method(cCallInfo, "add_total_time", prof_call_info_add_total_time, 1);
|
1751
1822
|
rb_define_method(cCallInfo, "self_time", prof_call_info_self_time, 0);
|
1823
|
+
rb_define_method(cCallInfo, "add_self_time", prof_call_info_add_self_time, 1);
|
1752
1824
|
rb_define_method(cCallInfo, "wait_time", prof_call_info_wait_time, 0);
|
1825
|
+
rb_define_method(cCallInfo, "add_wait_time", prof_call_info_add_wait_time, 1);
|
1753
1826
|
rb_define_method(cCallInfo, "line", prof_call_info_line, 0);
|
1754
1827
|
}
|