ruby-prof 0.11.0.rc3-x86-mingw32 → 0.11.2-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,3 +1,31 @@
1
+ 0.11.2 (2012-05-06)
2
+ ======================
3
+ * Fix compile issue with BOOL. Should be _Bool for C99.
4
+
5
+
6
+ 0.11.1 (2012-05-06)
7
+ ======================
8
+ * Added option --exclude-common-callbacks, plus exclude #map and #inject in common cycles (Vasily Fedoseyev)
9
+ * Add option --exclude-common-cycles to exclude common iterators (Vasily Fedoseyev)
10
+ * Allow method elimination from command line via '-x' and '-X' keys (Vasily Fedoseyev)
11
+
12
+
13
+ 0.11.0 (2012-05-05)
14
+ ======================
15
+ * Fix pause/resume so it actually works and add tests (David Barri)
16
+ * Resume now returns the result of the block when given (David Barri)
17
+ * Make recursive method explanation more clear (Charlie Savage)
18
+ * Fix ruby warnings (Charlie Savage)
19
+ * Toggle GC.enable_stats when profiling for memory to get the data (Vasily Fedoseyev)
20
+ * Fix patched ruby support and remove some warnings (Vasily Fedoseyev)
21
+ * Fix tests on 1.8.7 (rogerdpack)
22
+
23
+
24
+ 0.11.0.rc3 (2012-03-26)
25
+ ======================
26
+ * Include missing files in gemspec (Charlie Savage).
27
+
28
+
1
29
  0.11.0.rc2 (2012-03-25)
2
30
  ======================
3
31
  * Lots of improvements to Rack handler - this can be used to profile requests
data/Rakefile CHANGED
@@ -22,6 +22,7 @@ SO_NAME = 'ruby_prof'
22
22
 
23
23
  default_spec = Gem::Specification.load("#{GEM_NAME}.gemspec")
24
24
 
25
+ # specify which versions/builds to cross compile
25
26
  Rake::ExtensionTask.new do |ext|
26
27
  ext.gem_spec = default_spec
27
28
  ext.name = SO_NAME
@@ -172,6 +172,59 @@ opts = OptionParser.new do |opts|
172
172
  options.exec ||= []
173
173
  options.exec << code
174
174
  end
175
+
176
+ opts.on('-x regexp', '--exclude regexp', 'exclude methods by regexp (see method elimination)') do|meth|
177
+ options.eliminate_methods ||= []
178
+ options.eliminate_methods << Regexp.new(meth)
179
+ end
180
+
181
+ opts.on('-X file', '--exclude-file file', 'exclude methods by regexp listed in file (see method elimination)') do|file|
182
+ options.eliminate_methods_files ||= []
183
+ options.eliminate_methods_files << file
184
+ end
185
+
186
+ opts.on('--exclude-common-cycles', 'make common iterators like Integer#times appear inlined') do|meth|
187
+ options.eliminate_methods ||= []
188
+ options.eliminate_methods += %w{
189
+ Integer#times
190
+ Integer#upto
191
+ Integer#downto
192
+ Enumerator#each
193
+ Enumerator#each_with_index
194
+ Enumerator#each_with_object
195
+
196
+ Array#each
197
+ Array#each_index
198
+ Array#reverse_each
199
+ Array#map
200
+
201
+ Hash#each
202
+ Hash#each_pair
203
+ Hash#each_key
204
+ Hash#each_value
205
+
206
+ Range#each
207
+ Enumerable#each_cons
208
+ Enumerable#each_entry
209
+ Enumerable#each_slice
210
+ Enumerable#each_with_index
211
+ Enumerable#each_with_object
212
+ Enumerable#reverse_each
213
+ Enumerable#inject
214
+ Enumerable#collect
215
+ Enumerable#reduce
216
+ }
217
+ #TODO: may be the whole Enumerable module should be excluded via 'Enumerable#.*', we need feedback on use cases.
218
+ end
219
+
220
+ opts.on('--exclude-common-callbacks', 'make common callbacks invocations like Integer#times appear inlined so you can see call origins in graph') do|meth|
221
+ options.eliminate_methods ||= []
222
+ options.eliminate_methods += %w{
223
+ Method#call
224
+ Proc#call
225
+ ActiveSupport::Callbacks::ClassMethods#__run_callback
226
+ }
227
+ end
175
228
  end
