ruby-prof 1.4.2 → 1.4.4

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +29 -0
  3. data/README.md +5 -0
  4. data/Rakefile +3 -3
  5. data/ext/ruby_prof/extconf.rb +11 -5
  6. data/ext/ruby_prof/rp_allocation.c +1 -1
  7. data/ext/ruby_prof/rp_call_tree.c +0 -2
  8. data/ext/ruby_prof/rp_call_tree.h +1 -1
  9. data/ext/ruby_prof/rp_measure_allocations.c +10 -13
  10. data/ext/ruby_prof/rp_measure_memory.c +8 -4
  11. data/ext/ruby_prof/rp_measure_process_time.c +7 -6
  12. data/ext/ruby_prof/rp_measurement.c +2 -2
  13. data/ext/ruby_prof/rp_measurement.h +1 -1
  14. data/ext/ruby_prof/rp_method.c +2 -2
  15. data/ext/ruby_prof/rp_method.h +19 -19
  16. data/ext/ruby_prof/rp_profile.c +24 -17
  17. data/ext/ruby_prof/rp_stack.c +1 -1
  18. data/ext/ruby_prof/rp_thread.c +2 -2
  19. data/ext/ruby_prof/vc/ruby_prof.vcxproj +9 -7
  20. data/lib/ruby-prof/assets/call_stack_printer.html.erb +2 -1
  21. data/lib/ruby-prof/printers/abstract_printer.rb +1 -1
  22. data/lib/ruby-prof/printers/call_tree_printer.rb +3 -7
  23. data/lib/ruby-prof/printers/graph_html_printer.rb +1 -1
  24. data/lib/ruby-prof/version.rb +1 -1
  25. data/lib/ruby-prof.rb +1 -1
  26. data/ruby-prof.gemspec +2 -3
  27. data/test/alias_test.rb +97 -101
  28. data/test/duplicate_names_test.rb +4 -4
  29. data/test/dynamic_method_test.rb +23 -9
  30. data/test/gc_test.rb +12 -2
  31. data/test/marshal_test.rb +37 -5
  32. data/test/measure_allocations.rb +1 -5
  33. data/test/measure_allocations_test.rb +27 -69
  34. data/test/{measure_memory_trace_test.rb → measure_memory_test.rb} +57 -470
  35. data/test/measure_process_time_test.rb +1564 -735
  36. data/test/measure_wall_time_test.rb +6 -15
  37. data/test/printer_call_tree_test.rb +2 -2
  38. data/test/printer_flat_test.rb +1 -1
  39. data/test/printers_test.rb +2 -2
  40. data/test/recursive_test.rb +372 -148
  41. data/test/start_stop_test.rb +4 -4
  42. data/test/test_helper.rb +5 -5
  43. data/test/unique_call_path_test.rb +24 -8
  44. data/test/yarv_test.rb +8 -4
  45. metadata +10 -25
  46. data/README.rdoc +0 -5
  47. data/test/measure_allocations_trace_test.rb +0 -375
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6e62266e388c4742f279cccfd909bc167b83e2b2bc3438b52254855281ec3b56
4
- data.tar.gz: 4becfdabd8c0453c433f36fcc767a32e5ac50f295c45deaa9b9ed7e09763b8e2
3
+ metadata.gz: '097ef6e369b670ee95682e8f0a11924d3aa67dde85539c3211b40c4d85782022'
4
+ data.tar.gz: 6f91d032ee06ce82f146a4a3db0f7612f7a093517aef891687ac4becda8d20a8
5
5
  SHA512:
6
- metadata.gz: ecdc60504e71f9adc7bcc5df7deb3864e0fad1544cfc57ad225053a205bdb75cad3953a415834761c964e069907e232786f977f667a7492bd7521839a4663bb4
7
- data.tar.gz: d524f3cfa338fb190b362e42d29aaa1b60d1011e84945e73dd6bfc7f5979e0d3fe8702f6135f2c5a3f67ae4dddcd1915e7ddd1db7bab70ee00d22447cb02a398
6
+ metadata.gz: 757f7b033c8ecdb4a12aa94960e87094356722ff69d47afccc74229b520bdbdecd7360f8ae0c4190f24421aa25b0f5f99bb9f3f4efb667706894f68d0b3874cb
7
+ data.tar.gz: be6eca60b902c7629ff5a51c6a5d43e5d1400d4c4dfc04d4e2ddbd48048d5a9d5bde3a5ad185bbc2a843accaa615f09f9f930e78472d09878a79e03610b35f47
data/CHANGES CHANGED
@@ -1,3 +1,32 @@
1
+ 1.4.4 (2022-12-11)
2
+ =====================
3
+ * Update tests for Ruby 3.1 (Charlie Savage)
4
+ * When tracing allocations always use the RUBY_INTERNAL_EVENT_NEWOBJ trace event. Previously GC stats could also be used, but that includes the creation of internal T_IMEMO objects makes reviewing results confusing (Charlie Savage)
5
+ * Remove :profile option that lets a user set the prefix on callgrind output files since KCacheGrind will not automatically show these files in its open dialog. Fixes #313. (Charlie Savage)
6
+ * Don't expose threads to Ruby that don't have a call tree. This can happen when a user is profiling memory usage and then sends a signint to the profiled process. New objects will be created in a new thread, but no method enter/exit trace events are generated by Ruby. Thus the thread has no call tree. Fixes #312 (Charlie Savage)
7
+ * Update github Actions - change 3.0 to '3.0', add Windows mswin (MSP-Greg)
8
+ * Add Ruby 3.1 to test matrix (Charlie Savage)
9
+ * Use normal weight text instead of bold in call strack printer output. Fixes #297 (Charlie Savage)
10
+ * Update VC project to Ruby 3.1 and Visual Studio 2022 (Charlie Savage)
11
+ * Fix marshaling of profile measure. Fixes #315 (Charlie Savage)
12
+ * CI: Omit duplicate 'bundle install'. PR #309 (Olle Jonsson)
13
+ * Fix typo. s/perecent/percent/ (Paarth Madan)
14
+ * Remove support for Ruby 2.5 and 2.6 which are now end of life (Charlie Savage)
15
+
16
+ 1.4.3 (2021-02-16)
17
+ =====================
18
+ * Remove trailing spaces (sergioro)
19
+ * Load "ruby-prof.so" with require_relative (sergioro)
20
+ * Use same file permissions for all test files (sergioro)
21
+ * Create tmp directory for test output (sergioro)
22
+ * Update git-ignore to add mkmf log (sergioro)
23
+ * Fix minitest warning about using MT_CPU instead of N (sergioro)
24
+ * Fix minitest warning "Use assert_nil if expecting nil (sergioro)
25
+ * Add xcode project (Charlie Savage)
26
+ * Update test for Ruby 3.0 (Charlie Savage)
27
+ * Remove Ruby 2.4 support since it is no longer maintained (Charlie Savage)
28
+ * Replace travis status badge with github status badge (Charlie Savage)
29
+
1
30
  1.4.2 (2020-11-3)
2
31
  =====================
3
32
  * Do NOT use Ruby 2.7.0 and 2.7.1 with ruby-prof. A bug in those versions of ruby causes ruby-prof to
data/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # ruby-prof
2
+
3
+ ![ruby-prof](https://github.com/ruby-prof/ruby-prof/workflows/ruby-prof/badge.svg)
4
+
5
+ For an overview of ruby-prof please see https://ruby-prof.github.io
data/Rakefile CHANGED
@@ -42,7 +42,7 @@ end
42
42
  Rake::Task[:package].enhance [:rdoc]
43
43
 
44
44
  # Setup Windows Gem
45
- if RUBY_PLATFORM.match(/win32|mingw32/)
45
+ if RUBY_PLATFORM.match(/mswin|mingw/)
46
46
  # Windows specification
47
47
  win_spec = default_spec.clone
48
48
  win_spec.platform = Gem::Platform::CURRENT
@@ -65,13 +65,13 @@ RDoc::Task.new("rdoc") do |rdoc|
65
65
  # Show source inline with line numbers
66
66
  rdoc.options << "--line-numbers"
67
67
  # Make the readme file the start page for the generated html
68
- rdoc.options << '--main' << 'README.rdoc'
68
+ rdoc.options << '--main' << 'README.md'
69
69
  rdoc.rdoc_files.include('bin/*',
70
70
  'doc/*.rdoc',
71
71
  'lib/**/*.rb',
72
72
  'ext/ruby_prof/*.c',
73
73
  'ext/ruby_prof/*.h',
74
- 'README.rdoc',
74
+ 'README.md',
75
75
  'LICENSE')
76
76
  end
77
77
 
@@ -1,11 +1,17 @@
1
1
  require "mkmf"
2
2
 
3
- # This function was added in Ruby 2.5, so once Ruby 2.4 is no longer supported this can be removed
4
- have_func('rb_tracearg_callee_id', ["ruby.h"])
3
+ # Let's go with a modern version of C! want to intermix declarations and code (ie, don't define
4
+ # all variables at the top of the method). If using Visual Studio, you'll need 2019 version
5
+ # 16.8 or higher
6
+ if RUBY_PLATFORM =~ /mswin/
7
+ $CFLAGS += ' /std:c11'
8
+ else
9
+ $CFLAGS += ' -std=c11'
10
+ end
5
11
 
6
- # We want to intermix declarations and code (ie, don't define all variables at the top of the method)
7
- unless RUBY_PLATFORM =~ /mswin/
8
- $CFLAGS += ' -std=c99'
12
+ # For gcc add -s to strip symbols, reducing library size from 17MB to 78KB (at least on Windows with mingw64)
13
+ if RUBY_PLATFORM !~ /mswin/
14
+ $LDFLAGS += ' -s'
9
15
  end
10
16
 
11
17
  # And since we are using C99 we want to disable Ruby sending these warnings to gcc
@@ -141,7 +141,7 @@ static const rb_data_type_t allocation_type =
141
141
  },
