ruby-prof 0.11.0.rc1 → 0.11.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/CHANGES +20 -5
  2. data/README.rdoc +10 -3
  3. data/ext/ruby_prof/rp_call_info.c +108 -79
  4. data/ext/ruby_prof/rp_call_info.h +1 -0
  5. data/ext/ruby_prof/rp_measure_cpu_time.c +111 -111
  6. data/ext/ruby_prof/rp_measure_gc_runs.c +1 -1
  7. data/ext/ruby_prof/rp_measure_memory.c +1 -1
  8. data/ext/ruby_prof/rp_measure_process_time.c +71 -71
  9. data/ext/ruby_prof/rp_measure_wall_time.c +1 -1
  10. data/ext/ruby_prof/rp_method.c +143 -73
  11. data/ext/ruby_prof/rp_method.h +7 -4
  12. data/ext/ruby_prof/rp_stack.c +16 -1
  13. data/ext/ruby_prof/rp_stack.h +4 -1
  14. data/ext/ruby_prof/rp_thread.c +165 -35
  15. data/ext/ruby_prof/rp_thread.h +8 -2
  16. data/ext/ruby_prof/ruby_prof.c +164 -171
  17. data/ext/ruby_prof/ruby_prof.h +53 -54
  18. data/ext/ruby_prof/vc/ruby_prof.sln +26 -0
  19. data/ext/ruby_prof/vc/ruby_prof.vcxproj +109 -0
  20. data/ext/ruby_prof/vc/ruby_prof_18.vcxproj +105 -0
  21. data/lib/ruby-prof/aggregate_call_info.rb +9 -7
  22. data/lib/ruby-prof/call_info.rb +2 -27
  23. data/lib/ruby-prof/call_info_visitor.rb +42 -0
  24. data/lib/ruby-prof/{empty.png → images/empty.png} +0 -0
  25. data/lib/ruby-prof/{minus.png → images/minus.png} +0 -0
  26. data/lib/ruby-prof/{plus.png → images/plus.png} +0 -0
  27. data/lib/ruby-prof/method_info.rb +13 -15
  28. data/lib/ruby-prof/{abstract_printer.rb → printers/abstract_printer.rb} +36 -2
  29. data/lib/ruby-prof/printers/call_info_printer.rb +40 -0
  30. data/lib/ruby-prof/{call_stack_printer.rb → printers/call_stack_printer.rb} +11 -16
  31. data/lib/ruby-prof/{call_tree_printer.rb → printers/call_tree_printer.rb} +4 -4
  32. data/lib/ruby-prof/{dot_printer.rb → printers/dot_printer.rb} +11 -31
  33. data/lib/ruby-prof/{flat_printer.rb → printers/flat_printer.rb} +26 -35
  34. data/lib/ruby-prof/{flat_printer_with_line_numbers.rb → printers/flat_printer_with_line_numbers.rb} +14 -25
  35. data/lib/ruby-prof/printers/graph_html_printer.rb +248 -0
  36. data/lib/ruby-prof/{graph_printer.rb → printers/graph_printer.rb} +31 -73
  37. data/lib/ruby-prof/{multi_printer.rb → printers/multi_printer.rb} +0 -0
  38. data/lib/ruby-prof/profile.rb +27 -22
  39. data/lib/ruby-prof/rack.rb +22 -12
  40. data/ruby-prof.gemspec +58 -0
  41. data/test/aggregate_test.rb +6 -6
  42. data/test/call_info_visitor_test.rb +31 -0
  43. data/test/duplicate_names_test.rb +1 -1
  44. data/test/dynamic_method_test.rb +1 -1
  45. data/test/enumerable_test.rb +1 -1
  46. data/test/exclude_threads_test.rb +2 -2
  47. data/test/gc_test.rb +35 -0
  48. data/test/line_number_test.rb +2 -2
  49. data/test/measure_cpu_time_test.rb +5 -5
  50. data/test/measure_process_time_test.rb +5 -5
  51. data/test/measure_wall_time_test.rb +5 -5
  52. data/test/method_elimination_test.rb +3 -3
  53. data/test/module_test.rb +1 -1
  54. data/test/no_method_class_test.rb +1 -1
  55. data/test/printers_test.rb +16 -8
  56. data/test/recursive_test.rb +115 -91
  57. data/test/stack_test.rb +1 -1
  58. data/test/start_stop_test.rb +13 -13
  59. data/test/summarize_test.rb +48 -0
  60. data/test/test_suite.rb +1 -0
  61. data/test/thread_test.rb +16 -12
  62. data/test/unique_call_path_test.rb +10 -10
  63. metadata +64 -85
  64. data/lib/1.8/ruby_prof.so +0 -0
  65. data/lib/1.9/ruby_prof.exp +0 -0
  66. data/lib/1.9/ruby_prof.ilk +0 -0
  67. data/lib/1.9/ruby_prof.lib +0 -0
  68. data/lib/1.9/ruby_prof.pdb +0 -0
  69. data/lib/1.9/ruby_prof.so +0 -0
  70. data/lib/ruby-prof.rb +0 -70
  71. data/lib/ruby-prof/graph_html_printer.rb +0 -286
  72. data/lib/ruby-prof/symbol_to_proc.rb +0 -10
  73. data/lib/ruby_prof.exp +0 -0
  74. data/lib/ruby_prof.ilk +0 -0
  75. data/lib/ruby_prof.lib +0 -0
  76. data/lib/ruby_prof.pdb +0 -0
  77. data/lib/ruby_prof.so +0 -0
  78. data/lib/unprof.rb +0 -10
  79. data/test/do_nothing.rb +0 -0
