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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
  }