142
142
  .data = NULL,
143
143
  .flags = RUBY_TYPED_FREE_IMMEDIATELY
144
- };
144
+ };
145
145
 
146
146
  VALUE prof_allocation_wrap(prof_allocation_t* allocation)
147
147
  {
@@ -3,8 +3,6 @@
3
3
 
4
4
  #include "rp_call_tree.h"
5
5
 
6
- #define INITIAL_CALL_TREES_SIZE 2
7
-
8
6
  VALUE cRpCallTree;
9
7
 
10
8
  /* ======= prof_call_tree_t ========*/
@@ -38,6 +38,6 @@ uint32_t prof_call_figure_depth(prof_call_tree_t* call_tree_data);
38
38
  prof_call_tree_t* prof_get_call_tree(VALUE self);
39
39
  VALUE prof_call_tree_wrap(prof_call_tree_t* call_tree);
40
40
  void prof_call_tree_free(prof_call_tree_t* call_tree);
41
- void rp_init_call_tree(void);
41
+ void rp_init_call_tree();
42
42
 
43
43
  #endif //__RP_CALL_TREE_H__
@@ -8,20 +8,20 @@
8
8
  static VALUE cMeasureAllocations;
9
9
  VALUE total_allocated_objects_key;
10
10
 
11
- static double measure_allocations_via_gc_stats(rb_trace_arg_t* trace_arg)
12
- {
13
- return (double)rb_gc_stat(total_allocated_objects_key);
14
- }
15
-
16
- static double measure_allocations_via_tracing(rb_trace_arg_t* trace_arg)
11
+ static double measure_allocations(rb_trace_arg_t* trace_arg)
17
12
  {
18
13
  static double result = 0;
19
14
 
20
15
  if (trace_arg)
21
16
  {
17
+ // Only process creation of new objects
22
18
  rb_event_flag_t event = rb_tracearg_event_flag(trace_arg);
23
- if (event == RUBY_INTERNAL_EVENT_NEWOBJ)
24
- result++;
19
+ if (event == RUBY_INTERNAL_EVENT_NEWOBJ) {
20
+ // Don't count allocations of internal IMemo objects
21
+ VALUE object = rb_tracearg_object(trace_arg);
22
+ if (BUILTIN_TYPE(object) != T_IMEMO)
23
+ result++;
24
+ }
25
25
  }
26
26
  return result;
27
27
  }
@@ -30,14 +30,11 @@ prof_measurer_t* prof_measurer_allocations(bool track_allocations)
30
30
  {
31
31
  prof_measurer_t* measure = ALLOC(prof_measurer_t);
32
32
  measure->mode = MEASURE_ALLOCATIONS;
33
+ measure->measure = measure_allocations;
33
34
  measure->multiplier = 1;
35
+ // Need to track allocations to get RUBY_INTERNAL_EVENT_NEWOBJ event
34
36
  measure->track_allocations = track_allocations;
35
37
 
36
- if (track_allocations)
37
- measure->measure = measure_allocations_via_tracing;
38
- else
39
- measure->measure = measure_allocations_via_gc_stats;
40
-
41
38
  return measure;
42
39
  }
43
40
 
@@ -7,20 +7,23 @@
7
7
 
8
8
  static VALUE cMeasureMemory;
9
9
 
10
- static double
11
- measure_memory_via_tracing(rb_trace_arg_t* trace_arg)
10
+ static double measure_memory(rb_trace_arg_t* trace_arg)
12
11
  {
13
12
  static double result = 0;
14
13
 
15
14
  if (trace_arg)
16
15
  {
16
+ // Only process creation of new objects
17
17
  rb_event_flag_t event = rb_tracearg_event_flag(trace_arg);
18
18
  if (event == RUBY_INTERNAL_EVENT_NEWOBJ)
19
19
  {
20
+ // Don't count allocations of internal IMemo objects
20
21
  VALUE object = rb_tracearg_object(trace_arg);
21
- result += rb_obj_memsize_of(object);
22
+ if (BUILTIN_TYPE(object) != T_IMEMO)
23
+ result += rb_obj_memsize_of(object);
22
24
  }
23
25
  }
26
+
24
27
  return result;
25
28
  }
26
29
 
@@ -28,8 +31,9 @@ prof_measurer_t* prof_measurer_memory(bool track_allocations)
28
31
  {
29
32
  prof_measurer_t* measure = ALLOC(prof_measurer_t);
30
33
  measure->mode = MEASURE_MEMORY;
31
- measure->measure = measure_memory_via_tracing;
34
+ measure->measure = measure_memory;
32
35
  measure->multiplier = 1;
36
+ // Need to track allocations to get RUBY_INTERNAL_EVENT_NEWOBJ event
33
37
  measure->track_allocations = true;
34
38
  return measure;
35
39
  }
@@ -11,21 +11,22 @@ static double measure_process_time(rb_trace_arg_t* trace_arg)
11
11
  #if defined(_WIN32)
12
12
  FILETIME createTime;
13
13
  FILETIME exitTime;
14
- FILETIME sysTime;
14
+ FILETIME kernelTime;
15
15
  FILETIME userTime;
16
16
 
17
- ULARGE_INTEGER sysTimeInt;
17
+ ULARGE_INTEGER kernelTimeInt;
18
18
  ULARGE_INTEGER userTimeInt;
19
19
 
20
- GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &sysTime, &userTime);
20
+ GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime);
21
21
 
