ruby-prof 0.18.0-x64-mingw32 → 1.1.0-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +32 -0
  3. data/LICENSE +2 -2
  4. data/README.rdoc +1 -483
  5. data/Rakefile +3 -6
  6. data/bin/ruby-prof +65 -30
  7. data/ext/ruby_prof/extconf.rb +6 -38
  8. data/ext/ruby_prof/rp_allocation.c +279 -0
  9. data/ext/ruby_prof/rp_allocation.h +31 -0
  10. data/ext/ruby_prof/rp_call_info.c +129 -283
  11. data/ext/ruby_prof/rp_call_info.h +16 -34
  12. data/ext/ruby_prof/rp_measure_allocations.c +25 -49
  13. data/ext/ruby_prof/rp_measure_memory.c +21 -56
  14. data/ext/ruby_prof/rp_measure_process_time.c +35 -39
  15. data/ext/ruby_prof/rp_measure_wall_time.c +36 -19
  16. data/ext/ruby_prof/rp_measurement.c +230 -0
  17. data/ext/ruby_prof/rp_measurement.h +50 -0
  18. data/ext/ruby_prof/rp_method.c +389 -389
  19. data/ext/ruby_prof/rp_method.h +34 -39
  20. data/ext/ruby_prof/rp_profile.c +895 -0
  21. data/ext/ruby_prof/rp_profile.h +37 -0
  22. data/ext/ruby_prof/rp_stack.c +103 -80
  23. data/ext/ruby_prof/rp_stack.h +5 -12
  24. data/ext/ruby_prof/rp_thread.c +143 -83
  25. data/ext/ruby_prof/rp_thread.h +15 -6
  26. data/ext/ruby_prof/ruby_prof.c +11 -757
  27. data/ext/ruby_prof/ruby_prof.h +4 -47
  28. data/ext/ruby_prof/vc/ruby_prof.vcxproj +10 -8
  29. data/lib/{2.6.3 → 2.6.5}/ruby_prof.so +0 -0
  30. data/lib/ruby-prof.rb +2 -18
  31. data/lib/ruby-prof/assets/call_stack_printer.html.erb +713 -0
  32. data/lib/ruby-prof/assets/call_stack_printer.png +0 -0
  33. data/lib/ruby-prof/assets/graph_printer.html.erb +356 -0
  34. data/lib/ruby-prof/call_info.rb +35 -93
  35. data/lib/ruby-prof/call_info_visitor.rb +19 -21
  36. data/lib/ruby-prof/compatibility.rb +37 -107
  37. data/lib/ruby-prof/exclude_common_methods.rb +198 -0
  38. data/lib/ruby-prof/measurement.rb +14 -0
  39. data/lib/ruby-prof/method_info.rb +52 -83
  40. data/lib/ruby-prof/printers/abstract_printer.rb +73 -50
  41. data/lib/ruby-prof/printers/call_info_printer.rb +13 -3
  42. data/lib/ruby-prof/printers/call_stack_printer.rb +62 -145
  43. data/lib/ruby-prof/printers/call_tree_printer.rb +20 -12
  44. data/lib/ruby-prof/printers/dot_printer.rb +5 -5
  45. data/lib/ruby-prof/printers/flat_printer.rb +6 -24
  46. data/lib/ruby-prof/printers/graph_html_printer.rb +6 -192
  47. data/lib/ruby-prof/printers/graph_printer.rb +13 -15
  48. data/lib/ruby-prof/printers/multi_printer.rb +66 -23
  49. data/lib/ruby-prof/profile.rb +10 -3
  50. data/lib/ruby-prof/rack.rb +0 -3
  51. data/lib/ruby-prof/thread.rb +12 -12
  52. data/lib/ruby-prof/version.rb +1 -1
  53. data/ruby-prof.gemspec +2 -2
  54. data/test/abstract_printer_test.rb +0 -27
  55. data/test/alias_test.rb +129 -0
  56. data/test/basic_test.rb +41 -40
  57. data/test/call_info_visitor_test.rb +3 -3
  58. data/test/dynamic_method_test.rb +0 -2
  59. data/test/fiber_test.rb +11 -17
  60. data/test/gc_test.rb +96 -0
  61. data/test/line_number_test.rb +120 -39
  62. data/test/marshal_test.rb +119 -0
  63. data/test/measure_allocations.rb +30 -0
  64. data/test/measure_allocations_test.rb +371 -12
  65. data/test/measure_allocations_trace_test.rb +385 -0
  66. data/test/measure_memory_trace_test.rb +756 -0
  67. data/test/measure_process_time_test.rb +821 -33
  68. data/test/measure_times.rb +54 -0
  69. data/test/measure_wall_time_test.rb +349 -145
  70. data/test/multi_printer_test.rb +1 -34
  71. data/test/parser_timings.rb +24 -0
  72. data/test/pause_resume_test.rb +5 -5
  73. data/test/prime.rb +2 -0
  74. data/test/printer_call_stack_test.rb +28 -0
  75. data/test/printer_call_tree_test.rb +31 -0
  76. data/test/printer_flat_test.rb +68 -0
  77. data/test/printer_graph_html_test.rb +60 -0
  78. data/test/printer_graph_test.rb +41 -0
  79. data/test/printers_test.rb +32 -166
  80. data/test/printing_recursive_graph_test.rb +26 -72
  81. data/test/recursive_test.rb +72 -77
  82. data/test/stack_printer_test.rb +2 -15
  83. data/test/start_stop_test.rb +22 -25
  84. data/test/test_helper.rb +5 -248
  85. data/test/thread_test.rb +11 -54
  86. data/test/unique_call_path_test.rb +16 -28
  87. data/test/yarv_test.rb +1 -0
  88. metadata +28 -36
  89. data/examples/flat.txt +0 -50
  90. data/examples/graph.dot +0 -84
  91. data/examples/graph.html +0 -823
  92. data/examples/graph.txt +0 -139
  93. data/examples/multi.flat.txt +0 -23
  94. data/examples/multi.graph.html +0 -760
  95. data/examples/multi.grind.dat +0 -114
  96. data/examples/multi.stack.html +0 -547
  97. data/examples/stack.html +0 -547
  98. data/ext/ruby_prof/rp_measure.c +0 -40
  99. data/ext/ruby_prof/rp_measure.h +0 -45
  100. data/ext/ruby_prof/rp_measure_cpu_time.c +0 -136
  101. data/ext/ruby_prof/rp_measure_gc_runs.c +0 -73
  102. data/ext/ruby_prof/rp_measure_gc_time.c +0 -60
  103. data/lib/ruby-prof/aggregate_call_info.rb +0 -76
  104. data/lib/ruby-prof/assets/call_stack_printer.css.html +0 -117
  105. data/lib/ruby-prof/assets/call_stack_printer.js.html +0 -385
  106. data/lib/ruby-prof/printers/flat_printer_with_line_numbers.rb +0 -83
  107. data/lib/ruby-prof/profile/exclude_common_methods.rb +0 -207
  108. data/lib/ruby-prof/profile/legacy_method_elimination.rb +0 -50
  109. data/test/aggregate_test.rb +0 -136
  110. data/test/block_test.rb +0 -74
  111. data/test/call_info_test.rb +0 -78
  112. data/test/issue137_test.rb +0 -63
  113. data/test/measure_cpu_time_test.rb +0 -212
  114. data/test/measure_gc_runs_test.rb +0 -32
  115. data/test/measure_gc_time_test.rb +0 -36
  116. data/test/measure_memory_test.rb +0 -33
  117. data/test/method_elimination_test.rb +0 -84
  118. data/test/module_test.rb +0 -45
  119. data/test/stack_test.rb +0 -138
