ruby-prof 0.11.0.rc1-x86-mingw32 → 0.11.0.rc2-x86-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 (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/1.8/ruby_prof.so +0 -0
  22. data/lib/1.9/ruby_prof.so +0 -0
  23. data/lib/ruby-prof/aggregate_call_info.rb +9 -7
  24. data/lib/ruby-prof/call_info.rb +2 -27
  25. data/lib/ruby-prof/call_info_visitor.rb +42 -0
  26. data/lib/ruby-prof/{empty.png → images/empty.png} +0 -0
  27. data/lib/ruby-prof/{minus.png → images/minus.png} +0 -0
  28. data/lib/ruby-prof/{plus.png → images/plus.png} +0 -0
  29. data/lib/ruby-prof/method_info.rb +13 -15
  30. data/lib/ruby-prof/{abstract_printer.rb → printers/abstract_printer.rb} +36 -2
  31. data/lib/ruby-prof/printers/call_info_printer.rb +40 -0
  32. data/lib/ruby-prof/{call_stack_printer.rb → printers/call_stack_printer.rb} +11 -16
  33. data/lib/ruby-prof/{call_tree_printer.rb → printers/call_tree_printer.rb} +4 -4
  34. data/lib/ruby-prof/{dot_printer.rb → printers/dot_printer.rb} +11 -31
  35. data/lib/ruby-prof/{flat_printer.rb → printers/flat_printer.rb} +26 -35
  36. data/lib/ruby-prof/{flat_printer_with_line_numbers.rb → printers/flat_printer_with_line_numbers.rb} +14 -25
  37. data/lib/ruby-prof/printers/graph_html_printer.rb +248 -0
  38. data/lib/ruby-prof/{graph_printer.rb → printers/graph_printer.rb} +31 -73
  39. data/lib/ruby-prof/{multi_printer.rb → printers/multi_printer.rb} +0 -0
  40. data/lib/ruby-prof/profile.rb +27 -22
  41. data/lib/ruby-prof/rack.rb +22 -12
  42. data/ruby-prof.gemspec +58 -0
  43. data/test/aggregate_test.rb +6 -6
  44. data/test/call_info_visitor_test.rb +31 -0
  45. data/test/duplicate_names_test.rb +1 -1
  46. data/test/dynamic_method_test.rb +1 -1
  47. data/test/enumerable_test.rb +1 -1
  48. data/test/exclude_threads_test.rb +2 -2
  49. data/test/gc_test.rb +35 -0
  50. data/test/line_number_test.rb +2 -2
  51. data/test/measure_cpu_time_test.rb +5 -5
  52. data/test/measure_process_time_test.rb +5 -5
  53. data/test/measure_wall_time_test.rb +5 -5
  54. data/test/method_elimination_test.rb +3 -3
  55. data/test/module_test.rb +1 -1
  56. data/test/no_method_class_test.rb +1 -1
  57. data/test/printers_test.rb +16 -8
  58. data/test/recursive_test.rb +115 -91
  59. data/test/stack_test.rb +1 -1
  60. data/test/start_stop_test.rb +13 -13
  61. data/test/summarize_test.rb +48 -0
  62. data/test/test_suite.rb +1 -0
  63. data/test/thread_test.rb +16 -12
  64. data/test/unique_call_path_test.rb +10 -10
  65. metadata +65 -85
  66. data/lib/1.9/ruby_prof.exp +0 -0
  67. data/lib/1.9/ruby_prof.ilk +0 -0
  68. data/lib/1.9/ruby_prof.lib +0 -0
  69. data/lib/1.9/ruby_prof.pdb +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
@@ -81,7 +81,7 @@ void rp_init_measure_gc_runs()
81
81
  {
82
82
  rb_define_const(mProf, "GC_RUNS", INT2NUM(MEASURE_GC_RUNS));
83
83
  rb_define_const(mProf, "GC_RUNS_ENABLED", MEASURE_GC_RUNS_ENABLED);
84
-
84
+
85
85
  cMeasureGcRuns = rb_define_class_under(mMeasure, "GcRuns", rb_cObject);
86
86
  rb_define_singleton_method(cMeasureGcRuns, "measure", prof_measure_gc_runs, 0);
87
87
  }
@@ -74,7 +74,7 @@ prof_measure_memory(VALUE self)
74
74
  void rp_init_measure_memory()
75
75
  {
76
76
  rb_define_const(mProf, "MEMORY", INT2NUM(MEASURE_MEMORY));
77
- rb_define_const(mProf, "MEMORY_ENABLED", MEASURE_MEMORY_ENABLED);
77
+ rb_define_const(mProf, "MEMORY_ENABLED", MEASURE_MEMORY_ENABLED);
78
78
 
79
79
  cMeasureMemory = rb_define_class_under(mMeasure, "Memory", rb_cObject);
80
80
  rb_define_singleton_method(cMeasureMemory, "measure", prof_measure_memory, 0);
@@ -1,71 +1,71 @@
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
- #include <time.h>
6
-
7
- static VALUE cMeasureProcessTime;
8
-
9
- static double
10
- measure_process_time()
11
- {
12
- #if defined(__linux__)
13
- struct timespec clock;
14
- clock_gettime(CLOCK_PROCESS_CPUTIME_ID , &clock);
15
- return (clock.tv_sec * 1000000000 + clock.tv_nsec) / 1000000000.0;
16
- #elif defined(_win32)
17
- FILETIME createTime;
18
- FILETIME exitTime;
19
- FILETIME sysTime;
20
- FILETIME cpuTime;
21
-
22
- ULARGE_INTEGER sysTimeInt;
23
- ULARGE_INTEGER cpuTimeInt;
24
- ULONGLONG totalTime;
25
-
26
- GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &sysTime, &cpuTime);
27
-
28
- /* Doing this based on MSFT's recommendation in the FILETIME structure documentation at
29
- http://msdn.microsoft.com/en-us/library/ms724284%28VS.85%29.aspx*/
30
-
31
- sysTimeInt.LowPart = sysTime.dwLowDateTime;
32
- sysTimeInt.HighPart = sysTime.dwHighDateTime;
33
- cpuTimeInt.LowPart = cpuTime.dwLowDateTime;
34
- cpuTimeInt.HighPart = cpuTime.dwHighDateTime;
35
-
36
- totalTime = sysTimeInt.QuadPart + cpuTimeInt.QuadPart;
37
-
38
- // Times are in 100-nanosecond time units. So instead of 10-9 use 10-7
39
- return totalTime / 10000000.0;
40
- #else
41
- return ((double)clock()) / CLOCKS_PER_SEC;
42
- #endif
43
- }
44
-
45
- /* call-seq:
46
- measure_process_time -> float
47
-
48
- Returns the process time.*/
49
- static VALUE
50
- prof_measure_process_time(VALUE self)
51
- {
52
- return rb_float_new(measure_process_time());
53
- }
54
-
55
- prof_measurer_t* prof_measurer_process_time()
56
- {
57
- prof_measurer_t* measure = ALLOC(prof_measurer_t);
58
- measure->measure = measure_process_time;
59
- return measure;
60
- }
61
-
62
-
63
- void rp_init_measure_process_time()
64
- {
65
- rb_define_const(mProf, "CLOCKS_PER_SEC", INT2NUM(CLOCKS_PER_SEC));
66
- rb_define_const(mProf, "PROCESS_TIME", INT2NUM(MEASURE_PROCESS_TIME));
67
- rb_define_const(mProf, "PROCESS_TIME_ENABLED", Qtrue);
68
-
69
- cMeasureProcessTime = rb_define_class_under(mMeasure, "ProcessTime", rb_cObject);
70
- rb_define_singleton_method(cMeasureProcessTime, "measure", prof_measure_process_time, 0);
71
- }
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
+ #include <time.h>
6
+
7
+ static VALUE cMeasureProcessTime;
8
+
9
+ static double
10
+ measure_process_time()
11
+ {
12
+ #if defined(__linux__)
13
+ struct timespec clock;
14
+ clock_gettime(CLOCK_PROCESS_CPUTIME_ID , &clock);
15
+ return (clock.tv_sec * 1000000000 + clock.tv_nsec) / 1000000000.0;
16
+ #elif defined(_win32)
17
+ FILETIME createTime;
18
+ FILETIME exitTime;
19
+ FILETIME sysTime;
20
+ FILETIME cpuTime;
21
+
22
+ ULARGE_INTEGER sysTimeInt;
23
+ ULARGE_INTEGER cpuTimeInt;
24
+ ULONGLONG totalTime;
25
+
26
+ GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &sysTime, &cpuTime);
27
+
28
+ /* Doing this based on MSFT's recommendation in the FILETIME structure documentation at
29
+ http://msdn.microsoft.com/en-us/library/ms724284%28VS.85%29.aspx*/
30
+
31
+ sysTimeInt.LowPart = sysTime.dwLowDateTime;
32
+ sysTimeInt.HighPart = sysTime.dwHighDateTime;
33
+ cpuTimeInt.LowPart = cpuTime.dwLowDateTime;
34
+ cpuTimeInt.HighPart = cpuTime.dwHighDateTime;
35
+
36
+ totalTime = sysTimeInt.QuadPart + cpuTimeInt.QuadPart;
37
+
38
+ // Times are in 100-nanosecond time units. So instead of 10-9 use 10-7
39
+ return totalTime / 10000000.0;
40
+ #else
41
+ return ((double)clock()) / CLOCKS_PER_SEC;
42
+ #endif
43
+ }
44
+
45
+ /* call-seq:
46
+ measure_process_time -> float
47
+
48
+ Returns the process time.*/
49
+ static VALUE
50
+ prof_measure_process_time(VALUE self)
51
+ {
52
+ return rb_float_new(measure_process_time());
53
+ }
54
+
55
+ prof_measurer_t* prof_measurer_process_time()
56
+ {
57
+ prof_measurer_t* measure = ALLOC(prof_measurer_t);
58
+ measure->measure = measure_process_time;
59
+ return measure;
60
+ }
61
+
62
+
63
+ void rp_init_measure_process_time()
64
+ {
65
+ rb_define_const(mProf, "CLOCKS_PER_SEC", INT2NUM(CLOCKS_PER_SEC));
66
+ rb_define_const(mProf, "PROCESS_TIME", INT2NUM(MEASURE_PROCESS_TIME));
67
+ rb_define_const(mProf, "PROCESS_TIME_ENABLED", Qtrue);
68
+
69
+ cMeasureProcessTime = rb_define_class_under(mMeasure, "ProcessTime", rb_cObject);
70
+ rb_define_singleton_method(cMeasureProcessTime, "measure", prof_measure_process_time, 0);
71
+ }
@@ -37,6 +37,6 @@ void rp_init_measure_wall_time()
37
37
  rb_define_const(mProf, "WALL_TIME", INT2NUM(MEASURE_WALL_TIME));
