airbnb-ruby-prof 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. data/CHANGES +483 -0
  2. data/LICENSE +25 -0
  3. data/README.rdoc +426 -0
  4. data/Rakefile +51 -0
  5. data/bin/ruby-prof +279 -0
  6. data/bin/ruby-prof-check-trace +45 -0
  7. data/examples/flat.txt +50 -0
  8. data/examples/graph.dot +84 -0
  9. data/examples/graph.html +823 -0
  10. data/examples/graph.txt +139 -0
  11. data/examples/multi.flat.txt +23 -0
  12. data/examples/multi.graph.html +760 -0
  13. data/examples/multi.grind.dat +114 -0
  14. data/examples/multi.stack.html +547 -0
  15. data/examples/stack.html +547 -0
  16. data/ext/ruby_prof/extconf.rb +67 -0
  17. data/ext/ruby_prof/rp_call_info.c +374 -0
  18. data/ext/ruby_prof/rp_call_info.h +59 -0
  19. data/ext/ruby_prof/rp_fast_call_tree_printer.c +247 -0
  20. data/ext/ruby_prof/rp_fast_call_tree_printer.h +10 -0
  21. data/ext/ruby_prof/rp_measure.c +71 -0
  22. data/ext/ruby_prof/rp_measure.h +56 -0
  23. data/ext/ruby_prof/rp_measure_allocations.c +74 -0
  24. data/ext/ruby_prof/rp_measure_cpu_time.c +134 -0
  25. data/ext/ruby_prof/rp_measure_gc_runs.c +71 -0
  26. data/ext/ruby_prof/rp_measure_gc_time.c +58 -0
  27. data/ext/ruby_prof/rp_measure_memory.c +75 -0
  28. data/ext/ruby_prof/rp_measure_process_time.c +69 -0
  29. data/ext/ruby_prof/rp_measure_wall_time.c +43 -0
  30. data/ext/ruby_prof/rp_method.c +717 -0
  31. data/ext/ruby_prof/rp_method.h +79 -0
  32. data/ext/ruby_prof/rp_stack.c +221 -0
  33. data/ext/ruby_prof/rp_stack.h +81 -0
  34. data/ext/ruby_prof/rp_thread.c +312 -0
  35. data/ext/ruby_prof/rp_thread.h +36 -0
  36. data/ext/ruby_prof/ruby_prof.c +800 -0
  37. data/ext/ruby_prof/ruby_prof.h +64 -0
  38. data/ext/ruby_prof/vc/ruby_prof.sln +32 -0
  39. data/ext/ruby_prof/vc/ruby_prof_18.vcxproj +108 -0
  40. data/ext/ruby_prof/vc/ruby_prof_19.vcxproj +110 -0
  41. data/ext/ruby_prof/vc/ruby_prof_20.vcxproj +110 -0
  42. data/lib/ruby-prof.rb +63 -0
  43. data/lib/ruby-prof/aggregate_call_info.rb +76 -0
  44. data/lib/ruby-prof/assets/call_stack_printer.css.html +117 -0
  45. data/lib/ruby-prof/assets/call_stack_printer.js.html +385 -0
  46. data/lib/ruby-prof/assets/call_stack_printer.png +0 -0
  47. data/lib/ruby-prof/assets/flame_graph_printer.lib.css.html +149 -0
  48. data/lib/ruby-prof/assets/flame_graph_printer.lib.js.html +707 -0
  49. data/lib/ruby-prof/assets/flame_graph_printer.page.js.html +56 -0
  50. data/lib/ruby-prof/assets/flame_graph_printer.tmpl.html.erb +39 -0
  51. data/lib/ruby-prof/call_info.rb +111 -0
  52. data/lib/ruby-prof/call_info_visitor.rb +40 -0
  53. data/lib/ruby-prof/compatibility.rb +186 -0
  54. data/lib/ruby-prof/method_info.rb +109 -0
  55. data/lib/ruby-prof/printers/abstract_printer.rb +85 -0
  56. data/lib/ruby-prof/printers/call_info_printer.rb +41 -0
  57. data/lib/ruby-prof/printers/call_stack_printer.rb +260 -0
  58. data/lib/ruby-prof/printers/call_tree_printer.rb +130 -0
  59. data/lib/ruby-prof/printers/dot_printer.rb +132 -0
  60. data/lib/ruby-prof/printers/fast_call_tree_printer.rb +87 -0
  61. data/lib/ruby-prof/printers/flame_graph_html_printer.rb +59 -0
  62. data/lib/ruby-prof/printers/flame_graph_json_printer.rb +157 -0
  63. data/lib/ruby-prof/printers/flat_printer.rb +70 -0
  64. data/lib/ruby-prof/printers/flat_printer_with_line_numbers.rb +64 -0
  65. data/lib/ruby-prof/printers/graph_html_printer.rb +244 -0
  66. data/lib/ruby-prof/printers/graph_printer.rb +116 -0
  67. data/lib/ruby-prof/printers/multi_printer.rb +58 -0
  68. data/lib/ruby-prof/profile.rb +22 -0
  69. data/lib/ruby-prof/profile/exclude_common_methods.rb +201 -0
  70. data/lib/ruby-prof/rack.rb +95 -0
  71. data/lib/ruby-prof/task.rb +147 -0
  72. data/lib/ruby-prof/thread.rb +35 -0
  73. data/lib/ruby-prof/version.rb +4 -0
  74. data/lib/ruby-prof/walker.rb +95 -0
  75. data/lib/unprof.rb +10 -0
  76. data/ruby-prof.gemspec +56 -0
  77. data/test/aggregate_test.rb +136 -0
  78. data/test/basic_test.rb +128 -0
  79. data/test/block_test.rb +74 -0
  80. data/test/call_info_test.rb +78 -0
  81. data/test/call_info_visitor_test.rb +31 -0
  82. data/test/duplicate_names_test.rb +32 -0
  83. data/test/dynamic_method_test.rb +55 -0
  84. data/test/enumerable_test.rb +21 -0
  85. data/test/exceptions_test.rb +16 -0
  86. data/test/exclude_methods_test.rb +146 -0
  87. data/test/exclude_threads_test.rb +53 -0
  88. data/test/fiber_test.rb +79 -0
  89. data/test/issue137_test.rb +63 -0
  90. data/test/line_number_test.rb +71 -0
  91. data/test/measure_allocations_test.rb +26 -0
  92. data/test/measure_cpu_time_test.rb +213 -0
  93. data/test/measure_gc_runs_test.rb +32 -0
  94. data/test/measure_gc_time_test.rb +36 -0
  95. data/test/measure_memory_test.rb +33 -0
  96. data/test/measure_process_time_test.rb +63 -0
  97. data/test/measure_wall_time_test.rb +255 -0
  98. data/test/module_test.rb +45 -0
  99. data/test/multi_measure_test.rb +38 -0
  100. data/test/multi_printer_test.rb +83 -0
  101. data/test/no_method_class_test.rb +15 -0
  102. data/test/pause_resume_test.rb +166 -0
  103. data/test/prime.rb +54 -0
  104. data/test/printers_test.rb +255 -0
  105. data/test/printing_recursive_graph_test.rb +127 -0
  106. data/test/rack_test.rb +93 -0
  107. data/test/recursive_test.rb +212 -0
  108. data/test/singleton_test.rb +38 -0
  109. data/test/stack_printer_test.rb +65 -0
  110. data/test/stack_test.rb +138 -0
  111. data/test/start_stop_test.rb +112 -0
  112. data/test/test_helper.rb +264 -0
  113. data/test/thread_test.rb +187 -0
  114. data/test/unique_call_path_test.rb +202 -0
  115. data/test/yarv_test.rb +55 -0
  116. metadata +211 -0
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+
3
+ require "rubygems/package_task"
4
+ require "rake/extensiontask"
5
+ require "rake/testtask"
6
+ require "rdoc/task"
7
+ require "date"
8
+ require "rake/clean"
9
+ begin
10
+ require "bundler/setup"
11
+ Bundler::GemHelper.install_tasks
12
+ rescue LoadError
13
+ $stderr.puts "Install bundler to get support for simplified gem publishing"
14
+ end
15
+
16
+ GEM_NAME = 'ruby-prof'
17
+ SO_NAME = 'ruby_prof'
18
+
19
+ default_spec = Gem::Specification.load("#{GEM_NAME}.gemspec")
20
+
21
+ # specify which versions/builds to cross compile
22
+ Rake::ExtensionTask.new do |ext|
23
+ ext.gem_spec = default_spec
24
+ ext.name = SO_NAME
25
+ ext.ext_dir = "ext/#{SO_NAME}"
26
+ ext.lib_dir = "lib/#{RUBY_VERSION}"
27
+ end
28
+
29
+ # Rake task to build the default package
30
+ Gem::PackageTask.new(default_spec) do |pkg|
31
+ pkg.need_tar = true
32
+ end
33
+
34
+ task :default => :test
35
+
36
+ for file in Dir['lib/**/*.{o,so,bundle}']
37
+ CLEAN.include file
38
+ end
39
+ CLEAN.reject!{|f| !File.exist?(f)}
40
+ task :clean do
41
+ # remove tmp dir contents completely after cleaning
42
+ FileUtils.rm_rf('tmp/*')
43
+ end
44
+
45
+ desc 'Run the ruby-prof test suite'
46
+ Rake::TestTask.new do |t|
47
+ t.libs += %w(lib ext test)
48
+ t.test_files = Dir['test/**_test.rb']
49
+ t.verbose = true
50
+ t.warning = true
51
+ end
@@ -0,0 +1,279 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ # == Synopsis
4
+ #
5
+ # Profiles a Ruby program.
6
+ #
7
+ # == Usage
8
+ #
9
+ # ruby_prof [options] <script.rb> [--] [script-options]"
10
+ #
11
+ # Various options:
12
+ # run "$ ruby-prof --help" to see them
13
+ #
14
+ # See also the readme "reports" section for the various outputs
15
+
16
+ # First require ruby-prof
17
+ require 'rubygems'
18
+ require 'ruby-prof'
19
+
20
+ # Now setup option parser
21
+ require 'ostruct'
22
+ require 'optparse'
23
+
24
+ module RubyProf
25
+ class Cmd
26
+ attr_accessor :options
27
+
28
+ def initialize
29
+ setup_options
30
+ parse_args
31
+
32
+ load_pre_libs
33
+ load_pre_execs
34
+ end
35
+
36
+ def setup_options
37
+ @options = OpenStruct.new
38
+ options.printer = RubyProf::FlatPrinter
39
+ options.min_percent = 0
40
+ options.file = nil
41
+ options.replace_prog_name = false
42
+ options.specialized_instruction = false
43
+
44
+ options.pre_libs = Array.new
45
+ options.pre_execs = Array.new
46
+ end
47
+
48
+ def option_parser
49
+ OptionParser.new do |opts|
50
+ opts.banner = "ruby_prof #{RubyProf::VERSION}\n" +
51
+ "Usage: ruby-prof [options] <script.rb> [--] [profiled-script-command-line-options]"
52
+
53
+ opts.separator ""
54
+ opts.separator "Options:"
55
+
56
+ opts.on('-p printer', '--printer=printer', [:flat, :flat_with_line_numbers, :graph, :graph_html, :call_tree, :call_stack, :dot, :multi],
57
+ 'Select a printer:',
58
+ ' flat - Prints a flat profile as text (default).',
59
+ ' flat_with_line_numbers - same as flat, with line numbers.',
60
+ ' graph - Prints a graph profile as text.',
61
+ ' graph_html - Prints a graph profile as html.',
62
+ ' call_tree - format for KCacheGrind',
63
+ ' call_stack - prints a HTML visualization of the call tree',
64
+ ' dot - Prints a graph profile as a dot file',
65
+ ' multi - Creates several reports in output directory'
66
+ ) do |printer|
67
+
68
+
69
+ case printer
70
+ when :flat
71
+ options.printer = RubyProf::FlatPrinter
72
+ when :flat_with_line_numbers
73
+ options.printer = RubyProf::FlatPrinterWithLineNumbers
74
+ when :graph
75
+ options.printer = RubyProf::GraphPrinter
76
+ when :graph_html
77
+ options.printer = RubyProf::GraphHtmlPrinter
78
+ when :call_tree
79
+ options.printer = RubyProf::CallTreePrinter
80
+ when :call_stack
81
+ options.printer = RubyProf::CallStackPrinter
82
+ when :dot
83
+ options.printer = RubyProf::DotPrinter
84
+ when :multi
85
+ options.printer = RubyProf::MultiPrinter
86
+ end
87
+ end
88
+
89
+ opts.on('-m min_percent', '--min_percent=min_percent', Float,
90
+ 'The minimum percent a method must take before ',
91
+ ' being included in output reports.',
92
+ ' this option is not supported for call tree.') do |min_percent|
93
+ options.min_percent = min_percent
94
+ end
95
+
96
+ opts.on('-f path', '--file=path',
97
+ 'Output results to a file instead of standard out.') do |file|
98
+ options.file = file
99
+ options.old_wd = Dir.pwd
100
+ end
101
+
102
+ opts.on('--mode=measure_mode',
103
+ [:process, :wall, :cpu, :allocations, :memory, :gc_runs, :gc_time],
104
+ 'Select what ruby-prof should measure:',
105
+ ' wall - Wall time (default).',
106
+ ' process - Process time.',
107
+ ' cpu - CPU time (Pentium and PowerPCs only).',
108
+ ' allocations - Object allocations (requires patched Ruby interpreter).',
109
+ ' memory - Allocated memory in KB (requires patched Ruby interpreter).',
110
+ ' gc_runs - Number of garbage collections (requires patched Ruby interpreter).',
111
+ ' gc_time - Time spent in garbage collection (requires patched Ruby interpreter).') do |measure_mode|
112
+
113
+ case measure_mode
114
+ when :wall
115
+ options.measure_mode = RubyProf::WALL_TIME
116
+ when :process
117
+ options.measure_mode = RubyProf::PROCESS_TIME
118
+ when :cpu
119
+ options.measure_mode = RubyProf::CPU_TIME
120
+ when :allocations
121
+ options.measure_mode = RubyProf::ALLOCATIONS
122
+ when :memory
123
+ options.measure_mode = RubyProf::MEMORY
124
+ when :gc_runs
125
+ options.measure_mode = RubyProf::GC_RUNS
126
+ when :gc_time
127
+ options.measure_mode = RubyProf::GC_TIME
128
+ end
129
+ end
130
+
131
+ opts.on('-s sort_mode', '--sort=sort_mode', [:total, :self, :wait, :child],
132
+ 'Select how ruby-prof results should be sorted:',
133
+ ' total - Total time',
134
+ ' self - Self time',
135
+ ' wait - Wait time',
136
+ ' child - Child time') do |sort_mode|
137
+
138
+ options.sort_method = case sort_mode
139
+ when :total
140
+ :total_time
141
+ when :self
142
+ :self_time
143
+ when :wait
144
+ :wait_time
145
+ when :child
146
+ :children_time
147
+ end
148
+ end
149
+
150
+ opts.on("--replace-progname", "Replace $0 when loading the .rb files.") do
151
+ options.replace_prog_name = true
152
+ end
153
+
154
+ if defined?(RubyVM)
155
+ opts.on("--specialized-instruction", "Turn on specified instruction.") do
156
+ options.specialized_instruction = true
157
+ end
158
+ end
159
+
160
+ opts.on_tail("-h", "--help", "Show help message") do
161
+ puts opts
162
+ exit
163
+ end
164
+
165
+ opts.on_tail("--version", "Show version #{RubyProf::VERSION}") do
166
+ puts "ruby_prof " + RubyProf::VERSION
167
+ exit
168
+ end
169
+
170
+ opts.on("-v","Show version, set $VERBOSE to true, profile script if option given") do
171
+ puts "ruby version: " + [RUBY_PATCHLEVEL, RUBY_PLATFORM, RUBY_VERSION].join(' ')
172
+ $VERBOSE = true
173
+ end
174
+
175
+ opts.on("-d", "Set $DEBUG to true") do
176
+ $DEBUG = true
177
+ end
178
+
179
+ opts.on('-R lib', '--require-noprof lib', 'require a specific library (not profiled)') do |lib|
180
+ options.pre_libs << lib
181
+ end
182
+
183
+ opts.on('-E code', '--eval-noprof code', 'execute the ruby statements (not profiled)') do |code|
184
+ options.pre_execs << code
185
+ end
186
+ end
187
+ end
188
+
189
+
190
+ def parse_args
191
+ # Make sure the user specified at least one file
192
+ if ARGV.length < 1 and not options.exec
193
+ puts self.option_parser
194
+ puts ""
195
+ puts "Must specify a script to run"
196
+ exit(-1)
197
+ end
198
+
199
+ self.option_parser.parse! ARGV
200
+
201
+ if options.printer == RubyProf::MultiPrinter
202
+ options.file ||= "."
203
+ options.old_wd ||= Dir.pwd
204
+ end
205
+ rescue OptionParser::InvalidOption, OptionParser::InvalidArgument, OptionParser::MissingArgument => e
206
+ puts self.option_parser
207
+ puts e.message
208
+ exit(-1)
209
+ end
210
+
211
+ def load_pre_libs
212
+ options.pre_libs.each do |lib|
213
+ require lib
214
+ end
215
+ end
216
+
217
+ def load_pre_execs
218
+ options.pre_execs.each do |exec|
219
+ eval(exec)
220
+ end
221
+ end
222
+
223
+ def run
224
+ # Get the script we will execute
225
+ script = ARGV.shift
226
+ if options.replace_prog_name
227
+ $0 = File.expand_path(script)
228
+ end
229
+
230
+ # Set VM compile option
231
+ if defined?(RubyVM)
232
+ RubyVM::InstructionSequence.compile_option = {
233
+ :trace_instruction => true,
234
+ :specialized_instruction => options.specialized_instruction
235
+ }
236
+ end
237
+
238
+ # Set the measure mode
239
+ RubyProf.measure_mode = options.measure_mode if options.measure_mode
240
+ RubyProf.start_script(script)
241
+ end
242
+ end
243
+ end
244
+
245
+ # Parse command line options
246
+ cmd = RubyProf::Cmd.new
247
+
248
+ # Install at_exit handler. It is important that we do this
249
+ # before loading the scripts so our at_exit handler run
250
+ # *after* any other one that will be installed.
251
+
252
+ at_exit {
253
+ # Stop profiling
254
+ result = RubyProf.stop
255
+
256
+ # Create a printer
257
+ printer = cmd.options.printer.new(result)
258
+ printer_options = {:min_percent => cmd.options.min_percent, :sort_method => cmd.options.sort_method}
259
+
260
+ # Get output
261
+ if cmd.options.file
262
+ # write it relative to the dir they *started* in, as it's a bit surprising to write it in the dir they end up in.
263
+ Dir.chdir(cmd.options.old_wd) do
264
+ if printer.is_a?(RubyProf::MultiPrinter)
265
+ printer.print(printer_options.merge(:path => cmd.options.file))
266
+ else
267
+ File.open(cmd.options.file, 'w') do |file|
268
+ printer.print(file, printer_options)
269
+ end
270
+ end
271
+ end
272
+ else
273
+ # Print out results
274
+ printer.print(STDOUT, printer_options)
275
+ end
276
+ }
277
+
278
+ # Now profile some code
279
+ cmd.run
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ stacks = Hash.new{|h,k| h[k] = Hash.new{|h,k| h[k] = []}}
4
+ i = 0
5
+ File.open(ARGV[0]).each_line do |l|
6
+ i += 1
7
+ unless l =~ /^(\d+):(\d+): *\d+ms *([^ ]+) *(.*): *(\d+) *(.+)$/
8
+ next if l =~/^ *$/
9
+ puts "line doesn't match: #{l}"
10
+ next
11
+ end
12
+ details = $1.to_i, $2.to_i, $3, $4, $5.to_i, $6
13
+ thread, fiber, event, file, line, method = *details
14
+ # puts method
15
+ stack = stacks[thread][fiber]
16
+ case event
17
+ when 'call', 'c-call'
18
+ stack << method
19
+ when 'return', 'c-return'
20
+ last_method = stack.pop
21
+ if last_method != method
22
+ puts "LINE #{i}: return event without call: #{method}"
23
+ puts "STACK: #{stack.inspect}"
24
+ if stack.find(method)
25
+ puts "fixing stack"
26
+ while (popped = stack.pop) && (popped != method)
27
+ puts "popped #{popped}"
28
+ end
29
+ else
30
+ raise "stack unfixable"
31
+ end
32
+ # stack << last_method
33
+ end
34
+ when 'line'
35
+ last_method = stack[-1]
36
+ if last_method != method
37
+ unless stack.find(method)
38
+ raise "LINE #{i}: line event without call: #{method}"
39
+ end
40
+ end
41
+ else
42
+ puts "unkown event"
43
+ end
44
+ end
45
+ puts stacks.inspect
@@ -0,0 +1,50 @@
1
+ = Flat Profiles
2
+
3
+ Flat profiles show the total amount of time spent in each method.
4
+ As an example, here is the output from running printers_test.rb.
5
+
6
+ Measure Mode: wall_time
7
+ Thread ID: 70355159212340
8
+ Fiber ID: 70355171633140
9
+ Total: 0.060485
10
+ Sort by: self_time
11
+
12
+ %self total self wait child calls name
13
+ 97.07 0.059 0.059 0.000 0.000 1001 Integer#upto
14
+ 0.92 0.059 0.001 0.000 0.059 1000 Object#is_prime
15
+ 0.66 0.060 0.000 0.000 0.059 1 Array#select
16
+ 0.59 0.000 0.000 0.000 0.000 1000 Kernel#rand
17
+ 0.50 0.001 0.000 0.000 0.000 1 Array#each_index
18
+ 0.20 0.000 0.000 0.000 0.000 1000 Kernel#respond_to_missing?
19
+ 0.01 0.000 0.000 0.000 0.000 1 Object#find_largest
20
+ 0.01 0.060 0.000 0.000 0.060 1 PrintersTest#setup
21
+ 0.01 0.060 0.000 0.000 0.060 1 Object#find_primes
22
+ 0.01 0.000 0.000 0.000 0.000 1 Class#new
23
+ 0.01 0.060 0.000 0.000 0.060 1 Object#run_primes
24
+ 0.00 0.000 0.000 0.000 0.000 1 Array#first
25
+ 0.00 0.001 0.000 0.000 0.001 1 Object#make_random_array
26
+ 0.00 0.000 0.000 0.000 0.000 1 Array#initialize
27
+
28
+ All values are in seconds.
29
+
30
+ The columns are:
31
+
32
+ %self - The percentage of time spent in this method, derived from self_time/total_time
33
+ total - The time spent in this method and its children.
34
+ self - The time spent in this method.
35
+ wait - amount of time this method waited for other threads
36
+ child - The time spent in this method's children.
37
+ calls - The number of times this method was called.
38
+ name - The name of the method.
39
+
40
+ Methods are sorted based on %self, therefore the methods that execute the longest are listed
41
+ first.
42
+
43
+ For example, wee can see that Integer#upto took the most time, 0.059
44
+ seconds. Method Object#is_prime calls this method, so the 0.59
45
+ seconds appear as child time for Object#is_prime.
46
+
47
+ The interpretation of method names is:
48
+ * MyObject#test - An instance method "test" of the class "MyObject"
49
+ * <Object:MyObject>#test - The <> characters indicate a singleton method on a singleton class.
50
+
@@ -0,0 +1,84 @@
1
+ digraph "Profile" {
2
+ labelloc=t;
3
+ labeljust=l;
4
+ subgraph "Thread 70140045951280" {
5
+ 70140046535720 [label="setup\n(100%)"];
6
+ 70140046535720 -> 70140046535660 [label="1/1" fontsize=10 fontcolor="#666666"];
7
+ 70140046535660 [label="run_primes\n(100%)"];
8
+ 70140046535660 -> 70140046534940 [label="1/1" fontsize=10 fontcolor="#666666"];
9
+ 70140046535660 -> 70140046535640 [label="1/1" fontsize=10 fontcolor="#666666"];
10
+ 70140046535660 -> 70140046534640 [label="1/1" fontsize=10 fontcolor="#666666"];
11
+ 70140046534940 [label="find_primes\n(93%)"];
12
+ 70140046534940 -> 70140046534920 [label="1/1" fontsize=10 fontcolor="#666666"];
13
+ 70140046534920 [label="select\n(93%)"];
14
+ 70140046534920 -> 70140046534840 [label="200/200" fontsize=10 fontcolor="#666666"];
15
+ 70140046534840 [label="is_prime\n(90%)"];
16
+ 70140046534840 -> 70140046534820 [label="200/201" fontsize=10 fontcolor="#666666"];
17
+ 70140046534820 [label="upto\n(87%)"];
18
+ 70140046535640 [label="make_random_array\n(7%)"];
19
+ 70140046535640 -> 70140046535500 [label="1/1" fontsize=10 fontcolor="#666666"];
20
+ 70140046535640 -> 70140046535600 [label="1/1" fontsize=10 fontcolor="#666666"];
21
+ 70140046535500 [label="each_index\n(6%)"];
22
+ 70140046535500 -> 70140046535140 [label="200/200" fontsize=10 fontcolor="#666666"];
23
+ 70140046535140 [label="rand\n(4%)"];
24
+ 70140046535140 -> 70140046535100 [label="200/200" fontsize=10 fontcolor="#666666"];
25
+ 70140046535100 [label="respond_to_missing?\n(1%)"];
26
+ 70140046534640 [label="find_largest\n(1%)"];
27
+ 70140046534640 -> 70140046534820 [label="1/201" fontsize=10 fontcolor="#666666"];
28
+ 70140046534640 -> 70140046534620 [label="1/1" fontsize=10 fontcolor="#666666"];
29
+ 70140046535600 [label="new\n(0%)"];
30
+ 70140046535600 -> 70140046535580 [label="1/1" fontsize=10 fontcolor="#666666"];
31
+ 70140046535580 [label="initialize\n(0%)"];
32
+ 70140046534620 [label="first\n(0%)"];
33
+ }
34
+ subgraph cluster_70140046962360 {
35
+ label = "PrintersTest";
36
+ fontcolor = "#666666";
37
+ fontsize = 16;
38
+ color = "#666666";
39
+ 70140046535720;
40
+ }
41
+ subgraph cluster_70140046962240 {
42
+ label = "Object";
43
+ fontcolor = "#666666";
44
+ fontsize = 16;
45
+ color = "#666666";
46
+ 70140046535660;
47
+ 70140046535640;
48
+ 70140046534940;
49
+ 70140046534840;
50
+ 70140046534640;
51
+ }
52
+ subgraph cluster_70140046962040 {
53
+ label = "Class";
54
+ fontcolor = "#666666";
55
+ fontsize = 16;
56
+ color = "#666666";
57
+ 70140046535600;
58
+ }
59
+ subgraph cluster_70140046961920 {
60
+ label = "Array";
61
+ fontcolor = "#666666";
62
+ fontsize = 16;
63
+ color = "#666666";
64
+ 70140046535580;
65
+ 70140046535500;
66
+ 70140046534920;
67
+ 70140046534620;
68
+ }
69
+ subgraph cluster_70140046961720 {
70
+ label = "Kernel";
71
+ fontcolor = "#666666";
72
+ fontsize = 16;
73
+ color = "#666666";
74
+ 70140046535140;
75
+ 70140046535100;
76
+ }
77
+ subgraph cluster_70140046961280 {
78
+ label = "Integer";
79
+ fontcolor = "#666666";
80
+ fontsize = 16;
81
+ color = "#666666";
82
+ 70140046534820;
83
+ }
84
+ }