ruby-prof 1.4.3 → 1.6.3

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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +59 -9
  3. data/{README.rdoc → README.md} +2 -2
  4. data/Rakefile +4 -4
  5. data/bin/ruby-prof +100 -87
  6. data/ext/ruby_prof/rp_allocation.c +140 -85
  7. data/ext/ruby_prof/rp_allocation.h +8 -6
  8. data/ext/ruby_prof/rp_call_tree.c +502 -369
  9. data/ext/ruby_prof/rp_call_tree.h +47 -43
  10. data/ext/ruby_prof/rp_call_trees.c +16 -8
  11. data/ext/ruby_prof/rp_measure_allocations.c +10 -13
  12. data/ext/ruby_prof/rp_measure_memory.c +8 -4
  13. data/ext/ruby_prof/rp_measure_process_time.c +7 -6
  14. data/ext/ruby_prof/rp_measurement.c +147 -20
  15. data/ext/ruby_prof/rp_measurement.h +4 -1
  16. data/ext/ruby_prof/rp_method.c +142 -83
  17. data/ext/ruby_prof/rp_method.h +63 -62
  18. data/ext/ruby_prof/rp_profile.c +933 -900
  19. data/ext/ruby_prof/rp_profile.h +1 -0
  20. data/ext/ruby_prof/rp_thread.c +433 -362
  21. data/ext/ruby_prof/rp_thread.h +39 -39
  22. data/ext/ruby_prof/ruby_prof.c +0 -2
  23. data/ext/ruby_prof/ruby_prof.h +8 -0
  24. data/ext/ruby_prof/vc/ruby_prof.vcxproj +11 -8
  25. data/lib/ruby-prof/assets/call_stack_printer.html.erb +2 -1
  26. data/lib/ruby-prof/compatibility.rb +14 -0
  27. data/lib/ruby-prof/method_info.rb +8 -1
  28. data/lib/ruby-prof/printers/abstract_printer.rb +2 -1
  29. data/lib/ruby-prof/printers/call_tree_printer.rb +4 -10
  30. data/lib/ruby-prof/printers/graph_html_printer.rb +1 -1
  31. data/lib/ruby-prof/printers/multi_printer.rb +17 -17
  32. data/lib/ruby-prof/profile.rb +70 -37
  33. data/lib/ruby-prof/rack.rb +31 -21
  34. data/lib/ruby-prof/version.rb +1 -1
  35. data/lib/ruby-prof.rb +1 -1
  36. data/ruby-prof.gemspec +2 -3
  37. data/test/abstract_printer_test.rb +1 -0
  38. data/test/alias_test.rb +97 -106
  39. data/test/call_tree_builder.rb +126 -0
  40. data/test/call_tree_test.rb +94 -0
  41. data/test/call_tree_visitor_test.rb +1 -6
  42. data/test/call_trees_test.rb +6 -6
  43. data/test/{basic_test.rb → compatibility_test.rb} +8 -2
  44. data/test/duplicate_names_test.rb +5 -5
  45. data/test/dynamic_method_test.rb +24 -15
  46. data/test/enumerable_test.rb +1 -1
  47. data/test/exceptions_test.rb +2 -2
  48. data/test/exclude_methods_test.rb +3 -8
  49. data/test/exclude_threads_test.rb +4 -9
  50. data/test/fiber_test.rb +74 -8
  51. data/test/gc_test.rb +11 -9
  52. data/test/inverse_call_tree_test.rb +33 -34
  53. data/test/line_number_test.rb +37 -61
  54. data/test/marshal_test.rb +16 -3
  55. data/test/measure_allocations.rb +1 -5
  56. data/test/measure_allocations_test.rb +642 -357
  57. data/test/{measure_memory_trace_test.rb → measure_memory_test.rb} +180 -616
  58. data/test/measure_process_time_test.rb +1566 -741
  59. data/test/measure_wall_time_test.rb +179 -193
  60. data/test/measurement_test.rb +82 -0
  61. data/test/merge_test.rb +146 -0
  62. data/test/method_info_test.rb +95 -0
  63. data/test/multi_printer_test.rb +0 -5
  64. data/test/no_method_class_test.rb +1 -1
  65. data/test/pause_resume_test.rb +12 -16
  66. data/test/printer_call_stack_test.rb +2 -2
  67. data/test/printer_call_tree_test.rb +4 -4
  68. data/test/printer_flat_test.rb +1 -1
  69. data/test/printer_graph_html_test.rb +2 -2
  70. data/test/printer_graph_test.rb +2 -2
  71. data/test/printers_test.rb +14 -20
  72. data/test/printing_recursive_graph_test.rb +2 -2
  73. data/test/profile_test.rb +85 -0
  74. data/test/recursive_test.rb +374 -155
  75. data/test/scheduler.rb +363 -0
  76. data/test/singleton_test.rb +1 -1
  77. data/test/stack_printer_test.rb +5 -8
  78. data/test/start_stop_test.rb +11 -14
  79. data/test/test_helper.rb +11 -8
  80. data/test/thread_test.rb +106 -15
  81. data/test/unique_call_path_test.rb +28 -12
  82. data/test/yarv_test.rb +11 -7
  83. metadata +17 -29
  84. data/ext/ruby_prof/rp_aggregate_call_tree.c +0 -59
  85. data/ext/ruby_prof/rp_aggregate_call_tree.h +0 -13
  86. data/test/measure_allocations_trace_test.rb +0 -375
  87. data/test/temp.rb +0 -20