38
38
  rb_define_const(mProf, "WALL_TIME_ENABLED", Qtrue);
39
39
 
40
- cMeasureWallTime = rb_define_class_under(mMeasure, "WallTime", rb_cObject);
40
+ cMeasureWallTime = rb_define_class_under(mMeasure, "WallTime", rb_cObject);
41
41
  rb_define_singleton_method(cMeasureWallTime, "measure", prof_measure_wall_time, 0);
42
42
  }
@@ -118,6 +118,129 @@ full_name(VALUE klass, ID mid)
118
118
  return result;
119
119
  }
120
120
 
121
+ void
122
+ method_key(prof_method_key_t* key, VALUE klass, ID mid)
123
+ {
124
+ /* Is this an include for a module? If so get the actual
125
+ module class since we want to combine all profiling
126
+ results for that module. */
127
+ if (klass != 0)
128
+ klass = (BUILTIN_TYPE(klass) == T_ICLASS ? RBASIC(klass)->klass : klass);
129
+
130
+ key->klass = klass;
131
+ key->mid = mid;
132
+ key->key = (klass << 4) + (mid << 2);
133
+ }
134
+
135
+ /* ================ prof_method_t =================*/
136
+ prof_method_t*
137
+ prof_method_create(VALUE klass, ID mid, const char* source_file, int line)
138
+ {
139
+ prof_method_t *result = ALLOC(prof_method_t);
140
+ result->object = Qnil;
141
+ result->call_infos = prof_call_infos_create();
142
+ result->call_infos2 = Qnil;
143
+
144
+ result->key = ALLOC(prof_method_key_t);
145
+ method_key(result->key, klass, mid);
146
+
147
+ //result->call_info_table = call_info_table_create();
148
+
149
+ if (source_file != NULL)
150
+ {
151
+ size_t len = strlen(source_file) + 1;
152
+ char *buffer = ALLOC_N(char, len);
153
+
154
+ MEMCPY(buffer, source_file, char, len);
155
+ result->source_file = buffer;
156
+ }
157
+ else
158
+ {
159
+ result->source_file = source_file;
160
+ }
161
+ result->line = line;
162
+
163
+ return result;
164
+ }
165
+
166
+ /* The underlying c structures are freed when the parent profile is freed.
167
+ However, on shutdown the Ruby GC frees objects in any will-nilly order.
168
+ That means the ruby thread object wrapping the c thread struct may
169
+ be freed before the parent profile. Thus we add in a free function
170
+ for the garbage collector so that if it does get called will nil
171
+ out our Ruby object reference.*/
172
+ static void
173
+ prof_method_ruby_gc_free(prof_method_t* method)
174
+ {
175
+ /* Has this thread object been accessed by Ruby? If
176
+ yes clean it up so to avoid a segmentation fault. */
177
+ if (method->object != Qnil)
178
+ {
179
+ RDATA(method->object)->data = NULL;
180
+ RDATA(method->object)->dfree = NULL;
181
+ RDATA(method->object)->dmark = NULL;
182
+ }
183
+ method->object = Qnil;
184
+ }
185
+
186
+ static void
187
+ prof_method_free(prof_method_t* method)
188
+ {
189
+ prof_method_ruby_gc_free(method);
190
+ prof_call_infos_free(method->call_infos);
191
+
192
+ xfree(method->key);
193
+ method->key = NULL;
194
+
195
+ xfree(method);
196
+ }
197
+
198
+ /*static int
199
+ mark_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
+ prof_call_info_mark(call_info);
203
+ return ST_CONTINUE;
204
+ }
205
+ */
206
+
207
+ void
208
+ prof_method_mark(prof_method_t *method)
209
+ {
210
+ if (method->object)
211
+ rb_gc_mark(method->object);
212
+
213
+ if (method->call_infos2)
214
+ rb_gc_mark(method->call_infos2);
215
+
216
+ if (method->call_infos->object)
217
+ rb_gc_mark(method->call_infos->object);
218
+
219
+ //st_foreach(method->call_info_table, mark_call_infos, NULL);
220
+ }
221
+
222
+ VALUE
223
+ prof_method_wrap(prof_method_t *result)
224
+ {
225
+ if (result->object == Qnil)
226
+ {
227
+ result->object = Data_Wrap_Struct(cMethodInfo, prof_method_mark, prof_method_ruby_gc_free, result);
228
+ }
229
+ return result->object;
230
+ }
231
+
232
+ static prof_method_t *
233
+ get_prof_method(VALUE self)
234
+ {
235
+ /* Can't use Data_Get_Struct because that triggers the event hook
236
+ ending up in endless recursion. */
237
+ prof_method_t* result = DATA_PTR(self);
238
+
239
+ if (!result)
240
+ rb_raise(rb_eRuntimeError, "This RubyProf::MethodInfo instance has already been freed, likely because its profile has been freed.");
241
+
242
+ return result;
243
+ }
121
244
 
