ruby-prof 0.18.0-x64-mingw32 → 1.1.0-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +32 -0
  3. data/LICENSE +2 -2
  4. data/README.rdoc +1 -483
  5. data/Rakefile +3 -6
  6. data/bin/ruby-prof +65 -30
  7. data/ext/ruby_prof/extconf.rb +6 -38
  8. data/ext/ruby_prof/rp_allocation.c +279 -0
  9. data/ext/ruby_prof/rp_allocation.h +31 -0
  10. data/ext/ruby_prof/rp_call_info.c +129 -283
  11. data/ext/ruby_prof/rp_call_info.h +16 -34
  12. data/ext/ruby_prof/rp_measure_allocations.c +25 -49
  13. data/ext/ruby_prof/rp_measure_memory.c +21 -56
  14. data/ext/ruby_prof/rp_measure_process_time.c +35 -39
  15. data/ext/ruby_prof/rp_measure_wall_time.c +36 -19
  16. data/ext/ruby_prof/rp_measurement.c +230 -0
  17. data/ext/ruby_prof/rp_measurement.h +50 -0
  18. data/ext/ruby_prof/rp_method.c +389 -389
  19. data/ext/ruby_prof/rp_method.h +34 -39
  20. data/ext/ruby_prof/rp_profile.c +895 -0
  21. data/ext/ruby_prof/rp_profile.h +37 -0
  22. data/ext/ruby_prof/rp_stack.c +103 -80
  23. data/ext/ruby_prof/rp_stack.h +5 -12
  24. data/ext/ruby_prof/rp_thread.c +143 -83
  25. data/ext/ruby_prof/rp_thread.h +15 -6
  26. data/ext/ruby_prof/ruby_prof.c +11 -757
  27. data/ext/ruby_prof/ruby_prof.h +4 -47
  28. data/ext/ruby_prof/vc/ruby_prof.vcxproj +10 -8
  29. data/lib/{2.6.3 → 2.6.5}/ruby_prof.so +0 -0
  30. data/lib/ruby-prof.rb +2 -18
  31. data/lib/ruby-prof/assets/call_stack_printer.html.erb +713 -0
  32. data/lib/ruby-prof/assets/call_stack_printer.png +0 -0
  33. data/lib/ruby-prof/assets/graph_printer.html.erb +356 -0
  34. data/lib/ruby-prof/call_info.rb +35 -93
  35. data/lib/ruby-prof/call_info_visitor.rb +19 -21
  36. data/lib/ruby-prof/compatibility.rb +37 -107
  37. data/lib/ruby-prof/exclude_common_methods.rb +198 -0
  38. data/lib/ruby-prof/measurement.rb +14 -0
  39. data/lib/ruby-prof/method_info.rb +52 -83
  40. data/lib/ruby-prof/printers/abstract_printer.rb +73 -50
  41. data/lib/ruby-prof/printers/call_info_printer.rb +13 -3
  42. data/lib/ruby-prof/printers/call_stack_printer.rb +62 -145
  43. data/lib/ruby-prof/printers/call_tree_printer.rb +20 -12
  44. data/lib/ruby-prof/printers/dot_printer.rb +5 -5
  45. data/lib/ruby-prof/printers/flat_printer.rb +6 -24
  46. data/lib/ruby-prof/printers/graph_html_printer.rb +6 -192
  47. data/lib/ruby-prof/printers/graph_printer.rb +13 -15
  48. data/lib/ruby-prof/printers/multi_printer.rb +66 -23
  49. data/lib/ruby-prof/profile.rb +10 -3
  50. data/lib/ruby-prof/rack.rb +0 -3
  51. data/lib/ruby-prof/thread.rb +12 -12
  52. data/lib/ruby-prof/version.rb +1 -1
  53. data/ruby-prof.gemspec +2 -2
  54. data/test/abstract_printer_test.rb +0 -27
  55. data/test/alias_test.rb +129 -0
  56. data/test/basic_test.rb +41 -40
  57. data/test/call_info_visitor_test.rb +3 -3
  58. data/test/dynamic_method_test.rb +0 -2
  59. data/test/fiber_test.rb +11 -17
  60. data/test/gc_test.rb +96 -0
  61. data/test/line_number_test.rb +120 -39
  62. data/test/marshal_test.rb +119 -0
  63. data/test/measure_allocations.rb +30 -0
  64. data/test/measure_allocations_test.rb +371 -12
  65. data/test/measure_allocations_trace_test.rb +385 -0
  66. data/test/measure_memory_trace_test.rb +756 -0
  67. data/test/measure_process_time_test.rb +821 -33
  68. data/test/measure_times.rb +54 -0
  69. data/test/measure_wall_time_test.rb +349 -145
  70. data/test/multi_printer_test.rb +1 -34
  71. data/test/parser_timings.rb +24 -0
  72. data/test/pause_resume_test.rb +5 -5
  73. data/test/prime.rb +2 -0
  74. data/test/printer_call_stack_test.rb +28 -0
  75. data/test/printer_call_tree_test.rb +31 -0
  76. data/test/printer_flat_test.rb +68 -0
  77. data/test/printer_graph_html_test.rb +60 -0
  78. data/test/printer_graph_test.rb +41 -0
  79. data/test/printers_test.rb +32 -166
  80. data/test/printing_recursive_graph_test.rb +26 -72
  81. data/test/recursive_test.rb +72 -77
  82. data/test/stack_printer_test.rb +2 -15
  83. data/test/start_stop_test.rb +22 -25
  84. data/test/test_helper.rb +5 -248
  85. data/test/thread_test.rb +11 -54
  86. data/test/unique_call_path_test.rb +16 -28
  87. data/test/yarv_test.rb +1 -0
  88. metadata +28 -36
  89. data/examples/flat.txt +0 -50
  90. data/examples/graph.dot +0 -84
  91. data/examples/graph.html +0 -823
  92. data/examples/graph.txt +0 -139
  93. data/examples/multi.flat.txt +0 -23
  94. data/examples/multi.graph.html +0 -760
  95. data/examples/multi.grind.dat +0 -114
  96. data/examples/multi.stack.html +0 -547
  97. data/examples/stack.html +0 -547
  98. data/ext/ruby_prof/rp_measure.c +0 -40
  99. data/ext/ruby_prof/rp_measure.h +0 -45
  100. data/ext/ruby_prof/rp_measure_cpu_time.c +0 -136
  101. data/ext/ruby_prof/rp_measure_gc_runs.c +0 -73
  102. data/ext/ruby_prof/rp_measure_gc_time.c +0 -60
  103. data/lib/ruby-prof/aggregate_call_info.rb +0 -76
  104. data/lib/ruby-prof/assets/call_stack_printer.css.html +0 -117
  105. data/lib/ruby-prof/assets/call_stack_printer.js.html +0 -385
  106. data/lib/ruby-prof/printers/flat_printer_with_line_numbers.rb +0 -83
  107. data/lib/ruby-prof/profile/exclude_common_methods.rb +0 -207
  108. data/lib/ruby-prof/profile/legacy_method_elimination.rb +0 -50
  109. data/test/aggregate_test.rb +0 -136
  110. data/test/block_test.rb +0 -74
  111. data/test/call_info_test.rb +0 -78
  112. data/test/issue137_test.rb +0 -63
  113. data/test/measure_cpu_time_test.rb +0 -212
  114. data/test/measure_gc_runs_test.rb +0 -32
  115. data/test/measure_gc_time_test.rb +0 -36
  116. data/test/measure_memory_test.rb +0 -33
  117. data/test/method_elimination_test.rb +0 -84
  118. data/test/module_test.rb +0 -45
  119. data/test/stack_test.rb +0 -138
