ruby-prof 1.1.0-x64-mingw32 → 1.3.0-x64-mingw32

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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +19 -1
  3. data/bin/ruby-prof +100 -152
  4. data/ext/ruby_prof/rp_aggregate_call_tree.c +59 -0
  5. data/ext/ruby_prof/rp_aggregate_call_tree.h +13 -0
  6. data/ext/ruby_prof/rp_allocation.c +67 -59
  7. data/ext/ruby_prof/rp_allocation.h +3 -3
  8. data/ext/ruby_prof/rp_call_tree.c +369 -0
  9. data/ext/ruby_prof/rp_call_tree.h +43 -0
  10. data/ext/ruby_prof/rp_call_trees.c +288 -0
  11. data/ext/ruby_prof/rp_call_trees.h +28 -0
  12. data/ext/ruby_prof/rp_measure_allocations.c +11 -13
  13. data/ext/ruby_prof/rp_measure_process_time.c +11 -13
  14. data/ext/ruby_prof/rp_measure_wall_time.c +17 -15
  15. data/ext/ruby_prof/rp_measurement.c +47 -40
  16. data/ext/ruby_prof/rp_measurement.h +7 -7
  17. data/ext/ruby_prof/rp_method.c +116 -255
  18. data/ext/ruby_prof/rp_method.h +31 -39
  19. data/ext/ruby_prof/rp_profile.c +311 -281
  20. data/ext/ruby_prof/rp_profile.h +1 -2
  21. data/ext/ruby_prof/rp_stack.c +113 -105
  22. data/ext/ruby_prof/rp_stack.h +17 -20
  23. data/ext/ruby_prof/rp_thread.c +136 -111
  24. data/ext/ruby_prof/rp_thread.h +12 -9
  25. data/ext/ruby_prof/ruby_prof.c +27 -23
  26. data/ext/ruby_prof/ruby_prof.h +9 -0
  27. data/ext/ruby_prof/vc/ruby_prof.vcxproj +11 -7
  28. data/lib/ruby-prof.rb +2 -3
  29. data/lib/ruby-prof/assets/call_stack_printer.html.erb +4 -7
  30. data/lib/ruby-prof/assets/graph_printer.html.erb +5 -6
  31. data/lib/ruby-prof/{call_info.rb → call_tree.rb} +6 -6
  32. data/lib/ruby-prof/call_tree_visitor.rb +36 -0
  33. data/lib/ruby-prof/measurement.rb +5 -2
  34. data/lib/ruby-prof/method_info.rb +3 -15
  35. data/lib/ruby-prof/printers/call_info_printer.rb +12 -10
  36. data/lib/ruby-prof/printers/call_stack_printer.rb +19 -22
  37. data/lib/ruby-prof/printers/call_tree_printer.rb +1 -1
  38. data/lib/ruby-prof/printers/dot_printer.rb +3 -3
  39. data/lib/ruby-prof/printers/graph_printer.rb +3 -4
  40. data/lib/ruby-prof/printers/multi_printer.rb +2 -2
  41. data/lib/ruby-prof/rack.rb +3 -0
  42. data/lib/ruby-prof/thread.rb +3 -18
  43. data/lib/ruby-prof/version.rb +1 -1
  44. data/ruby-prof.gemspec +7 -0
  45. data/test/alias_test.rb +42 -45
  46. data/test/basic_test.rb +0 -86
  47. data/test/{call_info_visitor_test.rb → call_tree_visitor_test.rb} +6 -5
  48. data/test/call_trees_test.rb +66 -0
  49. data/test/exclude_methods_test.rb +17 -12
  50. data/test/fiber_test.rb +197 -9
  51. data/test/gc_test.rb +36 -42
  52. data/test/inverse_call_tree_test.rb +175 -0
  53. data/test/line_number_test.rb +67 -70
  54. data/test/marshal_test.rb +7 -11
  55. data/test/measure_allocations_test.rb +224 -234
  56. data/test/measure_allocations_trace_test.rb +224 -234
  57. data/test/measure_memory_trace_test.rb +814 -469
  58. data/test/measure_process_time_test.rb +0 -64
  59. data/test/measure_times.rb +2 -0
  60. data/test/measure_wall_time_test.rb +34 -58
  61. data/test/pause_resume_test.rb +19 -10
  62. data/test/prime.rb +1 -3
  63. data/test/prime_script.rb +6 -0
  64. data/test/printers_test.rb +1 -1
  65. data/test/recursive_test.rb +50 -54
  66. data/test/start_stop_test.rb +19 -19
  67. data/test/test_helper.rb +3 -15
  68. data/test/thread_test.rb +11 -11
  69. data/test/unique_call_path_test.rb +25 -95
  70. metadata +19 -10
  71. data/ext/ruby_prof/rp_call_info.c +0 -271
  72. data/ext/ruby_prof/rp_call_info.h +0 -35
  73. data/lib/2.6.5/ruby_prof.so +0 -0
  74. data/lib/ruby-prof/call_info_visitor.rb +0 -38
  75. data/test/parser_timings.rb +0 -24
@@ -9,62 +9,54 @@
9
9
 
10
10
  extern VALUE cRpMethodInfo;
11
11
 
12
- /* Source relation bit offsets. */
12
+ // Source relation bit offsets.
13
13
  enum {
14
- kModuleIncludee = 0x1, /* Included in module */
15
- kClassSingleton = 0x2, /* Singleton of a class */
16
- kModuleSingleton = 0x4, /* Singleton of a module */
17
- kObjectSingleton = 0x8, /* Singleton of an object */
18
- kOtherSingleton = 0x10 /* Singleton of unkown object */
14
+ kModuleIncludee = 0x1, // Included in module
15
+ kClassSingleton = 0x2, // Singleton of a class
16
+ kModuleSingleton = 0x4, // Singleton of a module
17
+ kObjectSingleton = 0x8, // Singleton of an object
18
+ kOtherSingleton = 0x10 // Singleton of unkown object
19
19
  };
20
20
 
