ruby-prof 0.13.1 → 0.14.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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +14 -0
  3. data/README.rdoc +1 -1
  4. data/Rakefile +2 -3
  5. data/bin/ruby-prof +4 -4
  6. data/bin/ruby-prof-check-trace +45 -0
  7. data/doc/LICENSE.html +49 -88
  8. data/doc/README_rdoc.html +92 -106
  9. data/doc/Rack.html +47 -116
  10. data/doc/Rack/RubyProf.html +119 -174
  11. data/doc/RubyProf.html +184 -216
  12. data/doc/RubyProf/AbstractPrinter.html +131 -162
  13. data/doc/RubyProf/AggregateCallInfo.html +136 -166
  14. data/doc/RubyProf/CallInfo.html +113 -154
  15. data/doc/RubyProf/CallInfoPrinter.html +56 -123
  16. data/doc/RubyProf/CallInfoVisitor.html +87 -216
  17. data/doc/RubyProf/CallStackPrinter.html +222 -215
  18. data/doc/RubyProf/CallTreePrinter.html +91 -142
  19. data/doc/RubyProf/Cmd.html +115 -157
  20. data/doc/RubyProf/DotPrinter.html +88 -140
  21. data/doc/RubyProf/FlatPrinter.html +66 -129
  22. data/doc/RubyProf/FlatPrinterWithLineNumbers.html +69 -132
  23. data/doc/RubyProf/GraphHtmlPrinter.html +115 -166
  24. data/doc/RubyProf/GraphPrinter.html +58 -125
  25. data/doc/RubyProf/MethodInfo.html +147 -172
  26. data/doc/RubyProf/MultiPrinter.html +104 -150
  27. data/doc/RubyProf/Profile.html +125 -179
  28. data/doc/RubyProf/ProfileTask.html +117 -157
  29. data/doc/RubyProf/Test.html +115 -154
  30. data/doc/RubyProf/Thread.html +87 -147
  31. data/doc/created.rid +13 -14
  32. data/doc/examples/flat_txt.html +51 -90
  33. data/doc/examples/graph_html.html +852 -0
  34. data/doc/examples/graph_txt.html +64 -92
  35. data/doc/fonts.css +167 -0
  36. data/doc/fonts/Lato-Light.ttf +0 -0
  37. data/doc/fonts/Lato-LightItalic.ttf +0 -0
  38. data/doc/fonts/Lato-Regular.ttf +0 -0
  39. data/doc/fonts/Lato-RegularItalic.ttf +0 -0
  40. data/doc/fonts/SourceCodePro-Bold.ttf +0 -0
  41. data/doc/fonts/SourceCodePro-Regular.ttf +0 -0
  42. data/doc/images/add.png +0 -0
  43. data/doc/images/arrow_up.png +0 -0
  44. data/doc/images/delete.png +0 -0
  45. data/doc/images/tag_blue.png +0 -0
  46. data/doc/index.html +75 -65
  47. data/doc/js/darkfish.js +0 -15
  48. data/doc/js/search.js +20 -5
  49. data/doc/js/search_index.js +1 -1
  50. data/doc/rdoc.css +255 -218
  51. data/doc/table_of_contents.html +751 -353
  52. data/ext/ruby_prof/extconf.rb +20 -22
  53. data/ext/ruby_prof/rp_measure_allocations.c +9 -5
  54. data/ext/ruby_prof/rp_measure_gc_runs.c +8 -0
  55. data/ext/ruby_prof/rp_measure_gc_time.c +5 -2
  56. data/ext/ruby_prof/rp_measure_wall_time.c +1 -0
  57. data/ext/ruby_prof/rp_method.c +0 -9
  58. data/ext/ruby_prof/rp_method.h +1 -6
  59. data/ext/ruby_prof/ruby_prof.c +32 -112
  60. data/ext/ruby_prof/ruby_prof.h +9 -10
  61. data/lib/ruby-prof.rb +2 -1
  62. data/lib/ruby-prof/aggregate_call_info.rb +4 -6
  63. data/lib/ruby-prof/call_info_visitor.rb +42 -44
  64. data/lib/ruby-prof/printers/graph_html_printer.rb +0 -8
  65. data/lib/ruby-prof/profile.rb +4 -4
  66. data/lib/ruby-prof/rack.rb +47 -47
  67. data/lib/ruby-prof/task.rb +0 -0
  68. data/lib/ruby-prof/thread.rb +22 -22
  69. data/lib/ruby-prof/version.rb +3 -0
  70. data/ruby-prof.gemspec +7 -11
  71. data/test/call_info_test.rb +78 -78
  72. data/test/call_info_visitor_test.rb +31 -31
  73. data/test/fiber_test.rb +2 -2
  74. data/test/measure_gc_runs_test.rb +1 -1
  75. data/test/measure_process_time_test.rb +7 -6
  76. data/test/printers_test.rb +4 -8
  77. data/test/recursive_test.rb +5 -9
  78. data/test/test_helper.rb +1 -1
  79. data/test/unique_call_path_test.rb +7 -29
  80. data/test/yarv_test.rb +55 -0
  81. metadata +63 -55
  82. data/ext/ruby_prof/version.h +0 -7
  83. data/lib/ruby-prof/test.rb +0 -150
  84. data/test/exec_test.rb +0 -14
  85. data/test/test_suite.rb +0 -37
