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.
- checksums.yaml +4 -4
- data/CHANGES +29 -0
- data/README.md +5 -0
- data/Rakefile +3 -3
- data/ext/ruby_prof/extconf.rb +11 -5
- data/ext/ruby_prof/rp_allocation.c +1 -1
- data/ext/ruby_prof/rp_call_tree.c +0 -2
- data/ext/ruby_prof/rp_call_tree.h +1 -1
- data/ext/ruby_prof/rp_measure_allocations.c +10 -13
- data/ext/ruby_prof/rp_measure_memory.c +8 -4
- data/ext/ruby_prof/rp_measure_process_time.c +7 -6
- data/ext/ruby_prof/rp_measurement.c +2 -2
- data/ext/ruby_prof/rp_measurement.h +1 -1
- data/ext/ruby_prof/rp_method.c +2 -2
- data/ext/ruby_prof/rp_method.h +19 -19
- data/ext/ruby_prof/rp_profile.c +24 -17
- data/ext/ruby_prof/rp_stack.c +1 -1
- data/ext/ruby_prof/rp_thread.c +2 -2
- data/ext/ruby_prof/vc/ruby_prof.vcxproj +9 -7
- data/lib/ruby-prof/assets/call_stack_printer.html.erb +2 -1
- data/lib/ruby-prof/printers/abstract_printer.rb +1 -1
- data/lib/ruby-prof/printers/call_tree_printer.rb +3 -7
- data/lib/ruby-prof/printers/graph_html_printer.rb +1 -1
- data/lib/ruby-prof/version.rb +1 -1
- data/lib/ruby-prof.rb +1 -1
- data/ruby-prof.gemspec +2 -3
- data/test/alias_test.rb +97 -101
- data/test/duplicate_names_test.rb +4 -4
- data/test/dynamic_method_test.rb +23 -9
- data/test/gc_test.rb +12 -2
- data/test/marshal_test.rb +37 -5
- data/test/measure_allocations.rb +1 -5
- data/test/measure_allocations_test.rb +27 -69
- data/test/{measure_memory_trace_test.rb → measure_memory_test.rb} +57 -470
- data/test/measure_process_time_test.rb +1564 -735
- data/test/measure_wall_time_test.rb +6 -15
- data/test/printer_call_tree_test.rb +2 -2
- data/test/printer_flat_test.rb +1 -1
- data/test/printers_test.rb +2 -2
- data/test/recursive_test.rb +372 -148
- data/test/start_stop_test.rb +4 -4
- data/test/test_helper.rb +5 -5
- data/test/unique_call_path_test.rb +24 -8
- data/test/yarv_test.rb +8 -4
- metadata +10 -25
- data/README.rdoc +0 -5
- data/test/measure_allocations_trace_test.rb +0 -375
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '097ef6e369b670ee95682e8f0a11924d3aa67dde85539c3211b40c4d85782022'
|
4
|
+
data.tar.gz: 6f91d032ee06ce82f146a4a3db0f7612f7a093517aef891687ac4becda8d20a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
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(/
|
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.
|
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.
|
74
|
+
'README.md',
|
75
75
|
'LICENSE')
|
76
76
|
end
|
77
77
|
|
data/ext/ruby_prof/extconf.rb
CHANGED
@@ -1,11 +1,17 @@
|
|
1
1
|
require "mkmf"
|
2
2
|
|
3
|
-
#
|
4
|
-
|
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
|
-
#
|
7
|
-
|
8
|
-
$
|
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
|
@@ -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(
|
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
|
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
|
-
|
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
|
-
|
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 =
|
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
|
14
|
+
FILETIME kernelTime;
|
15
15
|
FILETIME userTime;
|
16
16
|
|
17
|
-
ULARGE_INTEGER
|
17
|
+
ULARGE_INTEGER kernelTimeInt;
|
18
18
|
ULARGE_INTEGER userTimeInt;
|
19
19
|
|
20
|
-
GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &
|
20
|
+
GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime);
|
21
21
|
|
22
|
-
|
23
|
-
|
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)(
|
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*
|
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*
|
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);
|
data/ext/ruby_prof/rp_method.c
CHANGED
@@ -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
|
+
}
|
data/ext/ruby_prof/rp_method.h
CHANGED
@@ -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;
|
data/ext/ruby_prof/rp_profile.c
CHANGED
@@ -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
|
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 =
|
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
|
{
|
data/ext/ruby_prof/rp_stack.c
CHANGED
data/ext/ruby_prof/rp_thread.c
CHANGED
@@ -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>
|
42
|
+
<PlatformToolset>v143</PlatformToolset>
|
41
43
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
42
44
|
</PropertyGroup>
|
43
45
|
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
44
|
-
<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
|
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-
|
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
|
109
|
+
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
108
110
|
<WarningLevel>Level3</WarningLevel>
|
109
111
|
</ClCompile>
|
110
112
|
<Link>
|
111
|
-
<AdditionalLibraryDirectories>C:\msys64\usr\local\ruby-
|
112
|
-
<AdditionalDependencies>x64-vcruntime140-
|
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
|
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 {
|
@@ -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 = [
|
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
|
-
[
|
111
|
+
["callgrind.out", $$].join(".")
|
116
112
|
else
|
117
|
-
[
|
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
|
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)
|
data/lib/ruby-prof/version.rb
CHANGED
data/lib/ruby-prof.rb
CHANGED