@@ -2,32 +2,11 @@
2
2
  Please see the LICENSE file for copyright and distribution information */
3
3
 
4
4
  #include "rp_allocation.h"
5
+ #include "rp_method.h"
5
6
 
6
7
  VALUE cRpAllocation;
7
8
 
8
- prof_allocation_t* allocations_table_lookup(st_table* table, st_data_t key)
9
- {
10
- prof_allocation_t* result = NULL;
11
- st_data_t value;
12
- if (rb_st_lookup(table, key, &value))
13
- {
14
- result = (prof_allocation_t*)value;
15
- }
16
-
17
- return result;
18
- }
19
-
20
- void allocations_table_insert(st_table* table, st_data_t key, prof_allocation_t* allocation)
21
- {
22
- rb_st_insert(table, (st_data_t)key, (st_data_t)allocation);
23
- }
24
-
25
- st_data_t allocations_key(VALUE klass, int source_line)
26
- {
27
- return (klass << 4) + source_line;
28
- }
29
-
30
- /* ====== prof_allocation_t ====== */
9
+ // ------ prof_allocation_t ------
31
10
  prof_allocation_t* prof_allocation_create(void)
32
11
  {
33
12
  prof_allocation_t* result = ALLOC(prof_allocation_t);
@@ -43,48 +22,17 @@ prof_allocation_t* prof_allocation_create(void)
43
22
  return result;
44
23
  }
45
24
 
46
- prof_allocation_t* prof_get_allocation(VALUE self)
25
+ prof_allocation_t* prof_allocation_get(VALUE self)
47
26
  {
48
27
  /* Can't use Data_Get_Struct because that triggers the event hook
49
28
  ending up in endless recursion. */
50
29
  prof_allocation_t* result = RTYPEDDATA_DATA(self);
51
-
52
30
  if (!result)
53
31
  rb_raise(rb_eRuntimeError, "This RubyProf::Allocation instance has already been freed, likely because its profile has been freed.");
54
32
 
55
33
  return result;
56
34
  }
57
35
 
58
- prof_allocation_t* prof_allocate_increment(prof_method_t* method, rb_trace_arg_t* trace_arg)
59
- {
60
- VALUE object = rb_tracearg_object(trace_arg);
61
- if (BUILTIN_TYPE(object) == T_IMEMO)
62
- return NULL;
63
-
64
- VALUE klass = rb_obj_class(object);
65
-
66
- int source_line = FIX2INT(rb_tracearg_lineno(trace_arg));
67
- st_data_t key = allocations_key(klass, source_line);
68
-
69
- prof_allocation_t* allocation = allocations_table_lookup(method->allocations_table, key);
70
- if (!allocation)
71
- {
72
- allocation = prof_allocation_create();
73
- allocation->source_line = source_line;
74
- allocation->source_file = rb_tracearg_path(trace_arg);
75
- allocation->klass_flags = 0;
76
- allocation->klass = resolve_klass(klass, &allocation->klass_flags);
77
-
78
- allocation->key = key;
79
- allocations_table_insert(method->allocations_table, key, allocation);
80
- }
81
-
82
- allocation->count++;
83
- allocation->memory += rb_obj_memsize_of(object);
84
-
85
- return allocation;
86
- }
87
-
88
36
  static void prof_allocation_ruby_gc_free(void* data)