@@ -0,0 +1,230 @@
1
+ /* Copyright (C) 2005-2019 Shugo Maeda <shugo@ruby-lang.org> and Charlie Savage <cfis@savagexi.com>
2
+ Please see the LICENSE file for copyright and distribution information */
3
+
4
+ #include "rp_measurement.h"
5
+
6
+ VALUE mMeasure;
7
+ VALUE cRpMeasurement;
8
+
9
+ prof_measurer_t* prof_measurer_allocations(bool track_allocations);
10
+ prof_measurer_t* prof_measurer_memory(bool track_allocations);
11
+ prof_measurer_t* prof_measurer_process_time(bool track_allocations);
12
+ prof_measurer_t* prof_measurer_wall_time(bool track_allocations);
13
+
14
+ void rp_init_measure_allocations(void);
15
+ void rp_init_measure_memory(void);
16
+ void rp_init_measure_process_time(void);
17
+ void rp_init_measure_wall_time(void);
18
+
19
+ prof_measurer_t* prof_get_measurer(prof_measure_mode_t measure, bool track_allocations)
20
+ {
21
+ switch (measure)
22
+ {
23
+ case MEASURE_WALL_TIME:
24
+ return prof_measurer_wall_time(track_allocations);
25
+ case MEASURE_PROCESS_TIME:
26
+ return prof_measurer_process_time(track_allocations);
27
+ case MEASURE_ALLOCATIONS:
28
+ return prof_measurer_allocations(track_allocations);
29
+ case MEASURE_MEMORY:
30
+ return prof_measurer_memory(track_allocations);
31
+ default:
32
+ rb_raise(rb_eArgError, "Unknown measure mode: %d", measure);
33
+ }
34
+ };
35
+
36
+ double prof_measure(prof_measurer_t* measurer, rb_trace_arg_t* trace_arg)
37
+ {
38
+ double measurement = measurer->measure(trace_arg);
39
+ return measurement * measurer->multiplier;
40
+ }
41
+
42
+ /* ======= prof_measurement_t ========*/
43
+ prof_measurement_t *prof_measurement_create(void)
44
+ {
45
+ prof_measurement_t* result = ALLOC(prof_measurement_t);
46
+ result->total_time = 0;
47
+ result->self_time = 0;
48
+ result->wait_time = 0;
49
+ result->called = 0;
50
+ result->object = Qnil;
51
+ return result;
52
+ }
53
+
54
+ static void
55
+ prof_measurement_ruby_gc_free(void *data)
56
+ {
57
+ prof_measurement_t* measurement = (prof_measurement_t*)data;
58
+
59
+ /* Has this measurement object been accessed by Ruby? If
60
+ yes clean it up so to avoid a segmentation fault. */
61
+ if (measurement->object != Qnil)
62
+ {
63
+ RDATA(measurement->object)->dmark = NULL;
64
+ RDATA(measurement->object)->dfree = NULL;
65
+ RDATA(measurement->object)->data = NULL;
66
+ measurement->object = Qnil;
67
+ }
68
+ }
69
+
70
+ void
71
+ prof_measurement_free(prof_measurement_t* measurement)
72
+ {
73
+ prof_measurement_ruby_gc_free(measurement);
74
+ xfree(measurement);
75
+ }
76
+
77
+ size_t
78
+ prof_measurement_size(const void *data)
79
+ {
80
+ return sizeof(prof_measurement_t);
81
+ }
82
+
83
+ void
84
+ prof_measurement_mark(void *data)
85
+ {
86
+ prof_measurement_t* measurement = (prof_measurement_t*)data;
87
+ if (measurement->object != Qnil)
88
+ rb_gc_mark(measurement->object);
89
+ }
90
+
91
+ VALUE
92
+ prof_measurement_wrap(prof_measurement_t* measurement)
93
+ {
94
+ if (measurement->object == Qnil)
95
+ {
96
+ measurement->object = Data_Wrap_Struct(cRpMeasurement, prof_measurement_mark, prof_measurement_ruby_gc_free, measurement);
97
+ }
98
+ return measurement->object;
99
+ }
100
+
101
+ static VALUE
102
+ prof_measurement_allocate(VALUE klass)
103
+ {
104
+ prof_measurement_t *measurement = prof_measurement_create();
105
+ measurement->object = prof_measurement_wrap(measurement);
106
+ return measurement->object;
107
+ }
108
+
109
+ prof_measurement_t*
110
+ prof_get_measurement(VALUE self)
111
+ {
112
+ /* Can't use Data_Get_Struct because that triggers the event hook
113
+ ending up in endless recursion. */
114
+ prof_measurement_t* result = DATA_PTR(self);
115
+
116
+ if (!result)
117
+ rb_raise(rb_eRuntimeError, "This RubyProf::Measurement instance has already been freed, likely because its profile has been freed.");
118
+
119
+ return result;
120
+ }
121
+
122
+ /* call-seq:
123
+ total_time -> float
124
+
125
+ Returns the total amount of time spent in this method and its children. */
126
+ static VALUE
127
+ prof_measurement_total_time(VALUE self)
128
+ {
129
+ prof_measurement_t* result = prof_get_measurement(self);
130
+ return rb_float_new(result->total_time);
131
+ }
132
+
133
+ /* call-seq:
134
+ self_time -> float
135
+
136
+ Returns the total amount of time spent in this method. */
137
+ static VALUE
138
+ prof_measurement_self_time(VALUE self)
139
+ {
140
+ prof_measurement_t* result = prof_get_measurement(self);
141
+
142
+ return rb_float_new(result->self_time);
143
+ }
144
+
145
+ /* call-seq:
146
+ wait_time -> float
147
+
148
+ Returns the total amount of time this method waited for other threads. */
149
+ static VALUE
150
+ prof_measurement_wait_time(VALUE self)
151
+ {
152
+ prof_measurement_t* result = prof_get_measurement(self);
153
+
154
+ return rb_float_new(result->wait_time);
155
+ }
156
+
157
+ /* call-seq:
158
+ called -> int
159
+
160
+ Returns the total amount of times this method was called. */
161
+ static VALUE
162
+ prof_measurement_called(VALUE self)
163
+ {
164
+ prof_measurement_t *result = prof_get_measurement(self);
165
+ return INT2NUM(result->called);
166
+ }
167
+
168
+ /* call-seq:
169
+ called=n -> n
170
+
171
+ Sets the call count to n. */
172
+ static VALUE
173
+ prof_measurement_set_called(VALUE self, VALUE called)
174
+ {
175
+ prof_measurement_t *result = prof_get_measurement(self);
176
+ result->called = NUM2INT(called);
177
+ return called;
178
+ }
179
+
180
+ /* :nodoc: */
181
+ static VALUE
182
+ prof_measurement_dump(VALUE self)
183
+ {
184
+ prof_measurement_t* measurement_data = prof_get_measurement(self);
185
+ VALUE result = rb_hash_new();
186
+
187
+ rb_hash_aset(result, ID2SYM(rb_intern("total_time")), rb_float_new(measurement_data->total_time));
188
+ rb_hash_aset(result, ID2SYM(rb_intern("self_time")), rb_float_new(measurement_data->self_time));
189
+ rb_hash_aset(result, ID2SYM(rb_intern("wait_time")), rb_float_new(measurement_data->wait_time));
190
+ rb_hash_aset(result, ID2SYM(rb_intern("called")), INT2FIX(measurement_data->called));
191
+
192
+ return result;
193
+ }
194
+
195
+ /* :nodoc: */
196
+ static VALUE
197
+ prof_measurement_load(VALUE self, VALUE data)
198
+ {
199
+ prof_measurement_t* measurement = prof_get_measurement(self);
200
+ measurement->object = self;
201
+
202
+ measurement->total_time = rb_num2dbl(rb_hash_aref(data, ID2SYM(rb_intern("total_time"))));
203
+ measurement->self_time = rb_num2dbl(rb_hash_aref(data, ID2SYM(rb_intern("self_time"))));
204
+ measurement->wait_time = rb_num2dbl(rb_hash_aref(data, ID2SYM(rb_intern("wait_time"))));
205
+ measurement->called = FIX2INT(rb_hash_aref(data, ID2SYM(rb_intern("called"))));
206
+
207
+ return data;
208
+ }
209
+
210
+ void rp_init_measure()
211
+ {
212
+ mMeasure = rb_define_module_under(mProf, "Measure");
213
+ rp_init_measure_wall_time();
214
+ rp_init_measure_process_time();
215
+ rp_init_measure_allocations();
216
+ rp_init_measure_memory();
217
+
218
+ cRpMeasurement = rb_define_class_under(mProf, "Measurement", rb_cData);
219
+ rb_undef_method(CLASS_OF(cRpMeasurement), "new");
220
+ rb_define_alloc_func(cRpMeasurement, prof_measurement_allocate);
221
+
222
+ rb_define_method(cRpMeasurement, "called", prof_measurement_called, 0);
223
+ rb_define_method(cRpMeasurement, "called=", prof_measurement_set_called, 1);
224
+ rb_define_method(cRpMeasurement, "total_time", prof_measurement_total_time, 0);
225
+ rb_define_method(cRpMeasurement, "self_time", prof_measurement_self_time, 0);
226
+ rb_define_method(cRpMeasurement, "wait_time", prof_measurement_wait_time, 0);
227
+
228
+ rb_define_method(cRpMeasurement, "_dump_data", prof_measurement_dump, 0);
229
+ rb_define_method(cRpMeasurement, "_load_data", prof_measurement_load, 1);
230
+ }
@@ -0,0 +1,50 @@
1
+ /* Copyright (C) 2005-2019 Shugo Maeda <shugo@ruby-lang.org> and Charlie Savage <cfis@savagexi.com>
2
+ Please see the LICENSE file for copyright and distribution information */
3
+
4
+ #ifndef __rp_measurementMENT_H__
5
+ #define __rp_measurementMENT_H__
6
+
7
+ #include "ruby_prof.h"
8
+
9
+ extern VALUE mMeasure;
10
+
11
+ typedef double (*get_measurement)(rb_trace_arg_t *trace_arg);
12
+
13
+ typedef enum
14
+ {
15
+ MEASURE_WALL_TIME,
16
+ MEASURE_PROCESS_TIME,
17
+ MEASURE_ALLOCATIONS,
18
+ MEASURE_MEMORY
19
+ } prof_measure_mode_t;
20
+
21
+ typedef struct
22
+ {
23
+ get_measurement measure;
24
+ prof_measure_mode_t mode;
25
+ double multiplier;
26
+ bool track_allocations;
27
+ } prof_measurer_t;
28
+
29
+ /* Callers and callee information for a method. */
30
+ typedef struct prof_measurement_t
31
+ {
32
+ double total_time;
33
+ double self_time;
34
+ double wait_time;
35
+ int called;
36
+ VALUE object;
37
+ } prof_measurement_t;
38
+
39
+ prof_measurer_t *prof_get_measurer(prof_measure_mode_t measure, bool track_allocations);
40
+ double prof_measure(prof_measurer_t *measurer, rb_trace_arg_t* trace_arg);
41
+
42
+ prof_measurement_t *prof_measurement_create(void);
43
+ void prof_measurement_free(prof_measurement_t* measurement);
44
+ VALUE prof_measurement_wrap(prof_measurement_t *measurement);
45
+ prof_measurement_t* prof_get_measurement(VALUE self);
46
+ void prof_measurement_mark(void *data);
47
+
48
+ void rp_init_measure(void);
49
+
50
+ #endif //__rp_measurementMENT_H__
@@ -1,250 +1,229 @@
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
- #include "ruby_prof.h"
4
+ #include "rp_allocation.h"
5
+ #include "rp_call_info.h"
6
+ #include "rp_method.h"
5
7
 
