ruby-prof 1.4.3 → 1.6.3
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 +59 -9
- data/{README.rdoc → README.md} +2 -2
- data/Rakefile +4 -4
- data/bin/ruby-prof +100 -87
- data/ext/ruby_prof/rp_allocation.c +140 -85
- data/ext/ruby_prof/rp_allocation.h +8 -6
- data/ext/ruby_prof/rp_call_tree.c +502 -369
- data/ext/ruby_prof/rp_call_tree.h +47 -43
- data/ext/ruby_prof/rp_call_trees.c +16 -8
- 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 +147 -20
- data/ext/ruby_prof/rp_measurement.h +4 -1
- data/ext/ruby_prof/rp_method.c +142 -83
- data/ext/ruby_prof/rp_method.h +63 -62
- data/ext/ruby_prof/rp_profile.c +933 -900
- data/ext/ruby_prof/rp_profile.h +1 -0
- data/ext/ruby_prof/rp_thread.c +433 -362
- data/ext/ruby_prof/rp_thread.h +39 -39
- data/ext/ruby_prof/ruby_prof.c +0 -2
- data/ext/ruby_prof/ruby_prof.h +8 -0
- data/ext/ruby_prof/vc/ruby_prof.vcxproj +11 -8
- data/lib/ruby-prof/assets/call_stack_printer.html.erb +2 -1
- data/lib/ruby-prof/compatibility.rb +14 -0
- data/lib/ruby-prof/method_info.rb +8 -1
- data/lib/ruby-prof/printers/abstract_printer.rb +2 -1
- data/lib/ruby-prof/printers/call_tree_printer.rb +4 -10
- data/lib/ruby-prof/printers/graph_html_printer.rb +1 -1
- data/lib/ruby-prof/printers/multi_printer.rb +17 -17
- data/lib/ruby-prof/profile.rb +70 -37
- data/lib/ruby-prof/rack.rb +31 -21
- data/lib/ruby-prof/version.rb +1 -1
- data/lib/ruby-prof.rb +1 -1
- data/ruby-prof.gemspec +2 -3
- data/test/abstract_printer_test.rb +1 -0
- data/test/alias_test.rb +97 -106
- data/test/call_tree_builder.rb +126 -0
- data/test/call_tree_test.rb +94 -0
- data/test/call_tree_visitor_test.rb +1 -6
- data/test/call_trees_test.rb +6 -6
- data/test/{basic_test.rb → compatibility_test.rb} +8 -2
- data/test/duplicate_names_test.rb +5 -5
- data/test/dynamic_method_test.rb +24 -15
- data/test/enumerable_test.rb +1 -1
- data/test/exceptions_test.rb +2 -2
- data/test/exclude_methods_test.rb +3 -8
- data/test/exclude_threads_test.rb +4 -9
- data/test/fiber_test.rb +74 -8
- data/test/gc_test.rb +11 -9
- data/test/inverse_call_tree_test.rb +33 -34
- data/test/line_number_test.rb +37 -61
- data/test/marshal_test.rb +16 -3
- data/test/measure_allocations.rb +1 -5
- data/test/measure_allocations_test.rb +642 -357
- data/test/{measure_memory_trace_test.rb → measure_memory_test.rb} +180 -616
- data/test/measure_process_time_test.rb +1566 -741
- data/test/measure_wall_time_test.rb +179 -193
- data/test/measurement_test.rb +82 -0
- data/test/merge_test.rb +146 -0
- data/test/method_info_test.rb +95 -0
- data/test/multi_printer_test.rb +0 -5
- data/test/no_method_class_test.rb +1 -1
- data/test/pause_resume_test.rb +12 -16
- data/test/printer_call_stack_test.rb +2 -2
- data/test/printer_call_tree_test.rb +4 -4
- data/test/printer_flat_test.rb +1 -1
- data/test/printer_graph_html_test.rb +2 -2
- data/test/printer_graph_test.rb +2 -2
- data/test/printers_test.rb +14 -20
- data/test/printing_recursive_graph_test.rb +2 -2
- data/test/profile_test.rb +85 -0
- data/test/recursive_test.rb +374 -155
- data/test/scheduler.rb +363 -0
- data/test/singleton_test.rb +1 -1
- data/test/stack_printer_test.rb +5 -8
- data/test/start_stop_test.rb +11 -14
- data/test/test_helper.rb +11 -8
- data/test/thread_test.rb +106 -15
- data/test/unique_call_path_test.rb +28 -12
- data/test/yarv_test.rb +11 -7
- metadata +17 -29
- data/ext/ruby_prof/rp_aggregate_call_tree.c +0 -59
- data/ext/ruby_prof/rp_aggregate_call_tree.h +0 -13
- data/test/measure_allocations_trace_test.rb +0 -375
- data/test/temp.rb +0 -20
data/ext/ruby_prof/rp_thread.h
CHANGED
@@ -1,39 +1,39 @@
|
|
1
|
-
/* Copyright (C) 2005-2019 Shugo Maeda <shugo@ruby-lang.org> and Charlie Savage <cfis@savagexi.com>
|
2
|
-
Please see the LICENSE file for copyright and distribution information */
|
3
|
-
|
4
|
-
#ifndef __RP_THREAD__
|
5
|
-
#define __RP_THREAD__
|
6
|
-
|
7
|
-
#include "ruby_prof.h"
|
8
|
-
#include "rp_stack.h"
|
9
|
-
|
10
|
-
/* Profiling information for a thread. */
|
11
|
-
typedef struct thread_data_t
|
12
|
-
{
|
13
|
-
|
14
|
-
VALUE object; /* Cache to wrapped object */
|
15
|
-
VALUE fiber; /* Fiber */
|
16
|
-
prof_stack_t* stack; /* Stack of frames */
|
17
|
-
bool trace; /* Are we tracking this thread */
|
18
|
-
prof_call_tree_t* call_tree; /* The root of the call tree*/
|
19
|
-
VALUE thread_id; /* Thread id */
|
20
|
-
VALUE fiber_id; /* Fiber id */
|
21
|
-
VALUE methods; /* Array of RubyProf::MethodInfo */
|
22
|
-
st_table* method_table; /* Methods called in the thread */
|
23
|
-
} thread_data_t;
|
24
|
-
|
25
|
-
void rp_init_thread(void);
|
26
|
-
st_table* threads_table_create(void);
|
27
|
-
thread_data_t* threads_table_lookup(void* profile, VALUE fiber);
|
28
|
-
thread_data_t* threads_table_insert(void* profile, VALUE fiber);
|
29
|
-
void threads_table_free(st_table* table);
|
30
|
-
|
31
|
-
thread_data_t* prof_get_thread(VALUE self);
|
32
|
-
VALUE prof_thread_wrap(thread_data_t* thread);
|
33
|
-
void prof_thread_mark(void* data);
|
34
|
-
|
35
|
-
void switch_thread(void* profile, thread_data_t* thread_data, double measurement);
|
36
|
-
int pause_thread(st_data_t key, st_data_t value, st_data_t data);
|
37
|
-
int unpause_thread(st_data_t key, st_data_t value, st_data_t data);
|
38
|
-
|
39
|
-
#endif //__RP_THREAD__
|
1
|
+
/* Copyright (C) 2005-2019 Shugo Maeda <shugo@ruby-lang.org> and Charlie Savage <cfis@savagexi.com>
|
2
|
+
Please see the LICENSE file for copyright and distribution information */
|
3
|
+
|
4
|
+
#ifndef __RP_THREAD__
|
5
|
+
#define __RP_THREAD__
|
6
|
+
|
7
|
+
#include "ruby_prof.h"
|
8
|
+
#include "rp_stack.h"
|
9
|
+
|
10
|
+
/* Profiling information for a thread. */
|
11
|
+
typedef struct thread_data_t
|
12
|
+
{
|
13
|
+
prof_owner_t owner; /* Who owns this object */
|
14
|
+
VALUE object; /* Cache to wrapped object */
|
15
|
+
VALUE fiber; /* Fiber */
|
16
|
+
prof_stack_t* stack; /* Stack of frames */
|
17
|
+
bool trace; /* Are we tracking this thread */
|
18
|
+
prof_call_tree_t* call_tree; /* The root of the call tree*/
|
19
|
+
VALUE thread_id; /* Thread id */
|
20
|
+
VALUE fiber_id; /* Fiber id */
|
21
|
+
VALUE methods; /* Array of RubyProf::MethodInfo */
|
22
|
+
st_table* method_table; /* Methods called in the thread */
|
23
|
+
} thread_data_t;
|
24
|
+
|
25
|
+
void rp_init_thread(void);
|
26
|
+
st_table* threads_table_create(void);
|
27
|
+
thread_data_t* threads_table_lookup(void* profile, VALUE fiber);
|
28
|
+
thread_data_t* threads_table_insert(void* profile, VALUE fiber);
|
29
|
+
void threads_table_free(st_table* table);
|
30
|
+
|
31
|
+
thread_data_t* prof_get_thread(VALUE self);
|
32
|
+
VALUE prof_thread_wrap(thread_data_t* thread);
|
33
|
+
void prof_thread_mark(void* data);
|
34
|
+
|
35
|
+
void switch_thread(void* profile, thread_data_t* thread_data, double measurement);
|
36
|
+
int pause_thread(st_data_t key, st_data_t value, st_data_t data);
|
37
|
+
int unpause_thread(st_data_t key, st_data_t value, st_data_t data);
|
38
|
+
|
39
|
+
#endif //__RP_THREAD__
|
data/ext/ruby_prof/ruby_prof.c
CHANGED
@@ -29,7 +29,6 @@
|
|
29
29
|
#include "rp_measurement.h"
|
30
30
|
#include "rp_method.h"
|
31
31
|
#include "rp_call_tree.h"
|
32
|
-
#include "rp_aggregate_call_tree.h"
|
33
32
|
#include "rp_call_trees.h"
|
34
33
|
#include "rp_profile.h"
|
35
34
|
#include "rp_stack.h"
|
@@ -43,7 +42,6 @@ void Init_ruby_prof()
|
|
43
42
|
|
44
43
|
rp_init_allocation();
|
45
44
|
rp_init_call_tree();
|
46
|
-
rp_init_aggregate_call_tree();
|
47
45
|
rp_init_call_trees();
|
48
46
|
rp_init_measure();
|
49
47
|
rp_init_method_info();
|
data/ext/ruby_prof/ruby_prof.h
CHANGED
@@ -23,4 +23,12 @@ extern VALUE mProf;
|
|
23
23
|
// This method is not exposed in Ruby header files - at least not as of Ruby 2.6.3 :(
|
24
24
|
extern size_t rb_obj_memsize_of(VALUE);
|
25
25
|
|
26
|
+
typedef enum
|
27
|
+
{
|
28
|
+
OWNER_UNKNOWN = 0,
|
29
|
+
OWNER_RUBY = 1,
|
30
|
+
OWNER_C = 2
|
31
|
+
} prof_owner_t;
|
32
|
+
|
33
|
+
|
26
34
|
#endif //__RUBY_PROF_H__
|
@@ -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,17 +104,20 @@
|
|
102
104
|
</ItemDefinitionGroup>
|
103
105
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
104
106
|
<ClCompile>
|
105
|
-
<AdditionalIncludeDirectories>C:\msys64\usr\local\ruby-2.
|
107
|
+
<AdditionalIncludeDirectories>C:\msys64\usr\local\ruby-3.2.1-vc\include\ruby-3.2.0\x64-mswin64_140;C:\msys64\usr\local\ruby-3.2.1-vc\include\ruby-3.2.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
106
108
|
<Optimization>Disabled</Optimization>
|
107
109
|
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
108
110
|
<WarningLevel>Level3</WarningLevel>
|
109
111
|
</ClCompile>
|
110
112
|
<Link>
|
111
|
-
<AdditionalLibraryDirectories>C:\msys64\usr\local\ruby-2.
|
112
|
-
<AdditionalDependencies>x64-vcruntime140-
|
113
|
+
<AdditionalLibraryDirectories>C:\msys64\usr\local\ruby-3.2.1-vc\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
114
|
+
<AdditionalDependencies>x64-vcruntime140-ruby320.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
113
115
|
<ModuleDefinitionFile>ruby_prof.def</ModuleDefinitionFile>
|
114
116
|
<SubSystem>Console</SubSystem>
|
115
117
|
</Link>
|
118
|
+
<ProjectReference>
|
119
|
+
<LinkLibraryDependencies>false</LinkLibraryDependencies>
|
120
|
+
</ProjectReference>
|
116
121
|
</ItemDefinitionGroup>
|
117
122
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
118
123
|
<ClCompile>
|
@@ -125,7 +130,6 @@
|
|
125
130
|
</Link>
|
126
131
|
</ItemDefinitionGroup>
|
127
132
|
<ItemGroup>
|
128
|
-
<ClInclude Include="..\rp_aggregate_call_tree.h" />
|
129
133
|
<ClInclude Include="..\rp_allocation.h" />
|
130
134
|
<ClInclude Include="..\rp_call_tree.h" />
|
131
135
|
<ClInclude Include="..\rp_call_trees.h" />
|
@@ -137,7 +141,6 @@
|
|
137
141
|
<ClInclude Include="..\ruby_prof.h" />
|
138
142
|
</ItemGroup>
|
139
143
|
<ItemGroup>
|
140
|
-
<ClCompile Include="..\rp_aggregate_call_tree.c" />
|
141
144
|
<ClCompile Include="..\rp_allocation.c" />
|
142
145
|
<ClCompile Include="..\rp_call_tree.c" />
|
143
146
|
<ClCompile Include="..\rp_call_trees.c" />
|
@@ -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 {
|
@@ -96,4 +96,18 @@ module RubyProf
|
|
96
96
|
def self.ensure_not_running!
|
97
97
|
raise(RuntimeError, "RubyProf is already running") if running?
|
98
98
|
end
|
99
|
+
|
100
|
+
class << self
|
101
|
+
extend Gem::Deprecate
|
102
|
+
deprecate :measure_mode, "Profile#measure_mode", 2023, 6
|
103
|
+
deprecate :measure_mode=, "Profile#measure_mode=", 2023, 6
|
104
|
+
deprecate :exclude_threads, "Profile#exclude_threads", 2023, 6
|
105
|
+
deprecate :exclude_threads=, "Profile#initialize", 2023, 6
|
106
|
+
deprecate :start, "Profile#start", 2023, 6
|
107
|
+
deprecate :pause, "Profile#pause", 2023, 6
|
108
|
+
deprecate :stop, "Profile#stop", 2023, 6
|
109
|
+
deprecate :resume, "Profile#resume", 2023, 6
|
110
|
+
deprecate :running?, "Profile#running?", 2023, 6
|
111
|
+
deprecate :profile, "Profile.profile", 2023, 6
|
112
|
+
end
|
99
113
|
end
|
@@ -50,7 +50,7 @@ module RubyProf
|
|
50
50
|
# options - Hash of print options. Note that each printer can
|
51
51
|
# define its own set of options.
|
52
52
|
#
|
53
|
-
# :min_percent - Number 0 to 100 that
|
53
|
+
# :min_percent - Number 0 to 100 that specifies the minimum
|
54
54
|
# %self (the methods self time divided by the
|
55
55
|
# overall total time) that a method must take
|
56
56
|
# for it to be printed out in the report.
|
@@ -131,6 +131,7 @@ module RubyProf
|
|
131
131
|
|
132
132
|
* MyObject#test - An instance method "test" of the class "MyObject"
|
133
133
|
* <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
|
134
|
+
|
134
135
|
EOT
|
135
136
|
end
|
136
137
|
end
|
@@ -27,7 +27,7 @@ module RubyProf
|
|
27
27
|
|
28
28
|
def determine_event_specification_and_value_scale
|
29
29
|
@event_specification = "events: "
|
30
|
-
case
|
30
|
+
case @result.measure_mode
|
31
31
|
when RubyProf::PROCESS_TIME
|
32
32
|
@value_scale = RubyProf::CLOCKS_PER_SEC
|
33
33
|
@event_specification << 'process_time'
|
@@ -68,8 +68,6 @@ module RubyProf
|
|
68
68
|
|
69
69
|
def print_threads
|
70
70
|
remove_subsidiary_files_from_previous_profile_runs
|
71
|
-
# TODO: merge fibers of a given thread here, instead of relying
|
72
|
-
# on the profiler to merge fibers.
|
73
71
|
@result.threads.each do |thread|
|
74
72
|
print_thread(thread)
|
75
73
|
end
|
@@ -100,21 +98,17 @@ module RubyProf
|
|
100
98
|
true
|
101
99
|
end
|
102
100
|
|
103
|
-
def base_name
|
104
|
-
@options[:profile] || "profile"
|
105
|
-
end
|
106
|
-
|
107
101
|
def remove_subsidiary_files_from_previous_profile_runs
|
108
|
-
pattern = [
|
102
|
+
pattern = ["callgrind.out", $$, "*"].join(".")
|
109
103
|
files = Dir.glob(File.join(path, pattern))
|
110
104
|
FileUtils.rm_f(files)
|
111
105
|
end
|
112
106
|
|
113
107
|
def file_name_for_thread(thread)
|
114
108
|
if thread.fiber_id == Fiber.current.object_id
|
115
|
-
[
|
109
|
+
["callgrind.out", $$].join(".")
|
116
110
|
else
|
117
|
-
[
|
111
|
+
["callgrind.out", $$, thread.fiber_id].join(".")
|
118
112
|
end
|
119
113
|
end
|
120
114
|
|
@@ -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)
|
@@ -6,16 +6,16 @@ module RubyProf
|
|
6
6
|
# profile, a call stack profile and a graph profile.
|
7
7
|
class MultiPrinter
|
8
8
|
def initialize(result, printers = [:flat, :graph_html])
|
9
|
-
@flat_printer = FlatPrinter.new(result)
|
9
|
+
@flat_printer = printers.include?(:flat) ? FlatPrinter.new(result) : nil
|
10
10
|
|
11
|
-
@graph_printer = GraphPrinter.new(result)
|
12
|
-
@graph_html_printer = GraphHtmlPrinter.new(result)
|
11
|
+
@graph_printer = printers.include?(:graph) ? GraphPrinter.new(result) : nil
|
12
|
+
@graph_html_printer = printers.include?(:graph_html) ? GraphHtmlPrinter.new(result) : nil
|
13
13
|
|
14
|
-
@tree_printer = CallTreePrinter.new(result)
|
15
|
-
@call_info_printer = CallInfoPrinter.new(result)
|
14
|
+
@tree_printer = printers.include?(:tree) ? CallTreePrinter.new(result) : nil
|
15
|
+
@call_info_printer = printers.include?(:call_tree) ? CallInfoPrinter.new(result) : nil
|
16
16
|
|
17
|
-
@stack_printer = CallStackPrinter.new(result)
|
18
|
-
@dot_printer = DotPrinter.new(result)
|
17
|
+
@stack_printer = printers.include?(:stack) ? CallStackPrinter.new(result) : nil
|
18
|
+
@dot_printer = printers.include?(:dot) ? DotPrinter.new(result) : nil
|
19
19
|
end
|
20
20
|
|
21
21
|
def self.needs_dir?
|
@@ -28,7 +28,7 @@ module RubyProf
|
|
28
28
|
def print(options)
|
29
29
|
validate_print_params(options)
|
30
30
|
|
31
|
-
@
|
31
|
+
@file_name = options.delete(:profile) || "profile"
|
32
32
|
@directory = options.delete(:path) || File.expand_path(".")
|
33
33
|
|
34
34
|
print_to_flat(options) if @flat_printer
|
@@ -44,36 +44,36 @@ module RubyProf
|
|
44
44
|
|
45
45
|
# the name of the flat profile file
|
46
46
|
def flat_report
|
47
|
-
"#{@directory}/#{@
|
47
|
+
"#{@directory}/#{@file_name}.flat.txt"
|
48
48
|
end
|
49
49
|
|
50
50
|
# the name of the graph profile file
|
51
51
|
def graph_report
|
52
|
-
"#{@directory}/#{@
|
52
|
+
"#{@directory}/#{@file_name}.graph.txt"
|
53
53
|
end
|
54
54
|
|
55
55
|
def graph_html_report
|
56
|
-
"#{@directory}/#{@
|
56
|
+
"#{@directory}/#{@file_name}.graph.html"
|
57
57
|
end
|
58
58
|
|
59
59
|
# the name of the callinfo profile file
|
60
60
|
def call_info_report
|
61
|
-
"#{@directory}/#{@
|
61
|
+
"#{@directory}/#{@file_name}.call_tree.txt"
|
62
62
|
end
|
63
63
|
|
64
64
|
# the name of the callgrind profile file
|
65
65
|
def tree_report
|
66
|
-
"#{@directory}/#{@
|
66
|
+
"#{@directory}/#{@file_name}.callgrind.out.#{$$}"
|
67
67
|
end
|
68
68
|
|
69
69
|
# the name of the call stack profile file
|
70
70
|
def stack_report
|
71
|
-
"#{@directory}/#{@
|
71
|
+
"#{@directory}/#{@file_name}.stack.html"
|
72
72
|
end
|
73
73
|
|
74
74
|
# the name of the call stack profile file
|
75
75
|
def dot_report
|
76
|
-
"#{@directory}/#{@
|
76
|
+
"#{@directory}/#{@file_name}.dot"
|
77
77
|
end
|
78
78
|
|
79
79
|
def print_to_flat(options)
|
@@ -101,12 +101,12 @@ module RubyProf
|
|
101
101
|
end
|
102
102
|
|
103
103
|
def print_to_tree(options)
|
104
|
-
@tree_printer.print(options.merge(:path => @directory, :profile => @
|
104
|
+
@tree_printer.print(options.merge(:path => @directory, :profile => @file_name))
|
105
105
|
end
|
106
106
|
|
107
107
|
def print_to_stack(options)
|
108
108
|
File.open(stack_report, "wb") do |file|
|
109
|
-
@stack_printer.print(file, options.merge(:graph => "#{@
|
109
|
+
@stack_printer.print(file, options.merge(:graph => "#{@file_name}.graph.html"))
|
110
110
|
end
|
111
111
|
end
|
112
112
|
|
data/lib/ruby-prof/profile.rb
CHANGED
@@ -1,37 +1,70 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'ruby-prof/exclude_common_methods'
|
4
|
-
|
5
|
-
module RubyProf
|
6
|
-
class Profile
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
#
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'ruby-prof/exclude_common_methods'
|
4
|
+
|
5
|
+
module RubyProf
|
6
|
+
class Profile
|
7
|
+
def measure_mode_string
|
8
|
+
case self.measure_mode
|
9
|
+
when WALL_TIME
|
10
|
+
"wall_time"
|
11
|
+
when PROCESS_TIME
|
12
|
+
"process_time"
|
13
|
+
when ALLOCATIONS
|
14
|
+
"allocations"
|
15
|
+
when MEMORY
|
16
|
+
"memory"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Hides methods that, when represented as a call graph, have
|
21
|
+
# extremely large in and out degrees and make navigation impossible.
|
22
|
+
def exclude_common_methods!
|
23
|
+
ExcludeCommonMethods.apply!(self)
|
24
|
+
end
|
25
|
+
|
26
|
+
def exclude_methods!(mod, *method_names)
|
27
|
+
[method_names].flatten.each do |method_name|
|
28
|
+
exclude_method!(mod, method_name)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def exclude_singleton_methods!(mod, *method_names)
|
33
|
+
exclude_methods!(mod.singleton_class, *method_names)
|
34
|
+
end
|
35
|
+
|
36
|
+
# call-seq:
|
37
|
+
# merge! -> self
|
38
|
+
#
|
39
|
+
# Merges RubyProf threads whose root call_trees reference the same target method. This is useful
|
40
|
+
# when profiling code that uses a main thread/fiber to distribute work to multiple workers.
|
41
|
+
# If there are tens or hundreds of workers, viewing results per worker thread/fiber can be
|
42
|
+
# overwhelming. Using +merge!+ will combine the worker times together into one result.
|
43
|
+
#
|
44
|
+
# Note the reported time will be much greater than the actual wall time. For example, if there
|
45
|
+
# are 10 workers that each run for 5 seconds, merged results will show one thread that
|
46
|
+
# ran for 50 seconds.
|
47
|
+
#
|
48
|
+
def merge!
|
49
|
+
# First group threads by their root call tree target (method). If the methods are
|
50
|
+
# different than there is nothing to merge
|
51
|
+
grouped = threads.group_by do |thread|
|
52
|
+
thread.call_tree.target
|
53
|
+
end
|
54
|
+
|
55
|
+
# For each target, get the first thread. Then loop over the remaining threads,
|
56
|
+
# and merge them into the first one and ten delete them. So we will be left with
|
57
|
+
# one thread per target.
|
58
|
+
grouped.each do |target, threads|
|
59
|
+
thread = threads.shift
|
60
|
+
threads.each do |other_thread|
|
61
|
+
thread.merge!(other_thread)
|
62
|
+
remove_thread(other_thread)
|
63
|
+
end
|
64
|
+
thread
|
65
|
+
end
|
66
|
+
|
67
|
+
self
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/ruby-prof/rack.rb
CHANGED
@@ -6,7 +6,6 @@ module Rack
|
|
6
6
|
def initialize(app, options = {})
|
7
7
|
@app = app
|
8
8
|
@options = options
|
9
|
-
@options[:min_percent] ||= 1
|
10
9
|
|
11
10
|
@tmpdir = options[:path] || Dir.tmpdir
|
12
11
|
FileUtils.mkdir_p(@tmpdir)
|
@@ -26,14 +25,19 @@ module Rack
|
|
26
25
|
if should_profile?(request.path)
|
27
26
|
begin
|
28
27
|
result = nil
|
29
|
-
|
28
|
+
profile = ::RubyProf::Profile.profile(profiling_options) do
|
30
29
|
result = @app.call(env)
|
31
30
|
end
|
32
31
|
|
32
|
+
if @options[:merge_fibers]
|
33
|
+
profile.merge!
|
34
|
+
end
|
35
|
+
|
36
|
+
|
33
37
|
path = request.path.gsub('/', '-')
|
34
38
|
path.slice!(0)
|
35
39
|
|
36
|
-
print(
|
40
|
+
print(profile, path)
|
37
41
|
result
|
38
42
|
end
|
39
43
|
else
|
@@ -54,39 +58,45 @@ module Rack
|
|
54
58
|
end
|
55
59
|
|
56
60
|
def profiling_options
|
57
|
-
|
58
|
-
|
59
|
-
options[:
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
65
|
-
if @options[:request_thread_only]
|
66
|
-
options[:include_threads] = [Thread.current]
|
61
|
+
result = {}
|
62
|
+
result[:measure_mode] = @options[:measure_mode] || ::RubyProf::WALL_TIME
|
63
|
+
result[:track_allocations] = @options[:track_allocations] || false
|
64
|
+
result[:exclude_common] = @options[:exclude_common] || false
|
65
|
+
|
66
|
+
if @options[:ignore_existing_threads]
|
67
|
+
result[:exclude_threads] = Thread.list.select {|thread| thread != Thread.current}
|
67
68
|
end
|
68
|
-
|
69
|
-
|
69
|
+
|
70
|
+
if @options[:request_thread_only]
|
71
|
+
result[:include_threads] = [Thread.current]
|
70
72
|
end
|
71
|
-
|
73
|
+
|
74
|
+
result
|
75
|
+
end
|
76
|
+
|
77
|
+
def print_options
|
78
|
+
result = {}
|
79
|
+
result[:min_percent] = @options[:min_percent] || 1
|
80
|
+
result[:sort_method] = @options[:sort_method] || :total_time
|
81
|
+
result
|
72
82
|
end
|
73
83
|
|
74
|
-
def print(
|
84
|
+
def print(profile, path)
|
75
85
|
@printer_klasses.each do |printer_klass, base_name|
|
76
|
-
printer = printer_klass.new(
|
86
|
+
printer = printer_klass.new(profile)
|
77
87
|
|
78
88
|
if base_name.respond_to?(:call)
|
79
89
|
base_name = base_name.call
|
80
90
|
end
|
81
91
|
|
82
92
|
if printer_klass == ::RubyProf::MultiPrinter
|
83
|
-
printer.print(
|
93
|
+
printer.print(print_options.merge(:profile => "#{path}-#{base_name}"))
|
84
94
|
elsif printer_klass == ::RubyProf::CallTreePrinter
|
85
|
-
printer.print(
|
95
|
+
printer.print(print_options.merge(:profile => "#{path}-#{base_name}"))
|
86
96
|
else
|
87
97
|
file_name = ::File.join(@tmpdir, "#{path}-#{base_name}")
|
88
98
|
::File.open(file_name, 'wb') do |file|
|
89
|
-
printer.print(file,
|
99
|
+
printer.print(file, print_options)
|
90
100
|
end
|
91
101
|
end
|
92
102
|
end
|
data/lib/ruby-prof/version.rb
CHANGED
data/lib/ruby-prof.rb
CHANGED
data/ruby-prof.gemspec
CHANGED
@@ -36,7 +36,7 @@ EOF
|
|
36
36
|
spec.files = Dir['CHANGES',
|
37
37
|
'LICENSE',
|
38
38
|
'Rakefile',
|
39
|
-
'README.
|
39
|
+
'README.md',
|
40
40
|
'ruby-prof.gemspec',
|
41
41
|
'bin/ruby-prof',
|
42
42
|
'bin/ruby-prof-check-trace',
|
@@ -56,10 +56,9 @@ EOF
|
|
56
56
|
'test/*.rb']
|
57
57
|
|
58
58
|
spec.test_files = Dir["test/test_*.rb"]
|
59
|
-
spec.required_ruby_version = '>= 2.
|
59
|
+
spec.required_ruby_version = '>= 2.7.0'
|
60
60
|
spec.date = Time.now.strftime('%Y-%m-%d')
|
61
61
|
spec.homepage = 'https://github.com/ruby-prof/ruby-prof'
|
62
62
|
spec.add_development_dependency('minitest')
|
63
63
|
spec.add_development_dependency('rake-compiler')
|
64
|
-
spec.add_development_dependency('rdoc')
|
65
64
|
end
|