ruby-prof 1.1.0-x64-mingw32 → 1.3.0-x64-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES +19 -1
- data/bin/ruby-prof +100 -152
- data/ext/ruby_prof/rp_aggregate_call_tree.c +59 -0
- data/ext/ruby_prof/rp_aggregate_call_tree.h +13 -0
- data/ext/ruby_prof/rp_allocation.c +67 -59
- data/ext/ruby_prof/rp_allocation.h +3 -3
- data/ext/ruby_prof/rp_call_tree.c +369 -0
- data/ext/ruby_prof/rp_call_tree.h +43 -0
- data/ext/ruby_prof/rp_call_trees.c +288 -0
- data/ext/ruby_prof/rp_call_trees.h +28 -0
- data/ext/ruby_prof/rp_measure_allocations.c +11 -13
- data/ext/ruby_prof/rp_measure_process_time.c +11 -13
- data/ext/ruby_prof/rp_measure_wall_time.c +17 -15
- data/ext/ruby_prof/rp_measurement.c +47 -40
- data/ext/ruby_prof/rp_measurement.h +7 -7
- data/ext/ruby_prof/rp_method.c +116 -255
- data/ext/ruby_prof/rp_method.h +31 -39
- data/ext/ruby_prof/rp_profile.c +311 -281
- data/ext/ruby_prof/rp_profile.h +1 -2
- data/ext/ruby_prof/rp_stack.c +113 -105
- data/ext/ruby_prof/rp_stack.h +17 -20
- data/ext/ruby_prof/rp_thread.c +136 -111
- data/ext/ruby_prof/rp_thread.h +12 -9
- data/ext/ruby_prof/ruby_prof.c +27 -23
- data/ext/ruby_prof/ruby_prof.h +9 -0
- data/ext/ruby_prof/vc/ruby_prof.vcxproj +11 -7
- data/lib/ruby-prof.rb +2 -3
- data/lib/ruby-prof/assets/call_stack_printer.html.erb +4 -7
- data/lib/ruby-prof/assets/graph_printer.html.erb +5 -6
- data/lib/ruby-prof/{call_info.rb → call_tree.rb} +6 -6
- data/lib/ruby-prof/call_tree_visitor.rb +36 -0
- data/lib/ruby-prof/measurement.rb +5 -2
- data/lib/ruby-prof/method_info.rb +3 -15
- data/lib/ruby-prof/printers/call_info_printer.rb +12 -10
- data/lib/ruby-prof/printers/call_stack_printer.rb +19 -22
- data/lib/ruby-prof/printers/call_tree_printer.rb +1 -1
- data/lib/ruby-prof/printers/dot_printer.rb +3 -3
- data/lib/ruby-prof/printers/graph_printer.rb +3 -4
- data/lib/ruby-prof/printers/multi_printer.rb +2 -2
- data/lib/ruby-prof/rack.rb +3 -0
- data/lib/ruby-prof/thread.rb +3 -18
- data/lib/ruby-prof/version.rb +1 -1
- data/ruby-prof.gemspec +7 -0
- data/test/alias_test.rb +42 -45
- data/test/basic_test.rb +0 -86
- data/test/{call_info_visitor_test.rb → call_tree_visitor_test.rb} +6 -5
- data/test/call_trees_test.rb +66 -0
- data/test/exclude_methods_test.rb +17 -12
- data/test/fiber_test.rb +197 -9
- data/test/gc_test.rb +36 -42
- data/test/inverse_call_tree_test.rb +175 -0
- data/test/line_number_test.rb +67 -70
- data/test/marshal_test.rb +7 -11
- data/test/measure_allocations_test.rb +224 -234
- data/test/measure_allocations_trace_test.rb +224 -234
- data/test/measure_memory_trace_test.rb +814 -469
- data/test/measure_process_time_test.rb +0 -64
- data/test/measure_times.rb +2 -0
- data/test/measure_wall_time_test.rb +34 -58
- data/test/pause_resume_test.rb +19 -10
- data/test/prime.rb +1 -3
- data/test/prime_script.rb +6 -0
- data/test/printers_test.rb +1 -1
- data/test/recursive_test.rb +50 -54
- data/test/start_stop_test.rb +19 -19
- data/test/test_helper.rb +3 -15
- data/test/thread_test.rb +11 -11
- data/test/unique_call_path_test.rb +25 -95
- metadata +19 -10
- data/ext/ruby_prof/rp_call_info.c +0 -271
- data/ext/ruby_prof/rp_call_info.h +0 -35
- data/lib/2.6.5/ruby_prof.so +0 -0
- data/lib/ruby-prof/call_info_visitor.rb +0 -38
- data/test/parser_timings.rb +0 -24
data/ext/ruby_prof/rp_thread.h
CHANGED
@@ -8,14 +8,14 @@
|
|
8
8
|
#include "rp_stack.h"
|
9
9
|
|
10
10
|
/* Profiling information for a thread. */
|
11
|
-
typedef struct
|
11
|
+
typedef struct thread_data_t
|
12
12
|
{
|
13
13
|
// Runtime
|
14
14
|
VALUE object; /* Cache to wrapped object */
|
15
15
|
VALUE fiber; /* Fiber */
|
16
16
|
prof_stack_t* stack; /* Stack of frames */
|
17
17
|
bool trace; /* Are we tracking this thread */
|
18
|
-
|
18
|
+
prof_call_tree_t* call_tree; /* The root of the call tree*/
|
19
19
|
VALUE thread_id; /* Thread id */
|
20
20
|
VALUE fiber_id; /* Fiber id */
|
21
21
|
VALUE methods; /* Array of RubyProf::MethodInfo */
|
@@ -23,13 +23,16 @@ typedef struct
|
|
23
23
|
} thread_data_t;
|
24
24
|
|
25
25
|
void rp_init_thread(void);
|
26
|
-
st_table
|
27
|
-
thread_data_t
|
28
|
-
thread_data_t* threads_table_insert(void
|
29
|
-
void
|
30
|
-
|
31
|
-
|
32
|
-
|
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);
|
33
36
|
int pause_thread(st_data_t key, st_data_t value, st_data_t data);
|
34
37
|
int unpause_thread(st_data_t key, st_data_t value, st_data_t data);
|
35
38
|
|
data/ext/ruby_prof/ruby_prof.c
CHANGED
@@ -1,34 +1,36 @@
|
|
1
1
|
/* Copyright (C) 2005-2019 Shugo Maeda <shugo@ruby-lang.org> and Charlie Savage <cfis@savagexi.com>
|
2
2
|
Please see the LICENSE file for copyright and distribution information */
|
3
3
|
|
4
|
-
/* ruby-prof tracks the time spent executing every method in ruby programming.
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
*/
|
4
|
+
/* ruby-prof tracks the time spent executing every method in ruby programming.
|
5
|
+
The main players are:
|
6
|
+
|
7
|
+
profile_t - This represents 1 profile.
|
8
|
+
thread_data_t - Stores data about a single thread.
|
9
|
+
prof_stack_t - The method call stack in a particular thread
|
10
|
+
prof_method_t - Profiling information about each method
|
11
|
+
prof_call_tree_t - Keeps track a method's callers and callees.
|
12
|
+
|
13
|
+
The final result is an instance of a profile object which has a hash table of
|
14
|
+
thread_data_t, keyed on the thread id. Each thread in turn has a hash table
|
15
|
+
of prof_method_t, keyed on the method id. A hash table is used for quick
|
16
|
+
look up when doing a profile. However, it is exposed to Ruby as an array.
|
17
|
+
|
18
|
+
Each prof_method_t has two hash tables, parent and children, of prof_call_tree_t.
|
19
|
+
These objects keep track of a method's callers (who called the method) and its
|
20
|
+
callees (who the method called). These are keyed the method id, but once again,
|
21
|
+
are exposed to Ruby as arrays. Each prof_call_into_t maintains a pointer to the
|
22
|
+
caller or callee method, thereby making it easy to navigate through the call
|
23
|
+
hierarchy in ruby - which is very helpful for creating call graphs.
|
24
|
+
*/
|
25
25
|
|
26
26
|
#include "ruby_prof.h"
|
27
27
|
|
28
28
|
#include "rp_allocation.h"
|
29
29
|
#include "rp_measurement.h"
|
30
30
|
#include "rp_method.h"
|
31
|
-
#include "
|
31
|
+
#include "rp_call_tree.h"
|
32
|
+
#include "rp_aggregate_call_tree.h"
|
33
|
+
#include "rp_call_trees.h"
|
32
34
|
#include "rp_profile.h"
|
33
35
|
#include "rp_stack.h"
|
34
36
|
#include "rp_thread.h"
|
@@ -40,7 +42,9 @@ void Init_ruby_prof()
|
|
40
42
|
mProf = rb_define_module("RubyProf");
|
41
43
|
|
42
44
|
rp_init_allocation();
|
43
|
-
|
45
|
+
rp_init_call_tree();
|
46
|
+
rp_init_aggregate_call_tree();
|
47
|
+
rp_init_call_trees();
|
44
48
|
rp_init_measure();
|
45
49
|
rp_init_method_info();
|
46
50
|
rp_init_profile();
|
data/ext/ruby_prof/ruby_prof.h
CHANGED
@@ -9,6 +9,15 @@
|
|
9
9
|
#include <stdio.h>
|
10
10
|
#include <stdbool.h>
|
11
11
|
|
12
|
+
#ifndef rb_st_lookup
|
13
|
+
#define rb_st_foreach st_foreach
|
14
|
+
#define rb_st_free_table st_free_table
|
15
|
+
#define rb_st_init_numtable st_init_numtable
|
16
|
+
#define rb_st_insert st_insert
|
17
|
+
#define rb_st_lookup st_lookup
|
18
|
+
#endif
|
19
|
+
|
20
|
+
|
12
21
|
extern VALUE mProf;
|
13
22
|
|
14
23
|
// This method is not exposed in Ruby header files - at least not as of Ruby 2.6.3 :(
|
@@ -64,7 +64,7 @@
|
|
64
64
|
</PropertyGroup>
|
65
65
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
66
66
|
<TargetExt>.so</TargetExt>
|
67
|
-
<OutDir
|
67
|
+
<OutDir>..\..\..\lib</OutDir>
|
68
68
|
</PropertyGroup>
|
69
69
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
70
70
|
<ClCompile>
|
@@ -102,30 +102,34 @@
|
|
102
102
|
</ItemDefinitionGroup>
|
103
103
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
104
104
|
<ClCompile>
|
105
|
-
<AdditionalIncludeDirectories>C:\msys64\usr\local\ruby-2.
|
105
|
+
<AdditionalIncludeDirectories>C:\msys64\usr\local\ruby-2.7.0vc\include\ruby-2.7.0\x64-mswin64_140;C:\msys64\usr\local\ruby-2.7.0vc\include\ruby-2.7.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
106
106
|
<Optimization>Disabled</Optimization>
|
107
107
|
<PreprocessorDefinitions>HAVE_RB_TRACEARG_CALLEE_ID;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
108
108
|
</ClCompile>
|
109
109
|
<Link>
|
110
|
-
<AdditionalLibraryDirectories>C:\msys64\usr\local\ruby-2.
|
111
|
-
<AdditionalDependencies>x64-vcruntime140-
|
110
|
+
<AdditionalLibraryDirectories>C:\msys64\usr\local\ruby-2.7.0vc\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
111
|
+
<AdditionalDependencies>x64-vcruntime140-ruby270.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
112
112
|
<ModuleDefinitionFile>ruby_prof.def</ModuleDefinitionFile>
|
113
|
+
<SubSystem>Console</SubSystem>
|
113
114
|
</Link>
|
114
115
|
</ItemDefinitionGroup>
|
115
116
|
<ItemGroup>
|
117
|
+
<ClInclude Include="..\rp_aggregate_call_tree.h" />
|
116
118
|
<ClInclude Include="..\rp_allocation.h" />
|
117
|
-
<ClInclude Include="..\
|
119
|
+
<ClInclude Include="..\rp_call_tree.h" />
|
120
|
+
<ClInclude Include="..\rp_call_trees.h" />
|
118
121
|
<ClInclude Include="..\rp_measurement.h" />
|
119
122
|
<ClInclude Include="..\rp_method.h" />
|
120
123
|
<ClInclude Include="..\rp_profile.h" />
|
121
124
|
<ClInclude Include="..\rp_stack.h" />
|
122
125
|
<ClInclude Include="..\rp_thread.h" />
|
123
126
|
<ClInclude Include="..\ruby_prof.h" />
|
124
|
-
<ClInclude Include="..\version.h" />
|
125
127
|
</ItemGroup>
|
126
128
|
<ItemGroup>
|
129
|
+
<ClCompile Include="..\rp_aggregate_call_tree.c" />
|
127
130
|
<ClCompile Include="..\rp_allocation.c" />
|
128
|
-
<ClCompile Include="..\
|
131
|
+
<ClCompile Include="..\rp_call_tree.c" />
|
132
|
+
<ClCompile Include="..\rp_call_trees.c" />
|
129
133
|
<ClCompile Include="..\rp_measurement.c" />
|
130
134
|
<ClCompile Include="..\rp_measure_allocations.c" />
|
131
135
|
<ClCompile Include="..\rp_measure_memory.c" />
|
data/lib/ruby-prof.rb
CHANGED
@@ -9,7 +9,7 @@ rescue LoadError
|
|
9
9
|
end
|
10
10
|
|
11
11
|
require 'ruby-prof/version'
|
12
|
-
require 'ruby-prof/
|
12
|
+
require 'ruby-prof/call_tree'
|
13
13
|
require 'ruby-prof/compatibility'
|
14
14
|
require 'ruby-prof/measurement'
|
15
15
|
require 'ruby-prof/method_info'
|
@@ -18,8 +18,7 @@ require 'ruby-prof/rack'
|
|
18
18
|
require 'ruby-prof/thread'
|
19
19
|
|
20
20
|
module RubyProf
|
21
|
-
autoload :
|
22
|
-
|
21
|
+
autoload :CallTreeVisitor, 'ruby-prof/call_tree_visitor'
|
23
22
|
autoload :AbstractPrinter, 'ruby-prof/printers/abstract_printer'
|
24
23
|
autoload :CallInfoPrinter, 'ruby-prof/printers/call_info_printer'
|
25
24
|
autoload :CallStackPrinter, 'ruby-prof/printers/call_stack_printer'
|
@@ -697,13 +697,10 @@
|
|
697
697
|
<div class="thread">
|
698
698
|
<span>Thread: <%= thread.id %>, Fiber: <%= thread.fiber_id %> (<%= thread_info %>)</span>
|
699
699
|
<ul name="thread">
|
700
|
-
<%
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
print_stack(output, visited, call_info, call_info.total_time) %>
|
705
|
-
<%= output.string %>
|
706
|
-
<% end %>
|
700
|
+
<% visited = Set.new
|
701
|
+
output = StringIO.new('')
|
702
|
+
print_stack(output, visited, thread.call_tree, thread.call_tree.total_time) %>
|
703
|
+
<%= output.string %>
|
707
704
|
</ul>
|
708
705
|
</div>
|
709
706
|
<% end %>
|
@@ -217,8 +217,7 @@
|
|
217
217
|
self_percentage = (method.self_time/total_time) * 100 %>
|
218
218
|
|
219
219
|
<!-- Parents -->
|
220
|
-
<% for caller in method.callers.sort
|
221
|
-
next if method.root?
|
220
|
+
<% for caller in method.call_trees.callers.sort
|
222
221
|
next if min_time && caller.total_time < min_time %>
|
223
222
|
<tr>
|
224
223
|
<td> </td>
|
@@ -228,12 +227,12 @@
|
|
228
227
|
<td><%= sprintf("%.2f", caller.wait_time) %></td>
|
229
228
|
<td><%= sprintf("%.2f", caller.children_time) %></td>
|
230
229
|
<td><%= "#{caller.called}/#{method.called}" %></td>
|
231
|
-
<td class="method_name"><%= create_link(thread, total_time, caller.parent) %></td>
|
230
|
+
<td class="method_name"><%= create_link(thread, total_time, caller.parent.target) %></td>
|
232
231
|
<% if @result.track_allocations? %>
|
233
232
|
<td>-</td>
|
234
233
|
<% end %>
|
235
|
-
<td><%= if caller.parent.source_file
|
236
|
-
file_link(caller.parent.source_file, caller.line)
|
234
|
+
<td><%= if caller.parent.target.source_file
|
235
|
+
file_link(caller.parent.target.source_file, caller.line)
|
237
236
|
end %></td>
|
238
237
|
</tr>
|
239
238
|
<% end %>
|
@@ -293,7 +292,7 @@
|
|
293
292
|
<% end %>
|
294
293
|
|
295
294
|
<!-- Children -->
|
296
|
-
<% for callee in method.callees.sort_by(&:total_time).reverse
|
295
|
+
<% for callee in method.call_trees.callees.sort_by(&:total_time).reverse
|
297
296
|
next if min_time && callee.total_time < min_time %>
|
298
297
|
<tr>
|
299
298
|
<td> </td>
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
module RubyProf
|
4
|
-
# The
|
4
|
+
# The CallTree class is used to track the relationships between methods. It is a helper class used by
|
5
5
|
# RubyProf::MethodInfo to keep track of which methods called a given method and which methods a given
|
6
|
-
# method called. Each
|
6
|
+
# method called. Each CallTree has a parent and target method. You cannot create a CallTree object directly,
|
7
7
|
# they are generated while running a profile.
|
8
|
-
class
|
8
|
+
class CallTree
|
9
9
|
# The number of times the parent method called the target method
|
10
10
|
def called
|
11
11
|
self.measurement.called
|
@@ -31,7 +31,7 @@ module RubyProf
|
|
31
31
|
self.total_time - self.self_time - self.wait_time
|
32
32
|
end
|
33
33
|
|
34
|
-
# Compares two
|
34
|
+
# Compares two CallTree instances. The comparison is based on the CallTree#parent, CallTree#target,
|
35
35
|
# and total time.
|
36
36
|
def <=>(other)
|
37
37
|
if self.target == other.target && self.parent == other.parent
|
@@ -47,11 +47,11 @@ module RubyProf
|
|
47
47
|
|
48
48
|
# :nodoc:
|
49
49
|
def to_s
|
50
|
-
"
|
50
|
+
"<#{self.class.name} - #{self.target.full_name}>"
|
51
51
|
end
|
52
52
|
|
53
53
|
def inspect
|
54
|
-
|
54
|
+
self.to_s
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module RubyProf
|
2
|
+
# The call info visitor class does a depth-first traversal across a
|
3
|
+
# list of call infos. At each call_tree node, the visitor executes
|
4
|
+
# the block provided in the #visit method. The block is passed two
|
5
|
+
# parameters, the event and the call_tree instance. Event will be
|
6
|
+
# either :enter or :exit.
|
7
|
+
#
|
8
|
+
# visitor = RubyProf::CallTreeVisitor.new(result.threads.first.call_tree)
|
9
|
+
#
|
10
|
+
# method_names = Array.new
|
11
|
+
#
|
12
|
+
# visitor.visit do |call_tree, event|
|
13
|
+
# method_names << call_tree.target.full_name if event == :enter
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# puts method_names
|
17
|
+
class CallTreeVisitor
|
18
|
+
def initialize(call_tree)
|
19
|
+
@call_tree = call_tree
|
20
|
+
end
|
21
|
+
|
22
|
+
def visit(&block)
|
23
|
+
visit_call_tree(@call_tree, &block)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def visit_call_tree(call_tree, &block)
|
29
|
+
yield call_tree, :enter
|
30
|
+
call_tree.children.each do |child|
|
31
|
+
visit_call_tree(child, &block)
|
32
|
+
end
|
33
|
+
yield call_tree, :exit
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -1,8 +1,11 @@
|
|
1
1
|
module RubyProf
|
2
2
|
# The Measurement class is a helper class used by RubyProf::MethodInfo to store information about the method.
|
3
|
-
# You cannot create a
|
3
|
+
# You cannot create a CallTree object directly, they are generated while running a profile.
|
4
4
|
class Measurement
|
5
|
-
|
5
|
+
def children_time
|
6
|
+
self.total_time - self.self_time - self.wait_time
|
7
|
+
end
|
8
|
+
|
6
9
|
def to_s
|
7
10
|
"c: #{called}, tt: #{total_time}, st: #{self_time}"
|
8
11
|
end
|
@@ -52,14 +52,9 @@ module RubyProf
|
|
52
52
|
self.total_time - self.self_time - self.wait_time
|
53
53
|
end
|
54
54
|
|
55
|
-
# The min call depth of this method
|
56
|
-
def min_depth
|
57
|
-
@min_depth ||= callers.map(&:depth).min
|
58
|
-
end
|
59
|
-
|
60
55
|
# :enddoc:
|
61
56
|
def <=>(other)
|
62
|
-
if other
|
57
|
+
if other.nil?
|
63
58
|
-1
|
64
59
|
elsif self.full_name == other.full_name
|
65
60
|
0
|
@@ -67,9 +62,9 @@ module RubyProf
|
|
67
62
|
-1
|
68
63
|
elsif self.total_time > other.total_time
|
69
64
|
1
|
70
|
-
elsif self.min_depth < other.min_depth
|
65
|
+
elsif self.call_trees.min_depth < other.call_trees.min_depth
|
71
66
|
1
|
72
|
-
elsif self.min_depth > other.min_depth
|
67
|
+
elsif self.call_trees.min_depth > other.call_trees.min_depth
|
73
68
|
-1
|
74
69
|
else
|
75
70
|
self.full_name <=> other.full_name
|
@@ -79,12 +74,5 @@ module RubyProf
|
|
79
74
|
def to_s
|
80
75
|
"#{self.full_name} (c: #{self.called}, tt: #{self.total_time}, st: #{self.self_time}, wt: #{wait_time}, ct: #{self.children_time})"
|
81
76
|
end
|
82
|
-
|
83
|
-
# Remove method from the call graph. should not be called directly.
|
84
|
-
def eliminate!
|
85
|
-
# $stderr.puts "eliminating #{self}"
|
86
|
-
callers.each{ |call_info| call_info.eliminate! }
|
87
|
-
callers.clear
|
88
|
-
end
|
89
77
|
end
|
90
78
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
module RubyProf
|
4
|
-
# Prints out the call graph based on
|
4
|
+
# Prints out the call graph based on CallTree instances. This
|
5
5
|
# is mainly for debugging purposes as it provides access into
|
6
6
|
# into RubyProf's internals.
|
7
7
|
#
|
@@ -19,6 +19,7 @@ module RubyProf
|
|
19
19
|
private
|
20
20
|
|
21
21
|
def print_header(thread)
|
22
|
+
@output << "----------------------------------------------------\n"
|
22
23
|
@output << "Thread ID: #{thread.id}\n"
|
23
24
|
@output << "Fiber ID: #{thread.fiber_id}\n"
|
24
25
|
@output << "Total Time: #{thread.total_time}\n"
|
@@ -27,18 +28,18 @@ module RubyProf
|
|
27
28
|
end
|
28
29
|
|
29
30
|
def print_methods(thread)
|
30
|
-
visitor =
|
31
|
+
visitor = CallTreeVisitor.new(thread.call_tree)
|
31
32
|
|
32
|
-
visitor.visit do |
|
33
|
+
visitor.visit do |call_tree, event|
|
33
34
|
if event == :enter
|
34
|
-
@output << " " *
|
35
|
-
@output <<
|
35
|
+
@output << " " * call_tree.depth
|
36
|
+
@output << call_tree.target.full_name
|
36
37
|
@output << " ("
|
37
|
-
@output << "tt:#{sprintf("%#{TIME_WIDTH}.2f",
|
38
|
-
@output << "st:#{sprintf("%#{TIME_WIDTH}.2f",
|
39
|
-
@output << "wt:#{sprintf("%#{TIME_WIDTH}.2f",
|
40
|
-
@output << "ct:#{sprintf("%#{TIME_WIDTH}.2f",
|
41
|
-
@output << "call:#{
|
38
|
+
@output << "tt:#{sprintf("%#{TIME_WIDTH}.2f", call_tree.total_time)}, "
|
39
|
+
@output << "st:#{sprintf("%#{TIME_WIDTH}.2f", call_tree.self_time)}, "
|
40
|
+
@output << "wt:#{sprintf("%#{TIME_WIDTH}.2f", call_tree.wait_time)}, "
|
41
|
+
@output << "ct:#{sprintf("%#{TIME_WIDTH}.2f", call_tree.children_time)}, "
|
42
|
+
@output << "call:#{call_tree.called}, "
|
42
43
|
@output << ")"
|
43
44
|
@output << "\n"
|
44
45
|
end
|
@@ -46,6 +47,7 @@ module RubyProf
|
|
46
47
|
end
|
47
48
|
|
48
49
|
def print_footer(thread)
|
50
|
+
@output << "\n" << "\n"
|
49
51
|
end
|
50
52
|
end
|
51
53
|
end
|
@@ -46,7 +46,6 @@ module RubyProf
|
|
46
46
|
def print(output = STDOUT, options = {})
|
47
47
|
setup_options(options)
|
48
48
|
output << @erb.result(binding)
|
49
|
-
a = 1
|
50
49
|
end
|
51
50
|
|
52
51
|
# :enddoc:
|
@@ -55,50 +54,49 @@ module RubyProf
|
|
55
54
|
@erb = ERB.new(self.template)
|
56
55
|
end
|
57
56
|
|
58
|
-
def print_stack(output, visited,
|
59
|
-
total_time =
|
57
|
+
def print_stack(output, visited, call_tree, parent_time)
|
58
|
+
total_time = call_tree.total_time
|
60
59
|
percent_parent = (total_time/parent_time)*100
|
61
60
|
percent_total = (total_time/@overall_time)*100
|
62
61
|
return unless percent_total > min_percent
|
63
62
|
color = self.color(percent_total)
|
64
|
-
kids = call_info.target.callees
|
65
63
|
visible = percent_total >= threshold
|
66
64
|
expanded = percent_total >= expansion
|
67
65
|
display = visible ? "block" : "none"
|
68
66
|
|
69
67
|
output << "<li class=\"color#{color}\" style=\"display:#{display}\">" << "\n"
|
70
68
|
|
71
|
-
if visited.include?(
|
69
|
+
if visited.include?(call_tree)
|
72
70
|
output << "<a href=\"#\" class=\"toggle empty\" ></a>" << "\n"
|
73
|
-
output << "<span>%s %s</span>" % [link(
|
71
|
+
output << "<span>%s %s</span>" % [link(call_tree.target, true), graph_link(call_tree)] << "\n"
|
74
72
|
else
|
75
|
-
visited <<
|
73
|
+
visited << call_tree
|
76
74
|
|
77
|
-
if
|
75
|
+
if call_tree.children.empty?
|
78
76
|
output << "<a href=\"#\" class=\"toggle empty\" ></a>" << "\n"
|
79
77
|
else
|
80
|
-
visible_children =
|
78
|
+
visible_children = call_tree.children.any?{|ci| (ci.total_time/@overall_time)*100 >= threshold}
|
81
79
|
image = visible_children ? (expanded ? "minus" : "plus") : "empty"
|
82
80
|
output << "<a href=\"#\" class=\"toggle #{image}\" ></a>" << "\n"
|
83
81
|
end
|
84
82
|
output << "<span>%4.2f%% (%4.2f%%) %s %s</span>" % [percent_total, percent_parent,
|
85
|
-
link(
|
83
|
+
link(call_tree.target, false), graph_link(call_tree)] << "\n"
|
86
84
|
|
87
|
-
unless
|
85
|
+
unless call_tree.children.empty?
|
88
86
|
output << (expanded ? '<ul>' : '<ul style="display:none">') << "\n"
|
89
|
-
|
90
|
-
print_stack(output, visited,
|
87
|
+
call_tree.children.sort_by{|c| -c.total_time}.each do |child_call_tree|
|
88
|
+
print_stack(output, visited, child_call_tree, total_time)
|
91
89
|
end
|
92
90
|
output << '</ul>' << "\n"
|
93
91
|
end
|
94
92
|
|
95
|
-
visited.delete(
|
93
|
+
visited.delete(call_tree)
|
96
94
|
end
|
97
95
|
output << '</li>' << "\n"
|
98
96
|
end
|
99
97
|
|
100
|
-
def name(
|
101
|
-
method =
|
98
|
+
def name(call_tree)
|
99
|
+
method = call_tree.target
|
102
100
|
method.full_name
|
103
101
|
end
|
104
102
|
|
@@ -112,19 +110,18 @@ module RubyProf
|
|
112
110
|
end
|
113
111
|
end
|
114
112
|
|
115
|
-
def graph_link(
|
116
|
-
total_calls =
|
117
|
-
href = "#{method_href(call_info.target)}"
|
113
|
+
def graph_link(call_tree)
|
114
|
+
total_calls = call_tree.target.called
|
118
115
|
totals = total_calls.to_s
|
119
|
-
"[#{
|
116
|
+
"[#{call_tree.called} calls, #{totals} total]"
|
120
117
|
end
|
121
118
|
|
122
119
|
def method_href(method)
|
123
120
|
h(method.full_name.gsub(/[><#\.\?=:]/,"_"))
|
124
121
|
end
|
125
122
|
|
126
|
-
def total_time(
|
127
|
-
sum(
|
123
|
+
def total_time(call_trees)
|
124
|
+
sum(call_trees.map{|ci| ci.total_time})
|
128
125
|
end
|
129
126
|
|
130
127
|
def sum(a)
|