6
- #define RP_REL_GET(r, off) ((r) & (1 << (off)))
7
- #define RP_REL_SET(r, off) \
8
- do { \
9
- r |= (1 << (off)); \
10
- } while (0)
11
-
12
- VALUE cMethodInfo;
8
+ VALUE cRpMethodInfo;
13
9
 
14
10
  /* ================ Helper Functions =================*/
15
- static VALUE
16
- figure_singleton_name(VALUE klass)
11
+ VALUE
12
+ resolve_klass(VALUE klass, unsigned int *klass_flags)
17
13
  {
18
- volatile VALUE attached, super;
19
- volatile VALUE attached_str, super_str;
20
- volatile VALUE result = Qnil;
21
-
22
- /* We have come across a singleton object. First
23
- figure out what it is attached to.*/
24
- attached = rb_iv_get(klass, "__attached__");
14
+ VALUE result = klass;
25
15
 
26
- /* Is this a singleton class acting as a metaclass? */
27
- if (BUILTIN_TYPE(attached) == T_CLASS)
16
+ if (klass == 0 || klass == Qnil)
28
17
  {
29
- attached_str = rb_class_name(attached);
30
- result = rb_str_new2("<Class::");
31
- rb_str_append(result, attached_str);
32
- rb_str_cat2(result, ">");
18
+ result = Qnil;
33
19
  }
34
-
35
- /* Is this for singleton methods on a module? */
36
- else if (BUILTIN_TYPE(attached) == T_MODULE)
20
+ else if (BUILTIN_TYPE(klass) == T_CLASS && FL_TEST(klass, FL_SINGLETON))
37
21
  {
38
- attached_str = rb_class_name(attached);
39
- result = rb_str_new2("<Module::");
40
- rb_str_append(result, attached_str);
41
- rb_str_cat2(result, ">");
42
- }
22
+ /* We have come across a singleton object. First
23
+ figure out what it is attached to.*/
24
+ VALUE attached = rb_iv_get(klass, "__attached__");
43
25
 
44
- /* Is this for singleton methods on an object? */
45
- else if (BUILTIN_TYPE(attached) == T_OBJECT)
46
- {
47
- /* Make sure to get the super class so that we don't
48
- mistakenly grab a T_ICLASS which would lead to
49
- unknown method errors. */
50
- super = rb_class_superclass(klass);
51
- super_str = rb_class_name(super);
52
- result = rb_str_new2("<Object::");
53
- rb_str_append(result, super_str);
54
- rb_str_cat2(result, ">");
26
+ /* Is this a singleton class acting as a metaclass? */
27
+ if (BUILTIN_TYPE(attached) == T_CLASS)
28
+ {
29
+ *klass_flags |= kClassSingleton;
30
+ result = attached;
31
+ }
32
+ /* Is this for singleton methods on a module? */
33
+ else if (BUILTIN_TYPE(attached) == T_MODULE)
34
+ {
35
+ *klass_flags |= kModuleSingleton;
36
+ result = attached;
37
+ }
38
+ /* Is this for singleton methods on an object? */
39
+ else if (BUILTIN_TYPE(attached) == T_OBJECT)
40
+ {
41
+ *klass_flags |= kObjectSingleton;
42
+ result = rb_class_superclass(klass);
43
+ }
44
+ /* Ok, this could be other things like an array made put onto
45
+ a singleton object (yeah, it happens, see the singleton
46
+ objects test case). */
47
+ else
48
+ {
49
+ *klass_flags |= kOtherSingleton;
50
+ result = klass;
51
+ }
55
52
  }
56
-
57
- /* Ok, this could be other things like an array made put onto
58
- a singleton object (yeah, it happens, see the singleton
59
- objects test case). */
60
- else
53
+ /* Is this an include for a module? If so get the actual
54
+ module class since we want to combine all profiling
55
+ results for that module. */
56
+ else if (BUILTIN_TYPE(klass) == T_ICLASS)
61
57
  {
62
- result = rb_any_to_s(klass);
58
+ unsigned int dummy;
59
+ *klass_flags |= kModuleIncludee;
60
+ result = resolve_klass(RBASIC(klass)->klass, &dummy);
63
61
  }
64
-
65
62
  return result;
66
63
  }