89
37
  {
90
38
  if (data)
@@ -118,30 +66,39 @@ void prof_allocation_mark(void* data)
118
66
 
119
67
  prof_allocation_t* allocation = (prof_allocation_t*)data;
120
68
  if (allocation->object != Qnil)
121
- rb_gc_mark(allocation->object);
69
+ rb_gc_mark_movable(allocation->object);
122
70
 
123
71
  if (allocation->klass != Qnil)
124
- rb_gc_mark(allocation->klass);
72
+ rb_gc_mark_movable(allocation->klass);
125
73
 
126
74
  if (allocation->klass_name != Qnil)
127
- rb_gc_mark(allocation->klass_name);
75
+ rb_gc_mark_movable(allocation->klass_name);
128
76
 
129
77
  if (allocation->source_file != Qnil)
130
78
  rb_gc_mark(allocation->source_file);
131
79
  }
132
80
 
133
- static const rb_data_type_t allocation_type =
81
+ void prof_allocation_compact(void* data)
134
82
  {
135
- .wrap_struct_name = "Allocation",
136
- .function =
137
- {
138
- .dmark = prof_allocation_mark,
139
- .dfree = prof_allocation_ruby_gc_free,
140
- .dsize = prof_allocation_size,
141
- },
142
- .data = NULL,
143
- .flags = RUBY_TYPED_FREE_IMMEDIATELY
144
- };
83
+ prof_allocation_t* allocation = (prof_allocation_t*)data;
84
+ allocation->object = rb_gc_location(allocation->object);
85
+ allocation->klass = rb_gc_location(allocation->klass);
86
+ allocation->klass_name = rb_gc_location(allocation->klass_name);
87
+ }
88
+
89
+ static const rb_data_type_t allocation_type =
90
+ {
91
+ .wrap_struct_name = "Allocation",
92
+ .function =
93
+ {
94
+ .dmark = prof_allocation_mark,
95
+ .dfree = prof_allocation_ruby_gc_free,
96
+ .dsize = prof_allocation_size,
97
+ .dcompact = prof_allocation_compact
98
+ },
99
+ .data = NULL,
100
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY
101
+ };
145
102
 
146
103
  VALUE prof_allocation_wrap(prof_allocation_t* allocation)
147
104
  {
@@ -152,24 +109,122 @@ VALUE prof_allocation_wrap(prof_allocation_t* allocation)
152
109
  return allocation->object;
153
110
  }
154
111
 
155
- static VALUE prof_allocation_allocate(VALUE klass)
112
+ /* ====== Allocation Table ====== */
113
+ st_table* prof_allocations_create()
156
114
  {
157
- prof_allocation_t* allocation = prof_allocation_create();
158
- allocation->object = prof_allocation_wrap(allocation);
159
- return allocation->object;
115
+ return rb_st_init_numtable();
160
116
  }
161
117
 
