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

Sign up to get free protection for your applications and to get access to all the features.
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