22
- sysTimeInt.LowPart = sysTime.dwLowDateTime;
23
- sysTimeInt.HighPart = sysTime.dwHighDateTime;
22
+ kernelTimeInt.LowPart = kernelTime.dwLowDateTime;
23
+ kernelTimeInt.HighPart = kernelTime.dwHighDateTime;
24
24
  userTimeInt.LowPart = userTime.dwLowDateTime;
25
25
  userTimeInt.HighPart = userTime.dwHighDateTime;
26
26
 
27
- return (double)(sysTimeInt.QuadPart + userTimeInt.QuadPart);
27
+ return (double)(kernelTimeInt.QuadPart + userTimeInt.QuadPart);
28
28
  #elif !defined(CLOCK_PROCESS_CPUTIME_ID)
29
+ #include <sys/resource.h>
29
30
  struct rusage usage;
30
31
  getrusage(RUSAGE_SELF, &usage);
31
32
  return usage.ru_stime.tv_sec + usage.ru_utime.tv_sec + ((usage.ru_stime.tv_usec + usage.ru_utime.tv_usec) / 1000000.0);
@@ -16,7 +16,7 @@ void rp_init_measure_memory(void);
16
16
  void rp_init_measure_process_time(void);
17
17
  void rp_init_measure_wall_time(void);
18
18
 
19
- prof_measurer_t* prof_get_measurer(prof_measure_mode_t measure, bool track_allocations)
19
+ prof_measurer_t* prof_measurer_create(prof_measure_mode_t measure, bool track_allocations)
20
20
  {
21
21
  switch (measure)
22
22
  {
@@ -100,7 +100,7 @@ static const rb_data_type_t measurement_type =
100
100
  },
101
101
  .data = NULL,
102
102
  .flags = RUBY_TYPED_FREE_IMMEDIATELY
103
- };
103
+ };
104
104
 
105
105
  VALUE prof_measurement_wrap(prof_measurement_t* measurement)
106
106
  {
@@ -36,7 +36,7 @@ typedef struct prof_measurement_t
36
36
  VALUE object;
37
37
  } prof_measurement_t;
38
38
 
39
- prof_measurer_t* prof_get_measurer(prof_measure_mode_t measure, bool track_allocations);
39
+ prof_measurer_t* prof_measurer_create(prof_measure_mode_t measure, bool track_allocations);
40
40
  double prof_measure(prof_measurer_t* measurer, rb_trace_arg_t* trace_arg);
41
41
 
42
42
  prof_measurement_t* prof_measurement_create(void);
@@ -253,7 +253,7 @@ static const rb_data_type_t method_info_type =
253
253
  },
254
254
  .data = NULL,
255
255
  .flags = RUBY_TYPED_FREE_IMMEDIATELY