data/CHANGES CHANGED
@@ -1,13 +1,28 @@
1
+ 0.11.0.rc2 (2012-03-25)
2
+ ======================
3
+ * Lots of improvements to Rack handler - this can be used to profile requests
4
+ in Rails and other rack-based ruby web frameworks (Charlie Savage).
5
+ * Reimplemented handling of recursive calls using CallInfoVisitor (Charlie Savage).
6
+ * Fix bug where child times were not correctly reported in complicated
7
+ call graphs with recursion like in frameworks like Rails (Charlie Savage).
8
+ * Add in recursive call information to Flat, Graph and Graph HTML reports (Charlie Savage).
9
+ * Add in new thread class add added RubyProf::Thread#top_method to
10
+ make report generation easier (Charlie Savage).
11
+ * Add in CallInfoVisitor class to make it easy to iterate over a call graph (Charlie Savage).
12
+ * Add in CallInfoPrinter to make it visualize RubyProf's internal call graphs (Charlie Savage).
13
+ * Significant updates to documentation (Charlie Savage).
14
+ * More c code cleanup (Charlie Savage).
15
+
1
16
  0.11.0.rc1 (2012-03-24)
2
17
  ======================
18
+ * Big internal refactoring of C code to make RubyProf easier to understand and extend (Charlie Savage).
19
+ * Profile results are now returned as instances of a new class RubyProf::Profile. The old api
20
+ is supported via a compatability layer that at some point will be deprecated. (Charlie Savage).
3
21
  * On Windows, use QueryPerformanceCounter and QueryPerformanceFrequency to measure CPU time instead
4
22
  of rdtsc. This change is based on Microsoft's recommendation (Charlie Savage).
5
23
  * On Windows use GetProcessTimes to return real PROCESS_TIME times instead of wall times (Charlie Savage).
6
- * Big internal refactoring of C code to make RubyProf easier to understand and extend (Charlie Savage).
7
- * Profile results are now returned as instances of a new class RubyProf::Profile. The old api
8
- is supported via a compatability layer that at some point will be deprecated. (Charlie Savage).
9
- * Split out tests for cpu_time, process_time and wall_time into separate files (Charlie Savage).
10
- * Dropped support for Ruby 1.8.4 and 1.8.6 - does anybody still use these? (Charlie Savage).
24
+ * Split out tests for each time of measurement (cpu_time, process_time, etc.) (Charlie Savage).
25
+ * Dropped support for Ruby 1.8.4 and 1.8.6 and 1.9.0 (Charlie Savage).
11
26
  * Added support for sorting results by total, self, wait and child times (Jan Suchal)