21
- /* Forward declaration, see rp_call_info.h */
22
- struct prof_call_infos_t;
23
-
24
- /* Profiling information for each method. */
25
- /* Excluded methods have no call_infos, source_klass, or source_file. */
26
- typedef struct
21
+ // Profiling information for each method.
22
+ // Excluded methods have no call_trees, source_klass, or source_file.
23
+ typedef struct prof_method_t
27
24
  {
28
- st_data_t key; /* Table key */
29
-
30
- int visits; /* Current visits on the stack */
31
- bool excluded; /* Exclude from profile? */
32
-
33
- st_table* parent_call_infos; /* Call infos that call this method */
34
- st_table* child_call_infos; /* Call infos that this method calls */
35
- st_table* allocations_table; /* Tracks object allocations */
25
+ VALUE profile; // Profile this method is associated with - needed for mark phase
26
+ struct prof_call_trees_t* call_trees; // Call infos that call this method
27
+ st_table* allocations_table; // Tracks object allocations
36
28
 
37
- unsigned int klass_flags; /* Information about the type of class */
38
- VALUE klass; /* Resolved klass */
39
- VALUE klass_name; /* Resolved klass name for this method */
40
- VALUE method_name; /* Resolved method name for this method */
29
+ st_data_t key; // Table key
30
+ unsigned int klass_flags; // Information about the type of class
31
+ VALUE klass; // Resolved klass
32
+ VALUE klass_name; // Resolved klass name for this method
33
+ VALUE method_name; // Resolved method name for this method
41
34
 
42
- VALUE object; /* Cached ruby object */
35
+ VALUE object; // Cached ruby object
43
36
 
44
- bool root; /* Is this a root method */
45
37
  bool recursive;
46
- VALUE source_file; /* Source file */
47
- int source_line; /* Line number */
38
+ int visits; // Current visits on the stack
39
+ VALUE source_file; // Source file
40
+ int source_line; // Line number
48
41
 
49
- prof_measurement_t *measurement;
42
+ prof_measurement_t* measurement; // Stores measurement data for this method
50
43
  } prof_method_t;
51
44
 
52
45
  void rp_init_method_info(void);
53
46
 
54
47
  st_data_t method_key(VALUE klass, VALUE msym);
55
48
 
56
- st_table *method_table_create(void);
57
- prof_method_t* prof_method_create_excluded(VALUE klass, VALUE msym);
58
- prof_method_t *method_table_lookup(st_table *table, st_data_t key);
59
- size_t method_table_insert(st_table *table, st_data_t key, prof_method_t *val);
60
- void method_table_free(st_table *table);
61
- prof_method_t *prof_method_create(VALUE klass, VALUE msym, VALUE source_file, int source_line);
62
- prof_method_t *prof_method_get(VALUE self);
49
+ st_table* method_table_create(void);
50
+ prof_method_t* method_table_lookup(st_table* table, st_data_t key);
51
+ size_t method_table_insert(st_table* table, st_data_t key, prof_method_t* val);
52
+ void method_table_free(st_table* table);
53
+ prof_method_t* prof_method_create(VALUE profile, VALUE klass, VALUE msym, VALUE source_file, int source_line);
54
+ prof_method_t* prof_get_method(VALUE self);
63
55
 
64
- VALUE prof_method_wrap(prof_method_t *result);
65
- void prof_method_mark(void *data);
56
+ VALUE prof_method_wrap(prof_method_t* result);
57
+ void prof_method_mark(void* data);
66
58
 
67
- VALUE resolve_klass(VALUE klass, unsigned int *klass_flags);
59
+ VALUE resolve_klass(VALUE klass, unsigned int* klass_flags);
68
60
  VALUE resolve_klass_name(VALUE klass, unsigned int* klass_flags);
69
61
 
70
62
  #endif //__RP_METHOD_INFO__
@@ -1,28 +1,29 @@
1
1
  /* Copyright (C) 2005-2019 Shugo Maeda <shugo@ruby-lang.org> and Charlie Savage <cfis@savagexi.com>
2
2
  Please see the LICENSE file for copyright and distribution information */
3
3
 
4
- /* Document-class: RubyProf::Profile
4
+ /* Document-class: RubyProf::Profile
5
5
 
6
- The Profile class represents a single profiling run and provides the main API for using ruby-prof.
7
- After creating a Profile instance, start profiling code by calling the Profile#start method. To finish profiling,
8
- call Profile#stop. Once profiling is completed, the Profile instance contains the results.
6
+ The Profile class represents a single profiling run and provides the main API for using ruby-prof.
7
+ After creating a Profile instance, start profiling code by calling the Profile#start method. To finish profiling,
8
+ call Profile#stop. Once profiling is completed, the Profile instance contains the results.
9
9
 
10
- profile = RubyProf::Profile.new
11
- profile.start
12
- ...
13
- result = profile.stop
10
+ profile = RubyProf::Profile.new
11
+ profile.start
12
+ ...
13
+ result = profile.stop
14
14
 
15
- Alternatively, you can use the block syntax:
15
+ Alternatively, you can use the block syntax:
16
16
 
17
- profile = RubyProf::Profile.profile do
18
- ...
19
- end
20
- */
17
+ profile = RubyProf::Profile.profile do
18
+ ...
19
+ end
20
+ */
21
21
 
22
22
  #include <assert.h>
23
23
 
24
24
  #include "rp_allocation.h"
25
- #include "rp_call_info.h"
25
+ #include "rp_call_trees.h"
26
+ #include "rp_call_tree.h"
26
27
  #include "rp_profile.h"
27
28
  #include "rp_method.h"
28
29
 
@@ -35,69 +36,37 @@ VALUE cProfile;
35
36
  */
36
37
  FILE* trace_file = NULL;
37
38
 