162
- prof_allocation_t* prof_allocation_get(VALUE self)
118
+ static int allocations_table_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
163
119
  {
164
- /* Can't use Data_Get_Struct because that triggers the event hook
165
- ending up in endless recursion. */
166
- prof_allocation_t* result = RTYPEDDATA_DATA(self);
167
- if (!result)
168
- rb_raise(rb_eRuntimeError, "This RubyProf::Allocation instance has already been freed, likely because its profile has been freed.");
120
+ prof_allocation_free((prof_allocation_t*)value);
121
+ return ST_CONTINUE;
122
+ }
123
+
124
+ st_data_t allocations_key(VALUE klass, int source_line)
125
+ {
126
+ return (klass << 4) + source_line;
127
+ }
128
+
129
+ static int prof_allocations_collect(st_data_t key, st_data_t value, st_data_t result)
130
+ {
131
+ prof_allocation_t* allocation = (prof_allocation_t*)value;
132
+ VALUE arr = (VALUE)result;
133
+ rb_ary_push(arr, prof_allocation_wrap(allocation));
134
+ return ST_CONTINUE;
135
+ }
136
+
137
+ static int prof_allocations_mark_each(st_data_t key, st_data_t value, st_data_t data)
138
+ {
139
+ prof_allocation_t* allocation = (prof_allocation_t*)value;
140
+ prof_allocation_mark(allocation);
141
+ return ST_CONTINUE;
142
+ }
143
+
144
+ void prof_allocations_mark(st_table* allocations_table)
145
+ {
146
+ rb_st_foreach(allocations_table, prof_allocations_mark_each, 0);
147
+ }
148
+
149
+ void prof_allocations_free(st_table* table)
150
+ {
151
+ rb_st_foreach(table, allocations_table_free_iterator, 0);
152
+ rb_st_free_table(table);
153
+ }
154
+
155
+ prof_allocation_t* allocations_table_lookup(st_table* table, st_data_t key)
156
+ {
157
+ prof_allocation_t* result = NULL;
158
+ st_data_t value;
159
+ if (rb_st_lookup(table, key, &value))
160
+ {
161
+ result = (prof_allocation_t*)value;
162
+ }
169
163
 
170
164
  return result;
171
165
  }
172
166
 
167
+ void allocations_table_insert(st_table* table, st_data_t key, prof_allocation_t* allocation)
168
+ {
169
+ rb_st_insert(table, (st_data_t)key, (st_data_t)allocation);
170
+ }
171
+
172
+ prof_allocation_t* prof_allocate_increment(st_table* allocations_table, rb_trace_arg_t* trace_arg)
173
+ {
174
+ VALUE object = rb_tracearg_object(trace_arg);
175
+ if (BUILTIN_TYPE(object) == T_IMEMO)
176
+ return NULL;
177
+
178
+ VALUE klass = rb_obj_class(object);
179
+
180
+ int source_line = FIX2INT(rb_tracearg_lineno(trace_arg));
181
+ st_data_t key = allocations_key(klass, source_line);
182
+
183
+ prof_allocation_t* allocation = allocations_table_lookup(allocations_table, key);
184
+ if (!allocation)
185
+ {
186
+ allocation = prof_allocation_create();
187
+ allocation->source_line = source_line;
188
+ allocation->source_file = rb_tracearg_path(trace_arg);
189
+ allocation->klass_flags = 0;
190
+ allocation->klass = resolve_klass(klass, &allocation->klass_flags);
191
+
192
+ allocation->key = key;
193
+ allocations_table_insert(allocations_table, key, allocation);
194
+ }
195
+
196
+ allocation->count++;
197
+ allocation->memory += rb_obj_memsize_of(object);
198
+
199
+ return allocation;
200
+ }
201
+
202
+ // Returns an array of allocations
203
+ VALUE prof_allocations_wrap(st_table* allocations_table)
204
+ {
205
+ VALUE result = rb_ary_new();
206
+ rb_st_foreach(allocations_table, prof_allocations_collect, result);
207
+ return result;
208
+ }
209
+
210
+ void prof_allocations_unwrap(st_table* allocations_table, VALUE allocations)
211
+ {
212
+ for (int i = 0; i < rb_array_len(allocations); i++)
213
+ {
214
+ VALUE allocation = rb_ary_entry(allocations, i);
215
+ prof_allocation_t* allocation_data = prof_allocation_get(allocation);
216
+ rb_st_insert(allocations_table, allocation_data->key, (st_data_t)allocation_data);
217
+ }
218
+ }
219
+
220
+ /* ====== prof_allocation_t ====== */
221
+ static VALUE prof_allocation_allocate(VALUE klass)
222
+ {
223
+ prof_allocation_t* allocation = prof_allocation_create();
224
+ allocation->object = prof_allocation_wrap(allocation);
225
+ return allocation->object;
226
+ }
227
+
173
228
  /* call-seq:
174
229
  klass -> Class
175
230
 
@@ -238,17 +293,17 @@ static VALUE prof_allocation_memory(VALUE self)
238
293
  /* :nodoc: */
239
294
  static VALUE prof_allocation_dump(VALUE self)