256
- };
256
+ };
257
257
 
258
258
  VALUE prof_method_wrap(prof_method_t* method)
259
259
  {
@@ -488,4 +488,4 @@ void rp_init_method_info()
488
488
 
489
489
  rb_define_method(cRpMethodInfo, "_dump_data", prof_method_dump, 0);
490
490
  rb_define_method(cRpMethodInfo, "_load_data", prof_method_load, 1);
491
- }
491
+ }
@@ -9,35 +9,35 @@
9
9
 
10
10
  extern VALUE cRpMethodInfo;
11
11
 
12
- // Source relation bit offsets.
12
+ // Source relation bit offsets.
13
13
  enum {
14
- kModuleIncludee = 0x1, // Included in module
15
- kClassSingleton = 0x2, // Singleton of a class
16
- kModuleSingleton = 0x4, // Singleton of a module
17
- kObjectSingleton = 0x8, // Singleton of an object
18
- kOtherSingleton = 0x10 // Singleton of unkown object
14
+ kModuleIncludee = 0x1, // Included in module
15
+ kClassSingleton = 0x2, // Singleton of a class
16
+ kModuleSingleton = 0x4, // Singleton of a module
17
+ kObjectSingleton = 0x8, // Singleton of an object
18
+ kOtherSingleton = 0x10 // Singleton of unkown object
19
19
  };
20
20
 
21
- // Profiling information for each method.
22
- // Excluded methods have no call_trees, source_klass, or source_file.
21
+ // Profiling information for each method.
22
+ // Excluded methods have no call_trees, source_klass, or source_file.
23
23
  typedef struct prof_method_t
24
24
  {
25
25
  VALUE profile; // Profile this method is associated with - needed for mark phase
26
- struct prof_call_trees_t* call_trees; // Call infos that call this method
27
- st_table* allocations_table; // Tracks object allocations
26
+ struct prof_call_trees_t* call_trees; // Call infos that call this method
27
+ st_table* allocations_table; // Tracks object allocations
28
28
 
29
- st_data_t key; // Table key
30
- unsigned int klass_flags; // Information about the type of class
31
- VALUE klass; // Resolved klass
32
- VALUE klass_name; // Resolved klass name for this method
33
- VALUE method_name; // Resolved method name for this method
29
+ st_data_t key; // Table key
30
+ unsigned int klass_flags; // Information about the type of class
31
+ VALUE klass; // Resolved klass
32
+ VALUE klass_name; // Resolved klass name for this method
33
+ VALUE method_name; // Resolved method name for this method
34
34
 
35
- VALUE object; // Cached ruby object
35
+ VALUE object; // Cached ruby object
36
36
 
37
37
  bool recursive;
38
- int visits; // Current visits on the stack
39
- VALUE source_file; // Source file
40
- int source_line; // Line number
38
+ int visits; // Current visits on the stack
39
+ VALUE source_file; // Source file
40
+ int source_line; // Line number
41
41
 
42
42
  prof_measurement_t* measurement; // Stores measurement data for this method
43
43
  } prof_method_t;
@@ -138,11 +138,7 @@ prof_method_t* check_method(VALUE profile, rb_trace_arg_t* trace_arg, rb_event_f
138
138
  if (klass == cProfile)
139
139
  return NULL;
140
140
 
141
- #ifdef HAVE_RB_TRACEARG_CALLEE_ID
142
141
  VALUE msym = rb_tracearg_callee_id(trace_arg);
143
- #else
144
- VALUE msym = rb_tracearg_method_id(trace_arg);
145
- #endif
146
142
 
147
143
  st_data_t key = method_key(klass, msym);
148
144
 
@@ -158,7 +154,7 @@ prof_method_t* check_method(VALUE profile, rb_trace_arg_t* trace_arg, rb_event_f
158
154
  int source_line = (event != RUBY_EVENT_C_CALL ? FIX2INT(rb_tracearg_lineno(trace_arg)) : 0);
159
155
  result = create_method(profile, key, klass, msym, source_file, source_line);
160
156
  }
161
-
157
+
162
158
  return result;
163
159
  }
164
160
 
@@ -174,11 +170,7 @@ static void prof_trace(prof_profile_t* profile, rb_trace_arg_t* trace_arg, doubl
174
170
  VALUE source_file = rb_tracearg_path(trace_arg);
175
171
  int source_line = FIX2INT(rb_tracearg_lineno(trace_arg));
176
172
 
177
- #ifdef HAVE_RB_TRACEARG_CALLEE_ID
178
173
  VALUE msym = rb_tracearg_callee_id(trace_arg);
179
- #else
180
- VALUE msym = rb_tracearg_method_id(trace_arg);
181
- #endif
182
174
 
183
175
  unsigned int klass_flags;
184
176
  VALUE klass = rb_tracearg_defined_class(trace_arg);
@@ -219,7 +211,7 @@ static void prof_event_hook(VALUE trace_point, void* data)
219
211
  }