38
- static int
39
- excludes_method(st_data_t key, prof_profile_t* profile)
40
- {
41
- return (profile->exclude_methods_tbl &&
42
- method_table_lookup(profile->exclude_methods_tbl, key) != NULL);
43
- }
44
-
45
- static prof_method_t*
46
- create_method(prof_profile_t* profile, st_data_t key, VALUE klass, VALUE msym, VALUE source_file, int source_line)
47
- {
48
- prof_method_t* result = NULL;
49
-
50
- if (excludes_method(key, profile))
51
- {
52
- /* We found a exclusion sentinel so propagate it into the thread's local hash table. */
53
- /* TODO(nelgau): Is there a way to avoid this allocation completely so that all these
54
- tables share the same exclusion method struct? The first attempt failed due to my
55
- ignorance of the whims of the GC. */
56
- result = prof_method_create_excluded(klass, msym);
57
- }
58
- else
59
- {
60
- result = prof_method_create(klass, msym, source_file, source_line);
61
- }
62
-
63
- /* Insert the newly created method, or the exlcusion sentinel. */
64
- method_table_insert(profile->last_thread_data->method_table, result->key, result);
65
-
66
- return result;
67
- }
68
-
69
- static const char *
70
- get_event_name(rb_event_flag_t event)
39
+ static const char* get_event_name(rb_event_flag_t event)
71
40
  {
72
41
  switch (event) {
73
- case RUBY_EVENT_LINE:
74
- return "line";
75
- case RUBY_EVENT_CLASS:
76
- return "class";
77
- case RUBY_EVENT_END:
78
- return "end";
79
- case RUBY_EVENT_CALL:
80
- return "call";
81
- case RUBY_EVENT_RETURN:
82
- return "return";
83
- case RUBY_EVENT_B_CALL:
84
- return "b-call";
85
- case RUBY_EVENT_B_RETURN:
86
- return "b-return";
87
- case RUBY_EVENT_C_CALL:
88
- return "c-call";
89
- case RUBY_EVENT_C_RETURN:
90
- return "c-return";
91
- case RUBY_EVENT_THREAD_BEGIN:
92
- return "thread-begin";
93
- case RUBY_EVENT_THREAD_END:
94
- return "thread-end";
95
- case RUBY_EVENT_FIBER_SWITCH:
96
- return "fiber-switch";
97
- case RUBY_EVENT_RAISE:
98
- return "raise";
99
- default:
100
- return "unknown";
42
+ case RUBY_EVENT_LINE:
43
+ return "line";
44
+ case RUBY_EVENT_CLASS:
45
+ return "class";
46
+ case RUBY_EVENT_END:
47
+ return "end";
48
+ case RUBY_EVENT_CALL:
49
+ return "call";
50
+ case RUBY_EVENT_RETURN:
51
+ return "return";
52
+ case RUBY_EVENT_B_CALL:
53
+ return "b-call";
54
+ case RUBY_EVENT_B_RETURN:
55
+ return "b-return";
56
+ case RUBY_EVENT_C_CALL:
57
+ return "c-call";
58
+ case RUBY_EVENT_C_RETURN:
59
+ return "c-return";
60
+ case RUBY_EVENT_THREAD_BEGIN:
61
+ return "thread-begin";
62
+ case RUBY_EVENT_THREAD_END:
63
+ return "thread-end";
64
+ case RUBY_EVENT_FIBER_SWITCH:
65
+ return "fiber-switch";
66
+ case RUBY_EVENT_RAISE:
67
+ return "raise";
68
+ default:
69
+ return "unknown";
101
70
  }
102
71
  }
103
72
 
@@ -108,14 +77,14 @@ VALUE get_fiber(prof_profile_t* profile)
108
77
  else
109
78
  return rb_fiber_current();
110
79
  }
111
- /* =========== Profiling ================= */
112
- thread_data_t* check_fiber(prof_profile_t *profile, double measurement)
80
+
81
+ thread_data_t* check_fiber(prof_profile_t* profile, double measurement)
113
82
  {
114
83
  thread_data_t* result = NULL;
115
-
84
+
116
85
  /* Get the current thread and fiber information. */
117
86
  VALUE fiber = get_fiber(profile);
118
-
87
+
119
88
  /* We need to switch the profiling context if we either had none before,
120
89
  we don't merge fibers and the fiber ids differ, or the thread ids differ. */
121
90
  if (profile->last_thread_data->fiber != fiber)
@@ -134,160 +103,215 @@ thread_data_t* check_fiber(prof_profile_t *profile, double measurement)
134
103
  return result;
135
104
  }
136
105
 
137
- static void
138
- prof_trace(prof_profile_t* profile, rb_trace_arg_t *trace_arg, double measurement)
106
+ static int excludes_method(st_data_t key, prof_profile_t* profile)
107
+ {
108
+ return (profile->exclude_methods_tbl &&
109
+ method_table_lookup(profile->exclude_methods_tbl, key) != NULL);
110
+ }
111
+
112
+ static prof_method_t* create_method(VALUE profile, st_data_t key, VALUE klass, VALUE msym, VALUE source_file, int source_line)
113
+ {
114
+ prof_method_t* result = prof_method_create(profile, klass, msym, source_file, source_line);
115
+
116
+ prof_profile_t* profile_t = prof_get_profile(profile);
117
+ method_table_insert(profile_t->last_thread_data->method_table, result->key, result);
118
+
119
+ return result;
120
+ }
121
+
122
+ static prof_method_t* check_parent_method(VALUE profile, thread_data_t* thread_data)
123
+ {
124
+ VALUE msym = ID2SYM(rb_intern("_inserted_parent_"));
125
+ st_data_t key = method_key(cProfile, msym);
126
+
127
+ prof_method_t* result = method_table_lookup(thread_data->method_table, key);
128
+
129
+ if (!result)
130
+ {
131
+ result = create_method(profile, key, cProfile, msym, Qnil, 0);
132
+ }
133
+
134
+ return result;
135
+ }
136
+
137
+ prof_method_t* check_method(VALUE profile, rb_trace_arg_t* trace_arg, rb_event_flag_t event, thread_data_t* thread_data)
138
+ {
139
+ VALUE klass = rb_tracearg_defined_class(trace_arg);
140
+
141
+ /* Special case - skip any methods from the mProf
142
+ module or cProfile class since they clutter
143
+ the results but aren't important to them results. */
144
+ if (klass == cProfile)
145
+ return NULL;
146
+
147
+ #ifdef HAVE_RB_TRACEARG_CALLEE_ID
148
+ VALUE msym = rb_tracearg_callee_id(trace_arg);
149
+ #else
150
+ VALUE msym = rb_tracearg_method_id(trace_arg);
151
+ #endif
152
+
153
+ st_data_t key = method_key(klass, msym);
154
+
155
+ prof_profile_t* profile_t = prof_get_profile(profile);
156
+ if (excludes_method(key, profile_t))
157
+ return NULL;
158
+
159
+ prof_method_t* result = method_table_lookup(thread_data->method_table, key);
160
+
161
+ if (!result)
162
+ {
163
+ VALUE source_file = (event != RUBY_EVENT_C_CALL ? rb_tracearg_path(trace_arg) : Qnil);
164
+ int source_line = (event != RUBY_EVENT_C_CALL ? FIX2INT(rb_tracearg_lineno(trace_arg)) : 0);
165
+ result = create_method(profile, key, klass, msym, source_file, source_line);
166
+ }
167
+
168
+ return result;
169
+ }
170
+
171
+ /* =========== Profiling ================= */
172
+ static void prof_trace(prof_profile_t* profile, rb_trace_arg_t* trace_arg, double measurement)
139
173
  {
140
174
  static VALUE last_fiber = Qnil;
141
175
  VALUE fiber = get_fiber(profile);
142
-
176
+
143
177
  rb_event_flag_t event = rb_tracearg_event_flag(trace_arg);
144
178
  const char* event_name = get_event_name(event);
145
-
179
+
146
180
  VALUE source_file = rb_tracearg_path(trace_arg);
147
181
  int source_line = FIX2INT(rb_tracearg_lineno(trace_arg));
148
-
149
- #ifdef HAVE_RB_TRACEARG_CALLEE_ID
182
+
183
+ #ifdef HAVE_RB_TRACEARG_CALLEE_ID
150
184
  VALUE msym = rb_tracearg_callee_id(trace_arg);
151
- #else
185
+ #else
152
186
  VALUE msym = rb_tracearg_method_id(trace_arg);
153
- #endif
154
-
187
+ #endif
188
+
155
189
  unsigned int klass_flags;
156
190
  VALUE klass = rb_tracearg_defined_class(trace_arg);
157
191
  VALUE resolved_klass = resolve_klass(klass, &klass_flags);
158
192
  const char* class_name = "";
159
-
193
+
160
194
  if (resolved_klass != Qnil)
161
195
  class_name = rb_class2name(resolved_klass);
162
-
196
+
163
197
  if (last_fiber != fiber)
164
198
  {
165
199
  fprintf(trace_file, "\n");
166
200
  }
167
-
201
+
168
202
  const char* method_name_char = (msym != Qnil ? rb_id2name(SYM2ID(msym)) : "");
169
203
  const char* source_file_char = (source_file != Qnil ? StringValuePtr(source_file) : "");
170
-
204
+
171
205
  fprintf(trace_file, "%2lu:%2f %-8s %s#%s %s:%2d\n",
172
- FIX2ULONG(fiber), (double) measurement,
206
+ FIX2ULONG(fiber), (double)measurement,
173
207
  event_name, class_name, method_name_char, source_file_char, source_line);
174
208
  fflush(trace_file);
175
209
  last_fiber = fiber;
176
210
  }