@@ -1,33 +1,32 @@
1
1
  require "mkmf"
2
2
 
3
- if RUBY_VERSION == "1.8.6"
4
- STDERR.print("Ruby #{RUBY_VERSION} is no longer supported. Please upgrade to 1.8.7 or 1.9.2 or higher\n")
5
- exit(1)
6
- end
7
-
8
- if RUBY_VERSION == "1.9.0" or RUBY_VERSION == "1.9.1"
9
- STDERR.print("Ruby #{RUBY_VERSION} is no longer supported. Please upgrade to 1.9.2 or higher\n")
3
+ if RUBY_VERSION < "1.9.3"
4
+ STDERR.puts("Ruby version #{RUBY_VERSION} is no longer supported. Please upgrade to 1.9.3 or higher")
10
5
  exit(1)
11
6
  end
12
7
 
13
8
  have_header("sys/times.h")
14
9
 
15
- # Stefan Kaes / Alexander Dymo GC patch
10
+ # standard ruby methods
11
+ have_func("rb_gc_stat")
12
+ have_func("rb_gc_count")
13
+
14
+ # Alexander Dymo GC patch
16
15
  have_func("rb_os_allocated_objects")
17
16
  have_func("rb_gc_allocated_size")
17
+
18
+ # Stefan Kaes GC patches
18
19
  have_func("rb_gc_collections")
19
20
  have_func("rb_gc_time")
20
-
21
- # 1.9.3 superclass
22
- have_func("rb_class_superclass")
21
+ # for ruby 2.1
22
+ have_func("rb_gc_total_time")
23
+ have_func("rb_gc_total_mallocs")
24
+ have_func("rb_gc_total_malloced_bytes")
23
25
 
24
26
  # Lloyd Hilaiel's heap info patch
25
27
  have_func("rb_heap_total_mem")
26
28
  have_func("rb_gc_heap_info")
27
29
 
28
- # whether our ruby has fibers
29
- have_func("rb_fiber_current")
30
-
31
30
  def add_define(name, value = nil)
32
31
  if value
33
32
  $defs.push("-D#{name}=#{value}")
@@ -36,24 +35,23 @@ def add_define(name, value = nil)
36
35
  end
37
36
  end
38
37
 
39
- # if have_func("rb_gc_enable_stats")
40
- # add_define("TOGGLE_GC_STATS", 1)
41
- # end
42
-
43
- require 'rubygems'
44
- unless Gem.win_platform? || RUBY_PLATFORM =~ /(darwin|openbsd)/
38
+ if !Gem.win_platform? && RUBY_PLATFORM !~ /(darwin|openbsd)/
45
39
  $LDFLAGS += " -lrt" # for clock_gettime
46
40
  end
47
41
  add_define("RUBY_VERSION", RUBY_VERSION.gsub('.', ''))
48
42
 