176
229
 
177
230
  begin
@@ -201,6 +254,10 @@ at_exit {
201
254
  # Stop profiling
202
255
  result = RubyProf.stop
203
256
 
257
+ # Eliminate unwanted methods from call graph
258
+ result.eliminate_methods! options.eliminate_methods if options.eliminate_methods
259
+ options.eliminate_methods_files.each{|f| result.eliminate_methods!(f)} if options.eliminate_methods_files
260
+
204
261
  # Create a printer
205
262
  printer = options.printer.new(result)
206
263
  printer_options = {:min_percent => options.min_percent, :sort_method => options.sort_method}
@@ -8,50 +8,29 @@
8
8
  static VALUE cMeasureAllocations;
9
9
 
10
10
  #if defined(HAVE_RB_OS_ALLOCATED_OBJECTS)
11
- #define MEASURE_ALLOCATIONS_ENABLED Qtrue
11
+ unsigned LONG_LONG rb_os_allocated_objects();
12
+ #endif
13
+
14
+ #if defined(HAVE_RB_GC_MALLOC_ALLOCATIONS)
15
+ unsigned LONG_LONG rb_gc_malloc_allocations();
16
+ #endif
12
17
 
13
18
  static double
14
19
  measure_allocations()
15
20
  {
21
+ #if defined(HAVE_RB_OS_ALLOCATED_OBJECTS)
22
+ #define MEASURE_ALLOCATIONS_ENABLED Qtrue
16
23
  return rb_os_allocated_objects();
17
- }
18
-
19
- /* Document-method: prof_measure_allocations
20
- call-seq:
21
- measure_allocations -> int
22
-
23
- Returns the total number of object allocations since Ruby started.*/
24
- static VALUE
25
- prof_measure_allocations(VALUE self)
26
- {
27
- #if defined(HAVE_LONG_LONG)
28
- return ULL2NUM(rb_os_allocated_objects());
29
- #else
30
- return ULONG2NUM(rb_os_allocated_objects());
31
- #endif
32
- }
33
24
 
34
25
  #elif defined(HAVE_RB_GC_MALLOC_ALLOCATIONS)
35
-
36
26
  #define MEASURE_ALLOCATIONS_ENABLED Qtrue
37
-
38
- static double
39
- measure_allocations()
40
- {
41
27
  return rb_gc_malloc_allocations();
42
- }
43
28
 
44
29
  #else
45
-
46
30
  #define MEASURE_ALLOCATIONS_ENABLED Qfalse
47
-
48
- static double
49
- measure_allocations()
50
- {
51
31
  return 0;
52
- }
53
-
54
32
  #endif
33
+ }
55
34
 
56
35
 
57
36
  prof_measurer_t* prof_measurer_allocations()
@@ -8,53 +8,31 @@
8
8
  static VALUE cMeasureGcRuns;
9
9
 
10
10
  #if defined(HAVE_RB_GC_COLLECTIONS)
11
+ VALUE rb_gc_collections(void);
12
+ #endif
13
+
14
+ #if defined(HAVE_RB_GC_HEAP_INFO)
15
+ VALUE rb_gc_heap_info(void);
16
+ #endif
11
17
 
12
- #define MEASURE_GC_RUNS_ENABLED Qtrue
13
18
 
14
19
  static double
15
20
  measure_gc_runs()
16
21
  {
17
- return NUM2INT(rb_gc_collections());
18
- }
19
-
20
- /* call-seq:
21
- gc_runs -> Integer
22
-
23
- Returns the total number of garbage collections.*/
24
- static VALUE
25
- prof_measure_gc_runs(VALUE self)
26
- {
27
- return rb_gc_collections();
28
- }
22
+ #if defined(HAVE_RB_GC_COLLECTIONS)
23
+ #define MEASURE_GC_RUNS_ENABLED Qtrue
24
+ return NUM2INT(rb_gc_collections());
29
25
 