177
211
 
178
- static void
179
- prof_event_hook(VALUE trace_point, void* data)
212
+ static void prof_event_hook(VALUE trace_point, void* data)
180
213
  {
181
- prof_profile_t* profile = (prof_profile_t*)data;
182
- thread_data_t* thread_data = NULL;
183
- prof_frame_t *frame = NULL;
214
+ VALUE profile = (VALUE)data;
215
+ prof_profile_t* profile_t = prof_get_profile(profile);
216
+
184
217
  rb_trace_arg_t* trace_arg = rb_tracearg_from_tracepoint(trace_point);
185
- double measurement = prof_measure(profile->measurer, trace_arg);
218
+ double measurement = prof_measure(profile_t->measurer, trace_arg);
186
219
  rb_event_flag_t event = rb_tracearg_event_flag(trace_arg);
187
220
  VALUE self = rb_tracearg_self(trace_arg);
188
-
221
+
189
222
  if (trace_file != NULL)
190
223
  {
191
- prof_trace(profile, trace_arg, measurement);
224
+ prof_trace(profile_t, trace_arg, measurement);
192
225
  }
193
-
226
+
194
227
  /* Special case - skip any methods from the mProf
195
228
  module since they clutter the results but aren't important to them results. */
196
229
  if (self == mProf)
197
230
  return;
198
-
199
- thread_data = check_fiber(profile, measurement);
200
-
231
+
232
+ thread_data_t* thread_data = check_fiber(profile_t, measurement);
233
+
201
234
  if (!thread_data->trace)
202
235
  return;
203
-
204
- /* Get the current frame for the current thread. */
205
- frame = thread_data->stack->ptr;
206
-
236
+
207
237
  switch (event)
208
238
  {
209
239
  case RUBY_EVENT_LINE:
210
240
  {
211
- /* Keep track of the current line number in this method. When
212
- a new method is called, we know what line number it was
213
- called from. */
214
- if (frame->call_info)
241
+ prof_frame_t* frame = prof_frame_current(thread_data->stack);
242
+
243
+ if (!frame)
215
244
  {
216
- if (prof_frame_is_real(frame))
245
+ prof_method_t* method = check_method(profile, trace_arg, event, thread_data);
246
+
247
+ if (!method)
248
+ break;
249
+
250
+ prof_call_tree_t* call_tree = prof_call_tree_create(method, NULL, method->source_file, method->source_line);
251
+ prof_add_call_tree(method->call_trees, call_tree);
252
+
253
+ if (thread_data->call_tree)
217
254
  {
218
- frame->source_file = rb_tracearg_path(trace_arg);
219
- frame->source_line = FIX2INT(rb_tracearg_lineno(trace_arg));
255
+ prof_call_tree_add_parent(thread_data->call_tree, call_tree);
256
+ frame = prof_frame_unshift(thread_data->stack, call_tree, thread_data->call_tree, measurement);
220
257
  }
221
- break;
258
+ else
259
+ {
260
+ frame = prof_frame_push(thread_data->stack, call_tree, measurement, RTEST(profile_t->paused));
261
+ }
262
+
263
+ thread_data->call_tree = call_tree;
222
264
  }
223
265
 
224
- /* If we get here there was no frame, which means this is
225
- the first method seen for this thread, so fall through
226
- to below to create it. */
266
+ frame->source_file = rb_tracearg_path(trace_arg);
267
+ frame->source_line = FIX2INT(rb_tracearg_lineno(trace_arg));
268
+
269
+ break;
227
270
  }
228
271
  case RUBY_EVENT_CALL:
229
272
  case RUBY_EVENT_C_CALL:
230
273
  {
231
- prof_frame_t* next_frame;
232
- prof_call_info_t* call_info;
233
- prof_method_t* method;
274
+ prof_method_t* method = check_method(profile, trace_arg, event, thread_data);
234
275
 
235
- /* Get current measurement */
236
- measurement = prof_measure(profile->measurer, trace_arg);
276
+ if (!method)
277
+ break;
237
278
 
238
- VALUE klass = rb_tracearg_defined_class(trace_arg);
239
-
240
- /* Special case - skip any methods from the mProf
241
- module or cProfile class since they clutter
242
- the results but aren't important to them results. */
243
- if (klass == cProfile)
244
- return;
245
-
246
- #ifdef HAVE_RB_TRACEARG_CALLEE_ID
247
- VALUE msym = rb_tracearg_callee_id(trace_arg);
248
- #else
249
- VALUE msym = rb_tracearg_method_id(trace_arg);
250
- #endif
279
+ prof_frame_t* frame = prof_frame_current(thread_data->stack);
280
+ prof_call_tree_t* parent_call_tree = NULL;
281
+ prof_call_tree_t* call_tree = NULL;
251
282
 
252
- st_data_t key = method_key(klass, msym);
253
-
254
- method = method_table_lookup(thread_data->method_table, key);
255
-
256
- if (!method)
283
+ // Frame can be NULL if we are switching from one fiber to another (see FiberTest#fiber_test)
284
+ if (frame)
257
285
  {
258
- VALUE source_file = (event != RUBY_EVENT_C_CALL ? rb_tracearg_path(trace_arg) : Qnil);
259
- int source_line = (event != RUBY_EVENT_C_CALL ? FIX2INT(rb_tracearg_lineno(trace_arg)) : 0);
260
- method = create_method(profile, key, klass, msym, source_file, source_line);
286
+ parent_call_tree = frame->call_tree;
287
+ call_tree = call_tree_table_lookup(parent_call_tree->children, method->key);
261
288
  }
262
-
263
- if (method->excluded)
289
+ else if (!frame && thread_data->call_tree)
264
290
  {
265
- prof_stack_pass(thread_data->stack);
266
- break;
291
+ // There is no current parent - likely we have returned out of the highest level method we have profiled so far.
292
+ // This can happen with enumerators (see fiber_test.rb). So create a new dummy parent.
293
+ prof_method_t* parent_method = check_parent_method(profile, thread_data);
294
+ parent_call_tree = prof_call_tree_create(parent_method, NULL, Qnil, 0);
295
+ prof_add_call_tree(parent_method->call_trees, parent_call_tree);
296
+ prof_call_tree_add_parent(thread_data->call_tree, parent_call_tree);
297
+ frame = prof_frame_unshift(thread_data->stack, parent_call_tree, thread_data->call_tree, measurement);
298
+ thread_data->call_tree = parent_call_tree;
267
299
  }
268
-
269
- if (!frame->call_info)
300
+
301
+ if (!call_tree)
270
302
  {
271
- method->root = true;
272
- call_info = prof_call_info_create(method, NULL, method->source_file, method->source_line);
273
- st_insert(method->parent_call_infos, (st_data_t)&key, (st_data_t)call_info);
274
- }
275
- else
276
- {
277
- call_info = call_info_table_lookup(method->parent_call_infos, frame->call_info->method->key);
278
-
279
- if (!call_info)
280
- {
281
- /* This call info does not yet exist. So create it, then add
282
- it to previous callinfo's children and to the current method .*/
283
- call_info = prof_call_info_create(method, frame->call_info->method, frame->source_file, frame->source_line);
284
- call_info_table_insert(method->parent_call_infos, frame->call_info->method->key, call_info);
285
- call_info_table_insert(frame->call_info->method->child_call_infos, method->key, call_info);
286
- }
303
+ // This call info does not yet exist. So create it and add it to previous CallTree's children and the current method.
304
+ call_tree = prof_call_tree_create(method, parent_call_tree, frame ? frame->source_file : Qnil, frame? frame->source_line : 0);
305
+ prof_add_call_tree(method->call_trees, call_tree);
306
+ if (parent_call_tree)
307
+ prof_call_tree_add_child(parent_call_tree, call_tree);
287
308
  }
288
309
 
289
- /* Push a new frame onto the stack for a new c-call or ruby call (into a method) */
290
- next_frame = prof_stack_push(thread_data->stack, call_info, measurement, RTEST(profile->paused));
310
+ if (!thread_data->call_tree)
311
+ thread_data->call_tree = call_tree;
312
+
313
+ // Push a new frame onto the stack for a new c-call or ruby call (into a method)
314
+ prof_frame_t* next_frame = prof_frame_push(thread_data->stack, call_tree, measurement, RTEST(profile_t->paused));
291
315
  next_frame->source_file = method->source_file;
292
316
  next_frame->source_line = method->source_line;
293
317
  break;
@@ -295,8 +319,13 @@ prof_event_hook(VALUE trace_point, void* data)
295
319
  case RUBY_EVENT_RETURN:
296
320
  case RUBY_EVENT_C_RETURN:
297
321
  {
298
- /* Get current measurement */
299
- prof_stack_pop(thread_data->stack, measurement);
322
+ // We need to check for excluded methods so that we don't pop them off the stack
323
+ prof_method_t* method = check_method(profile, trace_arg, event, thread_data);
324
+
325
+ if (!method)
326
+ break;
327
+
328
+ prof_frame_pop(thread_data->stack, measurement);
300
329
  break;
301
330
  }
302
331
  case RUBY_INTERNAL_EVENT_NEWOBJ:
@@ -315,35 +344,33 @@ prof_event_hook(VALUE trace_point, void* data)
315
344
  }
316
345
  }
317
346
 
318
- void
319
- prof_install_hook(VALUE self)
347
+ void prof_install_hook(VALUE self)
320
348
  {
321
349
  prof_profile_t* profile = prof_get_profile(self);
322
-
350
+
323
351
  VALUE event_tracepoint = rb_tracepoint_new(Qnil,
324
352
  RUBY_EVENT_CALL | RUBY_EVENT_RETURN |
325
353
  RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN |
326
354
  RUBY_EVENT_LINE,
327
- prof_event_hook, profile);
355
+ prof_event_hook, (void*)self);
328
356
  rb_ary_push(profile->tracepoints, event_tracepoint);
329
-
357
+
330
358
  if (profile->measurer->track_allocations)
331
359
  {
332
- VALUE allocation_tracepoint = rb_tracepoint_new(Qnil, RUBY_INTERNAL_EVENT_NEWOBJ, prof_event_hook, profile);
360
+ VALUE allocation_tracepoint = rb_tracepoint_new(Qnil, RUBY_INTERNAL_EVENT_NEWOBJ, prof_event_hook, (void*)self);
333
361
  rb_ary_push(profile->tracepoints, allocation_tracepoint);
334
362
  }
335
-
363
+
336
364
  for (int i = 0; i < RARRAY_LEN(profile->tracepoints); i++)
337
365
  {
338
366
  rb_tracepoint_enable(rb_ary_entry(profile->tracepoints, i));
339
367
  }
340
368
  }