67
64
 
68
- static VALUE
69
- klass_name(VALUE klass)
65
+ VALUE
66
+ resolve_klass_name(VALUE klass, unsigned int* klass_flags)
70
67
  {
71
- volatile VALUE result = Qnil;
68
+ VALUE result = Qnil;
72
69
 
73
- if (klass == 0 || klass == Qnil)
70
+ if (klass == Qnil)
74
71
  {
75
72
  result = rb_str_new2("[global]");
76
73
  }
77
- else if (BUILTIN_TYPE(klass) == T_MODULE)
74
+ else if (*klass_flags & kOtherSingleton)
78
75
  {
79
- result = rb_class_name(klass);
80
- }
81
- else if (BUILTIN_TYPE(klass) == T_CLASS && FL_TEST(klass, FL_SINGLETON))
82
- {
83
- result = figure_singleton_name(klass);
84
- }
85
- else if (BUILTIN_TYPE(klass) == T_CLASS)
86
- {
87
- result = rb_class_name(klass);
76
+ result = rb_any_to_s(klass);
88
77
  }
89
78
  else
90
79
  {
91
- /* Should never happen. */
92
- result = rb_str_new2("[unknown]");
80
+ result = rb_class_name(klass);
93
81
  }
94
82
 
95
83
  return result;
96
84
  }
97
85
 