12
27
  * Added tests for sorting behaviour & removed options from constructor to print method (Jan Suchal)
13
28
  * Fix line number tests due to changes at top of file (Charlie Savage).
data/README.rdoc CHANGED
@@ -187,9 +187,16 @@ So to profile Rails:
187
187
 
188
188
  1. Create a new profile.rb environment. Make sure to turn on cache_classes
189
189
  and cache_template_loading. Otherwise your profiling results will be
190
- overwhelemed by the time Rails spends loading required files.
190
+ overwhelemed by the time Rails spends loading required files. You should
191
+ likely turn off caching.
191
192
 
192
- 2. Add the ruby prof rack adapter to your middleware stack. One way to
193
+ 2. Add the ruby-prof to your gemfile:
194
+
195
+ group :profile do
196
+ gem 'ruby-prof'
197
+ end
198
+
199
+ 3. Add the ruby prof rack adapter to your middleware stack. One way to
193
200
  do this is by adding the following code to config.ru:
194
201
 
195
202
  if Rails.env.profile?
@@ -199,7 +206,7 @@ do this is by adding the following code to config.ru:
199
206
  The path is where you want profiling results to be stored. By default the
200
207
  rack adapter will generate a html call graph report and flat text report.
201
208
 
202
- 3. Now make a request to your running server. New profiling information will
209
+ 4. Now make a request to your running server. New profiling information will
203
210
  be generated for each request. Note that each request will overwrite
204
211
  the profiling reports created by the previous request!
205
212
 
@@ -7,45 +7,13 @@
7
7
 
8
8
  VALUE cCallInfo;
9
9
 
10
- /* ======= Call Info ========*/
11
- st_table *
12
- call_info_table_create()
13
- {
14
- return st_init_table(&type_method_hash);
15
- }
16
-
17
- size_t
18
- call_info_table_insert(st_table *table, const prof_method_key_t *key, prof_call_info_t *val)
19
- {
20
- return st_insert(table, (st_data_t) key, (st_data_t) val);
21
- }
22
-
23
- prof_call_info_t *
24
- call_info_table_lookup(st_table *table, const prof_method_key_t *key)
25
- {
26
- st_data_t val;
27
- if (st_lookup(table, (st_data_t) key, &val))
28
- {
29
- return (prof_call_info_t *) val;
30
- }
31
- else
32
- {
33
- return NULL;
34
- }
35
- }
36
10
 
37
- static void
38
- call_info_table_free(st_table *table)
39
- {
40
- st_free_table(table);
41
- }
11
+ // Forward declarations
12
+ st_table * call_info_table_create();
13
+ void call_info_table_free(st_table *table);
42
14
 
43
- /* Document-class: RubyProf::CallInfo
44
- RubyProf::CallInfo is a helper class used by RubyProf::MethodInfo
45
- to keep track of which child methods were called and how long
46
- they took to execute. */
47
15
 
48
- /* :nodoc: */
16
+ /* ======= prof_call_info_t ========*/
49
17
  prof_call_info_t *
50
18
  prof_call_info_create(prof_method_t* method, prof_call_info_t* parent)
51
19
  {
@@ -65,35 +33,33 @@ prof_call_info_create(prof_method_t* method, prof_call_info_t* parent)
65
33
  }
66
34
 
67
35
  static void