@@ -5,56 +5,13 @@
5
5
  #define __RUBY_PROF_H__
6
6
 
7
7
  #include <ruby.h>
8
+ #include <ruby/debug.h>
8
9
  #include <stdio.h>
9
-
10
- #if RUBY_PROF_RUBY_VERSION == 10806
11
- # error 1.8.6 is not supported. Please upgrade to 1.9.3 or higher.
12
- #endif
13
-
14
- #if RUBY_PROF_RUBY_VERSION == 10807
15
- # error 1.8.7 is not supported. Please upgrade to 1.9.3 or higher.
16
- #endif
17
-
18
- #if RUBY_PROF_RUBY_VERSION == 10900
19
- # error 1.9.0 is not supported. Please upgrade to 1.9.3 or higher.
20
- #endif
21
-
22
- #if RUBY_PROF_RUBY_VERSION == 10901
23
- # error 1.9.1 is not supported. Please upgrade to 1.9.3 or higher.
24
- #endif
25
-
26
- #if RUBY_PROF_RUBY_VERSION == 10902
27
- # error 1.9.2 is not supported. Please upgrade to 1.9.3 or higher.
28
- #endif
29
-
30
- #include "rp_measure.h"
31
- #include "rp_method.h"
32
- #include "rp_call_info.h"
33
- #include "rp_stack.h"
34
- #include "rp_thread.h"
10
+ #include <stdbool.h>
35
11
 
36
12
  extern VALUE mProf;