30
26
  #elif defined(HAVE_RB_GC_HEAP_INFO)
31
-
32
27
  #define MEASURE_GC_RUNS_ENABLED Qtrue
33
-
34
- static double
35
- measure_gc_runs()
36
- {
37
28
  VALUE h = rb_gc_heap_info();
38
29
  return NUM2UINT(rb_hash_aref(h, rb_str_new2("num_gc_passes")));
39
- }
40
-
41
- static VALUE
42
- prof_measure_gc_runs(VALUE self)
43
- {
44
- VALUE h = rb_gc_heap_info();
45
- return rb_hash_aref(h, rb_str_new2("num_gc_passes"));
46
- }
47
-
48
- #else
49
30
 
31
+ #else
50
32
  #define MEASURE_GC_RUNS_ENABLED Qfalse
51
-
52
- static double
53
- measure_gc_runs()
54
- {
55
33
  return 0;
56
- }
57
34
  #endif
35
+ }
58
36
 
59
37
  prof_measurer_t* prof_measurer_gc_runs()
60
38
  {
@@ -8,40 +8,27 @@
8
8
  static VALUE cMeasureGcTimes;
9
9
 
10
10
  #if defined(HAVE_RB_GC_TIME)
11
+ VALUE rb_gc_time();
12
+ #endif
11
13
 
12
- #define MEASURE_GC_TIME_ENABLED Qtrue
13
14
 
14
15
  static double
15
16
  measure_gc_time()
16
17
  {
17
- int conversion = 1000000
18
+ #if defined(HAVE_RB_GC_TIME)
19
+ #define MEASURE_GC_TIME_ENABLED Qtrue
20
+ const int conversion = 1000000;
18
21
  #if HAVE_LONG_LONG
19
22
  return NUM2LL(rb_gc_time() / conversion);
20
23
  #else
21
24
  return NUM2LONG(rb_gc_time() / conversion));
22
25
  #endif
23
- }
24
-
25
- /* call-seq:
26
- gc_time -> Integer
27
-
28
- Returns the time spent doing garbage collections in microseconds.*/
29
- static VALUE
30
- prof_measure_gc_time(VALUE self)
31
- {
32
- return rb_gc_time();
33
- }
34
26
 
35
27
  #else
36
-
37
28
  #define MEASURE_GC_TIME_ENABLED Qfalse
38
-
39
- static double
40
- measure_gc_time()
41
- {
42
29
  return 0;
43
- }
44
30
  #endif
31
+ }
45
32
 
46
33
  prof_measurer_t* prof_measurer_gc_time()
47
34
  {
@@ -63,6 +50,7 @@ prof_measure_gc_time(VALUE self)
63
50
  return ULONG2NUM(measure_gc_time());
64
51
  #endif
65
52
  }
53
+
66
54
  void rp_init_measure_gc_time()
