ruby-prof 0.15.4 → 0.15.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +7 -1
  3. data/README.rdoc +1 -1
  4. data/bin/ruby-prof +16 -4
  5. data/doc/LICENSE.html +114 -0
  6. data/doc/README_rdoc.html +592 -0
  7. data/doc/Rack.html +95 -0
  8. data/doc/Rack/RubyProf.html +264 -0
  9. data/doc/RubyProf.html +962 -0
  10. data/doc/RubyProf/AbstractPrinter.html +546 -0
  11. data/doc/RubyProf/AggregateCallInfo.html +537 -0
  12. data/doc/RubyProf/CallInfo.html +468 -0
  13. data/doc/RubyProf/CallInfoPrinter.html +120 -0
  14. data/doc/RubyProf/CallInfoVisitor.html +200 -0
  15. data/doc/RubyProf/CallStackPrinter.html +1604 -0
  16. data/doc/RubyProf/CallTreePrinter.html +359 -0
  17. data/doc/RubyProf/Cmd.html +631 -0
  18. data/doc/RubyProf/DotPrinter.html +257 -0
  19. data/doc/RubyProf/FlatPrinter.html +163 -0
  20. data/doc/RubyProf/FlatPrinterWithLineNumbers.html +208 -0
  21. data/doc/RubyProf/GraphHtmlPrinter.html +575 -0
  22. data/doc/RubyProf/GraphPrinter.html +139 -0
  23. data/doc/RubyProf/MethodInfo.html +685 -0
  24. data/doc/RubyProf/MultiPrinter.html +358 -0
  25. data/doc/RubyProf/Profile.html +764 -0
  26. data/doc/RubyProf/ProfileTask.html +490 -0
  27. data/doc/RubyProf/Thread.html +199 -0
  28. data/doc/created.rid +14 -14
  29. data/doc/examples/flat_txt.html +149 -0
  30. data/doc/examples/graph_html.html +850 -0
  31. data/doc/examples/graph_txt.html +274 -0
  32. data/doc/images/add.png +0 -0
  33. data/doc/images/arrow_up.png +0 -0
  34. data/doc/images/brick.png +0 -0
  35. data/doc/images/brick_link.png +0 -0
  36. data/doc/images/bug.png +0 -0
  37. data/doc/images/bullet_black.png +0 -0
  38. data/doc/images/bullet_toggle_minus.png +0 -0
  39. data/doc/images/bullet_toggle_plus.png +0 -0
  40. data/doc/images/date.png +0 -0
  41. data/doc/images/delete.png +0 -0
  42. data/doc/images/find.png +0 -0
  43. data/doc/images/macFFBgHack.png +0 -0
  44. data/doc/images/package.png +0 -0
  45. data/doc/images/page_green.png +0 -0
  46. data/doc/images/page_white_text.png +0 -0
  47. data/doc/images/page_white_width.png +0 -0
  48. data/doc/images/plugin.png +0 -0
  49. data/doc/images/ruby.png +0 -0
  50. data/doc/images/tag_blue.png +0 -0
  51. data/doc/images/tag_green.png +0 -0
  52. data/doc/images/transparent.png +0 -0
  53. data/doc/images/wrench.png +0 -0
  54. data/doc/images/wrench_orange.png +0 -0
  55. data/doc/images/zoom.png +0 -0
  56. data/doc/index.html +618 -0
  57. data/doc/js/search_index.js.gz +0 -0
  58. data/doc/table_of_contents.html +859 -0
  59. data/lib/ruby-prof/printers/flat_printer_with_line_numbers.rb +21 -14
  60. data/lib/ruby-prof/printers/graph_printer.rb +1 -0
  61. data/lib/ruby-prof/version.rb +1 -1
  62. data/test/measure_cpu_time_test.rb +1 -1
  63. metadata +54 -2