341
369
 
342
- void
343
- prof_remove_hook(VALUE self)
370
+ void prof_remove_hook(VALUE self)
344
371
  {
345
372
  prof_profile_t* profile = prof_get_profile(self);
346
-
373
+
347
374
  for (int i = 0; i < RARRAY_LEN(profile->tracepoints); i++)
348
375
  {
349
376
  rb_tracepoint_disable(rb_ary_entry(profile->tracepoints, i));
@@ -351,18 +378,16 @@ prof_remove_hook(VALUE self)
351
378
  rb_ary_clear(profile->tracepoints);
352
379
  }
353
380
 
354
- prof_profile_t*
355
- prof_get_profile(VALUE self)
381
+ prof_profile_t* prof_get_profile(VALUE self)
356
382
  {
357
383
  /* Can't use Data_Get_Struct because that triggers the event hook
358
384
  ending up in endless recursion. */
359
- return DATA_PTR(self);
385
+ return RTYPEDDATA_DATA(self);
360
386
  }
361
387
 
362
- static int
363
- collect_threads(st_data_t key, st_data_t value, st_data_t result)
388
+ static int collect_threads(st_data_t key, st_data_t value, st_data_t result)
364
389
  {
365
- thread_data_t* thread_data = (thread_data_t*) value;
390
+ thread_data_t* thread_data = (thread_data_t*)value;
366
391
  if (thread_data->trace)
367
392
  {
368
393
  VALUE threads_array = (VALUE)result;
@@ -372,36 +397,41 @@ collect_threads(st_data_t key, st_data_t value, st_data_t result)
372
397
  }
373
398
 
374
399
  /* ======== Profile Class ====== */
375
- static int
376
- mark_threads(st_data_t key, st_data_t value, st_data_t result)
400
+ static int mark_threads(st_data_t key, st_data_t value, st_data_t result)
377
401
  {
378
- thread_data_t *thread = (thread_data_t *) value;
402
+ thread_data_t* thread = (thread_data_t*)value;
379
403
  prof_thread_mark(thread);
380
404
  return ST_CONTINUE;
381
405
  }
382
406
 
383
- static int
384
- mark_methods(st_data_t key, st_data_t value, st_data_t result)
407
+ static int prof_profile_mark_methods(st_data_t key, st_data_t value, st_data_t result)
385
408
  {
386
- prof_method_t *method = (prof_method_t *) value;
409
+ prof_method_t* method = (prof_method_t*)value;
387
410
  prof_method_mark(method);
388
411
  return ST_CONTINUE;
389
412
  }
390
413
 
391
- static void
392
- prof_mark(prof_profile_t *profile)
414
+ static void prof_profile_mark(void* data)
393
415
  {
416
+ prof_profile_t* profile = (prof_profile_t*)data;
394
417
  rb_gc_mark(profile->tracepoints);
395
- st_foreach(profile->threads_tbl, mark_threads, 0);
396
- st_foreach(profile->exclude_methods_tbl, mark_methods, 0);
418
+ rb_gc_mark(profile->running);
419
+ rb_gc_mark(profile->paused);
420
+
421
+ // If GC stress is true (useful for debugging), when threads_table_create is called in the
422
+ // allocate method Ruby will immediately call this mark method. Thus the threads_tbl will be NULL.
423
+ if (profile->threads_tbl)
424
+ rb_st_foreach(profile->threads_tbl, mark_threads, 0);
425
+
426
+ if (profile->exclude_methods_tbl)
427
+ rb_st_foreach(profile->exclude_methods_tbl, prof_profile_mark_methods, 0);
397
428
  }
398
429
 
399
- /* Freeing the profile creates a cascade of freeing.
400
- It fress the thread table, which frees its methods,
401
- which frees its call infos. */
402
- static void
403
- prof_free(prof_profile_t *profile)
430
+ /* Freeing the profile creates a cascade of freeing. It frees its threads table, which frees
431
+ each thread and its associated call treee and methods. */
432
+ static void prof_profile_ruby_gc_free(void* data)
404
433
  {
434
+ prof_profile_t* profile = (prof_profile_t*)data;
405
435
  profile->last_thread_data = NULL;
406
436
 
407
437
  threads_table_free(profile->threads_tbl);
@@ -409,13 +439,13 @@ prof_free(prof_profile_t *profile)
409
439
 
410
440
  if (profile->exclude_threads_tbl)
411
441
  {
412
- st_free_table(profile->exclude_threads_tbl);
442
+ rb_st_free_table(profile->exclude_threads_tbl);
413
443
  profile->exclude_threads_tbl = NULL;
414
444
  }
415
445
 
416
446
  if (profile->include_threads_tbl)
417
447
  {
418
- st_free_table(profile->include_threads_tbl);
448
+ rb_st_free_table(profile->include_threads_tbl);
419
449
  profile->include_threads_tbl = NULL;
420
450
  }
421
451
 
@@ -429,12 +459,29 @@ prof_free(prof_profile_t *profile)
429
459
  xfree(profile);
430
460
  }
431
461
 
432
- static VALUE
433
- prof_allocate(VALUE klass)
462
+ size_t prof_profile_size(const void* data)
463
+ {
464
+ return sizeof(prof_profile_t);
465
+ }
466
+
467
+ static const rb_data_type_t profile_type =
468
+ {
469
+ .wrap_struct_name = "Profile",
470
+ .function =
471
+ {
472
+ .dmark = prof_profile_mark,
473
+ .dfree = prof_profile_ruby_gc_free,
474
+ .dsize = prof_profile_size,
475
+ },
476
+ .data = NULL,
477
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY
478
+ };
479
+
480
+ static VALUE prof_allocate(VALUE klass)
434
481
  {
435
482
  VALUE result;
436
483
  prof_profile_t* profile;
437
- result = Data_Make_Struct(klass, prof_profile_t, prof_mark, prof_free, profile);
484
+ result = TypedData_Make_Struct(klass, prof_profile_t, &profile_type, profile);
438
485
  profile->threads_tbl = threads_table_create();
439
486
  profile->exclude_threads_tbl = NULL;
440
487
  profile->include_threads_tbl = NULL;
@@ -447,14 +494,12 @@ prof_allocate(VALUE klass)
447
494
  return result;
448
495
  }
449
496
 
450
- static void
451
- prof_exclude_common_methods(VALUE profile)
497
+ static void prof_exclude_common_methods(VALUE profile)
452
498
  {
453
499
  rb_funcall(profile, rb_intern("exclude_common_methods!"), 0);
454
500
  }
455
501
 
456
- static int
457
- pop_frames(VALUE key, st_data_t value, st_data_t data)
502
+ static int pop_frames(VALUE key, st_data_t value, st_data_t data)
458
503
  {
459
504
  thread_data_t* thread_data = (thread_data_t*)value;
460
505
  prof_profile_t* profile = (prof_profile_t*)data;
@@ -463,7 +508,7 @@ pop_frames(VALUE key, st_data_t value, st_data_t data)
463
508
  if (profile->last_thread_data->fiber != thread_data->fiber)
464
509
  switch_thread(profile, thread_data, measurement);
465
510
 
466
- while (prof_stack_pop(thread_data->stack, measurement));
511
+ while (prof_frame_pop(thread_data->stack, measurement));
467
512
 
468
513
  return ST_CONTINUE;
469
514
  }
@@ -471,7 +516,7 @@ pop_frames(VALUE key, st_data_t value, st_data_t data)
471
516
  static void
472
517
  prof_stop_threads(prof_profile_t* profile)
473
518
  {
474
- st_foreach(profile->threads_tbl, pop_frames, (st_data_t)profile);
519
+ rb_st_foreach(profile->threads_tbl, pop_frames, (st_data_t)profile);
475
520
  }
476
521
 
477
522
  /* call-seq:
@@ -480,19 +525,19 @@ prof_stop_threads(prof_profile_t* profile)
480
525
 
481
526
  Returns a new profiler. Possible options for the options hash are:
482
527
 
483
- measure_mode:: Measure mode. Specifies the profile measure mode.
528
+ measure_mode: Measure mode. Specifies the profile measure mode.
484
529
  If not specified, defaults to RubyProf::WALL_TIME.
485
- exclude_threads:: Threads to exclude from the profiling results.
486
- include_threads:: Focus profiling on only the given threads. This will ignore
487
- all other threads.
488
- allow_exceptions:: Whether to raise exceptions encountered during profiling,
530
+ allow_exceptions: Whether to raise exceptions encountered during profiling,
489
531
  or to suppress all exceptions during profiling
490
- merge_fibers:: Whether profiling data for a given thread's fibers should all be
532
+ merge_fibers: Whether profiling data for a given thread's fibers should all be
491
533
  subsumed under a single entry. Basically only useful to produce
492
534
  callgrind profiles.
493
- */
494
- static VALUE
495
- prof_initialize(int argc, VALUE *argv, VALUE self)
535
+ track_allocations: Whether to track object allocations while profiling. True or false.
536
+ exclude_common: Exclude common methods from the profile. True or false.
537
+ exclude_threads: Threads to exclude from the profiling results.
538
+ include_threads: Focus profiling on only the given threads. This will ignore
539
+ all other threads. */
540
+ static VALUE prof_initialize(int argc, VALUE* argv, VALUE self)
496
541
  {
497
542
  prof_profile_t* profile = prof_get_profile(self);
498
543
  VALUE mode_or_options;
@@ -552,7 +597,7 @@ prof_initialize(int argc, VALUE *argv, VALUE self)
552
597
  for (i = 0; i < RARRAY_LEN(exclude_threads); i++)
553
598
  {
554
599
  VALUE thread = rb_ary_entry(exclude_threads, i);
555
- st_insert(profile->exclude_threads_tbl, thread, Qtrue);
600
+ rb_st_insert(profile->exclude_threads_tbl, thread, Qtrue);
556
601
  }
557
602
  }
558
603
 
@@ -564,7 +609,7 @@ prof_initialize(int argc, VALUE *argv, VALUE self)
564
609
  for (i = 0; i < RARRAY_LEN(include_threads); i++)
565
610
  {
566
611
  VALUE thread = rb_ary_entry(include_threads, i);
567
- st_insert(profile->include_threads_tbl, thread, Qtrue);
612
+ rb_st_insert(profile->include_threads_tbl, thread, Qtrue);
568
613
  }
569
614
  }
570
615
 
@@ -580,8 +625,7 @@ prof_initialize(int argc, VALUE *argv, VALUE self)
580
625
  paused? -> boolean
581
626
 
582
627
  Returns whether a profile is currently paused.*/
583
- static VALUE
584
- prof_paused(VALUE self)
628
+ static VALUE prof_paused(VALUE self)
585
629
  {
586
630
  prof_profile_t* profile = prof_get_profile(self);
587
631
  return profile->paused;
@@ -602,8 +646,7 @@ prof_running(VALUE self)
602
646
  mode -> measure_mode
603
647
 
604
648
  Returns the measure mode used in this profile.*/
605
- static VALUE
606
- prof_profile_measure_mode(VALUE self)
649
+ static VALUE prof_profile_measure_mode(VALUE self)
607
650
  {
608
651
  prof_profile_t* profile = prof_get_profile(self);
609
652
  return INT2NUM(profile->measurer->mode);
@@ -613,8 +656,7 @@ prof_profile_measure_mode(VALUE self)
613
656
  track_allocations -> boolean
614
657
 
615
658
  Returns if object allocations were tracked in this profile.*/
616
- static VALUE
617
- prof_profile_track_allocations(VALUE self)
659
+ static VALUE prof_profile_track_allocations(VALUE self)
618
660
  {
619
661
  prof_profile_t* profile = prof_get_profile(self);
620
662
  return profile->measurer->track_allocations ? Qtrue : Qfalse;
@@ -624,8 +666,7 @@ prof_profile_track_allocations(VALUE self)
624
666
  start -> self
625
667
 
626
668
  Starts recording profile data.*/
627
- static VALUE
628
- prof_start(VALUE self)
669
+ static VALUE prof_start(VALUE self)
629
670
  {
630
671
  char* trace_file_name;
631
672
 
@@ -642,20 +683,21 @@ prof_start(VALUE self)
642
683
 
643
684
  /* open trace file if environment wants it */
644
685
  trace_file_name = getenv("RUBY_PROF_TRACE");
645
- if (trace_file_name != NULL)
646
- {
647
- if (strcmp(trace_file_name, "stdout") == 0)
648
- {
649
- trace_file = stdout;
650
- }
651
- else if (strcmp(trace_file_name, "stderr") == 0)
652
- {
653
- trace_file = stderr;
654
- }
655
- else
656
- {
657
- trace_file = fopen(trace_file_name, "w");
658
- }
686
+
687
+ if (trace_file_name != NULL)
688
+ {
689
+ if (strcmp(trace_file_name, "stdout") == 0)
690
+ {
691
+ trace_file = stdout;
692
+ }
693
+ else if (strcmp(trace_file_name, "stderr") == 0)
694
+ {
695
+ trace_file = stderr;
696
+ }
697
+ else
698
+ {
699
+ trace_file = fopen(trace_file_name, "w");
700
+ }
659
701
  }
660
702
 
661
703
  prof_install_hook(self);
@@ -666,8 +708,7 @@ prof_start(VALUE self)
666
708
  pause -> self
667
709
 
668
710
  Pauses collecting profile data. */
669
- static VALUE
670
- prof_pause(VALUE self)
711
+ static VALUE prof_pause(VALUE self)
671
712
  {
672
713
  prof_profile_t* profile = prof_get_profile(self);
673
714
  if (profile->running == Qfalse)
@@ -679,7 +720,7 @@ prof_pause(VALUE self)
679
720
  {
680
721
  profile->paused = Qtrue;
681
722
  profile->measurement_at_pause_resume = prof_measure(profile->measurer, NULL);
682
- st_foreach(profile->threads_tbl, pause_thread, (st_data_t) profile);
723
+ rb_st_foreach(profile->threads_tbl, pause_thread, (st_data_t)profile);
683
724
  }
684
725
 
685
726
  return self;
@@ -690,8 +731,7 @@ prof_pause(VALUE self)
690
731
  resume(&block) -> self
691
732
 
692
733
  Resumes recording profile data.*/
693
- static VALUE
694
- prof_resume(VALUE self)
734
+ static VALUE prof_resume(VALUE self)
695
735
  {
696
736
  prof_profile_t* profile = prof_get_profile(self);
697
737
  if (profile->running == Qfalse)
@@ -703,7 +743,7 @@ prof_resume(VALUE self)
703
743
  {
704
744
  profile->paused = Qfalse;
705
745
  profile->measurement_at_pause_resume = prof_measure(profile->measurer, NULL);
706
- st_foreach(profile->threads_tbl, unpause_thread, (st_data_t) profile);
746
+ rb_st_foreach(profile->threads_tbl, unpause_thread, (st_data_t)profile);
707
747
  }
708
748
 
709
749
  return rb_block_given_p() ? rb_ensure(rb_yield, self, prof_pause, self) : self;
@@ -713,8 +753,7 @@ prof_resume(VALUE self)
713
753
  stop -> self
714
754
 
715
755
  Stops collecting profile data.*/
716
- static VALUE
717
- prof_stop(VALUE self)
756
+ static VALUE prof_stop(VALUE self)
718
757
  {
719
758
  prof_profile_t* profile = prof_get_profile(self);
720
759
 
@@ -728,15 +767,15 @@ prof_stop(VALUE self)
728
767
  /* close trace file if open */
729
768
  if (trace_file != NULL)
730
769
  {
731
- if (trace_file !=stderr && trace_file != stdout)
732
- {
770
+ if (trace_file != stderr && trace_file != stdout)
771
+ {
733
772
  #ifdef _MSC_VER
734
- _fcloseall();
773
+ _fcloseall();
735
774
  #else
736
- fclose(trace_file);
775
+ fclose(trace_file);
737
776
  #endif
738
- }
739
- trace_file = NULL;
777
+ }
778
+ trace_file = NULL;
740
779
  }
741
780
 
742
781
  prof_stop_threads(profile);
@@ -753,12 +792,11 @@ prof_stop(VALUE self)
753
792
  threads -> Array of RubyProf::Thread
754
793
 
755
794
  Returns an array of RubyProf::Thread instances that were profiled. */
756
- static VALUE
757
- prof_threads(VALUE self)
795
+ static VALUE prof_threads(VALUE self)
758
796
  {
759
797
  VALUE result = rb_ary_new();
760
798
  prof_profile_t* profile = prof_get_profile(self);
761
- st_foreach(profile->threads_tbl, collect_threads, result);
799
+ rb_st_foreach(profile->threads_tbl, collect_threads, result);
762
800
  return result;
763
801
  }
764
802
 
@@ -773,8 +811,7 @@ prof_threads(VALUE self)
773
811
  ..
774
812
  end
775
813
  */
776
- static VALUE
777
- prof_profile_object(VALUE self)
814
+ static VALUE prof_profile_object(VALUE self)
778
815
  {
779
816
  int result;
780
817
  prof_profile_t* profile = prof_get_profile(self);
@@ -794,7 +831,6 @@ prof_profile_object(VALUE self)
794
831
  }
795
832
 
796
833
  return self;
797
-
798
834
  }
799
835
 
800
836
  /* Document-method: RubyProf::Profile::Profile
@@ -809,8 +845,7 @@ prof_profile_object(VALUE self)
809
845
  ..
810
846
  end
811
847
  */
812
- static VALUE
813
- prof_profile_class(int argc, VALUE *argv, VALUE klass)
848
+ static VALUE prof_profile_class(int argc, VALUE* argv, VALUE klass)
814
849
  {
815
850
  return prof_profile_object(rb_class_new_instance(argc, argv, cProfile));
816
851
  }
@@ -820,25 +855,22 @@ prof_profile_class(int argc, VALUE *argv, VALUE klass)
820
855
 
821
856
  Excludes the method from profiling results.
822
857
  */
823
- static VALUE
824
- prof_exclude_method(VALUE self, VALUE klass, VALUE msym)
858
+ static VALUE prof_exclude_method(VALUE self, VALUE klass, VALUE msym)
825
859
  {
826
860
  prof_profile_t* profile = prof_get_profile(self);
827
861
 
828
- st_data_t key = method_key(klass, msym);
829
- prof_method_t *method;
830
-
831
862
  if (profile->running == Qtrue)
832
863
  {
833
864
  rb_raise(rb_eRuntimeError, "RubyProf.start was already called");
834
865
  }
835
866
 
836
- method = method_table_lookup(profile->exclude_methods_tbl, key);
867
+ st_data_t key = method_key(klass, msym);
868
+ prof_method_t* method = method_table_lookup(profile->exclude_methods_tbl, key);
837
869
 
838
870
  if (!method)
839
871
  {
840
- method = prof_method_create_excluded(klass, msym);
841
- method_table_insert(profile->exclude_methods_tbl, method->key, method);
872
+ method = prof_method_create(self, klass, msym, Qnil, 0);
873
+ method_table_insert(profile->exclude_methods_tbl, method->key, method);
842
874
  }
843
875
 
844
876
  return self;
@@ -861,8 +893,8 @@ VALUE prof_profile_load(VALUE self, VALUE data)
861
893
  for (int i = 0; i < rb_array_len(threads); i++)
862
894
  {
863
895
  VALUE thread = rb_ary_entry(threads, i);
864
- thread_data_t* thread_data = DATA_PTR(thread);
865
- st_insert(profile->threads_tbl, (st_data_t)thread_data->fiber_id, (st_data_t)thread_data);
896
+ thread_data_t* thread_data = prof_get_thread(thread);
897
+ rb_st_insert(profile->threads_tbl, (st_data_t)thread_data->fiber_id, (st_data_t)thread_data);
866
898
  }
867
899
 
868
900
  return data;
@@ -870,8 +902,6 @@ VALUE prof_profile_load(VALUE self, VALUE data)
870
902
 
871
903
  void rp_init_profile(void)
872
904
  {
873
- mProf = rb_define_module("RubyProf");
874
-
875
905
  cProfile = rb_define_class_under(mProf, "Profile", rb_cObject);
876
906
  rb_define_alloc_func(cProfile, prof_allocate);
877
907