49
- # for ruby 1.9, determine whether threads inherit trace flags (latest 1.9.2 works correctly)
43
+ # for ruby 1.9, determine whether threads inherit trace flags (latest 1.9.2 and later should work correctly)
50
44
  if RUBY_VERSION > "1.9"
51
45
  require 'set'
52
46
  threads = Set.new
53
47
  set_trace_func lambda { |*args| threads << Thread.current.object_id }
54
48
  Thread.new{1}.join
55
49
  set_trace_func nil
56
- add_define("THREADS_INHERIT_EVENT_FLAGS", (threads.size == 2) ? "1" : "0")
50
+ if threads.size < 2
51
+ # if we end up here, ruby does not automatically active tracing in spawned threads
52
+ STDERR.puts("Ruby #{RUBY_VERSION} does not activate tracing in spawned threads. Consider upgrading.")
53
+ exit(1)
54
+ end
57
55
  end
58
56
 
59
57
  create_makefile("ruby_prof")
@@ -11,8 +11,8 @@ static VALUE cMeasureAllocations;
11
11
  unsigned LONG_LONG rb_os_allocated_objects();
12
12
  #endif
13
13
 
14
- #if defined(HAVE_RB_GC_MALLOC_ALLOCATIONS)
15
- unsigned LONG_LONG rb_gc_malloc_allocations();
14
+ #if defined(HAVE_RB_GC_STAT)
15
+ size_t rb_gc_stat(VALUE key);
16
16
  #endif
17
17
 
18
18
  static double
@@ -22,9 +22,13 @@ measure_allocations()
22
22
  #define MEASURE_ALLOCATIONS_ENABLED Qtrue
23
23
  return rb_os_allocated_objects();
24
24
 
25
- #elif defined(HAVE_RB_GC_MALLOC_ALLOCATIONS)
25
+ #elif defined(HAVE_RB_GC_STAT) && RUBY_VERSION == 210
26
26
  #define MEASURE_ALLOCATIONS_ENABLED Qtrue
27
- return rb_gc_malloc_allocations();
27
+ static VALUE total_alloc_symbol = 0;
28
+ if (!total_alloc_symbol) {
29
+ total_alloc_symbol = ID2SYM(rb_intern_const("total_allocated_object"));
30
+ }
31
+ return rb_gc_stat(total_alloc_symbol);
28
32
 
29
33
  #else
30
34
  #define MEASURE_ALLOCATIONS_ENABLED Qfalse
@@ -61,5 +65,5 @@ void rp_init_measure_allocations()
61
65
  rb_define_const(mProf, "ALLOCATIONS_ENABLED", MEASURE_ALLOCATIONS_ENABLED);
62
66
 
63
67
  cMeasureAllocations = rb_define_class_under(mMeasure, "Allocations", rb_cObject);
64
- rb_define_singleton_method(cMeasureAllocations, "measure", prof_measure_allocations, 0);
68
+ rb_define_singleton_method(cMeasureAllocations, "measure", prof_measure_allocations, 0);
65
69
  }
@@ -11,6 +11,10 @@ static VALUE cMeasureGcRuns;
11
11
  VALUE rb_gc_collections(void);
12
12
  #endif
13
13
 
14
+ #if defined(HAVE_RB_GC_COUNT)
15
+ size_t rb_gc_count(void);
16
+ #endif
17
+
14
18
  #if defined(HAVE_RB_GC_HEAP_INFO)
15
19
  VALUE rb_gc_heap_info(void);
16
20
  #endif
@@ -23,6 +27,10 @@ measure_gc_runs()
23
27
  #define MEASURE_GC_RUNS_ENABLED Qtrue
24
28
  return NUM2INT(rb_gc_collections());
25
29
 
30
+ #elif defined(HAVE_RB_GC_COUNT)
31
+ #define MEASURE_GC_RUNS_ENABLED Qtrue
32
+ return rb_gc_count();
33
+
26
34
  #elif defined(HAVE_RB_GC_HEAP_INFO)
27
35
  #define MEASURE_GC_RUNS_ENABLED Qtrue
28
36
  VALUE h = rb_gc_heap_info();
@@ -11,11 +11,14 @@ static VALUE cMeasureGcTimes;
11
11
  VALUE rb_gc_time();
12
12
  #endif