@@ -0,0 +1,274 @@
1
+ <!DOCTYPE html>
2
+
3
+ <html>
4
+ <head>
5
+ <meta charset="UTF-8">
6
+
7
+ <title>graph - ruby-prof</title>
8
+
9
+ <script type="text/javascript">
10
+ var rdoc_rel_prefix = "../";
11
+ </script>
12
+
13
+ <script src="../js/jquery.js"></script>
14
+ <script src="../js/darkfish.js"></script>
15
+
16
+ <link href="../css/fonts.css" rel="stylesheet">
17
+ <link href="../css/rdoc.css" rel="stylesheet">
18
+
19
+
20
+
21
+ <body id="top" role="document" class="file">
22
+ <nav role="navigation">
23
+ <div id="project-navigation">
24
+ <div id="home-section" role="region" title="Quick navigation" class="nav-section">
25
+ <h2>
26
+ <a href="../index.html" rel="home">Home</a>
27
+ </h2>
28
+
29
+ <div id="table-of-contents-navigation">
30
+ <a href="../table_of_contents.html#pages">Pages</a>
31
+ <a href="../table_of_contents.html#classes">Classes</a>
32
+ <a href="../table_of_contents.html#methods">Methods</a>
33
+ </div>
34
+ </div>
35
+
36
+ <div id="search-section" role="search" class="project-section initially-hidden">
37
+ <form action="#" method="get" accept-charset="utf-8">
38
+ <div id="search-field-wrapper">
39
+ <input id="search-field" role="combobox" aria-label="Search"
40
+ aria-autocomplete="list" aria-controls="search-results"
41
+ type="text" name="search" placeholder="Search" spellcheck="false"
42
+ title="Type to search, Up and Down to navigate, Enter to load">
43
+ </div>
44
+
45
+ <ul id="search-results" aria-label="Search Results"
46
+ aria-busy="false" aria-expanded="false"
47
+ aria-atomic="false" class="initially-hidden"></ul>
48
+ </form>
49
+ </div>
50
+
51
+ </div>
52
+
53
+
54
+ <div class="nav-section">
55
+ <h3>Table of Contents</h3>
56
+
57
+ <ul class="link-list" role="directory">
58
+ <li><a href="#label-Graph+Profiles">Graph Profiles</a>
59
+ <li><a href="#label-Overview">Overview</a>
60
+ <li><a href="#label-Parents">Parents</a>
61
+ <li><a href="#label-Children">Children</a>
62
+ </ul>
63
+ </div>
64
+
65
+
66
+ <div id="project-metadata">
67
+ <div id="fileindex-section" class="nav-section">
68
+ <h3>Pages</h3>
69
+
70
+ <ul class="link-list">
71
+
72
+ <li><a href="../LICENSE.html">LICENSE</a>
73
+
74
+ <li><a href="../README_rdoc.html">README</a>
75
+
76
+ <li><a href="../examples/flat_txt.html">flat</a>
77
+
78
+ <li><a href="../examples/graph_html.html">graph.html</a>
79
+
80
+ <li><a href="../examples/graph_txt.html">graph</a>
81
+
82
+ </ul>
83
+ </div>
84
+
85
+ </div>
86
+ </nav>
87
+
88
+ <main role="main" aria-label="Page examples/graph.txt">
89
+
90
+ <h1 id="label-Graph+Profiles">Graph Profiles<span><a href="#label-Graph+Profiles">&para;</a> <a href="#top">&uarr;</a></span></h1>
91
+
92
+ <p>Graph profiles show how long each method runs, which methods call it and
93
+ which methods it calls.</p>
94
+
95
+ <p>As an example, here is the output from running printers_test.rb:</p>
96
+
97
+ <p>Thread ID: 21277412</p>
98
+
99
+ <pre> %total %self total self children calls Name
100
+ --------------------------------------------------------------------------------
101
+ 100.00% 0.00% 8.77 0.00 8.77 1 #toplevel
102
+ 8.77 0.00 8.77 1/1 Object#run_primes
103
+ --------------------------------------------------------------------------------
104
+ 8.77 0.00 8.77 1/1 #toplevel
105
+ 100.00% 0.00% 8.77 0.00 8.77 1 Object#run_primes
106
+ 0.02 0.00 0.02 1/1 Object#make_random_array
107
+ 2.09 0.00 2.09 1/1 Object#find_largest
108
+ 6.66 0.00 6.66 1/1 Object#find_primes
109
+ --------------------------------------------------------------------------------
110
+ 6.63 4.06 2.56 500/501 Object#is_prime
111
+ 2.09 0.00 2.09 1/501 Object#find_largest
112
+ 99.48% 46.34% 8.72 4.06 4.66 501 Integer#upto
113
+ 0.00 0.00 0.00 61/61 Array#[]
114
+ 0.00 0.00 0.00 61/61 Fixnum#&gt;
115
+ 2.09 2.09 0.00 61/61 Kernel.sleep
116
+ 1.24 1.24 0.00 250862/250862 Fixnum#==
117
+ 1.33 1.33 0.00 250862/250862 Fixnum#%
118
+ --------------------------------------------------------------------------------
119
+ 6.66 0.01 6.64 1/1 Object#find_primes
120
+ 75.93% 0.17% 6.66 0.01 6.64 1 Array#select
121
+ 6.64 0.01 6.63 500/500 Object#is_prime
122
+ --------------------------------------------------------------------------------
123
+ 6.66 0.00 6.66 1/1 Object#run_primes
124
+ 75.93% 0.00% 6.66 0.00 6.66 1 Object#find_primes
125
+ 6.66 0.01 6.64 1/1 Array#select
126
+ --------------------------------------------------------------------------------
127
+ 6.64 0.01 6.63 500/500 Array#select
128
+ 75.76% 0.17% 6.64 0.01 6.63 500 Object#is_prime
129
+ 0.00 0.00 0.00 500/501 Fixnum#-
130
+ 6.63 4.06 2.56 500/501 Integer#upto
131
+ --------------------------------------------------------------------------------
132
+ 2.09 0.00 2.09 1/1 Object#run_primes
133
+ 23.89% 0.00% 2.09 0.00 2.09 1 Object#find_largest
134
+ 0.00 0.00 0.00 1/501 Fixnum#-
135
+ 2.09 0.00 2.09 1/501 Integer#upto
136
+ 0.00 0.00 0.00 1/1 Array#first
137
+ 0.00 0.00 0.00 1/1 Array#length
138
+ --------------------------------------------------------------------------------
139
+ 2.09 2.09 0.00 61/61 Integer#upto
140
+ 23.89% 23.89% 2.09 2.09 0.00 61 Kernel.sleep
141
+ --------------------------------------------------------------------------------
142
+ 1.33 1.33 0.00 250862/250862 Integer#upto
143
+ 15.12% 15.12% 1.33 1.33 0.00 250862 Fixnum#%
144
+ --------------------------------------------------------------------------------
145
+ 1.24 1.24 0.00 250862/250862 Integer#upto
146
+ 14.13% 14.13% 1.24 1.24 0.00 250862 Fixnum#==
147
+ --------------------------------------------------------------------------------
148
+ 0.02 0.00 0.02 1/1 Object#run_primes
149
+ 0.18% 0.00% 0.02 0.00 0.02 1 Object#make_random_array
150
+ 0.02 0.02 0.00 1/1 Array#each_index
151
+ 0.00 0.00 0.00 1/1 Class#new
152
+ --------------------------------------------------------------------------------
153
+ 0.02 0.02 0.00 1/1 Object#make_random_array
154
+ 0.18% 0.18% 0.02 0.02 0.00 1 Array#each_index
155
+ 0.00 0.00 0.00 500/500 Kernel.rand
156
+ 0.00 0.00 0.00 500/500 Array#[]=
157
+ --------------------------------------------------------------------------------
158
+ 0.00 0.00 0.00 500/501 Object#is_prime
159
+ 0.00 0.00 0.00 1/501 Object#find_largest
160
+ 0.00% 0.00% 0.00 0.00 0.00 501 Fixnum#-
161
+ --------------------------------------------------------------------------------
162
+ 0.00 0.00 0.00 1/1 Kernel.rand
163
+ 0.00% 0.00% 0.00 0.00 0.00 1 Integer#to_int
164
+ --------------------------------------------------------------------------------
165
+ 0.00 0.00 0.00 1/1 Object#find_largest
166
+ 0.00% 0.00% 0.00 0.00 0.00 1 Array#first
167
+ --------------------------------------------------------------------------------
168
+ 0.00 0.00 0.00 1/1 Class#new
169
+ 0.00% 0.00% 0.00 0.00 0.00 1 Array#initialize
170
+ --------------------------------------------------------------------------------
171
+ 0.00 0.00 0.00 1/1 Object#find_largest
172
+ 0.00% 0.00% 0.00 0.00 0.00 1 Array#length
173
+ --------------------------------------------------------------------------------
174
+ 0.00 0.00 0.00 1/1 Object#make_random_array
175
+ 0.00% 0.00% 0.00 0.00 0.00 1 Class#new
176
+ 0.00 0.00 0.00 1/1 Array#initialize
177
+ --------------------------------------------------------------------------------
178
+ 0.00 0.00 0.00 61/61 Integer#upto
179
+ 0.00% 0.00% 0.00 0.00 0.00 61 Fixnum#&gt;
180
+ --------------------------------------------------------------------------------
181
+ 0.00 0.00 0.00 61/61 Integer#upto
182
+ 0.00% 0.00% 0.00 0.00 0.00 61 Array#[]
183
+ --------------------------------------------------------------------------------
184
+ 0.00 0.00 0.00 500/500 Array#each_index
185
+ 0.00% 0.00% 0.00 0.00 0.00 500 Array#[]=
186
+ --------------------------------------------------------------------------------
187
+ 0.00 0.00 0.00 500/500 Array#each_index
188
+ 0.00% 0.00% 0.00 0.00 0.00 500 Kernel.rand
189
+ 0.00 0.00 0.00 1/1 Integer#to_int</pre>
190
+
191
+ <h2 id="label-Overview">Overview<span><a href="#label-Overview">&para;</a> <a href="#top">&uarr;</a></span></h2>
192
+
193
+ <p>Dashed lines divide the report into entries, with one entry per method.
194
+ Entries are sorted by total time which is the time spent in the method
195
+ plus its children.</p>
196
+
197
+ <p>Each entry has a primary line demarked by values in the %total and %self
198
+ columns. The primary line represents the method being profiled. Lines
199
+ above it are the methods that called this method (parents) while the lines
200
+ below it are the methods it called (children).</p>
201
+
202
+ <p>All values are in seconds. For the primary line, the columns represent:</p>
203
+
204
+ <pre>%total - The percentage of time spent in this method and its children
205
+ %self - The percentage of time spent in this method
206
+ total - The time spent in this method and its children.
207
+ self - The time spent in this method.
208
+ children - The time spent in this method&#39;s children.
209
+ calls - The number of times this method was called.
210
+ name - The name of the method.</pre>
211
+
212
+ <p>The interpretation of method names is:</p>
213
+ <ul><li>
214
+ <p>toplevel - The root method that calls all other methods</p>
215
+ </li><li>
216
+ <p>MyObject#test - An instance method “test” of the class “MyObject”</p>
217
+ </li><li>
218
+ <p>&lt;Object:MyObject&gt;#test - The &lt;&gt; characters indicate a singleton
219
+ method on a singleton class.</p>
220
+ </li></ul>
221
+
222
+ <p>For example, we see that 99.48% of the time was spent in Integer#upto and
223
+ its children. Of that time, 4.06 seconds was spent in Integer#upto itself
224
+ and 4.66 in its children. Overall, Integer#upto was called 501 times.</p>
225
+
226
+ <h2 id="label-Parents">Parents<span><a href="#label-Parents">&para;</a> <a href="#top">&uarr;</a></span></h2>
227
+
228
+ <p>In each entry, the lines above the primary line are the methods that
229
+ called the current method. If the current method is a root method then no
230
+ parents are shown.</p>
231
+
232
+ <p>For parent lines, the columns represent:</p>
233
+
234
+ <pre>total - The time spent in the current method and it children on behalf of the parent method.
235
+ self - The time spent in this method on behalf of the parent method.
236
+ children - The time spent in this method&#39;s children on behalf of the parent.
237
+ calls - The number of times the parent method called this child</pre>
238
+
239
+ <p>Looking at Integer#upto again, we see that it was called 500 times from
240
+ Object#is_prime and 1 time from find_largest. Of the 8.72 total seconds
241
+ spent in Integer#upto, 6.63 were done for Object#is_prime and 2.09 for
242
+ Object#find_largest.</p>
243
+
244
+ <h2 id="label-Children">Children<span><a href="#label-Children">&para;</a> <a href="#top">&uarr;</a></span></h2>
245
+
246
+ <p>In each entry, the lines below the primary line are the methods that the
247
+ current method called. If the current method is a leaf method then no
248
+ children are shown.</p>
249
+
250
+ <p>For children lines, the columns represent:</p>
251
+
252
+ <pre>total - The time spent in the child, and its children, on behalf of the current method
253
+ self - The time spent in the child on behalf of the current method.
254
+ children - The time spent in the child&#39;s children (ie, granchildren) in behalf of the current method
255
+ calls - The number of times the child method was called by the current method.</pre>
256
+
257
+ <p>Taking our example of Integer#upto, we see that it called five other
258
+ methods - Array#[], Fixnum#&gt;, Kernel.sleep, Fixnum#= and Fixnum#%.
259
+ Looking at Kernel.sleep, we see that its spent 2.09 seconds working for
260
+ Integer#upto and its children spent 0 time working for Integer#upto. To
261
+ see the overall time Kernel.sleep took we would have to look up its entry
262
+ in the graph table.</p>
263
+
264
+ <p></p>
265
+ </main>
266
+
267
+
268
+
269
+ <footer id="validator-badges" role="contentinfo">
270
+ <p><a href="http://validator.w3.org/check/referer">Validate</a>
271
+ <p>Generated by <a href="http://docs.seattlerb.org/rdoc/">RDoc</a> 4.2.0.
272
+ <p>Based on <a href="http://deveiate.org/projects/Darkfish-RDoc/">Darkfish</a> by <a href="http://deveiate.org">Michael Granger</a>.
273
+ </footer>
274
+
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,618 @@
1
+ <!DOCTYPE html>
2
+
3
+ <html>
4
+ <head>
5
+ <meta charset="UTF-8">
6
+
7
+ <title>ruby-prof</title>
8
+
9
+ <script type="text/javascript">
10
+ var rdoc_rel_prefix = "./";
11
+ </script>
12
+
13
+ <script src="./js/jquery.js"></script>
14
+ <script src="./js/darkfish.js"></script>
15
+
16
+ <link href="./css/fonts.css" rel="stylesheet">
17
+ <link href="./css/rdoc.css" rel="stylesheet">
18
+
19
+
20
+
21
+ <body id="top" role="document" class="file">
22
+ <nav role="navigation">
23
+ <div id="project-navigation">
24
+ <div id="home-section" role="region" title="Quick navigation" class="nav-section">
25
+ <h2>
26
+ <a href="./index.html" rel="home">Home</a>
27
+ </h2>
28
+
29
+ <div id="table-of-contents-navigation">
30
+ <a href="./table_of_contents.html#pages">Pages</a>
31
+ <a href="./table_of_contents.html#classes">Classes</a>
32
+ <a href="./table_of_contents.html#methods">Methods</a>
33
+ </div>
34
+ </div>
35
+
36
+
37
+ <div id="search-section" role="search" class="project-section initially-hidden">
38
+ <form action="#" method="get" accept-charset="utf-8">
39
+ <div id="search-field-wrapper">
40
+ <input id="search-field" role="combobox" aria-label="Search"
41
+ aria-autocomplete="list" aria-controls="search-results"
42
+ type="text" name="search" placeholder="Search" spellcheck="false"
43
+ title="Type to search, Up and Down to navigate, Enter to load">
44
+ </div>
45
+
46
+ <ul id="search-results" aria-label="Search Results"
47
+ aria-busy="false" aria-expanded="false"
48
+ aria-atomic="false" class="initially-hidden"></ul>
49
+ </form>
50
+ </div>
51
+
52
+ </div>
53
+
54
+ <div id="project-metadata">
55
+ <div id="fileindex-section" class="nav-section">
56
+ <h3>Pages</h3>
57
+
58
+ <ul class="link-list">
59
+
60
+ <li><a href="./LICENSE.html">LICENSE</a>
61
+
62
+ <li><a href="./README_rdoc.html">README</a>
63
+
64
+ <li><a href="./examples/flat_txt.html">flat</a>
65
+
66
+ <li><a href="./examples/graph_html.html">graph.html</a>
67
+
68
+ <li><a href="./examples/graph_txt.html">graph</a>
69
+
70
+ </ul>
71
+ </div>
72
+
73
+ <div id="classindex-section" class="nav-section">
74
+ <h3>Class and Module Index</h3>
75
+
76
+ <ul class="link-list">
77
+
78
+ <li><a href="./Rack.html">Rack</a>
79
+
80
+ <li><a href="./Rack/RubyProf.html">Rack::RubyProf</a>
81
+
82
+ <li><a href="./RubyProf.html">RubyProf</a>
83
+
84
+ <li><a href="./RubyProf/AbstractPrinter.html">RubyProf::AbstractPrinter</a>
85
+
86
+ <li><a href="./RubyProf/AggregateCallInfo.html">RubyProf::AggregateCallInfo</a>
87
+
88
+ <li><a href="./RubyProf/CallInfo.html">RubyProf::CallInfo</a>
89
+
90
+ <li><a href="./RubyProf/CallInfoPrinter.html">RubyProf::CallInfoPrinter</a>
91
+
92
+ <li><a href="./RubyProf/CallInfoVisitor.html">RubyProf::CallInfoVisitor</a>
93
+
94
+ <li><a href="./RubyProf/CallStackPrinter.html">RubyProf::CallStackPrinter</a>
95
+
96
+ <li><a href="./RubyProf/CallTreePrinter.html">RubyProf::CallTreePrinter</a>
97
+
98
+ <li><a href="./RubyProf/Cmd.html">RubyProf::Cmd</a>
99
+
100
+ <li><a href="./RubyProf/DotPrinter.html">RubyProf::DotPrinter</a>
101
+
102
+ <li><a href="./RubyProf/FlatPrinter.html">RubyProf::FlatPrinter</a>
103
+
104
+ <li><a href="./RubyProf/FlatPrinterWithLineNumbers.html">RubyProf::FlatPrinterWithLineNumbers</a>
105
+
106
+ <li><a href="./RubyProf/GraphHtmlPrinter.html">RubyProf::GraphHtmlPrinter</a>
107
+
108
+ <li><a href="./RubyProf/GraphPrinter.html">RubyProf::GraphPrinter</a>
109
+
110
+ <li><a href="./RubyProf/MethodInfo.html">RubyProf::MethodInfo</a>
111
+
112
+ <li><a href="./RubyProf/MultiPrinter.html">RubyProf::MultiPrinter</a>
113
+
114
+ <li><a href="./RubyProf/Profile.html">RubyProf::Profile</a>
115
+
116
+ <li><a href="./RubyProf/ProfileTask.html">RubyProf::ProfileTask</a>
117
+
118
+ <li><a href="./RubyProf/Thread.html">RubyProf::Thread</a>
119
+
120
+ </ul>
121
+ </div>
122
+
123
+ </div>
124
+ </nav>
125
+
126
+ <main role="main">
127
+
128
+
129
+ <h1 id="label-ruby-prof">ruby-prof<span><a href="#label-ruby-prof">&para;</a> <a href="#top">&uarr;</a></span></h1>
130
+
131
+ <p><a href="https://travis-ci.org/ruby-prof/ruby-prof"><img
132
+ src="https://travis-ci.org/ruby-prof/ruby-prof.png?branch=master"
133
+ alt="Build Status" /></a></p>
134
+
135
+ <h2 id="label-Overview">Overview<span><a href="#label-Overview">&para;</a> <a href="#top">&uarr;</a></span></h2>
136
+
137
+ <p>ruby-prof is a fast code profiler for Ruby. Its features include:</p>
138
+ <ul><li>
139
+ <p>Speed - it is a C extension and therefore many times faster than the
140
+ standard Ruby profiler.</p>
141
+ </li><li>
142
+ <p>Modes - Ruby prof can measure a number of different parameters, including
143
+ call times, memory usage and object allocations.</p>
144
+ </li><li>
145
+ <p>Reports - can generate text and cross-referenced html reports</p>
146
+ <ul><li>
147
+ <p>Flat Profiles - similar to the reports generated by the standard Ruby
148
+ profiler</p>
149
+ </li><li>
150
+ <p>Graph profiles - similar to GProf, these show how long a method runs, which
151
+ methods call it and which methods it calls.</p>
152
+ </li><li>
153
+ <p>Call tree profiles - outputs results in the calltree format suitable for
154
+ the KCacheGrind profiling tool.</p>
155
+ </li><li>
156
+ <p>Many more – see reports section of this <a
157
+ href="README_rdoc.html">README</a>.</p>
158
+ </li></ul>
159
+ </li><li>
160
+ <p>Threads - supports profiling multiple threads simultaneously</p>
161
+ </li></ul>
162
+
163
+ <h2 id="label-Requirements">Requirements<span><a href="#label-Requirements">&para;</a> <a href="#top">&uarr;</a></span></h2>
164
+
165
+ <p>ruby-prof requires Ruby 1.9.3 or higher.</p>
166
+
167
+ <p>If you are running Linux or Unix you&#39;ll need a C compiler so the
168
+ extension can be compiled when it is installed.</p>
169
+
170
+ <p>If you are running Windows, then you may need to install the Windows
171
+ specific RubyGem which includes an already built extension (see Install
172
+ section).</p>
173
+
174
+ <h2 id="label-Install">Install<span><a href="#label-Install">&para;</a> <a href="#top">&uarr;</a></span></h2>
175
+
176
+ <p>The easiest way to install ruby-prof is by using Ruby Gems. To install:</p>
177
+
178
+ <pre class="ruby"><span class="ruby-identifier">gem</span> <span class="ruby-identifier">install</span> <span class="ruby-identifier">ruby</span><span class="ruby-operator">-</span><span class="ruby-identifier">prof</span>
179
+ </pre>
180
+
181
+ <p>If you&#39;re on windows then please install the devkit first so that it
182
+ can compile.</p>
183
+
184
+ <h2 id="label-Usage">Usage<span><a href="#label-Usage">&para;</a> <a href="#top">&uarr;</a></span></h2>
185
+
186
+ <p>There are two ways of running ruby-prof, via the command line or via its
187
+ API.</p>
188
+
189
+ <h3 id="label-ruby-prof+executable">ruby-prof executable<span><a href="#label-ruby-prof+executable">&para;</a> <a href="#top">&uarr;</a></span></h3>
190
+
191
+ <p>The first is to use ruby-prof to run the Ruby program you want to profile.
192
+ For more information refer to the documentation of the ruby-prof command.</p>
193
+
194
+ <h3 id="label-ruby-prof+API">ruby-prof API<span><a href="#label-ruby-prof+API">&para;</a> <a href="#top">&uarr;</a></span></h3>
195
+
196
+ <p>The second way is to use the ruby-prof API to profile particular segments
197
+ of code.</p>
198
+
199
+ <pre>require &#39;ruby-prof&#39;
200
+
201
+ # Profile the code
202
+ RubyProf.start
203
+ ...
204
+ [code to profile]
205
+ ...
206
+ result = RubyProf.stop
207
+
208
+ # Print a flat profile to text
209
+ printer = RubyProf::FlatPrinter.new(result)
210
+ printer.print(STDOUT)</pre>
211
+
212
+ <p>Alternatively, you can use a block to tell ruby-prof what to profile:</p>
213
+
214
+ <pre>require &#39;ruby-prof&#39;
215
+
216
+ # Profile the code
217
+ result = RubyProf.profile do
218
+ ...
219
+ [code to profile]
220
+ ...
221
+ end
222
+
223
+ # Print a graph profile to text
224
+ printer = RubyProf::GraphPrinter.new(result)
225
+ printer.print(STDOUT, {})</pre>
226
+
227
+ <p>ruby-prof also supports pausing and resuming profiling runs.</p>
228
+
229
+ <pre>require &#39;ruby-prof&#39;
230
+
231
+ # Profile the code
232
+ RubyProf.start
233
+ [code to profile]
234
+ RubyProf.pause
235
+ [other code]
236
+ RubyProf.resume
237
+ [code to profile]
238
+ result = RubyProf.stop</pre>
239
+
240
+ <p>Note that resume will automatically call start if a profiling run has not
241
+ yet started. In addition, resume can also take a block:</p>
242
+
243
+ <pre>require &#39;ruby-prof&#39;
244
+
245
+ # Profile the code
246
+ RubyProf.resume do
247
+ [code to profile]
248
+ end
249
+
250
+ data = RubyProf.stop</pre>
251
+
252
+ <p>With this usage, resume will automatically call pause at the end of the
253
+ block.</p>
254
+
255
+ <h2 id="label-Method+and+Thread+Elimination">Method and Thread Elimination<span><a href="#label-Method+and+Thread+Elimination">&para;</a> <a href="#top">&uarr;</a></span></h2>
256
+
257
+ <p>ruby-prof supports eliminating specific methods and threads from profiling
258
+ results. This is useful for reducing connectivity in the call graph, making
259
+ it easier to identify the source of performance problems when using a graph
260
+ printer.</p>
261
+
262
+ <p>For example, consider Integer#times: it&#39;s hardly ever useful to know
263
+ how much time is spent in the method itself. We&#39;re much more interested
264
+ in how much the passed in block contributes to the time spent in the method
265
+ which contains the Integer#times call.</p>
266
+
267
+ <p>Methods are eliminated from the collected data by calling
268
+ `eliminate_methods!` on the profiling result, before submitting it to a
269
+ printer.</p>
270
+
271
+ <pre class="ruby"><span class="ruby-identifier">result</span> = <span class="ruby-constant">RubyProf</span>.<span class="ruby-identifier">stop</span>
272
+ <span class="ruby-identifier">result</span>.<span class="ruby-identifier">eliminate_methods!</span>([<span class="ruby-node">/Integer#times/</span>])
273
+ </pre>
274
+
275
+ <p>The argument given to `eliminate_methods!` is either an array of regular
276
+ expressions, or the name of a file containing a list of regular expressions
277
+ (line separated text).</p>
278
+
279
+ <p>After eliminating methods the resulting profile will appear exactly as if
280
+ those methods had been inlined at their call sites.</p>
281
+
282
+ <p>In a similar manner, threads can be excluded so they are not profiled at
283
+ all. To do this, pass an array of threads to exclude to ruby-prof:</p>
284
+
285
+ <pre class="ruby"><span class="ruby-constant">RubyProf</span><span class="ruby-operator">::</span><span class="ruby-identifier">exclude_threads</span> = [ <span class="ruby-identifier">thread2</span> ]
286
+ <span class="ruby-constant">RubyProf</span>.<span class="ruby-identifier">start</span>
287
+ </pre>
288
+
289
+ <p>Note that the excluded threads must be specified <strong>before</strong>
290
+ profiling.</p>
291
+
292
+ <h2 id="label-Benchmarking+full+load+time+including+rubygems+startup+cost">Benchmarking full load time including rubygems startup cost<span><a href="#label-Benchmarking+full+load+time+including+rubygems+startup+cost">&para;</a> <a href="#top">&uarr;</a></span></h2>
293
+
294
+ <p>If you want to get a more accurate measurement of what takes all of a
295
+ gem&#39;s bin/xxx command to load, you may want to also measure
296
+ rubygems&#39; startup penalty. You can do this by calling into
297
+ bin/ruby-prof directly, ex:</p>
298
+
299
+ <p>$ gem which ruby-prof</p>
300
+
301
+ <pre>g:/192/lib/ruby/gems/1.9.1/gems/ruby-prof-0.10.2/lib/ruby-prof.rb</pre>
302
+
303
+ <p>now run it thus (substitute lib/ruby-prof.rb with bin/ruby-prof):</p>
304
+
305
+ <p>$ ruby g:/192/lib/ruby/gems/1.9.1/gems/ruby-prof-0.10.2/bin/ruby-prof
306
+ g:192binsome_installed_gem_command</p>
307
+
308
+ <p>or</p>
309
+
310
+ <p>$ ruby g:/192/lib/ruby/gems/1.9.1/gems/ruby-prof-0.10.2/bin/ruby-prof
311
+ ./some_file_that_does_a_require_rubygems_at_the_beginning.rb</p>
312
+
313
+ <h2 id="label-Profiling+Rails">Profiling Rails<span><a href="#label-Profiling+Rails">&para;</a> <a href="#top">&uarr;</a></span></h2>
314
+
315
+ <p>To profile a Rails application it is vital to run it using production like
316
+ settings (cache classes, cache view lookups, etc.). Otherwise, Rail&#39;s
317
+ dependency loading code will overwhelm any time spent in the application
318
+ itself (our tests show that Rails dependency loading causes a roughly 6x
319
+ slowdown). The best way to do this is create a new Rails environment,
320
+ profile.rb.</p>
321
+
322
+ <p>So to profile Rails:</p>
323
+ <ol><li>
324
+ <p>Create a new profile.rb environment. Make sure to turn on cache_classes
325
+ and cache_template_loading. Otherwise your profiling results will be
326
+ overwhelemed by the time Rails spends loading required files. You should
327
+ likely turn off caching.</p>
328
+ </li><li>
329
+ <p>Add the ruby-prof to your gemfile:</p>
330
+
331
+ <pre class="ruby"><span class="ruby-identifier">group</span> :<span class="ruby-identifier">profile</span> <span class="ruby-keyword">do</span>
332
+ <span class="ruby-identifier">gem</span> <span class="ruby-string">&#39;ruby-prof&#39;</span>
333
+ <span class="ruby-keyword">end</span>
334
+ </pre>
335
+ </li><li>
336
+ <p>Add the ruby prof rack adapter to your middleware stack. One way to do
337
+ this is by adding the following code to config.ru:</p>
338
+
339
+ <pre class="ruby"><span class="ruby-keyword">if</span> <span class="ruby-constant">Rails</span>.<span class="ruby-identifier">env</span>.<span class="ruby-identifier">profile?</span>
340
+ <span class="ruby-identifier">use</span> <span class="ruby-constant">Rack</span><span class="ruby-operator">::</span><span class="ruby-constant">RubyProf</span>, :<span class="ruby-identifier">path</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-string">&#39;/temp/profile&#39;</span>
341
+ <span class="ruby-keyword">end</span>
342
+ </pre>
343
+
344
+ <p>The path is where you want profiling results to be stored. By default the
345
+ rack adapter will generate a html call graph report and flat text report.</p>
346
+ </li><li>
347
+ <p>Now make a request to your running server. New profiling information will
348
+ be generated for each request. Note that each request will overwrite the
349
+ profiling reports created by the previous request!</p>
350
+ </li></ol>
351
+
352
+ <h2 id="label-Reports">Reports<span><a href="#label-Reports">&para;</a> <a href="#top">&uarr;</a></span></h2>
353
+
354
+ <p>ruby-prof can generate a number of different reports:</p>
355
+ <ul><li>
356
+ <p>Flat Reports</p>
357
+ </li><li>
358
+ <p>Graph Reports</p>
359
+ </li><li>
360
+ <p>HTML Graph Reports</p>
361
+ </li><li>
362
+ <p>Call graphs</p>
363
+ </li><li>
364
+ <p>Call stack reports</p>
365
+ </li><li>
366
+ <p>More!</p>
367
+ </li></ul>
368
+
369
+ <p>Flat profiles show the overall time spent in each method. They are a good
370
+ way of quickly identifying which methods take the most time. An example of
371
+ a flat profile and an explanation can be found in <a
372
+ href="http://github.com/ruby-prof/ruby-prof/tree/master/examples/flat.txt">examples/flat.txt</a>.</p>
373
+
374
+ <p>There are several varieties of these – run $ ruby-prof –help</p>
375
+
376
+ <p>Graph profiles also show the overall time spent in each method. In
377
+ addition, they also show which methods call the current method and which
378
+ methods its calls. Thus they are good for understanding how methods gets
379
+ called and provide insight into the flow of your program. An example text
380
+ graph profile is located at <a
381
+ href="http://github.com/ruby-prof/ruby-prof/tree/master/examples/graph.txt">examples/graph.txt</a>.</p>
382
+
383
+ <p>HTML Graph profiles are the same as graph profiles, except output is
384
+ generated in hyper-linked HTML. Since graph profiles can be quite large,
385
+ the embedded links make it much easier to navigate the results. An example
386
+ html graph profile is located at <a
387
+ href="http://github.com/ruby-prof/ruby-prof/tree/master/examples/graph.html">examples/graph.html</a>.</p>
388
+
389
+ <p>Call graphs output results in the calltree profile format which is used by
390
+ KCachegrind. Call graph support was generously donated by Carl Shimer. More
391
+ information about the format can be found at the <a
392
+ href="http://kcachegrind.sourceforge.net/cgi-bin/show.cgi/KcacheGrindCalltreeFormat">KCachegrind</a>
393
+ site.</p>
394
+
395
+ <p>Call stack reports produce a HTML visualization of the time spent in each
396
+ execution path of the profiled code. An example can be found at <a
397
+ href="http://github.com/ruby-prof/ruby-prof/tree/master/examples/stack.html">examples/stack.html</a>.</p>
398
+
399
+ <p>Another good example: [<a
400
+ href="http://twitpic.com/28z94a">twitpic.com/28z94a</a>]</p>
401
+
402
+ <p>Finally, there&#39;s a so called MultiPrinter which can generate several
403
+ reports in one profiling run. See <a
404
+ href="http://github.com/ruby-prof/ruby-prof/tree/master/examples/multi.stack.html">examples/multi.stack.html</a>.</p>
405
+
406
+ <p>There is also a graphviz .dot visualiser.</p>
407
+
408
+ <h2 id="label-Printers">Printers<span><a href="#label-Printers">&para;</a> <a href="#top">&uarr;</a></span></h2>
409
+
410
+ <p>Reports are created by printers. Supported printers include:</p>
411
+ <ul><li>
412
+ <p><a href="RubyProf/FlatPrinter.html">RubyProf::FlatPrinter</a> - Creates a
413
+ flat report in text format</p>
414
+ </li><li>
415
+ <p><a
416
+ href="RubyProf/FlatPrinterWithLineNumbers.html">RubyProf::FlatPrinterWithLineNumbers</a>
417
+ - same as above but more verbose</p>
418
+ </li><li>
419
+ <p><a href="RubyProf/GraphPrinter.html">RubyProf::GraphPrinter</a> - Creates a
420
+ call graph report in text format</p>
421
+ </li><li>
422
+ <p><a href="RubyProf/GraphHtmlPrinter.html">RubyProf::GraphHtmlPrinter</a> -
423
+ Creates a call graph report in HTML (separate files per thread)</p>
424
+ </li><li>
425
+ <p><a href="RubyProf/DotPrinter.html">RubyProf::DotPrinter</a> - Creates a
426
+ call graph report in GraphViz&#39;s DOT format which can be converted to an
427
+ image</p>
428
+ </li><li>
429
+ <p><a href="RubyProf/CallTreePrinter.html">RubyProf::CallTreePrinter</a> -
430
+ Creates a call tree report compatible with KCachegrind.</p>
431
+ </li><li>
432
+ <p><a href="RubyProf/CallStackPrinter.html">RubyProf::CallStackPrinter</a> -
433
+ Creates a HTML visualization of the Ruby stack</p>
434
+ </li><li>
435
+ <p><a href="RubyProf/MultiPrinter.html">RubyProf::MultiPrinter</a> - Uses the
436
+ other printers to create several reports in one profiling run</p>
437
+ </li><li>
438
+ <p>More!</p>
439
+ </li></ul>
440
+
441
+ <p>To use a printer:</p>
442
+
443
+ <pre>...
444
+ result = RubyProf.stop
445
+ printer = RubyProf::GraphPrinter.new(result)
446
+ printer.print(STDOUT, :min_percent =&gt; 2)</pre>
447
+
448
+ <p>The first parameter is any writable IO object such as STDOUT or a file. The
449
+ second parameter, specifies the minimum percentage a method must take to be
450
+ printed. Percentages should be specified as integers in the range 0 to
451
+ 100. For more information please see the documentation for the different
452
+ printers.</p>
453
+
454
+ <p>The other option is :print_file =&gt; true (default false), which adds the
455
+ filename to the output (GraphPrinter only).</p>
456
+
457
+ <p>The MultiPrinter differs from the other printers in that it requires a
458
+ directory path and a basename for the files it produces.</p>
459
+
460
+ <pre class="ruby"><span class="ruby-identifier">printer</span> = <span class="ruby-constant">RubyProf</span><span class="ruby-operator">::</span><span class="ruby-constant">MultiPrinter</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">result</span>)
461
+ <span class="ruby-identifier">printer</span>.<span class="ruby-identifier">print</span>(:<span class="ruby-identifier">path</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-string">&quot;.&quot;</span>, :<span class="ruby-identifier">profile</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-string">&quot;profile&quot;</span>)
462
+ </pre>
463
+
464
+ <h2 id="label-Measurements">Measurements<span><a href="#label-Measurements">&para;</a> <a href="#top">&uarr;</a></span></h2>
465
+
466
+ <p>Depending on the mode and platform, ruby-prof can measure various aspects
467
+ of a Ruby program. Supported measurements include:</p>
468
+ <ul><li>
469
+ <p>wall time (RubyProf::WALL_TIME)</p>
470
+ </li><li>
471
+ <p>process time (RubyProf::PROCESS_TIME)</p>
472
+ </li><li>
473
+ <p>cpu time (RubyProf::CPU_TIME)</p>
474
+ </li><li>
475
+ <p>object allocations (RubyProf::ALLOCATIONS)</p>
476
+ </li><li>
477
+ <p>memory usage (RubyProf::MEMORY)</p>
478
+ </li><li>
479
+ <p>garbage collection time (RubyProf::GC_TIME)</p>
480
+ </li><li>
481
+ <p>garbage collections runs (RubyProf::GC_RUNS)</p>
482
+ </li></ul>
483
+
484
+ <p>Wall time measures the real-world time elapsed between any two moments. If
485
+ there are other processes concurrently running on the system that use
486
+ significant CPU or disk time during a profiling run then the reported
487
+ results will be larger than expected.</p>
488
+
489
+ <p>Process time measures the time used by a process between any two moments.
490
+ It is unaffected by other processes concurrently running on the system.
491
+ Note that Windows does not support measuring process times.</p>
492
+
493
+ <p>CPU time uses the CPU clock counter to measure time. The returned values
494
+ are dependent on the correctly setting the CPU&#39;s frequency. This mode
495
+ is only supported on Pentium or PowerPC platforms (linux only).</p>
496
+
497
+ <p>Object allocation reports show how many objects each method in a program
498
+ allocates. This support was added by Sylvain Joyeux and requires a patched
499
+ Ruby interpreter. See below.</p>
500
+
501
+ <p>Memory usage reports show how much memory each method in a program uses.
502
+ This support was added by Alexander Dymo and requires a patched Ruby
503
+ interpreter. See below.</p>
504
+
505
+ <p>Garbage collection time reports how much time is spent in Ruby&#39;s
506
+ garbage collector during a profiling session. This support was added by
507
+ Jeremy Kemper and requires a patched Ruby interpreter. See below.</p>
508
+
509
+ <p>Garbage collection runs report how many times Ruby&#39;s garbage collector
510
+ is invoked during a profiling session. This support was added by Jeremy
511
+ Kemper and requires a patched Ruby interpreter. See below.</p>
512
+
513
+ <p>Ruby patches: all of the patches to Ruby are included in the railsexpress
514
+ patchsets for rvm, see <a
515
+ href="https://github.com/skaes/rvm-patchsets">github.com/skaes/rvm-patchsets</a></p>
516
+
517
+ <p>To set the measurement:</p>
518
+ <ul><li>
519
+ <p><a href="RubyProf.html#method-c-measure_mode">RubyProf.measure_mode</a> =
520
+ RubyProf::WALL_TIME</p>
521
+ </li><li>
522
+ <p><a href="RubyProf.html#method-c-measure_mode">RubyProf.measure_mode</a> =
523
+ RubyProf::PROCESS_TIME</p>
524
+ </li><li>
525
+ <p><a href="RubyProf.html#method-c-measure_mode">RubyProf.measure_mode</a> =
526
+ RubyProf::CPU_TIME</p>
527
+ </li><li>
528
+ <p><a href="RubyProf.html#method-c-measure_mode">RubyProf.measure_mode</a> =
529
+ RubyProf::ALLOCATIONS</p>
530
+ </li><li>
531
+ <p><a href="RubyProf.html#method-c-measure_mode">RubyProf.measure_mode</a> =
532
+ RubyProf::MEMORY</p>
533
+ </li><li>
534
+ <p><a href="RubyProf.html#method-c-measure_mode">RubyProf.measure_mode</a> =
535
+ RubyProf::GC_TIME</p>
536
+ </li><li>
537
+ <p><a href="RubyProf.html#method-c-measure_mode">RubyProf.measure_mode</a> =
538
+ RubyProf::GC_RUNS</p>
539
+ </li></ul>
540
+
541
+ <p>The default value is RubyProf::WALL_TIME.</p>
542
+
543
+ <p>You may also specify the measure_mode by using the RUBY_PROF_MEASURE_MODE
544
+ environment variable:</p>
545
+ <ul><li>
546
+ <p>export RUBY_PROF_MEASURE_MODE=wall</p>
547
+ </li><li>
548
+ <p>export RUBY_PROF_MEASURE_MODE=process</p>
549
+ </li><li>
550
+ <p>export RUBY_PROF_MEASURE_MODE=cpu</p>
551
+ </li><li>
552
+ <p>export RUBY_PROF_MEASURE_MODE=allocations</p>
553
+ </li><li>
554
+ <p>export RUBY_PROF_MEASURE_MODE=memory</p>
555
+ </li><li>
556
+ <p>export RUBY_PROF_MEASURE_MODE=gc_time</p>
557
+ </li><li>
558
+ <p>export RUBY_PROF_MEASURE_MODE=gc_runs</p>
559
+ </li></ul>
560
+
561
+ <p>On Linux, process time is measured using the clock method provided by the C
562
+ runtime library. Note that the clock method does not report time spent in
563
+ the kernel or child processes and therefore does not measure time spent in
564
+ methods such as Kernel.sleep method. If you need to measure these values,
565
+ then use wall time. Wall time is measured using the gettimeofday kernel
566
+ method.</p>
567
+
568
+ <p>If you set the clock mode to PROCESS_TIME, then timings are read using the
569
+ clock method provided by the C runtime library. Note though, these values
570
+ are wall times on Windows and not process times like on Linux. Wall time
571
+ is measured using the GetLocalTime API.</p>
572
+
573
+ <p>If you use wall time, the results will be affected by other processes
574
+ running on your computer, network delays, disk access, etc. As result, for
575
+ the best results, try to make sure your computer is only performing your
576
+ profiling run and is otherwise quiescent.</p>
577
+
578
+ <h2 id="label-Multi-threaded+Applications">Multi-threaded Applications<span><a href="#label-Multi-threaded+Applications">&para;</a> <a href="#top">&uarr;</a></span></h2>
579
+
580
+ <p>Unfortunately, Ruby does not provide an internal api for detecting thread
581
+ context switches in 1.8. As a result, the timings ruby-prof reports for
582
+ each thread may be slightly inaccurate. In particular, this will happen
583
+ for newly spawned threads that go to sleep immediately (their first call).
584
+ For instance, if you use Ruby&#39;s timeout library to wait for 2 seconds,
585
+ the 2 seconds will be assigned to the foreground thread and not the newly
586
+ created background thread. These errors can largely be avoided if the
587
+ background thread performs any operation before going to sleep.</p>
588
+
589
+ <h2 id="label-Performance">Performance<span><a href="#label-Performance">&para;</a> <a href="#top">&uarr;</a></span></h2>
590
+
591
+ <p>Significant effort has been put into reducing ruby-prof&#39;s overhead as
592
+ much as possible. Our tests show that the overhead associated with
593
+ profiling code varies considerably with the code being profiled. Most
594
+ programs will run approximately twice as slow while highly recursive
595
+ programs (like the fibonacci series test) will run three times slower.</p>
596
+
597
+ <h2 id="label-License">License<span><a href="#label-License">&para;</a> <a href="#top">&uarr;</a></span></h2>
598
+
599
+ <p>See <a href="LICENSE.html">LICENSE</a> for license information.</p>
600
+
601
+ <h2 id="label-Development">Development<span><a href="#label-Development">&para;</a> <a href="#top">&uarr;</a></span></h2>
602
+
603
+ <p>Code is located at <a
604
+ href="https://github.com/ruby-prof/ruby-prof">github.com/ruby-prof/ruby-prof</a></p>
605
+
606
+ <p>Google group/mailing list: <a
607
+ href="http://groups.google.com/group/ruby-optimization">groups.google.com/group/ruby-optimization</a>
608
+ or start a github issue.</p>
609
+ </main>
610
+
611
+
612
+
613
+ <footer id="validator-badges" role="contentinfo">
614
+ <p><a href="http://validator.w3.org/check/referer">Validate</a>
615
+ <p>Generated by <a href="http://docs.seattlerb.org/rdoc/">RDoc</a> 4.2.0.
616
+ <p>Based on <a href="http://deveiate.org/projects/Darkfish-RDoc/">Darkfish</a> by <a href="http://deveiate.org">Michael Granger</a>.
617
+ </footer>
618
+