122
245
  /* ================ Method Table =================*/
123
246
  int
@@ -143,6 +266,21 @@ method_table_create()
143
266
  return st_init_table(&type_method_hash);
144
267
  }
145
268
 
269
+ static int
270
+ method_table_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
271
+ {
272
+ prof_method_free((prof_method_t*)value);
273
+ return ST_CONTINUE;
274
+ }
275
+
276
+ void
277
+ method_table_free(st_table *table)
278
+ {
279
+ st_foreach(table, method_table_free_iterator, 0);
280
+ st_free_table(table);
281
+ }
282
+
283
+
146
284
  size_t
147
285
  method_table_insert(st_table *table, const prof_method_key_t *key, prof_method_t *val)
148
286
  {
@@ -163,15 +301,6 @@ method_table_lookup(st_table *table, const prof_method_key_t* key)
163
301
  }
164
302
  }
165
303
 
166
- void
167
- method_table_free(st_table *table)
168
- {
169
- /* Don't free the contents since they are wrapped by
170
- Ruby objects! */
171
- st_free_table(table);
172
- }
173
-
174
-
175
304
  /* ================ Method Info =================*/
176
305
  /* Document-class: RubyProf::MethodInfo
177
306
  The RubyProf::MethodInfo class stores profiling data for a method.
@@ -182,69 +311,6 @@ created. RubyProf::MethodInfo objects can be accessed via
182
311
  the RubyProf::Result object.
183
312
  */
