bin/stackprof in stackprof-0.2.21 vs bin/stackprof in stackprof-0.2.22
- old
+ new
@@ -1,95 +1,130 @@
#!/usr/bin/env ruby
require 'optparse'
require 'stackprof'
-options = {}
+if ARGV.first == "run"
+ ARGV.shift
+ env = {}
+ parser = OptionParser.new(ARGV) do |o|
+ o.banner = "Usage: stackprof run [--mode|--out|--interval] -- COMMAND"
+ o.banner = "Usage: stackprof [file.dump]+ [--text|--method=NAME|--callgrind|--graphviz]"
-parser = OptionParser.new(ARGV) do |o|
- o.banner = "Usage: stackprof [file.dump]+ [--text|--method=NAME|--callgrind|--graphviz]"
+ o.on('--mode', 'Mode of sampling: cpu, wall, object, default to wall') do |mode|
+ env["STACKPROF_MODE"] = mode
+ end
- o.on('--text', 'Text summary per method (default)'){ options[:format] = :text }
- o.on('--json', 'JSON output (use with web viewers)'){ options[:format] = :json }
- o.on('--files', 'List of files'){ |f| options[:format] = :files }
- o.on('--limit [num]', Integer, 'Limit --text, --files, or --graphviz output to N entries'){ |n| options[:limit] = n }
- o.on('--sort-total', "Sort --text or --files output on total samples\n\n"){ options[:sort] = true }
- o.on('--method [grep]', 'Zoom into specified method'){ |f| options[:format] = :method; options[:filter] = f }
- o.on('--file [grep]', "Show annotated code for specified file"){ |f| options[:format] = :file; options[:filter] = f }
- o.on('--walk', "Walk the stacktrace interactively\n\n"){ |f| options[:walk] = true }
- o.on('--callgrind', 'Callgrind output (use with kcachegrind, stackprof-gprof2dot.py)'){ options[:format] = :callgrind }
- o.on('--graphviz', "Graphviz output (use with dot)"){ options[:format] = :graphviz }
- o.on('--node-fraction [frac]', OptionParser::DecimalNumeric, 'Drop nodes representing less than [frac] fraction of samples'){ |n| options[:node_fraction] = n }
- o.on('--stackcollapse', 'stackcollapse.pl compatible output (use with stackprof-flamegraph.pl)'){ options[:format] = :stackcollapse }
- o.on('--timeline-flamegraph', "timeline-flamegraph output (js)"){ options[:format] = :timeline_flamegraph }
- o.on('--alphabetical-flamegraph', "alphabetical-flamegraph output (js)"){ options[:format] = :alphabetical_flamegraph }
- o.on('--flamegraph', "alias to --timeline-flamegraph"){ options[:format] = :timeline_flamegraph }
- o.on('--flamegraph-viewer [f.js]', String, "open html viewer for flamegraph output"){ |file|
- puts("open file://#{File.expand_path('../../lib/stackprof/flamegraph/viewer.html', __FILE__)}?data=#{File.expand_path(file)}")
- exit
- }
- o.on('--d3-flamegraph', "flamegraph output (html using d3-flame-graph)\n\n"){ options[:format] = :d3_flamegraph }
- o.on('--select-files []', String, 'Show results of matching files'){ |path| (options[:select_files] ||= []) << File.expand_path(path) }
- o.on('--reject-files []', String, 'Exclude results of matching files'){ |path| (options[:reject_files] ||= []) << File.expand_path(path) }
- o.on('--select-names []', Regexp, 'Show results of matching method names'){ |regexp| (options[:select_names] ||= []) << regexp }
- o.on('--reject-names []', Regexp, 'Exclude results of matching method names'){ |regexp| (options[:reject_names] ||= []) << regexp }
- o.on('--dump', 'Print marshaled profile dump (combine multiple profiles)'){ options[:format] = :dump }
- o.on('--debug', 'Pretty print raw profile data'){ options[:format] = :debug }
-end
+ o.on('--out', 'The target file, which will be overwritten. Defaults to a random temporary file') do |out|
+ env['STACKPROF_OUT'] = out
+ end
-parser.parse!
-parser.abort(parser.help) if ARGV.empty?
+ o.on('--interval', 'Mode-relative sample rate') do |interval|
+ env['STACKPROF_INTERVAL'] = Integer(interval).to_s
+ end
-reports = []
-while ARGV.size > 0
- begin
- file = ARGV.pop
- reports << StackProf::Report.from_file(file)
- rescue TypeError => e
- STDERR.puts "** error parsing #{file}: #{e.inspect}"
+ o.on('--raw', 'collects the extra data required by the --flamegraph and --stackcollapse report types') do
+ env['STACKPROF_RAW'] = '1'
+ end
+
+ o.on('--ignore-gc', 'Ignore garbage collection frames') do
+ env['STACKPROF_IGNORE_GC'] = '1'
+ end
end
-end
-report = reports.inject(:+)
+ parser.parse!
+ parser.abort(parser.help) if ARGV.empty?
+ stackprof_path = File.expand_path('../lib', __dir__)
+ env['RUBYOPT'] = "-I #{stackprof_path} -r stackprof/autorun #{ENV['RUBYOPT']}"
+ Kernel.exec(env, *ARGV)
+else
+ options = {}
-default_options = {
- :format => :text,
- :sort => false,
- :limit => 30
-}
+ parser = OptionParser.new(ARGV) do |o|
+ o.banner = "Usage: stackprof run [--mode|--out|--interval] -- COMMAND"
+ o.banner = "Usage: stackprof [file.dump]+ [--text|--method=NAME|--callgrind|--graphviz]"
-if options[:format] == :graphviz
- default_options[:limit] = 120
- default_options[:node_fraction] = 0.005
-end
+ o.on('--text', 'Text summary per method (default)'){ options[:format] = :text }
+ o.on('--json', 'JSON output (use with web viewers)'){ options[:format] = :json }
+ o.on('--files', 'List of files'){ |f| options[:format] = :files }
+ o.on('--limit [num]', Integer, 'Limit --text, --files, or --graphviz output to N entries'){ |n| options[:limit] = n }
+ o.on('--sort-total', "Sort --text or --files output on total samples\n\n"){ options[:sort] = true }
+ o.on('--method [grep]', 'Zoom into specified method'){ |f| options[:format] = :method; options[:filter] = f }
+ o.on('--file [grep]', "Show annotated code for specified file"){ |f| options[:format] = :file; options[:filter] = f }
+ o.on('--walk', "Walk the stacktrace interactively\n\n"){ |f| options[:walk] = true }
+ o.on('--callgrind', 'Callgrind output (use with kcachegrind, stackprof-gprof2dot.py)'){ options[:format] = :callgrind }
+ o.on('--graphviz', "Graphviz output (use with dot)"){ options[:format] = :graphviz }
+ o.on('--node-fraction [frac]', OptionParser::DecimalNumeric, 'Drop nodes representing less than [frac] fraction of samples'){ |n| options[:node_fraction] = n }
+ o.on('--stackcollapse', 'stackcollapse.pl compatible output (use with stackprof-flamegraph.pl)'){ options[:format] = :stackcollapse }
+ o.on('--timeline-flamegraph', "timeline-flamegraph output (js)"){ options[:format] = :timeline_flamegraph }
+ o.on('--alphabetical-flamegraph', "alphabetical-flamegraph output (js)"){ options[:format] = :alphabetical_flamegraph }
+ o.on('--flamegraph', "alias to --timeline-flamegraph"){ options[:format] = :timeline_flamegraph }
+ o.on('--flamegraph-viewer [f.js]', String, "open html viewer for flamegraph output"){ |file|
+ puts("open file://#{File.expand_path('../../lib/stackprof/flamegraph/viewer.html', __FILE__)}?data=#{File.expand_path(file)}")
+ exit
+ }
+ o.on('--d3-flamegraph', "flamegraph output (html using d3-flame-graph)\n\n"){ options[:format] = :d3_flamegraph }
+ o.on('--select-files []', String, 'Show results of matching files'){ |path| (options[:select_files] ||= []) << File.expand_path(path) }
+ o.on('--reject-files []', String, 'Exclude results of matching files'){ |path| (options[:reject_files] ||= []) << File.expand_path(path) }
+ o.on('--select-names []', Regexp, 'Show results of matching method names'){ |regexp| (options[:select_names] ||= []) << regexp }
+ o.on('--reject-names []', Regexp, 'Exclude results of matching method names'){ |regexp| (options[:reject_names] ||= []) << regexp }
+ o.on('--dump', 'Print marshaled profile dump (combine multiple profiles)'){ options[:format] = :dump }
+ o.on('--debug', 'Pretty print raw profile data'){ options[:format] = :debug }
+ end
-options = default_options.merge(options)
-options.delete(:limit) if options[:limit] == 0
+ parser.parse!
+ parser.abort(parser.help) if ARGV.empty?
-case options[:format]
-when :text
- report.print_text(options[:sort], options[:limit], options[:select_files], options[:reject_files], options[:select_names], options[:reject_names])
-when :json
- report.print_json
-when :debug
- report.print_debug
-when :dump
- report.print_dump
-when :callgrind
- report.print_callgrind
-when :graphviz
- report.print_graphviz(options)
-when :stackcollapse
- report.print_stackcollapse
-when :timeline_flamegraph
- report.print_timeline_flamegraph
-when :alphabetical_flamegraph
- report.print_alphabetical_flamegraph
-when :d3_flamegraph
- report.print_d3_flamegraph
-when :method
- options[:walk] ? report.walk_method(options[:filter]) : report.print_method(options[:filter])
-when :file
- report.print_file(options[:filter])
-when :files
- report.print_files(options[:sort], options[:limit])
-else
- raise ArgumentError, "unknown format: #{options[:format]}"
+ reports = []
+ while ARGV.size > 0
+ begin
+ file = ARGV.pop
+ reports << StackProf::Report.from_file(file)
+ rescue TypeError => e
+ STDERR.puts "** error parsing #{file}: #{e.inspect}"
+ end
+ end
+ report = reports.inject(:+)
+
+ default_options = {
+ :format => :text,
+ :sort => false,
+ :limit => 30
+ }
+
+ if options[:format] == :graphviz
+ default_options[:limit] = 120
+ default_options[:node_fraction] = 0.005
+ end
+
+ options = default_options.merge(options)
+ options.delete(:limit) if options[:limit] == 0
+
+ case options[:format]
+ when :text
+ report.print_text(options[:sort], options[:limit], options[:select_files], options[:reject_files], options[:select_names], options[:reject_names])
+ when :json
+ report.print_json
+ when :debug
+ report.print_debug
+ when :dump
+ report.print_dump
+ when :callgrind
+ report.print_callgrind
+ when :graphviz
+ report.print_graphviz(options)
+ when :stackcollapse
+ report.print_stackcollapse
+ when :timeline_flamegraph
+ report.print_timeline_flamegraph
+ when :alphabetical_flamegraph
+ report.print_alphabetical_flamegraph
+ when :d3_flamegraph
+ report.print_d3_flamegraph
+ when :method
+ options[:walk] ? report.walk_method(options[:filter]) : report.print_method(options[:filter])
+ when :file
+ report.print_file(options[:filter])
+ when :files
+ report.print_files(options[:sort], options[:limit])
+ else
+ raise ArgumentError, "unknown format: #{options[:format]}"
+ end
end