67
55
  {
68
56
  rb_define_const(mProf, "GC_TIME", INT2NUM(MEASURE_GC_TIME));
@@ -7,52 +7,45 @@
7
7
 
8
8
  static VALUE cMeasureMemory;
9
9
 
10
+
10
11
  #if defined(HAVE_RB_GC_ALLOCATED_SIZE)
11
- #define TOGGLE_GC_STATS 1
12
- #define MEASURE_GC_TIME_ENABLED Qtrue
12
+ VALUE rb_gc_allocated_size();
13
+ #endif
14
+
15
+ #if defined(HAVE_RB_GC_MALLOC_ALLOCATED_SIZE)
16
+ size_t rb_gc_malloc_allocated_size();
17
+ #endif
18
+
19
+ #if defined(HAVE_RB_HEAP_TOTAL_MEM)
20
+ //FIXME: did not find the patch to check prototype, assuming it to return size_t
21
+ size_t rb_heap_total_mem();
22
+ #endif
13
23
 
14
24
  static double
15
25
  measure_memory()
16
26
  {
27
+ #if defined(HAVE_RB_GC_ALLOCATED_SIZE)
28
+ #define TOGGLE_GC_STATS 1
29
+ #define MEASURE_MEMORY_ENABLED Qtrue
17
30
  #if defined(HAVE_LONG_LONG)
18
- return NUM2LL(rb_gc_allocated_size() / 1024);
31
+ return NUM2LL(rb_gc_allocated_size()) / 1024.0;
19
32
  #else
20
- return NUM2ULONG(rb_gc_allocated_size() / 1024);
33
+ return NUM2ULONG(rb_gc_allocated_size()) / 1024.0;
21
34
  #endif
22
- }
23
35
 
24
36
  #elif defined(HAVE_RB_GC_MALLOC_ALLOCATED_SIZE)
25
-
26
37
  #define MEASURE_MEMORY_ENABLED Qtrue
27
-
28
- static double
29
- measure_memory()
30
- {
31
- return rb_gc_malloc_allocated_size() / 1024;
32
- }
33
-
38
+ return rb_gc_malloc_allocated_size() / 1024.0;
34
39
 
35
40
  #elif defined(HAVE_RB_HEAP_TOTAL_MEM)
36
-
37
41
  #define MEASURE_MEMORY_ENABLED Qtrue
38
-
39
- static double
40
- measure_memory()
41
- {
42
- return rb_heap_total_mem() / 1024;
43
- }
42
+ return rb_heap_total_mem() / 1024.0;
44
43
 
45
44
  #else
46
-
47
45
  #define MEASURE_MEMORY_ENABLED Qfalse
48
-
49
- static double
50
- measure_memory()
51
- {
52
46
  return 0;
53
- }
54
-
55
47
  #endif
48
+ }
56
49
 
57
50
  prof_measurer_t* prof_measurer_memory()
58
51
  {
@@ -5,6 +5,22 @@
5
5
 
6
6
  #define INITIAL_STACK_SIZE 8
7
7
 
8
+ void
9
+ frame_pause(prof_frame_t *frame, double current_measurement)
10
+ {
11
+ if (frame && frame_is_unpaused(frame))
12
+ frame->pause_time = current_measurement;
13
+ }
14
+
15
+ void
16
+ frame_unpause(prof_frame_t *frame, double current_measurement)
17
+ {
18
+ if (frame && frame_is_paused(frame)) {
19
+ frame->dead_time += (current_measurement - frame->pause_time);
20
+ frame->pause_time = -1;
21
+ }
22
+ }
23
+
8
24
 
9
25
  /* Creates a stack of prof_frame_t to keep track
10
26
  of timings for active methods. */
@@ -48,7 +64,7 @@ stack_push(prof_stack_t *stack)
48
64
  result->child_time = 0;
49
65
  result->switch_time = 0;
50
66
  result->wait_time = 0;
51
- result->depth = (stack->ptr - stack->start);
67
+ result->depth = (int)(stack->ptr - stack->start); // shortening of 64 bit into 32
52
68
 
53
69
  // Increment the stack ptr for next time
54
70
  stack->ptr++;
@@ -22,10 +22,18 @@ typedef struct
22
22
  double switch_time; /* Time at switch to different thread */
23
23
  double wait_time;
24
24
  double child_time;
25
+ double pause_time; // Time pause() was initiated
26
+ double dead_time; // Time to ignore (i.e. total amount of time between pause/resume blocks)
25
27
  int depth;
26
28
  unsigned int line;
27
29
  } prof_frame_t;
28
30
 
31
+ #define frame_is_paused(f) (f->pause_time >= 0)
32
+ #define frame_is_unpaused(f) (f->pause_time < 0)
33
+ void frame_pause(prof_frame_t*, double current_measurement);
34
+ void frame_unpause(prof_frame_t*, double current_measurement);
35
+
36
+
29
37
  /* Current stack of active methods.*/
30
38
  typedef struct