37
- extern VALUE cProfile;
38
-
39
- void method_key(prof_method_key_t* key, VALUE klass, ID mid);
40
-
41
- typedef struct
42
- {
43
- VALUE running;
44
- VALUE paused;
45
-
46
- prof_measurer_t* measurer;
47
- VALUE threads;
48
-
49
- st_table* threads_tbl;
50
- st_table* exclude_threads_tbl;
51
- st_table* include_threads_tbl;
52
- st_table* exclude_methods_tbl;
53
- thread_data_t* last_thread_data;
54
- double measurement_at_pause_resume;
55
- int merge_fibers;
56
- int allow_exceptions;
57
- } prof_profile_t;
58
13
 
14
+ // This method is not exposed in Ruby header files - at least not as of Ruby 2.6.3 :(
15
+ extern size_t rb_obj_memsize_of(VALUE);
59
16
 
60
17
  #endif //__RUBY_PROF_H__
@@ -64,7 +64,7 @@
64
64
  </PropertyGroup>
65
65
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
66
66
  <TargetExt>.so</TargetExt>
67
- <OutDir>..</OutDir>
67
+ <OutDir>..\</OutDir>
68
68
  </PropertyGroup>
69
69
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
70
70
  <ClCompile>
@@ -102,35 +102,37 @@
102
102
  </ItemDefinitionGroup>
103
103
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
104
104
  <ClCompile>
105
- <AdditionalIncludeDirectories>C:\msys64\usr\local\ruby263vc\include\ruby-2.6.0\x64-mswin64_140;C:\msys64\usr\local\ruby263vc\include\ruby-2.6.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
105
+ <AdditionalIncludeDirectories>C:\msys64\usr\local\ruby-2.6.5vc\include\ruby-2.6.0\x64-mswin64_140;C:\msys64\usr\local\ruby-2.6.5vc\include\ruby-2.6.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
106
106
  <Optimization>Disabled</Optimization>
107
+ <PreprocessorDefinitions>HAVE_RB_TRACEARG_CALLEE_ID;%(PreprocessorDefinitions)</PreprocessorDefinitions>
107
108
  </ClCompile>
108
109
  <Link>
109
- <AdditionalLibraryDirectories>C:\msys64\usr\local\ruby263vc\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
110
+ <AdditionalLibraryDirectories>C:\msys64\usr\local\ruby-2.6.5vc\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
110
111
  <AdditionalDependencies>x64-vcruntime140-ruby260.lib;%(AdditionalDependencies)</AdditionalDependencies>
111
112
  <ModuleDefinitionFile>ruby_prof.def</ModuleDefinitionFile>
112
113
  </Link>
113
114
  </ItemDefinitionGroup>
114
115
  <ItemGroup>
116
+ <ClInclude Include="..\rp_allocation.h" />
115
117
  <ClInclude Include="..\rp_call_info.h" />
116
- <ClInclude Include="..\rp_measure.h" />
118
+ <ClInclude Include="..\rp_measurement.h" />
117
119
  <ClInclude Include="..\rp_method.h" />
120
+ <ClInclude Include="..\rp_profile.h" />
118
121
  <ClInclude Include="..\rp_stack.h" />
119
122
  <ClInclude Include="..\rp_thread.h" />
120
123
  <ClInclude Include="..\ruby_prof.h" />
121
124
  <ClInclude Include="..\version.h" />
122
125
  </ItemGroup>
123
126
  <ItemGroup>
127
+ <ClCompile Include="..\rp_allocation.c" />
124
128
  <ClCompile Include="..\rp_call_info.c" />
125
- <ClCompile Include="..\rp_measure.c" />
129
+ <ClCompile Include="..\rp_measurement.c" />
126
130
  <ClCompile Include="..\rp_measure_allocations.c" />
127
- <ClCompile Include="..\rp_measure_cpu_time.c" />
128
- <ClCompile Include="..\rp_measure_gc_runs.c" />
129
- <ClCompile Include="..\rp_measure_gc_time.c" />
130
131
  <ClCompile Include="..\rp_measure_memory.c" />
131
132
  <ClCompile Include="..\rp_measure_process_time.c" />
132
133
  <ClCompile Include="..\rp_measure_wall_time.c" />
133
134
  <ClCompile Include="..\rp_method.c" />
135
+ <ClCompile Include="..\rp_profile.c" />
134
136
  <ClCompile Include="..\rp_stack.c" />
135
137
  <ClCompile Include="..\rp_thread.c" />
136
138
  <ClCompile Include="..\ruby_prof.c" />
Binary file
data/lib/ruby-prof.rb CHANGED
@@ -8,26 +8,16 @@ rescue LoadError
8
8
  require "ruby_prof.so"
9
9
  end
10
10
 
11
- module RubyProf
12
- module DeprecationWarnings
13
- def deprecation_warning(feature, recommendation = nil)
14
- $stderr.puts "DEPRECATION WARNING: #{feature}"
15
- $stderr.puts recommendation unless recommendation.nil?
16
- end
17
- end
18
- extend DeprecationWarnings
19
- end
20
-
21
11
  require 'ruby-prof/version'