98
- static VALUE
99
- method_name(ID mid)
86
+ st_data_t
87
+ method_key(VALUE klass, VALUE msym)
100
88
  {
101
- volatile VALUE name = Qnil;
89
+ VALUE resolved_klass = klass;
102
90
 
103
- if (RTEST(mid)) {
104
- name = rb_id2str(mid);
105
- return rb_str_dup(name);
106
- } else {
107
- return rb_str_new2("[no method]");
91
+ /* Is this an include for a module? If so get the actual
92
+ module class since we want to combine all profiling
93
+ results for that module. */
94
+ if (klass == 0 || klass == Qnil)
95
+ {
96
+ resolved_klass = Qnil;
97
+ }
98
+ else if (BUILTIN_TYPE(klass) == T_ICLASS)
99
+ {
100
+ resolved_klass = RBASIC(klass)->klass;
108
101
  }
102
+
103
+ return (resolved_klass << 4) + (msym);
109
104
  }
110
105
 
111
- static VALUE
112
- full_name(VALUE klass, ID mid)
106
+ /* ====== Allocation Table ====== */
107
+ st_table*
108
+ allocations_table_create()
113
109
  {
114
- volatile VALUE klass_str, method_str;
115
- volatile VALUE result = Qnil;
116
-
117
- klass_str = klass_name(klass);
118
- method_str = method_name(mid);
119
-
120
- result = rb_str_dup(klass_str);
121
- rb_str_cat2(result, "#");
122
- rb_str_append(result, method_str);
110
+ return st_init_numtable();
111
+ }
123
112
 
124
- return result;
113
+ static int
114
+ allocations_table_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
115
+ {
116
+ prof_allocation_free((prof_allocation_t*)value);
117
+ return ST_CONTINUE;
125
118
  }
126
119
 
127
- static VALUE
128
- source_klass_name(VALUE source_klass)
120
+ static int
121
+ prof_method_collect_allocations(st_data_t key, st_data_t value, st_data_t result)
129
122
  {
130
- volatile VALUE klass_str;
131
- volatile VALUE result = Qnil;
132
-
133
- if (RTEST(source_klass)) {
134
- klass_str = rb_class_name(source_klass);
135
- result = rb_str_dup(klass_str);
136
- } else {
137
- result = rb_str_new2("[global]");
138
- }
139
-
140
- return result;
123
+ prof_allocation_t* allocation = (prof_allocation_t*)value;
124
+ VALUE arr = (VALUE)result;
125
+ rb_ary_push(arr, prof_allocation_wrap(allocation));
126
+ return ST_CONTINUE;
141
127
  }
142
128
 
143
- static VALUE
144
- calltree_name(VALUE source_klass, int relation, ID mid)
129
+ static int
130
+ prof_method_mark_allocations(st_data_t key, st_data_t value, st_data_t data)
145
131
  {
146
- volatile VALUE klass_str, klass_path, joiner;
147
- volatile VALUE method_str;
148
- volatile VALUE result = Qnil;
149
-
150
- klass_str = source_klass_name(source_klass);
151
- method_str = method_name(mid);
152
-
153
- klass_path = rb_str_split(klass_str, "::");
154
- joiner = rb_str_new2("/");
155
- result = rb_ary_join(klass_path, joiner);
156
-
157
- rb_str_cat2(result, "::");
158
-
159
- if (RP_REL_GET(relation, kObjectSingleton)) {
160
- rb_str_cat2(result, "*");
161
- }
162
-
163
- if (RP_REL_GET(relation, kModuleSingleton)) {
164
- rb_str_cat2(result, "^");
165
- }
166
-
167
- rb_str_append(result, method_str);
168
-
169
- return result;
132
+ prof_allocation_t* allocation = (prof_allocation_t*)value;
133
+ prof_allocation_mark(allocation);
134
+ return ST_CONTINUE;
170
135
  }
171
136
 
172
137
  void
173
- method_key(prof_method_key_t* key, VALUE klass, ID mid)
138
+ allocations_table_free(st_table* table)
174
139
  {
175
- /* Is this an include for a module? If so get the actual
176
- module class since we want to combine all profiling
177
- results for that module. */
178
- if (klass != 0 && BUILTIN_TYPE(klass) == T_ICLASS) {
179
- klass = RBASIC(klass)->klass;
180
- }
181
-
182
- key->klass = klass;
183
- key->mid = mid;
184
- key->key = (klass << 4) + (mid << 2);
140
+ st_foreach(table, allocations_table_free_iterator, 0);
141
+ st_free_table(table);
185
142
  }
186
143
 
187
144
  /* ================ prof_method_t =================*/
188
-
189
- prof_method_t*
190
- prof_method_create(VALUE klass, ID mid, const char* source_file, int line)
145
+ static prof_method_t*
146
+ prof_get_method(VALUE self)
191
147
  {
192
- prof_method_t *result = ALLOC(prof_method_t);
148
+ /* Can't use Data_Get_Struct because that triggers the event hook
149
+ ending up in endless recursion. */
150
+ prof_method_t* result = DATA_PTR(self);
193
151
 
194
- result->key = ALLOC(prof_method_key_t);
195
- method_key(result->key, klass, mid);
152
+ if (!result)
153
+ rb_raise(rb_eRuntimeError, "This RubyProf::MethodInfo instance has already been freed, likely because its profile has been freed.");
196
154
 
197
- result->excluded = 0;
198
- result->recursive = 0;
155
+ return result;
156
+ }
199
157
 
200
- result->call_infos = prof_call_infos_create();
158
+ prof_method_t*
159
+ prof_method_create(VALUE klass, VALUE msym, VALUE source_file, int source_line)
160
+ {
161
+ prof_method_t *result = ALLOC(prof_method_t);
162
+ result->key = method_key(klass, msym);
163
+ result->klass_flags = 0;
164
+
165
+ /* Note we do not call resolve_klass_name now because that causes an object allocation that shows up
166
+ in the allocation results so we want to avoid it until after the profile run is complete. */
167
+ result->klass = resolve_klass(klass, &result->klass_flags);
168
+ result->klass_name = Qnil;
169
+ result->method_name = msym;
170
+ result->measurement = prof_measurement_create();
171
+
172
+ result->root = false;
173
+ result->excluded = false;
174
+
175
+ result->parent_call_infos = method_table_create();
176
+ result->child_call_infos = method_table_create();
177
+ result->allocations_table = allocations_table_create();
178
+
201
179
  result->visits = 0;
180
+ result->recursive = false;
202
181
 
203
182
  result->object = Qnil;
204
183
 
205
- if (source_file != NULL)
206
- {
207
- size_t len = strlen(source_file) + 1;
208
- char *buffer = ALLOC_N(char, len);
209
-
210
- MEMCPY(buffer, source_file, char, len);
211
- result->source_file = buffer;
212
- } else {
213
- result->source_file = source_file;
214
- }
215
-
216
- result->source_klass = Qnil;
217
- result->line = line;
218
-
219
- result->resolved = 0;
220
- result->relation = 0;
184
+ result->source_file = source_file;
185
+ result->source_line = source_line;
221
186
 
222
187
  return result;
223
188
  }
224
189
 
225
190
  prof_method_t*
226
- prof_method_create_excluded(VALUE klass, ID mid)
191
+ prof_method_create_excluded(VALUE klass, VALUE msym)
227
192
  {
228
- prof_method_t *result = ALLOC(prof_method_t);
229
-
230
- result->key = ALLOC(prof_method_key_t);
231
- method_key(result->key, klass, mid);
232
-
233
- /* Invisible with this flag set. */
193
+ prof_method_t* result = prof_method_create(klass, msym, Qnil, 0);
234
194
  result->excluded = 1;
235
- result->recursive = 0;
195
+ return result;
196
+ }
236
197
 
237
- result->call_infos = 0;
238
- result->visits = 0;
198
+ static int
199
+ prof_method_collect_call_infos(st_data_t key, st_data_t value, st_data_t result)
200
+ {
201
+ prof_call_info_t* call_info = (prof_call_info_t*)value;
202
+ VALUE arr = (VALUE)result;
203
+ rb_ary_push(arr, prof_call_info_wrap(call_info));
204
+ return ST_CONTINUE;
205
+ }
239
206
 
240
- result->object = Qnil;
241
- result->source_klass = Qnil;
242
- result->line = 0;
207
+ static int
208
+ prof_method_mark_call_infos(st_data_t key, st_data_t value, st_data_t data)
209
+ {
210
+ prof_call_info_t* call_info = (prof_call_info_t*)value;
211
+ prof_call_info_mark(call_info);
212
+ return ST_CONTINUE;
213
+ }
243
214
 
244
- result->resolved = 0;
245
- result->relation = 0;
215
+ static int
216
+ call_infos_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
217
+ {
218
+ prof_call_info_free((prof_call_info_t*)value);
219
+ return ST_CONTINUE;
220
+ }
246
221
 
247
- return result;
222
+ void
223
+ call_info_table_free(st_table* table)
224
+ {
225
+ st_foreach(table, call_infos_free_iterator, 0);
226
+ st_free_table(table);
248
227
  }
249
228
 
250
229
  /* The underlying c structures are freed when the parent profile is freed.
@@ -254,180 +233,101 @@ prof_method_create_excluded(VALUE klass, ID mid)
254
233
  for the garbage collector so that if it does get called will nil
255
234
  out our Ruby object reference.*/
256
235
  static void
257
- prof_method_ruby_gc_free(prof_method_t* method)
236
+ prof_method_ruby_gc_free(void *data)
258
237
  {
259
- /* Has this thread object been accessed by Ruby? If
238
+ prof_method_t* method = (prof_method_t*)data;
239
+
240
+ /* Has this method object been accessed by Ruby? If
260
241
  yes clean it up so to avoid a segmentation fault. */
261
242
  if (method->object != Qnil)
262
243
  {
263
- RDATA(method->object)->data = NULL;
264
- RDATA(method->object)->dfree = NULL;
265
- RDATA(method->object)->dmark = NULL;
266
- }
267
- method->object = Qnil;
244
+ RDATA(method->object)->dmark = NULL;
245
+ RDATA(method->object)->dfree = NULL;
246
+ RDATA(method->object)->data = NULL;
247
+ method->object = Qnil;
248
+ }
249
+ method->klass_name = Qnil;
250
+ method->method_name = Qnil;
268
251
  }
269
252
 
270
253
  static void
271
254
  prof_method_free(prof_method_t* method)
272
255
  {
273
256
  prof_method_ruby_gc_free(method);
257
+ allocations_table_free(method->allocations_table);
274
258
 
275
- if (method->call_infos) {
276
- prof_call_infos_free(method->call_infos);
277
- xfree(method->call_infos);
278
- }
279
-
280
- xfree(method->key);
259
+ /* Remember call infos are referenced by their parent method and child method, so we only want
260
+ to iterate over one of them to avoid a double freeing */
261
+ call_info_table_free(method->parent_call_infos);
262
+ xfree(method->child_call_infos);
281
263
 
282
- method->key = NULL;
283
- method->source_klass = Qnil;
264
+ prof_measurement_free(method->measurement);
265
+ xfree(method);
266
+ }
284
267
 
285
- xfree(method);
268
+ size_t
269
+ prof_method_size(const void *data)
270
+ {
271
+ return sizeof(prof_method_t);
286
272
  }
287
273
 
288
274
  void