220
212
 
221
213
  /* Special case - skip any methods from the mProf
222
- module since they clutter the results but aren't important to them results. */
214
+ module since they clutter the results but aren't important. */
223
215
  if (self == mProf)
224
216
  return;
225
217
 
@@ -234,6 +226,8 @@ static void prof_event_hook(VALUE trace_point, void* data)
234
226
  {
235
227
  prof_frame_t* frame = prof_frame_current(thread_data->stack);
236
228
 
229
+ /* If there is no frame then this is either the first method being profiled or we have climbed the
230
+ call stack higher than where we started. */
237
231
  if (!frame)
238
232
  {
239
233
  prof_method_t* method = check_method(profile, trace_arg, event, thread_data);
@@ -244,22 +238,24 @@ static void prof_event_hook(VALUE trace_point, void* data)
244
238
  prof_call_tree_t* call_tree = prof_call_tree_create(method, NULL, method->source_file, method->source_line);
245
239
  prof_add_call_tree(method->call_trees, call_tree);
246
240
 
241
+ // We have climbed higher in the stack then where we started
247
242
  if (thread_data->call_tree)
248
243
  {
249
244
  prof_call_tree_add_parent(thread_data->call_tree, call_tree);
250
245
  frame = prof_frame_unshift(thread_data->stack, call_tree, thread_data->call_tree, measurement);
251
246
  }
247
+ // This is the first method to be profiled
252
248
  else
253
249
  {
254
250
  frame = prof_frame_push(thread_data->stack, call_tree, measurement, RTEST(profile_t->paused));
255
251
  }
256
-
252
+
257
253
  thread_data->call_tree = call_tree;
258
254
  }
259
-
255
+
260
256
  frame->source_file = rb_tracearg_path(trace_arg);
261
257
  frame->source_line = FIX2INT(rb_tracearg_lineno(trace_arg));
262
-
258
+
263
259
  break;
264
260
  }
265
261
  case RUBY_EVENT_CALL:
@@ -282,7 +278,7 @@ static void prof_event_hook(VALUE trace_point, void* data)
282
278
  }
283
279
  else if (!frame && thread_data->call_tree)