22
12
  require 'ruby-prof/call_info'
23
13
  require 'ruby-prof/compatibility'
14
+ require 'ruby-prof/measurement'
24
15
  require 'ruby-prof/method_info'
25
16
  require 'ruby-prof/profile'
26
17
  require 'ruby-prof/rack'
27
18
  require 'ruby-prof/thread'
28
19
 
29
20
  module RubyProf
30
- autoload :AggregateCallInfo, 'ruby-prof/aggregate_call_info'
31
21
  autoload :CallInfoVisitor, 'ruby-prof/call_info_visitor'
32
22
 
33
23
  autoload :AbstractPrinter, 'ruby-prof/printers/abstract_printer'
@@ -36,29 +26,23 @@ module RubyProf
36
26
  autoload :CallTreePrinter, 'ruby-prof/printers/call_tree_printer'
37
27
  autoload :DotPrinter, 'ruby-prof/printers/dot_printer'
38
28
  autoload :FlatPrinter, 'ruby-prof/printers/flat_printer'
39
- autoload :FlatPrinterWithLineNumbers, 'ruby-prof/printers/flat_printer_with_line_numbers'
40
29
  autoload :GraphHtmlPrinter, 'ruby-prof/printers/graph_html_printer'
41
30
  autoload :GraphPrinter, 'ruby-prof/printers/graph_printer'
42
31
  autoload :MultiPrinter, 'ruby-prof/printers/multi_printer'
43
32
 
33
+ # :nodoc:
44
34
  # Checks if the user specified the clock mode via
45
35
  # the RUBY_PROF_MEASURE_MODE environment variable
46
36
  def self.figure_measure_mode
47
37
  case ENV["RUBY_PROF_MEASURE_MODE"]
48
38
  when "wall", "wall_time"
49
39
  RubyProf.measure_mode = RubyProf::WALL_TIME
50
- when "cpu", "cpu_time"
51
- RubyProf.measure_mode = RubyProf::CPU_TIME
52
40
  when "allocations"
53
41
  RubyProf.measure_mode = RubyProf::ALLOCATIONS
54
42
  when "memory"
55
43
  RubyProf.measure_mode = RubyProf::MEMORY
56
44
  when "process", "process_time"
57
45
  RubyProf.measure_mode = RubyProf::PROCESS_TIME
58
- when "gc_time"
59
- RubyProf.measure_mode = RubyProf::GC_TIME
60
- when "gc_runs"
61
- RubyProf.measure_mode = RubyProf::GC_RUNS
62
46
  else
63
47
  # the default is defined in the measure_mode reader
64
48
  end