31
39
  {
@@ -133,6 +133,11 @@ pop_frame(prof_profile_t* profile, thread_data_t *thread_data)
133
133
  double measurement = profile->measurer->measure();
134
134
  double total_time;
135
135
  double self_time;
136
+ #ifdef _MSC_VER
137
+ BOOL frame_paused;
138
+ #else
139
+ _Bool frame_paused;
140
+ #endif
136
141
 
137
142
  frame = stack_pop(thread_data->stack); // only time it's called
138
143
 
@@ -140,11 +145,13 @@ pop_frame(prof_profile_t* profile, thread_data_t *thread_data)
140
145
  a method that exits. And it can happen if an exception is raised
141
146
  in code that is being profiled and the stack unwinds (RubyProf is
142
147
  not notified of that by the ruby runtime. */
143
- if (frame == NULL)
148
+ if (frame == NULL)
144
149
  return NULL;
145
150
 
146
151
  /* Calculate the total time this method took */
147
- total_time = measurement - frame->start_time;
152
+ frame_paused = frame_is_paused(frame);
153
+ frame_unpause(frame, measurement);
154
+ total_time = measurement - frame->start_time - frame->dead_time;
148
155
  self_time = total_time - frame->child_time - frame->wait_time;
149
156
 
150
157
  /* Update information about the current method */
@@ -158,6 +165,12 @@ pop_frame(prof_profile_t* profile, thread_data_t *thread_data)
158
165
  if (parent_frame)
159
166
  {
160
167
  parent_frame->child_time += total_time;
168
+ parent_frame->dead_time += frame->dead_time;
169
+
170
+ // Repause parent if currently paused
171
+ if (frame_paused)
172
+ frame_pause(parent_frame, measurement);
173
+
161
174
  call_info->line = parent_frame->line;
162
175
  }
163
176
 
@@ -333,6 +346,11 @@ prof_event_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE kla
333
346
  call_info_table_insert(frame->call_info->call_infos, method->key, call_info);
334
347
  prof_add_call_info(method->call_infos, call_info);
335
348
  }
349
+
350
+ // Unpause the parent frame. If currently paused then:
351
+ // 1) The child frame will begin paused.
352
+ // 2) The parent will inherit the child's dead time.
353
+ frame_unpause(frame, measurement);
336
354
  }
337
355
 
338
356
  /* Push a new frame onto the stack for a new c-call or ruby call (into a method) */
@@ -340,6 +358,8 @@ prof_event_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE kla
340
358
  frame->call_info = call_info;
341
359
  frame->call_info->depth = frame->depth;
342
360
  frame->start_time = measurement;
361
+ frame->pause_time = profile->paused == Qtrue ? measurement : -1;
362
+ frame->dead_time = 0;
343
363
  frame->line = rb_sourceline();
344
364
  break;
345
365
  }
@@ -459,7 +479,7 @@ prof_initialize(int argc, VALUE *argv, VALUE self)
459
479
  {
460
480
  prof_profile_t* profile = prof_get_profile(self);
461
481
  VALUE mode;
462
- prof_measure_mode_t measurer;
482
+ prof_measure_mode_t measurer = MEASURE_WALL_TIME;
463
483
  VALUE exclude_threads;
464
484
  int i;
465
485
 
@@ -497,6 +517,39 @@ prof_initialize(int argc, VALUE *argv, VALUE self)
497
517
  return self;
498
518
  }
499
519
 