184
313
 
185
- prof_method_t*
186
- prof_method_create(prof_method_key_t *key, const char* source_file, int line)
187
- {
188
- prof_method_t *result = ALLOC(prof_method_t);
189
- result->object = Qnil;
190
- result->key = ALLOC(prof_method_key_t);
191
- method_key(result->key, key->klass, key->mid);
192
-
193
- result->call_infos = prof_call_infos_create();
194
-
195
- if (source_file != NULL)
196
- {
197
- size_t len = strlen(source_file) + 1;
198
- char *buffer = ALLOC_N(char, len);
199
-
200
- MEMCPY(buffer, source_file, char, len);
201
- result->source_file = buffer;
202
- }
203
- else
204
- {
205
- result->source_file = source_file;
206
- }
207
- result->line = line;
208
-
209
- return result;
210
- }
211
-
212
- void
213
- prof_method_mark(prof_method_t *method)
214
- {
215
- rb_gc_mark(method->call_infos->object);
216
- rb_gc_mark(method->key->klass);
217
- }
218
-
219
- static void
220
- prof_method_free(prof_method_t *method)
221
- {
222
- if (method->source_file)
223
- {
224
- xfree((char*)method->source_file);
225
- }
226
-
227
- prof_call_infos_free(method->call_infos);
228
- xfree(method->key);
229
- xfree(method);
230
- }
231
-
232
- VALUE
233
- prof_method_wrap(prof_method_t *result)
234
- {
235
- if (result->object == Qnil)
236
- {
237
- result->object = Data_Wrap_Struct(cMethodInfo, prof_method_mark, prof_method_free, result);
238
- }
239
- return result->object;
240
- }
241
-
242
- static prof_method_t *
243
- get_prof_method(VALUE obj)
244
- {
245
- return (prof_method_t *) DATA_PTR(obj);
246
- }
247
-
248
314
  /* call-seq:
249
315
  line_no -> int
250
316
 
@@ -343,7 +409,11 @@ static VALUE
343
409
  prof_method_call_infos(VALUE self)
344
410
  {
345
411
  prof_method_t *method = get_prof_method(self);
346
- return prof_call_infos_wrap(method->call_infos);
412
+ if (method->call_infos2 == Qnil)
413
+ {
414
+ method->call_infos2 = prof_call_infos_wrap(method->call_infos);
415
+ }
416
+ return method->call_infos2;
347
417
  }
348
418
 
349
419
  void rp_init_method_info()
@@ -6,7 +6,7 @@
6
6
 
7
7
  #include <ruby.h>
8
8
 
9
- #ifndef RUBY_VM
9
+ #ifndef RUBY_VM
10
10
  #include <st.h>
11
11
  typedef st_data_t st_index_t;
12
12
  #endif
@@ -18,10 +18,10 @@ typedef struct
18
18
  {
19
19
  VALUE klass; /* The method's class. */