289
- prof_method_mark(prof_method_t *method)
275
+ prof_method_mark(void *data)
290
276
  {
291
- if (method->key->klass) {
292
- rb_gc_mark(method->key->klass);
293
- }
277
+ prof_method_t* method = (prof_method_t*)data;
278
+ rb_gc_mark(method->klass_name);
279
+ rb_gc_mark(method->method_name);
280
+
281
+ if (method->klass != Qnil)
282
+ rb_gc_mark(method->klass);
294
283
 
295
- if (method->source_klass) {
296
- rb_gc_mark(method->source_klass);
297
- }
298
-
299
- if (method->object) {
284
+ if (method->object != Qnil)
300
285
  rb_gc_mark(method->object);
301
- }
302
286
 
303
- if (method->call_infos) {
304
- prof_call_infos_mark(method->call_infos);
305
- }
287
+ prof_measurement_mark(method->measurement);
288
+
289
+ st_foreach(method->parent_call_infos, prof_method_mark_call_infos, 0);
290
+ st_foreach(method->child_call_infos, prof_method_mark_call_infos, 0);
291
+ st_foreach(method->allocations_table, prof_method_mark_allocations, 0);
306
292
  }
307
293
 
308
294
  static VALUE
309
- resolve_source_klass(prof_method_t* method)
295
+ prof_method_allocate(VALUE klass)
310
296
  {
311
- volatile VALUE klass, next_klass;
312
- volatile VALUE attached;
313
- unsigned int relation;
314
-
315
- /* We want to group methods according to their source-level
316
- definitions, not their implementation class. Follow module
317
- inclusions and singleton classes back to a meaningful root
318
- while keeping track of these relationships. */
319
-
320
- if (method->resolved) {
321
- return method->source_klass;
322
- }
323
-
324
- klass = method->key->klass;
325
- relation = 0;
326
-
327
- while (1)
328
- {
329
- /* This is a global/unknown class */
330
- if (klass == 0 || klass == Qnil)
331
- break;
332
-
333
- /* Is this a singleton class? (most common case) */
334
- if (BUILTIN_TYPE(klass) == T_CLASS && FL_TEST(klass, FL_SINGLETON))
335
- {
336
- /* We have come across a singleton object. First
337
- figure out what it is attached to.*/
338
- attached = rb_iv_get(klass, "__attached__");
339
-
340
- /* Is this a singleton class acting as a metaclass?
341
- Or for singleton methods on a module? */
342
- if (BUILTIN_TYPE(attached) == T_CLASS ||
343
- BUILTIN_TYPE(attached) == T_MODULE)
344
- {
345
- RP_REL_SET(relation, kModuleSingleton);
346
- klass = attached;
347
- }
348
- /* Is this for singleton methods on an object? */
349
- else if (BUILTIN_TYPE(attached) == T_OBJECT)
350
- {
351
- RP_REL_SET(relation, kObjectSingleton);
352
- next_klass = rb_class_superclass(klass);
353
- klass = next_klass;
354
- }
355
- /* This is a singleton of an instance of a builtin type. */
356
- else
357
- {
358
- RP_REL_SET(relation, kObjectSingleton);
359
- next_klass = rb_class_superclass(klass);
360
- klass = next_klass;
361
- }
362
- }
363
- /* Is this an include for a module? If so get the actual
364
- module class since we want to combine all profiling
365
- results for that module. */
366
- else if (BUILTIN_TYPE(klass) == T_ICLASS)
367
- {
368
- RP_REL_SET(relation, kModuleIncludee);
369
- next_klass = RBASIC(klass)->klass;
370
- klass = next_klass;
371
- }
372
- /* No transformations apply; so bail. */
373
- else
374
- {
375
- break;
376
- }
377
- }
378
-
379
- method->resolved = 1;
380
- method->relation = relation;
381
- method->source_klass = klass;
382
-
383
- return klass;
297
+ prof_method_t* method_data = prof_method_create(Qnil, Qnil, Qnil, 0);
298
+ method_data->object = prof_method_wrap(method_data);
299
+ return method_data->object;
384
300
  }
385
301
 
386
302
  VALUE