284
280
  {
285
- // There is no current parent - likely we have returned out of the highest level method we have profiled so far.
281
+ // There is no current parent - likely we have returned out of the highest level method we have profiled so far.
286
282
  // This can happen with enumerators (see fiber_test.rb). So create a new dummy parent.
287
283
  prof_method_t* parent_method = check_parent_method(profile, thread_data);
288
284
  parent_call_tree = prof_call_tree_create(parent_method, NULL, Qnil, 0);
@@ -382,7 +378,7 @@ prof_profile_t* prof_get_profile(VALUE self)
382
378
  static int collect_threads(st_data_t key, st_data_t value, st_data_t result)
383
379
  {
384
380
  thread_data_t* thread_data = (thread_data_t*)value;
385
- if (thread_data->trace)
381
+ if (thread_data->trace && thread_data->call_tree)
386
382
  {
387
383
  VALUE threads_array = (VALUE)result;
388
384
  rb_ary_push(threads_array, prof_thread_wrap(thread_data));
@@ -421,7 +417,7 @@ static void prof_profile_mark(void* data)
421
417
  rb_st_foreach(profile->exclude_methods_tbl, prof_profile_mark_methods, 0);
422
418
  }
423
419
 
424
- /* Freeing the profile creates a cascade of freeing. It frees its threads table, which frees
420
+ /* Freeing the profile creates a cascade of freeing. It frees its threads table, which frees
425
421
  each thread and its associated call treee and methods. */
426
422
  static void prof_profile_ruby_gc_free(void* data)
427
423
  {
@@ -573,7 +569,7 @@ static VALUE prof_initialize(int argc, VALUE* argv, VALUE self)
573
569
  {
574
570
  Check_Type(mode, T_FIXNUM);
575
571
  }
576
- profile->measurer = prof_get_measurer(NUM2INT(mode), track_allocations == Qtrue);
572
+ profile->measurer = prof_measurer_create(NUM2INT(mode), track_allocations == Qtrue);
577
573
  profile->allow_exceptions = (allow_exceptions == Qtrue);
578
574
 
579
575
  if (exclude_threads != Qnil)
@@ -862,8 +858,14 @@ static VALUE prof_exclude_method(VALUE self, VALUE klass, VALUE msym)
862
858
  /* :nodoc: */
863
859
  VALUE prof_profile_dump(VALUE self)
864
860
  {
861
+ prof_profile_t* profile = prof_get_profile(self);
862
+
865
863
  VALUE result = rb_hash_new();
866
864
  rb_hash_aset(result, ID2SYM(rb_intern("threads")), prof_threads(self));
865
+ rb_hash_aset(result, ID2SYM(rb_intern("measurer_mode")), INT2NUM(profile->measurer->mode));
866
+ rb_hash_aset(result, ID2SYM(rb_intern("measurer_track_allocations")),
867
+ profile->measurer->track_allocations ? Qtrue : Qfalse);
868
+
867
869
  return result;
868
870
  }
869
871
 
@@ -872,6 +874,11 @@ VALUE prof_profile_load(VALUE self, VALUE data)
872
874
  {
873
875
  prof_profile_t* profile = prof_get_profile(self);
874
876
 
877
+ VALUE measurer_mode = rb_hash_aref(data, ID2SYM(rb_intern("measurer_mode")));
878
+ VALUE measurer_track_allocations = rb_hash_aref(data, ID2SYM(rb_intern("measurer_track_allocations")));
879
+ profile->measurer = prof_measurer_create((prof_measure_mode_t)(NUM2INT(measurer_mode)),
880
+ measurer_track_allocations == Qtrue ? true : false);
881
+
875
882
  VALUE threads = rb_hash_aref(data, ID2SYM(rb_intern("threads")));
876
883
  for (int i = 0; i < rb_array_len(threads); i++)
877
884
  {
@@ -180,7 +180,7 @@ prof_frame_t* prof_frame_pop(prof_stack_t* stack, double measurement)
180
180
  call_tree->measurement->total_time += total_time;
181
181
 
182
182
  call_tree->visits--;
183
-
183
+
184
184
  prof_frame_t* parent_frame = prof_stack_last(stack);
185
185
  if (parent_frame)
186
186
  {
@@ -21,7 +21,7 @@ You cannot create an instance of RubyProf::Thread, instead you access it from a
21
21
 
22
22
  VALUE cRpThread;
23
23
 
24
- // ====== thread_data_t ======
24
+ // ====== thread_data_t ======
25
25
  thread_data_t* thread_data_create(void)
26
26
  {
27
27
  thread_data_t* result = ALLOC(thread_data_t);
@@ -146,7 +146,7 @@ thread_data_t* prof_get_thread(VALUE self)
146
146
  }
147
147
 
148
148
  // ====== Thread Table ======
149
- // The thread table is hash keyed on ruby fiber_id that stores instances of thread_data_t.
149
+ // The thread table is hash keyed on ruby fiber_id that stores instances of thread_data_t.
150
150
 
151
151
  st_table* threads_table_create()
152
152
  {
@@ -29,19 +29,21 @@
29
29
  <ConfigurationType>DynamicLibrary</ConfigurationType>
30
30
  <UseDebugLibraries>true</UseDebugLibraries>
31
31
  <CharacterSet>Unicode</CharacterSet>
32
+ <PlatformToolset>v143</PlatformToolset>
32
33
  </PropertyGroup>
33
34
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
34
35
  <ConfigurationType>DynamicLibrary</ConfigurationType>
35
36
  <UseDebugLibraries>false</UseDebugLibraries>
36
37
  <WholeProgramOptimization>true</WholeProgramOptimization>
37
38
  <CharacterSet>Unicode</CharacterSet>
39
+ <PlatformToolset>v143</PlatformToolset>
38
40
  </PropertyGroup>
39
41
  <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
40
- <PlatformToolset>v142</PlatformToolset>
42
+ <PlatformToolset>v143</PlatformToolset>
41
43
  <ConfigurationType>DynamicLibrary</ConfigurationType>
42
44
  </PropertyGroup>
43
45
  <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
44
- <PlatformToolset>v142</PlatformToolset>
46
+ <PlatformToolset>v143</PlatformToolset>
45
47
  </PropertyGroup>
46
48
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
47
49
  <ImportGroup Label="ExtensionSettings">
@@ -64,7 +66,7 @@
64
66
  </PropertyGroup>
65
67
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
66
68
  <TargetExt>.so</TargetExt>
67
- <OutDir>..\..\..\lib\</OutDir>
69
+ <OutDir>$(SolutionDir)\..</OutDir>
68
70
  </PropertyGroup>
69
71
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
70
72
  <ClCompile>
@@ -102,14 +104,14 @@
102
104
  </ItemDefinitionGroup>
103
105
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
104
106
  <ClCompile>
105
- <AdditionalIncludeDirectories>C:\msys64\usr\local\ruby-2.7.2vc\include\ruby-2.7.0\x64-mswin64_140;C:\msys64\usr\local\ruby-2.7.2vc\include\ruby-2.7.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
107
+ <AdditionalIncludeDirectories>C:\msys64\usr\local\ruby-3.1.2-vc\include\ruby-3.1.0\x64-mswin64_140;C:\msys64\usr\local\ruby-3.1.2-vc\include\ruby-3.1.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
106
108
  <Optimization>Disabled</Optimization>
107
- <PreprocessorDefinitions>HAVE_RB_TRACEARG_CALLEE_ID;%(PreprocessorDefinitions)</PreprocessorDefinitions>
109
+ <PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
108
110
  <WarningLevel>Level3</WarningLevel>
109
111
  </ClCompile>
110
112
  <Link>
111
- <AdditionalLibraryDirectories>C:\msys64\usr\local\ruby-2.7.2vc\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
112
- <AdditionalDependencies>x64-vcruntime140-ruby270.lib;%(AdditionalDependencies)</AdditionalDependencies>
113
+ <AdditionalLibraryDirectories>C:\msys64\usr\local\ruby-3.1.2-vc\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
114
+ <AdditionalDependencies>x64-vcruntime140-ruby310.lib;%(AdditionalDependencies)</AdditionalDependencies>
113
115
  <ModuleDefinitionFile>ruby_prof.def</ModuleDefinitionFile>
114
116
  <SubSystem>Console</SubSystem>
115
117
  </Link>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
5
5
  <title>ruby-prof call tree</title>
6
- <style type="text/css">
6
+ <style>
7
7
  body {
8
8
  font-size: 70%;
9
9
  padding: 0;
@@ -19,6 +19,7 @@
19
19
  margin-bottom: 0px;
20
20
  padding-left: 0px;
21
21
  list-style-type: none;
22
+ font-weight: normal;
22
23
  }
23
24
 
24
25
  li {
@@ -113,7 +113,7 @@ module RubyProf
113
113
 
114
114
  def print_footer(thread)
115
115
  @output << <<~EOT
116
-
116
+
117
117
  * recursively called methods
118
118
 
119
119
  Columns are:
@@ -100,21 +100,17 @@ module RubyProf
100
100
  true
101
101
  end
102
102
 
103
- def base_name
104
- @options[:profile] || "profile"
105
- end
106
-
107
103
  def remove_subsidiary_files_from_previous_profile_runs
108
- pattern = [base_name, "callgrind.out", $$, "*"].join(".")
104
+ pattern = ["callgrind.out", $$, "*"].join(".")
109
105
  files = Dir.glob(File.join(path, pattern))
110
106
  FileUtils.rm_f(files)
111
107
  end
112
108
 
113
109
  def file_name_for_thread(thread)
114
110
  if thread.fiber_id == Fiber.current.object_id
115
- [base_name, "callgrind.out", $$].join(".")
111
+ ["callgrind.out", $$].join(".")
116
112
  else
117
- [base_name, "callgrind.out", $$, thread.fiber_id].join(".")
113
+ ["callgrind.out", $$, thread.fiber_id].join(".")
118
114
  end
119
115
  end
120
116
 
@@ -29,7 +29,7 @@ module RubyProf
29
29
  end
30
30
 
31
31
  # Creates a link to a method. Note that we do not create
32
- # links to methods which are under the min_perecent
32
+ # links to methods which are under the min_percent
33
33
  # specified by the user, since they will not be
34
34
  # printed out.
35
35
  def create_link(thread, overall_time, method)
@@ -1,3 +1,3 @@
1
1
  module RubyProf
2
- VERSION = "1.4.2"
2
+ VERSION = "1.4.4"
3
3
  end
data/lib/ruby-prof.rb CHANGED
@@ -6,7 +6,7 @@ begin
6
6
  version = Gem::Version.new(RUBY_VERSION)
7
7
  require "#{version.segments[0..1].join('.')}/ruby_prof.so"
8
8
  rescue LoadError
9
- require "ruby_prof.so"
9
+ require_relative "../ext/ruby_prof/ruby_prof.so"
10
10
  end
11
11
 
12
12
  require 'ruby-prof/version'