20
20
  ID mid; /* The method id. */
21
- int depth; /* The recursion depth. */
22
21
  st_index_t key; /* Cache calculated key */
23
22
  } prof_method_key_t;
24
23
 
24
+
25
25
  /* Forward declaration, see rp_call_info.h */
26
26
  struct prof_call_infos_t;
27
27
 
@@ -31,18 +31,21 @@ typedef struct
31
31
  prof_method_key_t *key; /* Method key */
32
32
  const char *source_file; /* The method's source file */
33
33
  int line; /* The method's line number. */
34
- struct prof_call_infos_t *call_infos; /* Call info objects for this method */
34
+ struct prof_call_infos_t *call_infos; /* Call info objects for this method */
35
35
  VALUE object; /* Cached ruby object */
36
+ VALUE call_infos2; /* Cached array of RubyProf::CallInfo */
36
37
  } prof_method_t;
37
38
 
38
39
  void rp_init_method_info(void);
39
40
 
41
+ void method_key(prof_method_key_t* key, VALUE klass, ID mid);
42
+
40
43
  st_table * method_table_create();
41
44
  prof_method_t * method_table_lookup(st_table *table, const prof_method_key_t* key);
42
45
  size_t method_table_insert(st_table *table, const prof_method_key_t *key, prof_method_t *val);
43
46
  void method_table_free(st_table *table);
44
47
 
45
- prof_method_t* prof_method_create(prof_method_key_t *key, const char* source_file, int line);
48
+ prof_method_t* prof_method_create(VALUE klass, ID mid, const char* source_file, int line);
46
49
  VALUE prof_method_wrap(prof_method_t *result);
47
50
  void prof_method_mark(prof_method_t *method);
48
51