387
- prof_method_wrap(prof_method_t *result)
303
+ prof_method_wrap(prof_method_t *method)
388
304
  {
389
- if (result->object == Qnil) {
390
- result->object = Data_Wrap_Struct(cMethodInfo, prof_method_mark, prof_method_ruby_gc_free, result);
305
+ if (method->object == Qnil)
306
+ {
307
+ method->object = Data_Wrap_Struct(cRpMethodInfo, prof_method_mark, prof_method_ruby_gc_free, method);
391
308
  }
392
- return result->object;
309
+ return method->object;
393
310
  }
394
311
 
395
- static prof_method_t *
396
- get_prof_method(VALUE self)
312
+ prof_method_t *
313
+ prof_method_get(VALUE self)
397
314
  {
398
315
  /* Can't use Data_Get_Struct because that triggers the event hook
399
316
  ending up in endless recursion. */
400
317
  prof_method_t* result = DATA_PTR(self);
401
318
 
402
- if (!result) {
319
+ if (!result)
320
+ {
403
321
  rb_raise(rb_eRuntimeError, "This RubyProf::MethodInfo instance has already been freed, likely because its profile has been freed.");
404
322
  }
405
323
 
406
324
  return result;
407
325
  }
408
326
 
409
- /* ================ Method Table =================*/
410
- int
411
- method_table_cmp(prof_method_key_t *key1, prof_method_key_t *key2)
412
- {
413
- return (key1->klass != key2->klass) || (key1->mid != key2->mid);
414
- }
415
-
416
- st_index_t
417
- method_table_hash(prof_method_key_t *key)
418
- {
419
- return key->key;
420
- }
421
-
422
- struct st_hash_type type_method_hash = {
423
- method_table_cmp,
424
- method_table_hash
425
- };
426
-
427
327
  st_table *
428
328
  method_table_create()
429
329
  {
430
- return st_init_table(&type_method_hash);
330
+ return st_init_numtable();
431
331
  }
432
332
 
433
333
  static int
@@ -445,18 +345,21 @@ method_table_free(st_table *table)
445
345
  }
446
346
 
447
347
  size_t
448
- method_table_insert(st_table *table, const prof_method_key_t *key, prof_method_t *val)
348
+ method_table_insert(st_table *table, st_data_t key, prof_method_t *val)
449
349
  {
450
- return st_insert(table, (st_data_t) key, (st_data_t) val);
350
+ return st_insert(table, (st_data_t) key, (st_data_t) val);
451
351
  }
452
352
 
453
353
  prof_method_t *
454
- method_table_lookup(st_table *table, const prof_method_key_t* key)
354
+ method_table_lookup(st_table *table, st_data_t key)
455
355
  {
456
356
  st_data_t val;
457
- if (st_lookup(table, (st_data_t)key, &val)) {
357
+ if (st_lookup(table, (st_data_t)key, &val))
358
+ {
458
359
  return (prof_method_t *) val;
459
- } else {
360
+ }
361
+ else
362
+ {
460
363
  return NULL;
461
364
  }
462
365
  }
@@ -472,52 +375,75 @@ the RubyProf::Profile object.
472
375
  */
473
376
 
474
377
  /* call-seq:
475
- line_no -> int
378
+ callers -> array
476
379
 
477
- returns the line number of the method */
380
+ Returns an array of call info objects that called this method (ie, parents).*/
478
381
  static VALUE
479
- prof_method_line(VALUE self)
382
+ prof_method_callers(VALUE self)
480
383
  {
481
- int line = get_prof_method(self)->line;
482
- return rb_int_new(line);
384
+ prof_method_t* method = prof_get_method(self);
385
+ VALUE result = rb_ary_new();
386
+ st_foreach(method->parent_call_infos, prof_method_collect_call_infos, result);
387
+ return result;
483
388
  }
484
389
 
485
390
  /* call-seq:
486
- source_file => string
391
+ callees -> array
487
392
 
488
- return the source file of the method
489
- */
490
- static VALUE prof_method_source_file(VALUE self)
393
+ Returns an array of call info objects that this method called (ie, children).*/
394
+ static VALUE
395
+ prof_method_callees(VALUE self)
491
396
  {
492
- const char* sf = get_prof_method(self)->source_file;
493
- if(!sf) {
494
- return rb_str_new2("ruby_runtime");
495
- } else {
496
- return rb_str_new2(sf);
497
- }
397
+ prof_method_t* method = prof_get_method(self);
398
+ VALUE result = rb_ary_new();
399
+ st_foreach(method->child_call_infos, prof_method_collect_call_infos, result);
400
+ return result;
498
401
  }
499
402
 
403
+ /* call-seq:
404
+ allocations -> array
405
+
406
+ Returns an array of allocation information.*/
407
+ static VALUE
408
+ prof_method_allocations(VALUE self)
409
+ {
410
+ prof_method_t* method = prof_get_method(self);
411
+ VALUE result = rb_ary_new();
412
+ st_foreach(method->allocations_table, prof_method_collect_allocations, result);
413
+ return result;
414
+ }
500
415
 
501
416
  /* call-seq:
502
- method_class -> klass
417
+ called -> Measurement
503
418
 
504
- Returns the Ruby klass that owns this method. */
419
+ Returns the measurement associated with this method. */
505
420
  static VALUE
506
- prof_method_klass(VALUE self)
421
+ prof_method_measurement(VALUE self)
422
+ {
423
+ prof_method_t* method = prof_get_method(self);
424
+ return prof_measurement_wrap(method->measurement);
425
+ }
426
+
427
+ /* call-seq:
428
+ source_file => string
429
+
430
+ return the source file of the method
431
+ */
432
+ static VALUE prof_method_source_file(VALUE self)
507
433
  {
508
- prof_method_t *result = get_prof_method(self);
509
- return result->key->klass;
434
+ prof_method_t* method = prof_method_get(self);
435
+ return method->source_file;
510
436
  }
511
437
 
512
438
  /* call-seq:
513
- method_id -> ID
439
+ line_no -> int
514
440
 
515
- Returns the id of this method. */
441
+ returns the line number of the method */
516
442
  static VALUE
517
- prof_method_id(VALUE self)
443
+ prof_method_line(VALUE self)
518
444
  {
519
- prof_method_t *result = get_prof_method(self);
520
- return ID2SYM(result->key->mid);
445
+ prof_method_t* method = prof_method_get(self);
446
+ return INT2FIX(method->source_line);
521
447
  }
522
448
 
523
449
  /* call-seq:
@@ -527,104 +453,178 @@ Returns the name of this method's class. Singleton classes
527
453
  will have the form <Object::Object>. */
528
454
 
529
455
  static VALUE
530
- prof_klass_name(VALUE self)
456
+ prof_method_klass_name(VALUE self)
531
457
  {
532
- prof_method_t *method = get_prof_method(self);
533
- return klass_name(method->key->klass);
458
+ prof_method_t *method = prof_method_get(self);
459
+ if (method->klass_name == Qnil)
460
+ method->klass_name = resolve_klass_name(method->klass, &method->klass_flags);
461
+
462
+ return method->klass_name;
534
463
  }
535
464
 
536
465
  /* call-seq:
537
- method_name -> string
466
+ klass_flags -> integer
538
467
 
539
- Returns the name of this method in the format Object#method. Singletons
540
- methods will be returned in the format <Object::Object>#method.*/
468
+ Returns the klass flags */
541
469
 
542
470
  static VALUE
543
- prof_method_name(VALUE self)
471
+ prof_method_klass_flags(VALUE self)
544
472
  {
545
- prof_method_t *method = get_prof_method(self);
546
- return method_name(method->key->mid);
473
+ prof_method_t* method = prof_method_get(self);
474
+ return INT2FIX(method->klass_flags);
547
475
  }
548
476
 
549
477
  /* call-seq:
550
- full_name -> string
478
+ method_name -> string
551
479
 
552
- Returns the full name of this method in the format Object#method.*/
480
+ Returns the name of this method in the format Object#method. Singletons
481
+ methods will be returned in the format <Object::Object>#method.*/
553
482
 
554
483
  static VALUE
555
- prof_full_name(VALUE self)
484
+ prof_method_name(VALUE self)
556
485
  {
557
- prof_method_t *method = get_prof_method(self);
558
- return full_name(method->key->klass, method->key->mid);
486
+ prof_method_t *method = prof_method_get(self);
487
+ return method->method_name;
559
488
  }
560
489
 
561
490
  /* call-seq:
562
- call_infos -> Array of call_info
491
+ root? -> boolean
563
492
 
564
- Returns an array of call info objects that contain profiling information
565
- about the current method.*/
493
+ Returns the true if this method is at the top of the call stack */
566
494
  static VALUE
567
- prof_method_call_infos(VALUE self)
495
+ prof_method_root(VALUE self)
568
496
  {
569
- prof_method_t *method = get_prof_method(self);
570
- if (method->call_infos->object == Qnil) {
571
- method->call_infos->object = prof_call_infos_wrap(method->call_infos);
572
- }
573
- return method->call_infos->object;
497
+ prof_method_t *method = prof_method_get(self);
498
+ return method->root ? Qtrue : Qfalse;
574
499
  }
575
500
 
576
501
  /* call-seq:
577
502
  recursive? -> boolean
578
503
 
579
- Returns the true if this method is recursive */
504
+ Returns the true if this method is recursively invoked */
580
505
  static VALUE
581
506
  prof_method_recursive(VALUE self)
582
507
  {
583
- prof_method_t *method = get_prof_method(self);
584
- return method->recursive ? Qtrue : Qfalse;
508
+ prof_method_t* method = prof_method_get(self);
509
+ return method->recursive ? Qtrue : Qfalse;
585
510
  }
586
511
 
587
512
  /* call-seq:
588
- source_klass -> klass
513
+ excluded? -> boolean
589
514
 
590
- Returns the Ruby klass of the natural source-level definition. */
515
+ Returns the true if this method was excluded */
591
516
  static VALUE
592
- prof_source_klass(VALUE self)
517
+ prof_method_excluded(VALUE self)
593
518
  {
594
- prof_method_t *method = get_prof_method(self);
595
- return resolve_source_klass(method);
519
+ prof_method_t* method = prof_method_get(self);
520
+ return method->excluded ? Qtrue : Qfalse;
596
521
  }
597
522
 
598
- /* call-seq:
599
- calltree_name -> string
523
+ /* :nodoc: */
524
+ static VALUE
525
+ prof_method_dump(VALUE self)
526
+ {
527
+ prof_method_t* method_data = DATA_PTR(self);
528
+ VALUE result = rb_hash_new();
529
+
530
+ rb_hash_aset(result, ID2SYM(rb_intern("klass_name")), prof_method_klass_name(self));
531
+ rb_hash_aset(result, ID2SYM(rb_intern("klass_flags")), INT2FIX(method_data->klass_flags));
532
+ rb_hash_aset(result, ID2SYM(rb_intern("method_name")), method_data->method_name);
600
533
 
601
- Returns the full name of this method in the calltree format.*/
534
+ rb_hash_aset(result, ID2SYM(rb_intern("key")), INT2FIX(method_data->key));
535
+ rb_hash_aset(result, ID2SYM(rb_intern("root")), prof_method_root(self));
536
+ rb_hash_aset(result, ID2SYM(rb_intern("recursive")), prof_method_recursive(self));
537
+ rb_hash_aset(result, ID2SYM(rb_intern("excluded")), prof_method_excluded(self));
538
+ rb_hash_aset(result, ID2SYM(rb_intern("source_file")), method_data->source_file);
539
+ rb_hash_aset(result, ID2SYM(rb_intern("source_line")), INT2FIX(method_data->source_line));
602
540
 
541
+ rb_hash_aset(result, ID2SYM(rb_intern("measurement")), prof_measurement_wrap(method_data->measurement));
542
+
543
+ rb_hash_aset(result, ID2SYM(rb_intern("callers")), prof_method_callers(self));
544
+ rb_hash_aset(result, ID2SYM(rb_intern("callees")), prof_method_callees(self));
545
+
546
+ rb_hash_aset(result, ID2SYM(rb_intern("allocations")), prof_method_allocations(self));
547
+
548
+ return result;
549
+ }
550
+
551
+ /* :nodoc: */
603
552
  static VALUE
604
- prof_calltree_name(VALUE self)
553
+ prof_method_load(VALUE self, VALUE data)
605
554
  {
606
- prof_method_t *method = get_prof_method(self);
607
- volatile VALUE source_klass = resolve_source_klass(method);
608
- return calltree_name(source_klass, method->relation, method->key->mid);
555
+ prof_method_t* method_data = RDATA(self)->data;
556
+ method_data->object = self;
557
+
558
+ method_data->klass_name = rb_hash_aref(data, ID2SYM(rb_intern("klass_name")));
559
+ method_data->klass_flags = FIX2INT(rb_hash_aref(data, ID2SYM(rb_intern("klass_flags"))));
560
+ method_data->method_name = rb_hash_aref(data, ID2SYM(rb_intern("method_name")));
561
+ method_data->key = FIX2LONG(rb_hash_aref(data, ID2SYM(rb_intern("key"))));
562
+
563
+ method_data->root = rb_hash_aref(data, ID2SYM(rb_intern("root"))) == Qtrue ? true : false;
564
+ method_data->recursive = rb_hash_aref(data, ID2SYM(rb_intern("recursive"))) == Qtrue ? true : false;
565
+ method_data->excluded = rb_hash_aref(data, ID2SYM(rb_intern("excluded"))) == Qtrue ? true : false;
566
+
567
+ method_data->source_file = rb_hash_aref(data, ID2SYM(rb_intern("source_file")));
568
+ method_data->source_line = FIX2INT(rb_hash_aref(data, ID2SYM(rb_intern("source_line"))));
569
+
570
+ VALUE measurement = rb_hash_aref(data, ID2SYM(rb_intern("measurement")));
571
+ method_data->measurement = prof_get_measurement(measurement);
572
+
573
+ VALUE callers = rb_hash_aref(data, ID2SYM(rb_intern("callers")));
574
+ for (int i = 0; i < rb_array_len(callers); i++)
575
+ {
576
+ VALUE call_info = rb_ary_entry(callers, i);
577
+ prof_call_info_t *call_info_data = prof_get_call_info(call_info);
578
+ st_data_t key = call_info_data->parent ? call_info_data->parent->key : method_key(Qnil, 0);
579
+ call_info_table_insert(method_data->parent_call_infos, key, call_info_data);
580
+ }
581
+
582
+ VALUE callees = rb_hash_aref(data, ID2SYM(rb_intern("callees")));
583
+ for (int i = 0; i < rb_array_len(callees); i++)
584
+ {
585
+ VALUE call_info = rb_ary_entry(callees, i);
586
+ prof_call_info_t *call_info_data = prof_get_call_info(call_info);
587
+
588
+ st_data_t key = call_info_data->method ? call_info_data->method->key : method_key(Qnil, 0);
589
+ call_info_table_insert(method_data->child_call_infos, key, call_info_data);
590
+ }
591
+
592
+ VALUE allocations = rb_hash_aref(data, ID2SYM(rb_intern("allocations")));
593
+ for (int i = 0; i < rb_array_len(allocations); i++)
594
+ {
595
+ VALUE allocation = rb_ary_entry(allocations, i);
596
+ prof_allocation_t* allocation_data = prof_allocation_get(allocation);
597
+
598
+ st_insert(method_data->allocations_table, allocation_data->key, (st_data_t)allocation_data);
599
+ }
600
+ return data;
609
601
  }
610
602
 
611
603
  void rp_init_method_info()
612
604
  {
613
605
  /* MethodInfo */
614
- cMethodInfo = rb_define_class_under(mProf, "MethodInfo", rb_cObject);
615
- rb_undef_method(CLASS_OF(cMethodInfo), "new");
616
-
617
- rb_define_method(cMethodInfo, "klass", prof_method_klass, 0);
618
- rb_define_method(cMethodInfo, "klass_name", prof_klass_name, 0);
619
- rb_define_method(cMethodInfo, "method_name", prof_method_name, 0);
620
- rb_define_method(cMethodInfo, "full_name", prof_full_name, 0);
621
- rb_define_method(cMethodInfo, "method_id", prof_method_id, 0);
622
-
623
- rb_define_method(cMethodInfo, "call_infos", prof_method_call_infos, 0);
624
- rb_define_method(cMethodInfo, "source_klass", prof_source_klass, 0);
625
- rb_define_method(cMethodInfo, "source_file", prof_method_source_file, 0);
626
- rb_define_method(cMethodInfo, "line", prof_method_line, 0);
627
-
628
- rb_define_method(cMethodInfo, "recursive?", prof_method_recursive, 0);
629
- rb_define_method(cMethodInfo, "calltree_name", prof_calltree_name, 0);
606
+ cRpMethodInfo = rb_define_class_under(mProf, "MethodInfo", rb_cData);
607
+ rb_undef_method(CLASS_OF(cRpMethodInfo), "new");
608
+ rb_define_alloc_func(cRpMethodInfo, prof_method_allocate);
609
+
610
+ rb_define_method(cRpMethodInfo, "klass_name", prof_method_klass_name, 0);
611
+ rb_define_method(cRpMethodInfo, "klass_flags", prof_method_klass_flags, 0);
612
+
613
+ rb_define_method(cRpMethodInfo, "method_name", prof_method_name, 0);
614
+
615
+ rb_define_method(cRpMethodInfo, "callers", prof_method_callers, 0);
616
+ rb_define_method(cRpMethodInfo, "callees", prof_method_callees, 0);
617
+ rb_define_method(cRpMethodInfo, "allocations", prof_method_allocations, 0);
618
+
619
+ rb_define_method(cRpMethodInfo, "measurement", prof_method_measurement, 0);
620
+
621
+ rb_define_method(cRpMethodInfo, "source_file", prof_method_source_file, 0);
622
+ rb_define_method(cRpMethodInfo, "line", prof_method_line, 0);
623
+
624
+ rb_define_method(cRpMethodInfo, "root?", prof_method_root, 0);
625
+ rb_define_method(cRpMethodInfo, "recursive?", prof_method_recursive, 0);
626
+ rb_define_method(cRpMethodInfo, "excluded?", prof_method_excluded, 0);
627
+
628
+ rb_define_method(cRpMethodInfo, "_dump_data", prof_method_dump, 0);
629
+ rb_define_method(cRpMethodInfo, "_load_data", prof_method_load, 1);
630
630
  }