68
- prof_call_info_mark(prof_call_info_t *call_info)
36
+ prof_call_info_free(prof_call_info_t *call_info)
69
37
  {
70
- {
71
- VALUE target = call_info->target->object;
72
- if (NIL_P(target))
73
- prof_method_mark(call_info->target);
74
- else
75
- rb_gc_mark(target);
76
- }
77
- rb_gc_mark(call_info->children);
78
- if (call_info->parent) {
79
- VALUE parent = call_info->parent->object;
80
- if (NIL_P(parent)) {
81
- prof_call_info_mark(call_info->parent);
38
+ /* Has this thread object been accessed by Ruby? If
39
+ yes clean it up so to avoid a segmentation fault. */
40
+ if (call_info->object != Qnil)
41
+ {
42
+ RDATA(call_info->object)->data = NULL;
43
+ RDATA(call_info->object)->dfree = NULL;
44
+ RDATA(call_info->object)->dmark = NULL;
82
45
  }
83
- else {
84
- rb_gc_mark(parent);
85
- }
86
- }
46
+ call_info->object = Qnil;
47
+
48
+ call_info_table_free(call_info->call_infos);
49
+ xfree(call_info);
87
50
  }
88
51
 
89
52
  static void
90
- prof_call_info_free(prof_call_info_t *call_info)
53
+ prof_call_info_mark(prof_call_info_t *call_info)
91
54
  {
92
- call_info_table_free(call_info->call_infos);
93
- xfree(call_info);
55
+ if (call_info->object)
56
+ rb_gc_mark(call_info->children);
57
+
58
+ if (call_info->children)
59
+ rb_gc_mark(call_info->children);
94
60
  }
95
61
 
96
- static VALUE
62
+ VALUE
97
63
  prof_call_info_wrap(prof_call_info_t *call_info)
98
64
  {
99
65
  if (call_info->object == Qnil)
@@ -104,17 +70,68 @@ prof_call_info_wrap(prof_call_info_t *call_info)
104
70
  }
105
71
 
106
72
  static prof_call_info_t *
107
- prof_get_call_info_result(VALUE obj)
73
+ prof_get_call_info(VALUE self)
74
+ {
75
+ /* Can't use Data_Get_Struct because that triggers the event hook
76
+ ending up in endless recursion. */
77
+ prof_call_info_t* result = DATA_PTR(self);
78
+
79
+ if (!result)
80
+ rb_raise(rb_eRuntimeError, "This RubyProf::CallInfo instance has already been freed, likely because its profile has been freed.");
81
+
82
+ return result;
83
+ }
84
+
85
+ /* ======= Call Info Table ========*/
86
+ st_table *
87
+ call_info_table_create()
88
+ {
89
+ return st_init_table(&type_method_hash);
90
+ }
91
+
92
+ /*static int
93
+ call_info_table_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
94
+ {
95
+ prof_call_info_free((prof_call_info_t*)value);
96
+ return ST_CONTINUE;
97
+ }*/
98
+
99
+ void
100
+ call_info_table_free(st_table *table)
101
+ {
102
+ //st_foreach(table, call_info_table_free_iterator, 0);
103
+ st_free_table(table);
104
+ }
105
+
106
+ size_t
107
+ call_info_table_insert(st_table *table, const prof_method_key_t *key, prof_call_info_t *val)
108
+ {
109
+ return st_insert(table, (st_data_t) key, (st_data_t) val);
110
+ }
111
+
112
+ prof_call_info_t *
113
+ call_info_table_lookup(st_table *table, const prof_method_key_t *key)
108
114
  {
109
- if (BUILTIN_TYPE(obj) != T_DATA)
115
+ st_data_t val;
116
+ if (st_lookup(table, (st_data_t) key, &val))
110
117
  {
111
- /* Should never happen */
112
- rb_raise(rb_eTypeError, "Not a call info object");
118
+ return (prof_call_info_t *) val;
119
+ }
120
+ else
121
+ {
122
+ return NULL;
113
123
  }
114
- return (prof_call_info_t *) DATA_PTR(obj);
115
124
  }
116
125
 
117
126
 
127
+ /* ======= RubyProf::CallInfo ========*/
128
+
129
+ /* Document-class: RubyProf::CallInfo
130
+ RubyProf::CallInfo is a helper class used by RubyProf::MethodInfo
131
+ to keep track of which child methods were called and how long
132
+ they took to execute. */
133
+
134
+
118
135
  /* call-seq:
119
136
  called -> MethodInfo
120
137
 
@@ -126,7 +143,7 @@ prof_call_info_target(VALUE self)
126
143
  about the GC. We will wrap the method_info but provide no
127
144
  free method so the underlying object is not freed twice! */
128
145
 
129
- prof_call_info_t *result = prof_get_call_info_result(self);
146
+ prof_call_info_t *result = prof_get_call_info(self);
130
147
  return prof_method_wrap(result->target);
131
148
  }