240
295
  {
241
- prof_allocation_t* allocation = prof_get_allocation(self);
296
+ prof_allocation_t* allocation = prof_allocation_get(self);
242
297
 
243
298
  VALUE result = rb_hash_new();
244
299
 
245
- rb_hash_aset(result, ID2SYM(rb_intern("key")), INT2FIX(allocation->key));
300
+ rb_hash_aset(result, ID2SYM(rb_intern("key")), ULL2NUM(allocation->key));
246
301
  rb_hash_aset(result, ID2SYM(rb_intern("klass_name")), prof_allocation_klass_name(self));
247
302
  rb_hash_aset(result, ID2SYM(rb_intern("klass_flags")), INT2FIX(allocation->klass_flags));
248
303
  rb_hash_aset(result, ID2SYM(rb_intern("source_file")), allocation->source_file);
249
304
  rb_hash_aset(result, ID2SYM(rb_intern("source_line")), INT2FIX(allocation->source_line));
250
305
  rb_hash_aset(result, ID2SYM(rb_intern("count")), INT2FIX(allocation->count));
251
- rb_hash_aset(result, ID2SYM(rb_intern("memory")), LONG2FIX(allocation->memory));
306
+ rb_hash_aset(result, ID2SYM(rb_intern("memory")), ULL2NUM(allocation->memory));
252
307
 
253
308
  return result;
254
309
  }
@@ -256,16 +311,16 @@ static VALUE prof_allocation_dump(VALUE self)
256
311
  /* :nodoc: */
257
312
  static VALUE prof_allocation_load(VALUE self, VALUE data)
258
313
  {
259
- prof_allocation_t* allocation = prof_get_allocation(self);
314
+ prof_allocation_t* allocation = prof_allocation_get(self);
260
315
  allocation->object = self;
261
316
 
262
- allocation->key = FIX2LONG(rb_hash_aref(data, ID2SYM(rb_intern("key"))));
317
+ allocation->key = RB_NUM2ULL(rb_hash_aref(data, ID2SYM(rb_intern("key"))));
263
318
  allocation->klass_name = rb_hash_aref(data, ID2SYM(rb_intern("klass_name")));
264
319
  allocation->klass_flags = FIX2INT(rb_hash_aref(data, ID2SYM(rb_intern("klass_flags"))));
265
320
  allocation->source_file = rb_hash_aref(data, ID2SYM(rb_intern("source_file")));
266
321
  allocation->source_line = FIX2INT(rb_hash_aref(data, ID2SYM(rb_intern("source_line"))));
267
322
  allocation->count = FIX2INT(rb_hash_aref(data, ID2SYM(rb_intern("count"))));
268
- allocation->memory = FIX2LONG(rb_hash_aref(data, ID2SYM(rb_intern("memory"))));
323
+ allocation->memory = NUM2ULONG(rb_hash_aref(data, ID2SYM(rb_intern("memory"))));
269
324
 
270
325
  return data;
271
326
  }
@@ -5,7 +5,6 @@
5
5
  #define _RP_ALLOCATION_
6
6
 
7
7
  #include "ruby_prof.h"
8
- #include "rp_method.h"
9
8
 
10
9
  typedef struct prof_allocation_t
11
10
  {
@@ -20,12 +19,15 @@ typedef struct prof_allocation_t
20
19
  VALUE object; /* Cache to wrapped object */
21
20
  } prof_allocation_t;
22
21
 
22
+ // Allocation (prof_allocation_t*)
23
23
  void rp_init_allocation(void);
24
- void prof_allocation_free(prof_allocation_t* allocation);
25
- void prof_allocation_mark(void* data);
26
- VALUE prof_allocation_wrap(prof_allocation_t* allocation);
27
- prof_allocation_t* prof_allocation_get(VALUE self);
28
- prof_allocation_t* prof_allocate_increment(prof_method_t* method, rb_trace_arg_t* trace_arg);
24
+ prof_allocation_t* prof_allocate_increment(st_table* allocations_table, rb_trace_arg_t* trace_arg);
29
25
 
26
+ // Allocations (st_table*)
27
+ st_table* prof_allocations_create(void);
28
+ VALUE prof_allocations_wrap(st_table* allocations_table);
29
+ void prof_allocations_unwrap(st_table* allocations_table, VALUE allocations);
30
+ void prof_allocations_mark(st_table* allocations_table);
31
+ void prof_allocations_free(st_table* table);
30
32
 
31
33
  #endif //_RP_ALLOCATION_