@@ -0,0 +1,713 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
5
+ <title>ruby-prof call tree</title>
6
+ <style type="text/css">
7
+ body {
8
+ font-size: 70%;
9
+ padding: 0;
10
+ margin: 5px;
11
+ margin-right: 0px;
12
+ margin-left: 0px;
13
+ background: #ffffff;
14
+ }
15
+
16
+ ul {
17
+ margin-left: 0px;
18
+ margin-top: 0px;
19
+ margin-bottom: 0px;
20
+ padding-left: 0px;
21
+ list-style-type: none;
22
+ }
23
+
24
+ li {
25
+ margin-left: 11px;
26
+ padding: 0px;
27
+ white-space: nowrap;
28
+ border-top: 1px solid #cccccc;
29
+ border-left: 1px solid #cccccc;
30
+ border-bottom: none;
31
+ }
32
+
33
+ .thread {
34
+ margin-left: 11px;
35
+ background: #708090;
36
+ padding-top: 3px;
37
+ padding-left: 12px;
38
+ padding-bottom: 2px;
39
+ border-left: 1px solid #CCCCCC;
40
+ border-top: 1px solid #CCCCCC;
41
+ font-weight: bold;
42
+ }
43
+
44
+ .hidden {
45
+ display: none;
46
+ width: 0px;
47
+ height: 0px;
48
+ margin: 0px;
49
+ padding: 0px;
50
+ border-style: none;
51
+ }
52
+
53
+ .color01 {
54
+ background: #adbdeb
55
+ }
56
+
57
+ .color05 {
58
+ background: #9daddb
59
+ }
60
+
61
+ .color0 {
62
+ background: #8d9dcb
63
+ }
64
+
65
+ .color1 {
66
+ background: #89bccb
67
+ }
68
+
69
+ .color2 {
70
+ background: #56e3e7
71
+ }
72
+
73
+ .color3 {
74
+ background: #32cd70
75
+ }
76
+
77
+ .color4 {
78
+ background: #a3d53c
79
+ }
80
+
81
+ .color5 {
82
+ background: #c4cb34
83
+ }
84
+
85
+ .color6 {
86
+ background: #dcb66d
87
+ }
88
+
89
+ .color7 {
90
+ background: #cda59e
91
+ }
92
+
93
+ .color8 {
94
+ background: #be9d9c
95
+ }
96
+
97
+ .color9 {
98
+ background: #cf947a
99
+ }
100
+
101
+ #commands {
102
+ font-size: 10pt;
103
+ padding: 10px;
104
+ margin-left: 11px;
105
+ margin-bottom: 0px;
106
+ margin-top: 0px;
107
+ background: #708090;
108
+ border-top: 1px solid #cccccc;
109
+ border-left: 1px solid #cccccc;
110
+ border-bottom: none;
111
+ }
112
+
113
+ #titlebar {
114
+ font-size: 10pt;
115
+ padding: 10px;
116
+ margin-left: 11px;
117
+ margin-bottom: 0px;
118
+ margin-top: 10px;
119
+ background: #8090a0;
120
+ border-top: 1px solid #cccccc;
121
+ border-left: 1px solid #cccccc;
122
+ border-bottom: none;
123
+ }
124
+
125
+ #help {
126
+ font-size: 10pt;
127
+ padding: 10px;
128
+ margin-left: 11px;
129
+ margin-bottom: 0px;
130
+ margin-top: 0px;
131
+ background: #8090a0;
132
+ display: none;
133
+ border-top: 1px solid #cccccc;
134
+ border-left: 1px solid #cccccc;
135
+ border-bottom: none;
136
+ }
137
+
138
+ #sentinel {
139
+ height: 400px;
140
+ margin-left: 11px;
141
+ background: #8090a0;
142
+ border-top: 1px solid #cccccc;
143
+ border-left: 1px solid #cccccc;
144
+ border-bottom: none;
145
+ }
146
+
147
+ input {
148
+ margin-left: 10px;
149
+ }
150
+
151
+ .toggle {
152
+ background: url(data:image/png;base64,<%= base64_image %>) no-repeat left center;
153
+ float: left;
154
+ width: 9px;
155
+ height: 9px;
156
+ margin: 2px 1px 1px 1px;
157
+ }
158
+
159
+ .toggle.minus {
160
+ background-position: -9px 0;
161
+ }
162
+
163
+ .toggle.plus {
164
+ background-position: -18px 0;
165
+ }
166
+ </style>
167
+
168
+ <script type="text/javascript">
169
+ function rootNode()
170
+ {
171
+ return currentThread
172
+ }
173
+
174
+ function showUL(node, show)
175
+ {
176
+ Array.prototype.forEach.call(node.childNodes, function(child)
177
+ {
178
+ if (child.nodeName == 'LI')
179
+ toggle(child, show)
180
+ })
181
+ }
182
+
183
+ function findUlChild(li)
184
+ {
185
+ var ul = li.childNodes[2]
186
+ while (ul && ul.nodeName != "UL")
187
+ {
188
+ ul = ul.nextSibling
189
+ }
190
+ return ul
191
+ }
192
+
193
+ function isLeafNode(li)
194
+ {
195
+ var element = li.querySelector('a')
196
+ return element.classList.contains('empty')
197
+ }
198
+
199
+ function toggle(li, show)
200
+ {
201
+ if (isLeafNode(li))
202
+ return
203
+
204
+ var img = li.firstChild
205
+ img.className = 'toggle '
206
+ img.className += show ? 'minus' : 'plus'
207
+
208
+ var ul = findUlChild(li)
209
+ if (ul)
210
+ {
211
+ ul.style.display = show ? 'block' : 'none'
212
+ showUL(ul, true)
213
+ }
214
+ }
215
+
216
+ function toggleLI(li)
217
+ {
218
+ var img = li.firstChild
219
+ if (img.className.indexOf("minus") > -1)
220
+ toggle(li, false)
221
+ else
222
+ {
223
+ if (img.className.indexOf("plus") > -1)
224
+ toggle(li, true)
225
+ }
226
+ }
227
+
228
+ function aboveThreshold(text, threshold)
229
+ {
230
+ var match = text.match(/\d+[.,]\d+%/)
231
+ if (!match)
232
+ {
233
+ return true
234
+ }
235
+ else
236
+ {
237
+ var value = parseFloat(match[0].replace(/,/, '.'))
238
+ return value >= threshold
239
+ }
240
+ }
241
+
242
+ function setThresholdLI(li, threshold)
243
+ {
244
+ var a = li.querySelector('a')
245
+ var span = li.querySelector('span')
246
+ var ul = li.querySelector('ul')
247
+
248
+ var visible = aboveThreshold(span.textContent, threshold) ? 1 : 0
249
+
250
+ var count = 0
251
+ if (ul)
252
+ {
253
+ count = setThresholdUL(ul, threshold)
254
+ }
255
+
256
+ if (count > 0)
257
+ {
258
+ a.className = 'toggle minus'
259
+ }
260
+ else
261
+ {
262
+ a.className = 'toggle empty'
263
+ }
264
+
265
+ if (visible)
266
+ {
267
+ li.style.display = 'block'
268
+ } else
269
+ {
270
+ li.style.display = 'none'
271
+ }
272
+ return visible
273
+ }
274
+
275
+ function setThresholdUL(node, threshold)
276
+ {
277
+ var count = 0
278
+ Array.prototype.forEach.call(node.childNodes, function(child)
279
+ {
280
+ if (child.nodeName == 'LI')
281
+ count = count + setThresholdLI(child, threshold)
282
+ })
283
+
284
+ var visible = (count > 0) ? 1 : 0
285
+ if (visible)
286
+ {
287
+ node.style.display = 'block'
288
+ } else
289
+ {
290
+ node.style.display = 'none'
291
+ }
292
+ return visible
293
+ }
294
+
295
+ function toggleChildren(img, event)
296
+ {
297
+ event.cancelBubble = true
298
+ if (img.className.indexOf('empty') > -1)
299
+ return
300
+
301
+ var minus = (img.className.indexOf('minus') > -1)
302
+
303
+ if (minus)
304
+ {
305
+ img.className = 'toggle plus'
306
+ } else
307
+ img.className = 'toggle minus'
308
+
309
+ var li = img.parentNode
310
+ var ul = findUlChild(li)
311
+ if (ul)
312
+ {
313
+ if (minus)
314
+ ul.style.display = 'none'
315
+ else
316
+ ul.style.display = 'block'
317
+ }
318
+ if (minus)
319
+ moveSelectionIfNecessary(li)
320
+ }
321
+
322
+ function showChildren(li)
323
+ {
324
+ var img = li.firstChild
325
+ if (img.className.indexOf('empty') > -1)
326
+ return
327
+ img.className = 'toggle minus'
328
+
329
+ var ul = findUlChild(li)
330
+ if (ul)
331
+ {
332
+ ul.style.display = 'block'
333
+ }
334
+ }
335
+
336
+ function setThreshold()
337
+ {
338
+ var tv = document.getElementById("threshold").value
339
+ if (tv.match(/[0-9]+([.,][0-9]+)?/))
340
+ {
341
+ var f = parseFloat(tv.replace(/,/, '.'))
342
+ var threads = document.getElementsByName("thread")
343
+ var l = threads.length
344
+ for (var i = 0; i < l; i++)
345
+ {
346
+ setThresholdUL(threads[i], f)
347
+ }
348
+ var p = selectedNode
349
+ while (p && p.style.display == 'none')
350
+ p = p.parentNode.parentNode
351
+ if (p && p.nodeName == "LI")
352
+ selectNode(p)
353
+ } else
354
+ {
355
+ alert("Please specify a decimal number as threshold value!")
356
+ }
357
+ }
358
+
359
+ function expandAll(event)
360
+ {
361
+ toggleAll(event, true)
362
+ }
363
+
364
+ function collapseAll(event)
365
+ {
366
+ toggleAll(event, false)
367
+ selectNode(rootNode(), null)
368
+ }
369
+
370
+ function toggleAll(event, show)
371
+ {
372
+ event.cancelBubble = true
373
+ var threads = document.getElementsByName("thread")
374
+ var l = threads.length
375
+ for (var i = 0; i < l; i++)
376
+ {
377
+ showUL(threads[i], show)
378
+ }
379
+ }
380
+
381
+ function toggleHelp(node)
382
+ {
383
+ var help = document.getElementById("help")
384
+ if (node.value == "Show Help")
385
+ {
386
+ node.value = "Hide Help"
387
+ help.style.display = 'block'
388
+ } else
389
+ {
390
+ node.value = "Show Help"
391
+ help.style.display = 'none'
392
+ }
393
+ }
394
+
395
+ var selectedNode = null
396
+ var selectedColor = null
397
+ var selectedThread = null
398
+
399
+ function descendentOf(a, b)
400
+ {
401
+ while (a != b && b != null)
402
+ b = b.parentNode
403
+ return (a == b)
404
+ }
405
+
406
+ function moveSelectionIfNecessary(node)
407
+ {
408
+ if (descendentOf(node, selectedNode))
409
+ selectNode(node, null)
410
+ }
411
+
412
+ function selectNode(node, event)
413
+ {
414
+ if (event)
415
+ {
416
+ event.cancelBubble = true
417
+ thread = findThread(node)
418
+ selectThread(thread)
419
+ }
420
+ if (selectedNode)
421
+ {
422
+ selectedNode.style.background = selectedColor
423
+ }
424
+ selectedNode = node
425
+ selectedColor = node.style.background
426
+ selectedNode.style.background = "red"
427
+ selectedNode.scrollIntoView()
428
+ window.scrollBy(0, -400)
429
+ }
430
+
431
+ function moveUp()
432
+ {
433
+ move(selectedNode.previousSibling)
434
+ }
435
+
436
+ function moveDown()
437
+ {
438
+ move(selectedNode.nextSibling)
439
+ }
440
+
441
+ function move(p)
442
+ {
443
+ while (p && p.style.display == 'none')
444
+ p = p.nextSibling
445
+ if (p && p.nodeName == "LI")
446
+ {
447
+ selectNode(p, null)
448
+ }
449
+ }
450
+
451
+ function moveLeft()
452
+ {
453
+ var p = selectedNode.parentNode.parentNode
454
+ if (p && p.nodeName == "LI")
455
+ {
456
+ selectNode(p, null)
457
+ }
458
+ }
459
+
460
+ function moveRight()
461
+ {
462
+ if (!isLeafNode(selectedNode))
463
+ {
464
+ showChildren(selectedNode)
465
+ var ul = findUlChild(selectedNode)
466
+ if (ul)
467
+ {
468
+ selectNode(ul.firstChild, null)
469
+ }
470
+ }
471
+ }
472
+
473
+ function moveForward()
474
+ {
475
+ if (isLeafNode(selectedNode))
476
+ {
477
+ var p = selectedNode
478
+ while ((p.nextSibling == null || p.nextSibling.style.display == 'none') && p.nodeName == "LI")
479
+ {
480
+ p = p.parentNode.parentNode
481
+ }
482
+ if (p.nodeName == "LI")
483
+ selectNode(p.nextSibling, null)
484
+ } else
485
+ {
486
+ moveRight()
487
+ }
488
+ }
489
+
490
+ function isExpandedNode(li)
491
+ {
492
+ var img = li.firstChild
493
+ return (img.className.indexOf('minus') > -1)
494
+ }
495
+
496
+ function moveBackward()
497
+ {
498
+ var p = selectedNode
499
+ var q = p.previousSibling
500
+ while (q != null && q.style.display == 'none')
501
+ q = q.previousSibling
502
+ if (q == null)
503
+ {
504
+ p = p.parentNode.parentNode
505
+ } else
506
+ {
507
+ while (!isLeafNode(q) && isExpandedNode(q))
508
+ {
509
+ q = findUlChild(q).lastChild
510
+ while (q.style.display == 'none')
511
+ q = q.previousSibling
512
+ }
513
+ p = q
514
+ }
515
+ if (p.nodeName == "LI")
516
+ selectNode(p, null)
517
+ }
518
+
519
+ function moveHome()
520
+ {
521
+ selectNode(currentThread)
522
+ }
523
+
524
+ var currentThreadIndex = null
525
+
526
+ function findThread(node)
527
+ {
528
+ while (node && !node.parentNode.nodeName.match(/BODY|DIV/g))
529
+ {
530
+ node = node.parentNode
531
+ }
532
+ return node.firstChild
533
+ }
534
+
535
+ function selectThread(node)
536
+ {
537
+ var threads = document.getElementsByName("thread")
538
+ currentThread = node
539
+ for (var i = 0; i < threads.length; i++)
540
+ {
541
+ if (threads[i] == currentThread.parentNode)
542
+ currentThreadIndex = i
543
+ }
544
+ }
545
+
546
+ function nextThread()
547
+ {
548
+ var threads = document.getElementsByName("thread")
549
+ if (currentThreadIndex == threads.length - 1)
550
+ currentThreadIndex = 0
551
+ else
552
+ currentThreadIndex += 1
553
+ currentThread = threads[currentThreadIndex].firstChild
554
+ selectNode(currentThread, null)
555
+ }
556
+
557
+ function previousThread()
558
+ {
559
+ var threads = document.getElementsByName("thread")
560
+ if (currentThreadIndex == 0)
561
+ currentThreadIndex = threads.length - 1
562
+ else
563
+ currentThreadIndex -= 1
564
+ currentThread = threads[currentThreadIndex].firstChild
565
+ selectNode(currentThread, null)
566
+ }
567
+
568
+ function switchThread(node, event)
569
+ {
570
+ event.cancelBubble = true
571
+ selectThread(node.nextSibling.firstChild)
572
+ selectNode(currentThread, null)
573
+ }
574
+
575
+ function handleKeyEvent(event)
576
+ {
577
+ var code = event.charCode ? event.charCode : event.keyCode
578
+ var str = String.fromCharCode(code)
579
+ switch (str)
580
+ {
581
+ case "a":
582
+ moveLeft()
583
+ break
584
+ case "s":
585
+ moveDown()
586
+ break
587
+ case "d":
588
+ moveRight()
589
+ break
590
+ case "w":
591
+ moveUp()
592
+ break
593
+ case "f":
594
+ moveForward()
595
+ break
596
+ case "b":
597
+ moveBackward()
598
+ break
599
+ case "x":
600
+ toggleChildren(selectedNode.firstChild, event)
601
+ break
602
+ case "*":
603
+ toggleLI(selectedNode)
604
+ break
605
+ case "n":
606
+ nextThread()
607
+ break
608
+ case "h":
609
+ moveHome()
610
+ break
611
+ case "p":
612
+ previousThread()
613
+ break
614
+ }
615
+ }
616
+
617
+ document.onkeypress = function (event)
618
+ {
619
+ handleKeyEvent(event)
620
+ }
621
+
622
+ window.onload = function ()
623
+ {
624
+ var images = document.querySelectorAll(".toggle")
625
+ for (var i = 0; i < images.length; i++)
626
+ {
627
+ var img = images[i]
628
+ img.onclick = function (event)
629
+ {
630
+ toggleChildren(this, event)
631
+ return false
632
+ }
633
+ }
634
+ var divs = document.getElementsByTagName("div")
635
+ for (i = 0; i < divs.length; i++)
636
+ {
637
+ var div = divs[i]
638
+ if (div.className == "thread")
639
+ div.onclick = function (event)
640
+ {
641
+ switchThread(this, event)
642
+ }
643
+ }
644
+ var lis = document.getElementsByTagName("li")
645
+ for (var i = 0; i < lis.length; i++)
646
+ {
647
+ lis[i].onclick = function (event)
648
+ {
649
+ selectNode(this, event)
650
+ }
651
+ }
652
+
653
+ var threads = document.getElementsByName("thread")
654
+ currentThreadIndex = 0
655
+ currentThread = threads[0].querySelector('li')
656
+ selectNode(currentThread, null)
657
+ }
658
+ </script>
659
+
660
+ <% @overall_time = @result.threads.reduce(0) do |val, thread|
661
+ val += thread.total_time
662
+ end %>
663
+ </head>
664
+ <body>
665
+ <div style="display: inline-block;">
666
+ <div id="titlebar">
667
+ Call tree for application <strong><%= application %> <%= arguments %></strong><br/> Generated on <%= Time.now %>
668
+ with options <%= @options.inspect %><br/>
669
+ </div>
670
+ <div id="commands">
671
+ <span style="font-size: 11pt; font-weight: bold;">Threshold:</span>
672
+ <input value="1.0" size="3" id="threshold" type="text">
673
+ <input value="Apply" onclick="setThreshold();" type="submit">
674
+ <input value="Expand All" onclick="expandAll(event);" type="submit">
675
+ <input value="Collapse All" onclick="collapseAll(event);" type="submit">
676
+ <input value="Show Help" onclick="toggleHelp(this);" type="submit">
677
+ </div>
678
+ <ul style="display: none;" id="help">
679
+ <li>* indicates recursively called methods</li>
680
+ <li>Enter a decimal value <i>d</i> into the threshold field and click "Apply" to hide all nodes marked with time
681
+ values lower than <em>d</em>.
682
+ </li>
683
+ <li>Click on "Expand All" for full tree expansion.</li>
684
+ <li>Click on "Collapse All" to show only top level nodes.</li>
685
+ <li>Use a, s, d, w as in Quake or Urban Terror to navigate the tree.</li>
686
+ <li>Use f and b to navigate the tree in preorder forward and backwards.</li>
687
+ <li>Use x to toggle visibility of a subtree.</li>
688
+ <li>Use * to expand/collapse a whole subtree.</li>
689
+ <li>Use h to navigate to thread root.</li>
690
+ <li>Use n and p to navigate between threads.</li>
691
+ <li>Click on background to move focus to a subtree.</li>
692
+ </ul>
693
+
694
+ <% @result.threads.each do |thread| %>
695
+ <% thread_percent = 100 * (thread.total_time / @overall_time)
696
+ thread_info = "#{"%4.2f%%" % thread_percent} ~ #{@overall_time}" %>
697
+ <div class="thread">
698
+ <span>Thread: <%= thread.id %>, Fiber: <%= thread.fiber_id %> (<%= thread_info %>)</span>
699
+ <ul name="thread">
700
+ <% call_infos = thread.root_methods.map(&:callers).flatten %>
701
+ <% call_infos.each do |call_info| %>
702
+ <% visited = Set.new
703
+ output = StringIO.new('')
704
+ print_stack(output, visited, call_info, call_info.total_time) %>
705
+ <%= output.string %>
706
+ <% end %>
707
+ </ul>
708
+ </div>
709
+ <% end %>
710
+ <div id="sentinel"></div>
711
+ </div>
712
+ </body>
713
+ </html>