13
13
 
14
-
15
14
  static double
16
15
  measure_gc_time()
17
16
  {
18
- #if defined(HAVE_RB_GC_TIME)
17
+ #if defined(HAVE_RB_GC_TOTAL_TIME)
18
+ #define MEASURE_GC_TIME_ENABLED Qtrue
19
+ return rb_gc_total_time();
20
+
21
+ #elif defined(HAVE_RB_GC_TIME)
19
22
  #define MEASURE_GC_TIME_ENABLED Qtrue
20
23
  const double conversion = 1000000.0;
21
24
  #if HAVE_LONG_LONG
@@ -3,6 +3,7 @@
3
3
 
4
4
  /* :nodoc: */
5
5
  #include "ruby_prof.h"
6
+ #include <sys/time.h>
6
7
 
7
8
  static VALUE cMeasureWallTime;
8
9
 
@@ -37,16 +37,7 @@ figure_singleton_name(VALUE klass)
37
37
  /* Make sure to get the super class so that we don't
38
38
  mistakenly grab a T_ICLASS which would lead to
39
39
  unknown method errors. */
40
- #ifdef HAVE_RB_CLASS_SUPERCLASS
41
- // 1.9.3
42
40
  VALUE super = rb_class_superclass(klass);
43
- #else
44
- # ifdef RCLASS_SUPER
45
- VALUE super = rb_class_real(RCLASS_SUPER(klass));
46
- # else
47
- VALUE super = rb_class_real(RCLASS(klass)->super);
48
- # endif
49
- #endif
50
41
  result = rb_str_new2("<Object::");
51
42
  rb_str_append(result, rb_inspect(super));
52
43
  rb_str_cat2(result, ">");
@@ -6,15 +6,10 @@
6
6
 
7
7
  #include <ruby.h>
8
8
 
9
- #ifndef RUBY_VM
10
- #include <st.h>
11
- typedef st_data_t st_index_t;
12
- #endif
13
-
14
9
  extern VALUE cMethodInfo;
15
10
 
16
11
  /* A key used to identify each method */
17
- typedef struct
12
+ typedef struct
18
13
  {
19
14
  VALUE klass; /* The method's class. */
20
15
  ID mid; /* The method id. */
@@ -29,12 +29,6 @@
29
29
  VALUE mProf;
30
30
  VALUE cProfile;
31
31
 
32
- #ifndef RUBY_VM
33
- /* Global variable to hold current profile - needed
34
- prior to Ruby 1.9 */
35
- static prof_profile_t* pCurrentProfile;
36
- #endif
37
-
38
32
  static prof_profile_t*
39
33
  prof_get_profile(VALUE self)
40
34
  {
@@ -50,35 +44,29 @@ prof_get_profile(VALUE self)
50
44
  */
51
45
  static FILE* trace_file = NULL;
52
46
 
53
- /* Copied from eval.c (1.8.x) / thread.c (1.9.2) */
47
+ /* Copied from thread.c (1.9.3) */
54
48
  static const char *
55
49
  get_event_name(rb_event_flag_t event)
56
50
  {
57
51
  switch (event) {
58
- case RUBY_EVENT_LINE:
59
- return "line";
60
- case RUBY_EVENT_CLASS:
61
- return "class";
62
- case RUBY_EVENT_END:
63
- return "end";
64
- case RUBY_EVENT_CALL:
65
- return "call";
66
- case RUBY_EVENT_RETURN:
67
- return "return";
68
- case RUBY_EVENT_C_CALL:
69
- return "c-call";
70
- case RUBY_EVENT_C_RETURN:
71
- return "c-return";
72
- case RUBY_EVENT_RAISE:
73
- return "raise";
74
-
75
- #ifdef RUBY_VM
76
- case RUBY_EVENT_SWITCH:
77
- return "thread-interrupt";
78
- #endif
79
-
80
- default:
81
- return "unknown";
52
+ case RUBY_EVENT_LINE:
53
+ return "line";
54
+ case RUBY_EVENT_CLASS:
55
+ return "class";
56
+ case RUBY_EVENT_END:
57
+ return "end";
58
+ case RUBY_EVENT_CALL:
59
+ return "call";
60
+ case RUBY_EVENT_RETURN:
61
+ return "return";
62
+ case RUBY_EVENT_C_CALL:
63
+ return "c-call";
64
+ case RUBY_EVENT_C_RETURN:
65
+ return "c-return";
66
+ case RUBY_EVENT_RAISE:
67
+ return "raise";
68
+ default:
69
+ return "unknown";
82
70
  }
83
71
  }
84
72
 
@@ -97,11 +85,7 @@ create_method(rb_event_flag_t event, VALUE klass, ID mid, const char* source_fil
97
85
 
98
86
 
99
87
  static prof_method_t*
100
- #ifdef RUBY_VM
101
- get_method(rb_event_flag_t event, VALUE klass, ID mid, thread_data_t* thread_data)
102
- # else
103
- get_method(rb_event_flag_t event, NODE *node, VALUE klass, ID mid, thread_data_t* thread_data)
104
- #endif
88
+ get_method(rb_event_flag_t event, VALUE klass, ID mid, thread_data_t* thread_data)
105
89
  {
106
90
  prof_method_key_t key;
107
91
  prof_method_t *method = NULL;
@@ -147,24 +131,15 @@ prof_pop_threads(prof_profile_t* profile)
147
131
  }
148
132
 
149
133
  /* =========== Profiling ================= */
150
- #ifdef RUBY_VM
151
134
  static void
152
135
  prof_trace(prof_profile_t* profile, rb_event_flag_t event, ID mid, VALUE klass, double measurement)
153
- #else
154
- static void
155
- prof_trace(prof_profile_t* profile, rb_event_flag_t event, NODE *node, ID mid, VALUE klass, double measurement)
156
- #endif
157
136
  {
158
137
  static VALUE last_fiber_id = Qnil;
159
138
 
160
139
  VALUE thread = rb_thread_current();
161
140
  VALUE thread_id = rb_obj_id(thread);
162
- #if defined(HAVE_RB_FIBER_CURRENT)
163
141
  VALUE fiber = rb_fiber_current();
164
142
  VALUE fiber_id = rb_obj_id(fiber);
165
- #else
166
- VALUE fiber_id = thread_id;
167
- #endif
168
143
  const char* class_name = NULL;
169
144
  const char* method_name = rb_id2name(mid);
170
145
  const char* source_file = rb_sourcefile();
@@ -189,20 +164,10 @@ prof_trace(prof_profile_t* profile, rb_event_flag_t event, NODE *node, ID mid, V
189
164
  last_fiber_id = fiber_id;
190
165
  }
191
166
 
192
- #ifdef RUBY_VM
193
167
  static void
194
168
  prof_event_hook(rb_event_flag_t event, VALUE data, VALUE self, ID mid, VALUE klass)
195
- #else
196
- static void
197
- prof_event_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE klass)
198
- #endif
199
169
  {
200
- #ifndef RUBY_VM
201
- prof_profile_t* profile = pCurrentProfile;
202
- #else
203
170
  prof_profile_t* profile = prof_get_profile(data);
204
- #endif
205
-
206
171
  VALUE thread = Qnil;
207
172
  VALUE thread_id = Qnil;
208
173
  VALUE fiber = Qnil;
@@ -211,41 +176,30 @@ prof_event_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE kla
211
176
  prof_frame_t *frame = NULL;
212
177
  double measurement;
213
178
 
214
- #ifdef RUBY_VM
215
- if (event != RUBY_EVENT_C_CALL && event != RUBY_EVENT_C_RETURN) {
179
+ if (event != RUBY_EVENT_C_CALL && event != RUBY_EVENT_C_RETURN) {
216
180
  // guess these are already set for C calls in 1.9, then?
217
181
  rb_frame_method_id_and_class(&mid, &klass);
218
- }
219
- #endif
182
+ }
220
183
 
221
184
  /* Get current measurement */
222
185
  measurement = profile->measurer->measure();
223
186
 
224
- if (trace_file != NULL)
225
- {
226
- #ifdef RUBY_VM
227
- prof_trace(profile, event, mid, klass, measurement);
228
- #else
229
- prof_trace(profile, event, node, mid, klass, measurement);
230
- #endif
231
- }
232
-
233
187
  /* Special case - skip any methods from the mProf
234
188
  module or cProfile class since they clutter
235
189
  the results but aren't important to them results. */
236
190
  if (self == mProf || klass == cProfile)
237
191
  return;
238
192
 
239
- /* Get the current thread information. */
193
+ if (trace_file != NULL)
194
+ {
195
+ prof_trace(profile, event, mid, klass, measurement);
196
+ }
197
+
198
+ /* Get the current thread and fiber information. */
240
199
  thread = rb_thread_current();
241
200
  thread_id = rb_obj_id(thread);
242
- #if defined(HAVE_RB_FIBER_CURRENT)
243
201
  fiber = rb_fiber_current();
244
202
  fiber_id = rb_obj_id(fiber);
245
- #else
246
- fiber = thread;
247
- fiber_id = thread_id;
248
- #endif
249
203
 
250
204
  if (st_lookup(profile->exclude_threads_tbl, (st_data_t) thread_id, 0))
251
205
  {
@@ -284,11 +238,7 @@ prof_event_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE kla
284
238
  prof_call_info_t *call_info = NULL;
285
239
  prof_method_t *method = NULL;
286
240
 
287
- #ifdef RUBY_VM
288
241
  method = get_method(event, klass, mid, thread_data);
289
- #else
290
- method = get_method(event, node, klass, mid, thread_data);
291
- #endif
292
242
 
293
243
  if (!frame)
294
244
  {
@@ -334,37 +284,15 @@ prof_event_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE kla
334
284
  void
335
285
  prof_install_hook(VALUE self)
336
286
  {
337
- #ifdef RUBY_VM
338
287
  rb_add_event_hook(prof_event_hook,
339
288
  RUBY_EVENT_CALL | RUBY_EVENT_RETURN |
340
- RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN
341
- | RUBY_EVENT_LINE, self); // RUBY_EVENT_SWITCH
342
- #else
343
- rb_add_event_hook(prof_event_hook,
344
- RUBY_EVENT_CALL | RUBY_EVENT_RETURN |
345
- RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN
346
- | RUBY_EVENT_LINE);
347
-
348
- pCurrentProfile = prof_get_profile(self);
349
- #endif
350
-
351
- #if defined(TOGGLE_GC_STATS)
352
- rb_gc_enable_stats();
353
- #endif
289
+ RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN |
290
+ RUBY_EVENT_LINE, self);
354
291
  }
355
292
 
356
293
  void
357
294
  prof_remove_hook()
358
295
  {
359
- #if defined(TOGGLE_GC_STATS)
360
- rb_gc_disable_stats();
361
- #endif
362
-
363
- #ifndef RUBY_VM
364
- pCurrentProfile = NULL;
365
- #endif
366
-
367
- /* Now unregister from event */
368
296
  rb_remove_event_hook(prof_event_hook);
369
297
  }
370
298
 
@@ -508,19 +436,12 @@ prof_start(VALUE self)
508
436
  char* trace_file_name;
509
437
 
510
438
  prof_profile_t* profile = prof_get_profile(self);
511
-
439
+
512
440
  if (profile->running == Qtrue)
513
441
  {
514
442
  rb_raise(rb_eRuntimeError, "RubyProf.start was already called");
515
443
  }
516
444
 
517
- #ifndef RUBY_VM
518
- if (pCurrentProfile != NULL)
519
- {
520
- rb_raise(rb_eRuntimeError, "Only one profile can run at a time on Ruby 1.8.*");
521
- }
522
- #endif
523
-
524
445
  profile->running = Qtrue;
525
446
  profile->paused = Qfalse;
526
447
  profile->last_thread_data = NULL;
@@ -674,8 +595,7 @@ prof_threads(VALUE self)
674
595
  void Init_ruby_prof()
675
596
  {
676
597
  mProf = rb_define_module("RubyProf");
677
- rb_define_const(mProf, "VERSION", rb_str_new2(RUBY_PROF_VERSION));
678
-
598
+
679
599
  rp_init_measure();
680
600
  rp_init_method_info();
681
601
  rp_init_call_info();