520
+ static int pause_thread(st_data_t key, st_data_t value, st_data_t data)
521
+ {
522
+ thread_data_t* thread_data = (thread_data_t *) value;
523
+ prof_profile_t* profile = (prof_profile_t*) data;
524
+
525
+ prof_frame_t* frame = stack_peek(thread_data->stack);
526
+ frame_pause(frame, profile->measurement_at_pause_resume);
527
+
528
+ return ST_CONTINUE;
529
+ }
530
+
531
+ static int unpause_thread(st_data_t key, st_data_t value, st_data_t data)
532
+ {
533
+ thread_data_t* thread_data = (thread_data_t *) value;
534
+ prof_profile_t* profile = (prof_profile_t*) data;
535
+
536
+ prof_frame_t* frame = stack_peek(thread_data->stack);
537
+ frame_unpause(frame, profile->measurement_at_pause_resume);
538
+
539
+ return ST_CONTINUE;
540
+ }
541
+
542
+ /* call-seq:
543
+ paused? -> boolean
544
+
545
+ Returns whether a profile is currently paused.*/
546
+ static VALUE
547
+ prof_paused(VALUE self)
548
+ {
549
+ prof_profile_t* profile = prof_get_profile(self);
550
+ return profile->paused;
551
+ }
552
+
500
553
  /* call-seq:
501
554
  running? -> boolean
502
555
 
@@ -516,6 +569,7 @@ static VALUE
516
569
  prof_start(VALUE self)
517
570
  {
518
571
  char* trace_file_name;
572
+
519
573
  prof_profile_t* profile = prof_get_profile(self);
520
574
 
521
575
  if (profile->running == Qtrue)
@@ -523,7 +577,15 @@ prof_start(VALUE self)
523
577
  rb_raise(rb_eRuntimeError, "RubyProf.start was already called");
524
578
  }
525
579
 
580
+ #ifndef RUBY_VM
581
+ if (pCurrentProfile != NULL)
582
+ {
583
+ rb_raise(rb_eRuntimeError, "Only one profile can run at a time on Ruby 1.8.*");
584
+ }
585
+ #endif
586
+
526
587
  profile->running = Qtrue;
588
+ profile->paused = Qfalse;
527
589
  profile->last_thread_data = NULL;
528
590
 
529
591
 
@@ -562,9 +624,13 @@ prof_pause(VALUE self)
562
624
  rb_raise(rb_eRuntimeError, "RubyProf is not running.");
563
625
  }
564
626
 
565
- profile->running = Qfalse;
627
+ if (profile->paused == Qfalse)
628
+ {
629
+ profile->paused = Qtrue;
630
+ profile->measurement_at_pause_resume = profile->measurer->measure();
631
+ st_foreach(profile->threads_tbl, pause_thread, (st_data_t) profile);
632
+ }
566
633
 
567
- prof_remove_hook();
568
634
  return self;
569
635
  }
570
636
 
@@ -578,20 +644,17 @@ prof_resume(VALUE self)
578
644
  prof_profile_t* profile = prof_get_profile(self);
579
645
  if (profile->running == Qfalse)
580
646
  {
581
- prof_start(self);
582
- }
583
- else
584
- {
585
- profile->running = Qtrue;
586
- prof_install_hook(self);
647
+ rb_raise(rb_eRuntimeError, "RubyProf is not running.");
587
648
  }
588
649
 
589
- if (rb_block_given_p())
650
+ if (profile->paused == Qtrue)
590
651
  {
591
- rb_ensure(rb_yield, self, prof_pause, self);
652
+ profile->paused = Qfalse;
653
+ profile->measurement_at_pause_resume = profile->measurer->measure();
654
+ st_foreach(profile->threads_tbl, unpause_thread, (st_data_t) profile);
592
655
  }
593
656
 
594
- return self;
657
+ return rb_block_given_p() ? rb_ensure(rb_yield, self, prof_pause, self) : self;
595
658
  }
596
659
 
597
660
  /* call-seq:
@@ -628,7 +691,7 @@ prof_stop(VALUE self)
628
691
 
629
692
  /* Unset the last_thread_data (very important!)
630
693
  and the threads table */
631
- profile->running = Qfalse;
694
+ profile->running = profile->paused = Qfalse;
632
695
  profile->last_thread_data = NULL;
633
696
 
634
697
  /* Post process result */
@@ -686,10 +749,10 @@ void Init_ruby_prof()
686
749
  rb_define_alloc_func (cProfile, prof_allocate);
687
750
  rb_define_method(cProfile, "initialize", prof_initialize, -1);
688
751
  rb_define_method(cProfile, "start", prof_start, 0);
689
- rb_define_method(cProfile, "start", prof_start, 0);
690
752
  rb_define_method(cProfile, "stop", prof_stop, 0);
691
753
  rb_define_method(cProfile, "resume", prof_resume, 0);
692
754
  rb_define_method(cProfile, "pause", prof_pause, 0);
693
755
  rb_define_method(cProfile, "running?", prof_running, 0);
756
+ rb_define_method(cProfile, "paused?", prof_paused, 0);
694
757
  rb_define_method(cProfile, "threads", prof_threads, 0);
695
758
  }