132
149
 
@@ -137,7 +154,7 @@ Returns the total amount of times this method was called. */
137
154
  static VALUE
138
155
  prof_call_info_called(VALUE self)
139
156
  {
140
- prof_call_info_t *result = prof_get_call_info_result(self);
157
+ prof_call_info_t *result = prof_get_call_info(self);
141
158
  return INT2NUM(result->called);
142
159
  }
143
160
 
@@ -148,11 +165,22 @@ Sets the call count to n. */
148
165
  static VALUE
149
166
  prof_call_info_set_called(VALUE self, VALUE called)
150
167
  {
151
- prof_call_info_t *result = prof_get_call_info_result(self);
168
+ prof_call_info_t *result = prof_get_call_info(self);
152
169
  result->called = NUM2INT(called);
153
170
  return called;
154
171
  }
155
172
 
173
+ /* call-seq:
174
+ depth -> int
175
+
176
+ returns the depth of this call info in the call graph */
177
+ static VALUE
178
+ prof_call_info_depth(VALUE self)
179
+ {
180
+ prof_call_info_t *result = prof_get_call_info(self);
181
+ return rb_int_new(result->depth);
182
+ }
183
+
156
184
  /* call-seq:
157
185
  line_no -> int
158
186
 
@@ -160,7 +188,7 @@ prof_call_info_set_called(VALUE self, VALUE called)
160
188
  static VALUE
161
189
  prof_call_info_line(VALUE self)
162
190
  {
163
- prof_call_info_t *result = prof_get_call_info_result(self);
191
+ prof_call_info_t *result = prof_get_call_info(self);
164
192
  return rb_int_new(result->line);
165
193
  }
166
194
 
@@ -171,7 +199,7 @@ Returns the total amount of time spent in this method and its children. */
171
199
  static VALUE
172
200
  prof_call_info_total_time(VALUE self)
173
201
  {
174
- prof_call_info_t *result = prof_get_call_info_result(self);
202
+ prof_call_info_t *result = prof_get_call_info(self);
175
203
  return rb_float_new(result->total_time);
176
204
  }
177
205
 
@@ -182,8 +210,8 @@ adds total time time from call_info to self. */
182
210
  static VALUE
183
211
  prof_call_info_add_total_time(VALUE self, VALUE other)
