Skip to content
Newer
Older
100755 85 lines (73 sloc) 2.65 KB
8ee0c59 @jeremy Tool for profiling resource usage in each require call.
jeremy authored
1 #!/usr/bin/env ruby
2 # Example:
a43213c @rochefort fix Example: Rename tools/profile_requires -> tools/profile
rochefort authored
3 # tools/profile activesupport/lib/active_support.rb
8ee0c59 @jeremy Tool for profiling resource usage in each require call.
jeremy authored
4 abort 'Use REE so you can profile memory and object allocation' unless GC.respond_to?(:enable_stats)
5
886eeed @jeremy Clean up tools/profile_requires a bit
jeremy authored
6 ENV['NO_RELOAD'] ||= '1'
7 ENV['RAILS_ENV'] ||= 'development'
8
8ee0c59 @jeremy Tool for profiling resource usage in each require call.
jeremy authored
9 GC.enable_stats
10 Gem.source_index
11 require 'benchmark'
12
886eeed @jeremy Clean up tools/profile_requires a bit
jeremy authored
13 module RequireProfiler
577034d @jeremy Ensure require and load are private - h/t apeiros
jeremy authored
14 private
886eeed @jeremy Clean up tools/profile_requires a bit
jeremy authored
15 def require(file, *args) RequireProfiler.profile(file) { super } end
16 def load(file, *args) RequireProfiler.profile(file) { super } end
17
18 @depth, @stats = 0, []
8ee0c59 @jeremy Tool for profiling resource usage in each require call.
jeremy authored
19 class << self
886eeed @jeremy Clean up tools/profile_requires a bit
jeremy authored
20 attr_accessor :depth
8ee0c59 @jeremy Tool for profiling resource usage in each require call.
jeremy authored
21 attr_accessor :stats
22
886eeed @jeremy Clean up tools/profile_requires a bit
jeremy authored
23 def profile(file)
24 stats << [file, depth]
25 self.depth += 1
26 heap_before, objects_before = GC.allocated_size, ObjectSpace.allocated_objects
27 result = nil
28 elapsed = Benchmark.realtime { result = yield }
29 heap_after, objects_after = GC.allocated_size, ObjectSpace.allocated_objects
30 self.depth -= 1
31 stats.pop if stats.last.first == file
32 stats << [file, depth, elapsed, heap_after - heap_before, objects_after - objects_before] if result
33 result
34 end
8ee0c59 @jeremy Tool for profiling resource usage in each require call.
jeremy authored
35 end
36 end
37
38 GC.start
39 before = GC.allocated_size
7b730a2 @jeremy Show GC time and # of runs too
jeremy authored
40 before_gctime, before_gcruns = GC.time, GC.collections
8ee0c59 @jeremy Tool for profiling resource usage in each require call.
jeremy authored
41 before_rss = `ps -o rss= -p #{Process.pid}`.to_i
42 before_live_objects = ObjectSpace.live_objects
43
44 path = ARGV.shift
45 if mode = ARGV.shift
46 require 'ruby-prof'
47 RubyProf.measure_mode = RubyProf.const_get(mode.upcase)
48 RubyProf.start
886eeed @jeremy Clean up tools/profile_requires a bit
jeremy authored
49 else
50 Object.instance_eval { include RequireProfiler }
8ee0c59 @jeremy Tool for profiling resource usage in each require call.
jeremy authored
51 end
52
53 elapsed = Benchmark.realtime { require path }
54 results = RubyProf.stop if mode
55
7b730a2 @jeremy Show GC time and # of runs too
jeremy authored
56 after_gctime, after_gcruns = GC.time, GC.collections
8ee0c59 @jeremy Tool for profiling resource usage in each require call.
jeremy authored
57 GC.start
58 after_live_objects = ObjectSpace.live_objects
59 after_rss = `ps -o rss= -p #{Process.pid}`.to_i
60 after = GC.allocated_size
61 usage = (after - before) / 1024.0
62
63 if mode
4883082 @jeremy Support an extra profile printer arg
jeremy authored
64 if printer = ARGV.shift
65 RubyProf.const_get("#{printer.to_s.classify}Printer").new(results).print($stdout)
66 elsif RubyProf.const_defined?(:CallStackPrinter)
50cdb65 @jeremy Use call stack printer if available
jeremy authored
67 File.open("#{File.basename(path, '.rb')}.#{mode}.html", 'w') do |out|
68 RubyProf::CallStackPrinter.new(results).print(out)
69 end
70 else
71 File.open("#{File.basename(path, '.rb')}.#{mode}.callgrind", 'w') do |out|
72 RubyProf::CallTreePrinter.new(results).print(out)
73 end
8ee0c59 @jeremy Tool for profiling resource usage in each require call.
jeremy authored
74 end
75 end
76
886eeed @jeremy Clean up tools/profile_requires a bit
jeremy authored
77 RequireProfiler.stats.each do |file, depth, sec, bytes, objects|
e9c5750 @jeremy Preserve ordering
jeremy authored
78 if sec
886eeed @jeremy Clean up tools/profile_requires a bit
jeremy authored
79 puts "%10.2f KB %10d obj %8.1f ms %s%s" % [bytes / 1024.0, objects, sec * 1000, ' ' * depth, file]
e9c5750 @jeremy Preserve ordering
jeremy authored
80 else
886eeed @jeremy Clean up tools/profile_requires a bit
jeremy authored
81 puts "#{' ' * (42 + depth)}#{file}"
e9c5750 @jeremy Preserve ordering
jeremy authored
82 end
8ee0c59 @jeremy Tool for profiling resource usage in each require call.
jeremy authored
83 end
7b730a2 @jeremy Show GC time and # of runs too
jeremy authored
84 puts "%10.2f KB %10d obj %8.1f ms %d KB RSS %8.1f ms GC time %d GC runs" % [usage, after_live_objects - before_live_objects, elapsed * 1000, after_rss - before_rss, (after_gctime - before_gctime) / 1000.0, after_gcruns - before_gcruns]
Something went wrong with that request. Please try again.