184
212
  {
185
- prof_call_info_t *result = prof_get_call_info_result(self);
186
- prof_call_info_t *other_info = prof_get_call_info_result(other);
213
+ prof_call_info_t *result = prof_get_call_info(self);
214
+ prof_call_info_t *other_info = prof_get_call_info(other);
187
215
 
188
216
  result->total_time += other_info->total_time;
189
217
  return Qnil;
@@ -196,7 +224,7 @@ Returns the total amount of time spent in this method. */
196
224
  static VALUE
197
225
  prof_call_info_self_time(VALUE self)
198
226
  {
199
- prof_call_info_t *result = prof_get_call_info_result(self);
227
+ prof_call_info_t *result = prof_get_call_info(self);
200
228
 
201
229
  return rb_float_new(result->self_time);
202
230
  }
@@ -208,8 +236,8 @@ adds self time from call_info to self. */
208
236
  static VALUE
209
237
  prof_call_info_add_self_time(VALUE self, VALUE other)
210
238
  {
211
- prof_call_info_t *result = prof_get_call_info_result(self);
212
- prof_call_info_t *other_info = prof_get_call_info_result(other);
239
+ prof_call_info_t *result = prof_get_call_info(self);
240
+ prof_call_info_t *other_info = prof_get_call_info(other);
213
241
 
214
242
  result->self_time += other_info->self_time;
215
243
  return Qnil;
@@ -222,7 +250,7 @@ Returns the total amount of time this method waited for other threads. */
222
250
  static VALUE
223
251
  prof_call_info_wait_time(VALUE self)
224
252
  {
225
- prof_call_info_t *result = prof_get_call_info_result(self);
253
+ prof_call_info_t *result = prof_get_call_info(self);
226
254
 
227
255
  return rb_float_new(result->wait_time);
228
256
  }
@@ -235,8 +263,8 @@ adds wait time from call_info to self. */
235
263
  static VALUE
236
264
  prof_call_info_add_wait_time(VALUE self, VALUE other)
237
265
  {
238
- prof_call_info_t *result = prof_get_call_info_result(self);
239
- prof_call_info_t *other_info = prof_get_call_info_result(other);
266
+ prof_call_info_t *result = prof_get_call_info(self);
267
+ prof_call_info_t *other_info = prof_get_call_info(other);
240
268
 
241
269
  result->wait_time += other_info->wait_time;
242
270
  return Qnil;
@@ -249,7 +277,7 @@ Returns the call_infos parent call_info object (the method that called this meth
249
277
  static VALUE
250
278
  prof_call_info_parent(VALUE self)
251
279
  {
252
- prof_call_info_t *result = prof_get_call_info_result(self);
280
+ prof_call_info_t *result = prof_get_call_info(self);
253
281
  if (result->parent)
254
282
  return prof_call_info_wrap(result->parent);
255
283
  else
@@ -263,11 +291,11 @@ Changes the parent of self to new_parent and returns it.*/
263
291
  static VALUE
264
292
  prof_call_info_set_parent(VALUE self, VALUE new_parent)
265
293
  {
266
- prof_call_info_t *result = prof_get_call_info_result(self);
294
+ prof_call_info_t *result = prof_get_call_info(self);
267
295
  if (new_parent == Qnil)
268
296
  result->parent = NULL;
269
297
  else
270
- result->parent = prof_get_call_info_result(new_parent);
298
+ result->parent = prof_get_call_info(new_parent);
271
299
  return prof_call_info_parent(self);
272
300
  }
273
301
 
@@ -288,7 +316,7 @@ called (ie, children).*/
288
316
  static VALUE
289
317
  prof_call_info_children(VALUE self)
290
318
  {
291
- prof_call_info_t *call_info = prof_get_call_info_result(self);
319
+ prof_call_info_t *call_info = prof_get_call_info(self);
292
320
  if (call_info->children == Qnil)
293
321
  {
294
322
  call_info->children = rb_ary_new();
@@ -365,5 +393,6 @@ void rp_init_call_info()
365
393
  rb_define_method(cCallInfo, "add_self_time", prof_call_info_add_self_time, 1);
366
394
  rb_define_method(cCallInfo, "wait_time", prof_call_info_wait_time, 0);
367
395
  rb_define_method(cCallInfo, "add_wait_time", prof_call_info_add_wait_time, 1);
396
+ rb_define_method(cCallInfo, "depth", prof_call_info_depth, 0);
368
397
  rb_define_method(cCallInfo, "line", prof_call_info_line, 0);
369
398
  }
@@ -16,6 +16,7 @@ typedef struct prof_call_info_t
16
16
  struct prof_call_info_t *parent;
17
17
  st_table *call_infos;
18
18
  int called;
19
+ int depth;
19
20
  double total_time;
20
21
  double self_time;
21
22
  double wait_time;
@@ -1,112 +1,112 @@
1
- /* Copyright (C) 2005-2011 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 "ruby_prof.h"
5
-
6
- static VALUE cMeasureCpuTime;
7
-
8
- static unsigned long long cpu_frequency = 0;
9
-
10
- /* The _WIN32 check is needed for msys (and maybe cygwin?) */
11
- #if defined(__GNUC__) && !defined(_WIN32)
12
-
13
- #include <stdint.h>
14
- #include <time.h>
15
-
16
- static unsigned long long get_cpu_time()
17
- {
18
- #if defined(__i386__) || defined(__x86_64__)
19
- uint32_t a, d;
20
- __asm__ volatile("rdtsc" : "=a" (a), "=d" (d));
21
- return ((uint64_t)d << 32) + a;
22
- #elif defined(__powerpc__) || defined(__ppc__)
23
- unsigned long long x, y;
24
-
25
- __asm__ __volatile__ ("\n\
26
- 1: mftbu %1\n\
27
- mftb %L0\n\
28
- mftbu %0\n\
29
- cmpw %0,%1\n\
30
- bne- 1b"
31
- : "=r" (x), "=r" (y));
32
- return x;
33
- #endif
34
- }
35
-
36
- static unsigned long long get_cpu_frequency()
37
- {
38
- unsigned long long x, y;
39
-
40
- struct timespec ts;
41
- ts.tv_sec = 0;
42
- ts.tv_nsec = 500000000;
43
- x = get_cpu_time();
44
- nanosleep(&ts, NULL);
45
- y = get_cpu_time();
46
- return (y - x) * 2;
47
- }
48
-
49
- #elif defined(_WIN32)
50
-
51
- static unsigned long long get_cpu_time()
52
- {
53
- LARGE_INTEGER time;
54
- QueryPerformanceCounter(&time);
55
- return time.QuadPart;
56
- };
57
-
58
- static unsigned long long get_cpu_frequency()
59
- {
60
- LARGE_INTEGER cpu_frequency;
61
- QueryPerformanceFrequency(&cpu_frequency);
62
- return cpu_frequency.QuadPart;
63
- };
64
- #endif
65
-
66
- static double
67
- measure_cpu_time()
68
- {
69
- return ((double)get_cpu_time()) / cpu_frequency;
70
- }
71
-
72
-
73
- prof_measurer_t* prof_measurer_cpu_time()
74
- {
75
- prof_measurer_t* measure = ALLOC(prof_measurer_t);
76
- measure->measure = measure_cpu_time;
77
- return measure;
78
- }
79
-
80
- /* call-seq:
81
- measure -> float
82
-
83
- Returns the cpu time.*/
84
- static VALUE
85
- prof_measure_cpu_time(VALUE self)
86
- {
87
- return rb_float_new(measure_cpu_time());
88
- }
89
-
90
- /* call-seq:
91
- cpu_frequency -> int
92
-
93
- Returns the cpu's frequency. This value is needed when
94
- RubyProf::measure_mode is set to CPU_TIME. */
95
- static VALUE
96
- prof_get_cpu_frequency(VALUE self)
97
- {
98
- return ULL2NUM(cpu_frequency);
99
- }
100
-
101
- void rp_init_measure_cpu_time()
102
- {
103
- rb_define_const(mProf, "CPU_TIME", INT2NUM(MEASURE_CPU_TIME));
1
+ /* Copyright (C) 2005-2011 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 "ruby_prof.h"
5
+
6
+ static VALUE cMeasureCpuTime;
7
+
8
+ static unsigned long long cpu_frequency = 0;
9
+
10
+ /* The _WIN32 check is needed for msys (and maybe cygwin?) */
11
+ #if defined(__GNUC__) && !defined(_WIN32)
12
+
13
+ #include <stdint.h>
14
+ #include <time.h>
15
+
16
+ static unsigned long long get_cpu_time()
17
+ {
18
+ #if defined(__i386__) || defined(__x86_64__)
19
+ uint32_t a, d;
20
+ __asm__ volatile("rdtsc" : "=a" (a), "=d" (d));
21
+ return ((uint64_t)d << 32) + a;
22
+ #elif defined(__powerpc__) || defined(__ppc__)
23
+ unsigned long long x, y;
24
+
25
+ __asm__ __volatile__ ("\n\
26
+ 1: mftbu %1\n\
27
+ mftb %L0\n\
28
+ mftbu %0\n\
29
+ cmpw %0,%1\n\
30
+ bne- 1b"
31
+ : "=r" (x), "=r" (y));
32
+ return x;
33
+ #endif
34
+ }
35
+
36
+ static unsigned long long get_cpu_frequency()
37
+ {
38
+ unsigned long long x, y;
39
+
40
+ struct timespec ts;
41
+ ts.tv_sec = 0;
42
+ ts.tv_nsec = 500000000;
43
+ x = get_cpu_time();
44
+ nanosleep(&ts, NULL);
45
+ y = get_cpu_time();
46
+ return (y - x) * 2;
47
+ }
48
+
49
+ #elif defined(_WIN32)
50
+
51
+ static unsigned long long get_cpu_time()
52
+ {
53
+ LARGE_INTEGER time;
54
+ QueryPerformanceCounter(&time);
55
+ return time.QuadPart;
56
+ };
57
+
58
+ static unsigned long long get_cpu_frequency()
59
+ {
60
+ LARGE_INTEGER cpu_frequency;
61
+ QueryPerformanceFrequency(&cpu_frequency);
62
+ return cpu_frequency.QuadPart;
63
+ };
64
+ #endif
65
+
66
+ static double
67
+ measure_cpu_time()
68
+ {
69
+ return ((double)get_cpu_time()) / cpu_frequency;
70
+ }
71
+
72
+
73
+ prof_measurer_t* prof_measurer_cpu_time()
74
+ {
75
+ prof_measurer_t* measure = ALLOC(prof_measurer_t);
76
+ measure->measure = measure_cpu_time;
77
+ return measure;
78
+ }
79
+
80
+ /* call-seq:
81
+ measure -> float
82
+
83
+ Returns the cpu time.*/
84
+ static VALUE
85
+ prof_measure_cpu_time(VALUE self)
86
+ {
87
+ return rb_float_new(measure_cpu_time());
88
+ }
89
+
90
+ /* call-seq:
91
+ cpu_frequency -> int
92
+
93
+ Returns the cpu's frequency. This value is needed when
94
+ RubyProf::measure_mode is set to CPU_TIME. */
95
+ static VALUE
96
+ prof_get_cpu_frequency(VALUE self)
97
+ {
98
+ return ULL2NUM(cpu_frequency);
99
+ }
100
+
101
+ void rp_init_measure_cpu_time()
102
+ {
103
+ rb_define_const(mProf, "CPU_TIME", INT2NUM(MEASURE_CPU_TIME));
104
104
  rb_define_const(mProf, "CPU_TIME_ENABLED", Qtrue);
105
-
106
- cMeasureCpuTime = rb_define_class_under(mMeasure, "CpuTime", rb_cObject);
107
- rb_define_singleton_method(cMeasureCpuTime, "measure", prof_measure_cpu_time, 0);
108
- rb_define_singleton_method(cMeasureCpuTime, "frequency", prof_get_cpu_frequency, 0);
109
-
110
- /* Get cpu_frequency */
111
- cpu_frequency = get_cpu_frequency();
112
- }
105
+
106
+ cMeasureCpuTime = rb_define_class_under(mMeasure, "CpuTime", rb_cObject);
107
+ rb_define_singleton_method(cMeasureCpuTime, "measure", prof_measure_cpu_time, 0);
108
+ rb_define_singleton_method(cMeasureCpuTime, "frequency", prof_get_cpu_frequency, 0);
109
+
110
+ /* Get cpu_frequency */
111
+ cpu_frequency = get_cpu_frequency();
112
+ }