stackprof 0.2.20 → 0.2.22
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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +1 -1
- data/Rakefile +14 -4
- data/bin/stackprof +116 -81
- data/ext/stackprof/extconf.rb +6 -0
- data/ext/stackprof/stackprof.c +8 -8
- data/lib/stackprof/autorun.rb +19 -0
- data/lib/stackprof/report.rb +3 -3
- data/lib/stackprof/truffleruby.rb +37 -0
- data/lib/stackprof.rb +6 -2
- data/stackprof.gemspec +1 -1
- data/test/test_stackprof.rb +1 -1
- data/test/test_truffleruby.rb +18 -0
- metadata +8 -5
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 8e473c6b4408f04dc69f4abd425ab68896b4f705adadd467ded771003eb84da1
         | 
| 4 | 
            +
              data.tar.gz: 5bfaa3c22d7e59271f65136b0237cddc4d1a97edf9650db4caf53c9b36fda55e
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: eb0ffc8bac6c1c66b13ce67d89bac3fbd1c601754024c3e8455e194a35e58f3c515586aa0ffeee4e30985a6e140ce64724c0960dce8de67d8a3e0f0e912d3898
         | 
| 7 | 
            +
              data.tar.gz: 4cfc9aa211ab10a7b0a0c222e94538311bd91950fa32fc0602e2535468df4c48158219cad2f2f6fee015f94a9b415c3a285406fcc66ab27676a6572492b2d7f9
         | 
    
        data/.github/workflows/ci.yml
    CHANGED
    
    | @@ -8,7 +8,7 @@ jobs: | |
| 8 8 | 
             
                strategy:
         | 
| 9 9 | 
             
                  fail-fast: false
         | 
| 10 10 | 
             
                  matrix:
         | 
| 11 | 
            -
                    ruby: [ ruby-head, '3.1', '3.0', '2.7', '2.6', '2.5', '2.4', '2.3', '2.2' ]
         | 
| 11 | 
            +
                    ruby: [ ruby-head, '3.1', '3.0', '2.7', '2.6', '2.5', '2.4', '2.3', '2.2', truffleruby ]
         | 
| 12 12 | 
             
                steps:
         | 
| 13 13 | 
             
                  - name: Checkout
         | 
| 14 14 | 
             
                    uses: actions/checkout@v2
         | 
    
        data/Rakefile
    CHANGED
    
    | @@ -7,11 +7,21 @@ Rake::TestTask.new(:test) do |t| | |
| 7 7 | 
             
              t.test_files = FileList["test/**/test_*.rb"]
         | 
| 8 8 | 
             
            end
         | 
| 9 9 |  | 
| 10 | 
            -
             | 
| 10 | 
            +
            if RUBY_ENGINE == "truffleruby"
         | 
| 11 | 
            +
              task :compile do
         | 
| 12 | 
            +
                # noop
         | 
| 13 | 
            +
              end
         | 
| 11 14 |  | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
               | 
| 15 | 
            +
              task :clean do
         | 
| 16 | 
            +
                # noop
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            else
         | 
| 19 | 
            +
              require "rake/extensiontask"
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              Rake::ExtensionTask.new("stackprof") do |ext|
         | 
| 22 | 
            +
                ext.ext_dir = "ext/stackprof"
         | 
| 23 | 
            +
                ext.lib_dir = "lib/stackprof"
         | 
| 24 | 
            +
              end
         | 
| 15 25 | 
             
            end
         | 
| 16 26 |  | 
| 17 27 | 
             
            task default: %i(compile test)
         | 
    
        data/bin/stackprof
    CHANGED
    
    | @@ -2,94 +2,129 @@ | |
| 2 2 | 
             
            require 'optparse'
         | 
| 3 3 | 
             
            require 'stackprof'
         | 
| 4 4 |  | 
| 5 | 
            -
             | 
| 5 | 
            +
            if ARGV.first == "run"
         | 
| 6 | 
            +
              ARGV.shift
         | 
| 7 | 
            +
              env = {}
         | 
| 8 | 
            +
              parser = OptionParser.new(ARGV) do |o|
         | 
| 9 | 
            +
                o.banner = "Usage: stackprof run [--mode|--out|--interval] -- COMMAND"
         | 
| 10 | 
            +
                o.banner = "Usage: stackprof [file.dump]+ [--text|--method=NAME|--callgrind|--graphviz]"
         | 
| 6 11 |  | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 12 | 
            +
                o.on('--mode', 'Mode of sampling: cpu, wall, object, default to wall') do |mode|
         | 
| 13 | 
            +
                  env["STACKPROF_MODE"] = mode
         | 
| 14 | 
            +
                end
         | 
| 9 15 |  | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
              o.on('--limit [num]', Integer, 'Limit --text, --files, or --graphviz output to N entries'){ |n| options[:limit] = n }
         | 
| 14 | 
            -
              o.on('--sort-total', "Sort --text or --files output on total samples\n\n"){ options[:sort] = true }
         | 
| 15 | 
            -
              o.on('--method [grep]', 'Zoom into specified method'){ |f| options[:format] = :method; options[:filter] = f }
         | 
| 16 | 
            -
              o.on('--file [grep]', "Show annotated code for specified file"){ |f| options[:format] = :file; options[:filter] = f }
         | 
| 17 | 
            -
              o.on('--walk', "Walk the stacktrace interactively\n\n"){ |f| options[:walk] = true }
         | 
| 18 | 
            -
              o.on('--callgrind', 'Callgrind output (use with kcachegrind, stackprof-gprof2dot.py)'){ options[:format] = :callgrind }
         | 
| 19 | 
            -
              o.on('--graphviz', "Graphviz output (use with dot)"){ options[:format] = :graphviz }
         | 
| 20 | 
            -
              o.on('--node-fraction [frac]', OptionParser::DecimalNumeric, 'Drop nodes representing less than [frac] fraction of samples'){ |n| options[:node_fraction] = n }
         | 
| 21 | 
            -
              o.on('--stackcollapse', 'stackcollapse.pl compatible output (use with stackprof-flamegraph.pl)'){ options[:format] = :stackcollapse }
         | 
| 22 | 
            -
              o.on('--timeline-flamegraph', "timeline-flamegraph output (js)"){ options[:format] = :timeline_flamegraph }
         | 
| 23 | 
            -
              o.on('--alphabetical-flamegraph', "alphabetical-flamegraph output (js)"){ options[:format] = :alphabetical_flamegraph }
         | 
| 24 | 
            -
              o.on('--flamegraph', "alias to --timeline-flamegraph"){ options[:format] = :timeline_flamegraph }
         | 
| 25 | 
            -
              o.on('--flamegraph-viewer [f.js]', String, "open html viewer for flamegraph output"){ |file|
         | 
| 26 | 
            -
                puts("open file://#{File.expand_path('../../lib/stackprof/flamegraph/viewer.html', __FILE__)}?data=#{File.expand_path(file)}")
         | 
| 27 | 
            -
                exit
         | 
| 28 | 
            -
              }
         | 
| 29 | 
            -
              o.on('--d3-flamegraph', "flamegraph output (html using d3-flame-graph)\n\n"){ options[:format] = :d3_flamegraph }
         | 
| 30 | 
            -
              o.on('--select-files []', String, 'Show results of matching files'){ |path| (options[:select_files] ||= []) << File.expand_path(path) }
         | 
| 31 | 
            -
              o.on('--reject-files []', String, 'Exclude results of matching files'){ |path| (options[:reject_files] ||= []) << File.expand_path(path) }
         | 
| 32 | 
            -
              o.on('--select-names []', Regexp, 'Show results of matching method names'){ |regexp| (options[:select_names] ||= []) << regexp }
         | 
| 33 | 
            -
              o.on('--reject-names []', Regexp, 'Exclude results of matching method names'){ |regexp| (options[:reject_names] ||= []) << regexp }
         | 
| 34 | 
            -
              o.on('--dump', 'Print marshaled profile dump (combine multiple profiles)'){ options[:format] = :dump }
         | 
| 35 | 
            -
              o.on('--debug', 'Pretty print raw profile data'){ options[:format] = :debug }
         | 
| 36 | 
            -
            end
         | 
| 16 | 
            +
                o.on('--out', 'The target file, which will be overwritten. Defaults to a random temporary file') do |out|
         | 
| 17 | 
            +
                  env['STACKPROF_OUT'] = out
         | 
| 18 | 
            +
                end
         | 
| 37 19 |  | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 20 | 
            +
                o.on('--interval', 'Mode-relative sample rate') do |interval|
         | 
| 21 | 
            +
                  env['STACKPROF_INTERVAL'] = Integer(interval).to_s
         | 
| 22 | 
            +
                end
         | 
| 40 23 |  | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
                 | 
| 46 | 
            -
             | 
| 47 | 
            -
                 | 
| 24 | 
            +
                o.on('--raw', 'collects the extra data required by the --flamegraph and --stackcollapse report types') do
         | 
| 25 | 
            +
                  env['STACKPROF_RAW'] = '1'
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                o.on('--ignore-gc', 'Ignore garbage collection frames') do
         | 
| 29 | 
            +
                  env['STACKPROF_IGNORE_GC'] = '1'
         | 
| 30 | 
            +
                end
         | 
| 48 31 | 
             
              end
         | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 32 | 
            +
              parser.parse!
         | 
| 33 | 
            +
              parser.abort(parser.help) if ARGV.empty?
         | 
| 34 | 
            +
              stackprof_path = File.expand_path('../lib', __dir__)
         | 
| 35 | 
            +
              env['RUBYOPT'] = "-I #{stackprof_path} -r stackprof/autorun #{ENV['RUBYOPT']}"
         | 
| 36 | 
            +
              Kernel.exec(env, *ARGV)
         | 
| 37 | 
            +
            else
         | 
| 38 | 
            +
              options = {}
         | 
| 51 39 |  | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
              :limit => 30
         | 
| 56 | 
            -
            }
         | 
| 40 | 
            +
              parser = OptionParser.new(ARGV) do |o|
         | 
| 41 | 
            +
                o.banner = "Usage: stackprof run [--mode|--out|--interval] -- COMMAND"
         | 
| 42 | 
            +
                o.banner = "Usage: stackprof [file.dump]+ [--text|--method=NAME|--callgrind|--graphviz]"
         | 
| 57 43 |  | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 44 | 
            +
                o.on('--text', 'Text summary per method (default)'){ options[:format] = :text }
         | 
| 45 | 
            +
                o.on('--json', 'JSON output (use with web viewers)'){ options[:format] = :json }
         | 
| 46 | 
            +
                o.on('--files', 'List of files'){ |f| options[:format] = :files }
         | 
| 47 | 
            +
                o.on('--limit [num]', Integer, 'Limit --text, --files, or --graphviz output to N entries'){ |n| options[:limit] = n }
         | 
| 48 | 
            +
                o.on('--sort-total', "Sort --text or --files output on total samples\n\n"){ options[:sort] = true }
         | 
| 49 | 
            +
                o.on('--method [grep]', 'Zoom into specified method'){ |f| options[:format] = :method; options[:filter] = f }
         | 
| 50 | 
            +
                o.on('--file [grep]', "Show annotated code for specified file"){ |f| options[:format] = :file; options[:filter] = f }
         | 
| 51 | 
            +
                o.on('--walk', "Walk the stacktrace interactively\n\n"){ |f| options[:walk] = true }
         | 
| 52 | 
            +
                o.on('--callgrind', 'Callgrind output (use with kcachegrind, stackprof-gprof2dot.py)'){ options[:format] = :callgrind }
         | 
| 53 | 
            +
                o.on('--graphviz', "Graphviz output (use with dot)"){ options[:format] = :graphviz }
         | 
| 54 | 
            +
                o.on('--node-fraction [frac]', OptionParser::DecimalNumeric, 'Drop nodes representing less than [frac] fraction of samples'){ |n| options[:node_fraction] = n }
         | 
| 55 | 
            +
                o.on('--stackcollapse', 'stackcollapse.pl compatible output (use with stackprof-flamegraph.pl)'){ options[:format] = :stackcollapse }
         | 
| 56 | 
            +
                o.on('--timeline-flamegraph', "timeline-flamegraph output (js)"){ options[:format] = :timeline_flamegraph }
         | 
| 57 | 
            +
                o.on('--alphabetical-flamegraph', "alphabetical-flamegraph output (js)"){ options[:format] = :alphabetical_flamegraph }
         | 
| 58 | 
            +
                o.on('--flamegraph', "alias to --timeline-flamegraph"){ options[:format] = :timeline_flamegraph }
         | 
| 59 | 
            +
                o.on('--flamegraph-viewer [f.js]', String, "open html viewer for flamegraph output"){ |file|
         | 
| 60 | 
            +
                  puts("open file://#{File.expand_path('../../lib/stackprof/flamegraph/viewer.html', __FILE__)}?data=#{File.expand_path(file)}")
         | 
| 61 | 
            +
                  exit
         | 
| 62 | 
            +
                }
         | 
| 63 | 
            +
                o.on('--d3-flamegraph', "flamegraph output (html using d3-flame-graph)\n\n"){ options[:format] = :d3_flamegraph }
         | 
| 64 | 
            +
                o.on('--select-files []', String, 'Show results of matching files'){ |path| (options[:select_files] ||= []) << File.expand_path(path) }
         | 
| 65 | 
            +
                o.on('--reject-files []', String, 'Exclude results of matching files'){ |path| (options[:reject_files] ||= []) << File.expand_path(path) }
         | 
| 66 | 
            +
                o.on('--select-names []', Regexp, 'Show results of matching method names'){ |regexp| (options[:select_names] ||= []) << regexp }
         | 
| 67 | 
            +
                o.on('--reject-names []', Regexp, 'Exclude results of matching method names'){ |regexp| (options[:reject_names] ||= []) << regexp }
         | 
| 68 | 
            +
                o.on('--dump', 'Print marshaled profile dump (combine multiple profiles)'){ options[:format] = :dump }
         | 
| 69 | 
            +
                o.on('--debug', 'Pretty print raw profile data'){ options[:format] = :debug }
         | 
| 70 | 
            +
              end
         | 
| 62 71 |  | 
| 63 | 
            -
             | 
| 64 | 
            -
             | 
| 72 | 
            +
              parser.parse!
         | 
| 73 | 
            +
              parser.abort(parser.help) if ARGV.empty?
         | 
| 65 74 |  | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 74 | 
            -
               | 
| 75 | 
            -
             | 
| 76 | 
            -
             | 
| 77 | 
            -
             | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 81 | 
            -
             | 
| 82 | 
            -
             | 
| 83 | 
            -
             | 
| 84 | 
            -
             | 
| 85 | 
            -
             | 
| 86 | 
            -
               | 
| 87 | 
            -
             | 
| 88 | 
            -
              options | 
| 89 | 
            -
             | 
| 90 | 
            -
             | 
| 91 | 
            -
             | 
| 92 | 
            -
               | 
| 93 | 
            -
             | 
| 94 | 
            -
               | 
| 75 | 
            +
              reports = []
         | 
| 76 | 
            +
              while ARGV.size > 0
         | 
| 77 | 
            +
                begin
         | 
| 78 | 
            +
                  file = ARGV.pop
         | 
| 79 | 
            +
                  reports << StackProf::Report.from_file(file)
         | 
| 80 | 
            +
                rescue TypeError => e
         | 
| 81 | 
            +
                  STDERR.puts "** error parsing #{file}: #{e.inspect}"
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
              end
         | 
| 84 | 
            +
              report = reports.inject(:+)
         | 
| 85 | 
            +
             | 
| 86 | 
            +
              default_options = {
         | 
| 87 | 
            +
                :format => :text,
         | 
| 88 | 
            +
                :sort => false,
         | 
| 89 | 
            +
                :limit => 30
         | 
| 90 | 
            +
              }
         | 
| 91 | 
            +
             | 
| 92 | 
            +
              if options[:format] == :graphviz
         | 
| 93 | 
            +
                default_options[:limit] = 120
         | 
| 94 | 
            +
                default_options[:node_fraction] = 0.005
         | 
| 95 | 
            +
              end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
              options = default_options.merge(options)
         | 
| 98 | 
            +
              options.delete(:limit) if options[:limit] == 0
         | 
| 99 | 
            +
             | 
| 100 | 
            +
              case options[:format]
         | 
| 101 | 
            +
              when :text
         | 
| 102 | 
            +
                report.print_text(options[:sort], options[:limit], options[:select_files], options[:reject_files], options[:select_names], options[:reject_names])
         | 
| 103 | 
            +
              when :json
         | 
| 104 | 
            +
                report.print_json
         | 
| 105 | 
            +
              when :debug
         | 
| 106 | 
            +
                report.print_debug
         | 
| 107 | 
            +
              when :dump
         | 
| 108 | 
            +
                report.print_dump
         | 
| 109 | 
            +
              when :callgrind
         | 
| 110 | 
            +
                report.print_callgrind
         | 
| 111 | 
            +
              when :graphviz
         | 
| 112 | 
            +
                report.print_graphviz(options)
         | 
| 113 | 
            +
              when :stackcollapse
         | 
| 114 | 
            +
                report.print_stackcollapse
         | 
| 115 | 
            +
              when :timeline_flamegraph
         | 
| 116 | 
            +
                report.print_timeline_flamegraph
         | 
| 117 | 
            +
              when :alphabetical_flamegraph
         | 
| 118 | 
            +
                report.print_alphabetical_flamegraph
         | 
| 119 | 
            +
              when :d3_flamegraph
         | 
| 120 | 
            +
                report.print_d3_flamegraph
         | 
| 121 | 
            +
              when :method
         | 
| 122 | 
            +
                options[:walk] ? report.walk_method(options[:filter]) : report.print_method(options[:filter])
         | 
| 123 | 
            +
              when :file
         | 
| 124 | 
            +
                report.print_file(options[:filter])
         | 
| 125 | 
            +
              when :files
         | 
| 126 | 
            +
                report.print_files(options[:sort], options[:limit])
         | 
| 127 | 
            +
              else
         | 
| 128 | 
            +
                raise ArgumentError, "unknown format: #{options[:format]}"
         | 
| 129 | 
            +
              end
         | 
| 95 130 | 
             
            end
         | 
    
        data/ext/stackprof/extconf.rb
    CHANGED
    
    
    
        data/ext/stackprof/stackprof.c
    CHANGED
    
    | @@ -146,6 +146,7 @@ stackprof_start(int argc, VALUE *argv, VALUE self) | |
| 146 146 | 
             
                VALUE opts = Qnil, mode = Qnil, interval = Qnil, metadata = rb_hash_new(), out = Qfalse;
         | 
| 147 147 | 
             
                int ignore_gc = 0;
         | 
| 148 148 | 
             
                int raw = 0, aggregate = 1;
         | 
| 149 | 
            +
                VALUE metadata_val;
         | 
| 149 150 |  | 
| 150 151 | 
             
                if (_stackprof.running)
         | 
| 151 152 | 
             
            	return Qfalse;
         | 
| @@ -160,7 +161,7 @@ stackprof_start(int argc, VALUE *argv, VALUE self) | |
| 160 161 | 
             
            	    ignore_gc = 1;
         | 
| 161 162 | 
             
            	}
         | 
| 162 163 |  | 
| 163 | 
            -
            	 | 
| 164 | 
            +
            	metadata_val = rb_hash_aref(opts, sym_metadata);
         | 
| 164 165 | 
             
            	if (RTEST(metadata_val)) {
         | 
| 165 166 | 
             
            	    if (!RB_TYPE_P(metadata_val, T_HASH))
         | 
| 166 167 | 
             
            		rb_raise(rb_eArgError, "metadata should be a hash");
         | 
| @@ -597,14 +598,15 @@ stackprof_record_sample_for_stack(int num, uint64_t sample_timestamp, int64_t ti | |
| 597 598 | 
             
            void
         | 
| 598 599 | 
             
            stackprof_buffer_sample(void)
         | 
| 599 600 | 
             
            {
         | 
| 601 | 
            +
                uint64_t start_timestamp = 0;
         | 
| 602 | 
            +
                int64_t timestamp_delta = 0;
         | 
| 603 | 
            +
                int num;
         | 
| 604 | 
            +
             | 
| 600 605 | 
             
                if (_stackprof.buffer_count > 0) {
         | 
| 601 606 | 
             
            	// Another sample is already pending
         | 
| 602 607 | 
             
            	return;
         | 
| 603 608 | 
             
                }
         | 
| 604 609 |  | 
| 605 | 
            -
                uint64_t start_timestamp = 0;
         | 
| 606 | 
            -
                int64_t timestamp_delta = 0;
         | 
| 607 | 
            -
                int num;
         | 
| 608 610 | 
             
                if (_stackprof.raw) {
         | 
| 609 611 | 
             
            	struct timestamp_t t;
         | 
| 610 612 | 
             
            	capture_timestamp(&t);
         | 
| @@ -828,15 +830,13 @@ stackprof_use_postponed_job_l(VALUE self) | |
| 828 830 | 
             
            void
         | 
| 829 831 | 
             
            Init_stackprof(void)
         | 
| 830 832 | 
             
            {
         | 
| 833 | 
            +
                size_t i;
         | 
| 831 834 | 
             
               /*
         | 
| 832 835 | 
             
                * As of Ruby 3.0, it should be safe to read stack frames at any time, unless YJIT is enabled
         | 
| 833 836 | 
             
                * See https://github.com/ruby/ruby/commit/0e276dc458f94d9d79a0f7c7669bde84abe80f21
         | 
| 834 837 | 
             
                */
         | 
| 835 | 
            -
                 | 
| 836 | 
            -
                stackprof_use_postponed_job = 0;
         | 
| 837 | 
            -
                #endif
         | 
| 838 | 
            +
                stackprof_use_postponed_job = RUBY_API_VERSION_MAJOR < 3;
         | 
| 838 839 |  | 
| 839 | 
            -
                size_t i;
         | 
| 840 840 | 
             
            #define S(name) sym_##name = ID2SYM(rb_intern(#name));
         | 
| 841 841 | 
             
                S(object);
         | 
| 842 842 | 
             
                S(custom);
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            require "stackprof"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            options = {}
         | 
| 4 | 
            +
            options[:mode] = ENV["STACKPROF_MODE"].to_sym if ENV.key?("STACKPROF_MODE")
         | 
| 5 | 
            +
            options[:interval] = Integer(ENV["STACKPROF_INTERVAL"]) if ENV.key?("STACKPROF_INTERVAL")
         | 
| 6 | 
            +
            options[:raw] = true if ENV["STACKPROF_RAW"]
         | 
| 7 | 
            +
            options[:ignore_gc] = true if ENV["STACKPROF_IGNORE_GC"]
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            at_exit do
         | 
| 10 | 
            +
              StackProf.stop
         | 
| 11 | 
            +
              output_path = ENV.fetch("STACKPROF_OUT") do
         | 
| 12 | 
            +
                require "tempfile"
         | 
| 13 | 
            +
                Tempfile.create(["stackprof", ".dump"]).path
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
              StackProf.results(output_path)
         | 
| 16 | 
            +
              $stderr.puts("StackProf results dumped at: #{output_path}")
         | 
| 17 | 
            +
            end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            StackProf.start(**options)
         | 
    
        data/lib/stackprof/report.rb
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            require 'pp'
         | 
| 4 | 
            -
            require 'digest/ | 
| 4 | 
            +
            require 'digest/sha2'
         | 
| 5 5 | 
             
            require 'json'
         | 
| 6 6 |  | 
| 7 7 | 
             
            module StackProf
         | 
| @@ -52,7 +52,7 @@ module StackProf | |
| 52 52 | 
             
                def normalized_frames
         | 
| 53 53 | 
             
                  id2hash = {}
         | 
| 54 54 | 
             
                  @data[:frames].each do |frame, info|
         | 
| 55 | 
            -
                    id2hash[frame.to_s] = info[:hash] = Digest:: | 
| 55 | 
            +
                    id2hash[frame.to_s] = info[:hash] = Digest::SHA256.hexdigest("#{info[:name]}#{info[:file]}#{info[:line]}")
         | 
| 56 56 | 
             
                  end
         | 
| 57 57 | 
             
                  @data[:frames].inject(Hash.new) do |hash, (frame, info)|
         | 
| 58 58 | 
             
                    info = hash[id2hash[frame.to_s]] = info.dup
         | 
| @@ -225,7 +225,7 @@ module StackProf | |
| 225 225 | 
             
                      end
         | 
| 226 226 | 
             
                    else
         | 
| 227 227 | 
             
                      frame = @data[:frames][val]
         | 
| 228 | 
            -
                      child_name = "#{ frame[:name] } : #{ frame[:file] }"
         | 
| 228 | 
            +
                      child_name = "#{ frame[:name] } : #{ frame[:file] } : #{ frame[:line] }"
         | 
| 229 229 | 
             
                      child_data = convert_to_d3_flame_graph_format(child_name, child_stacks, depth + 1)
         | 
| 230 230 | 
             
                      weight += child_data["value"]
         | 
| 231 231 | 
             
                      children << child_data
         | 
| @@ -0,0 +1,37 @@ | |
| 1 | 
            +
            module StackProf
         | 
| 2 | 
            +
              # Define the same methods as stackprof.c
         | 
| 3 | 
            +
              class << self
         | 
| 4 | 
            +
                def running?
         | 
| 5 | 
            +
                  false
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def run(*args)
         | 
| 9 | 
            +
                  unimplemented
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def start(*args)
         | 
| 13 | 
            +
                  unimplemented
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def stop
         | 
| 17 | 
            +
                  unimplemented
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def results(*args)
         | 
| 21 | 
            +
                  unimplemented
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def sample
         | 
| 25 | 
            +
                  unimplemented
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def use_postponed_job!
         | 
| 29 | 
            +
                  # noop
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                private def unimplemented
         | 
| 33 | 
            +
                  raise "Use --cpusampler=flamegraph or --cpusampler instead of StackProf on TruffleRuby.\n" \
         | 
| 34 | 
            +
                        "See https://www.graalvm.org/tools/profiling/ and `ruby --help:cpusampler` for more details."
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
            end
         | 
    
        data/lib/stackprof.rb
    CHANGED
    
    | @@ -1,11 +1,15 @@ | |
| 1 | 
            -
             | 
| 1 | 
            +
            if RUBY_ENGINE == 'truffleruby'
         | 
| 2 | 
            +
              require "stackprof/truffleruby"
         | 
| 3 | 
            +
            else
         | 
| 4 | 
            +
              require "stackprof/stackprof"
         | 
| 5 | 
            +
            end
         | 
| 2 6 |  | 
| 3 7 | 
             
            if defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?
         | 
| 4 8 | 
             
              StackProf.use_postponed_job!
         | 
| 5 9 | 
             
            end
         | 
| 6 10 |  | 
| 7 11 | 
             
            module StackProf
         | 
| 8 | 
            -
              VERSION = '0.2. | 
| 12 | 
            +
              VERSION = '0.2.22'
         | 
| 9 13 | 
             
            end
         | 
| 10 14 |  | 
| 11 15 | 
             
            StackProf.autoload :Report, "stackprof/report.rb"
         | 
    
        data/stackprof.gemspec
    CHANGED
    
    
    
        data/test/test_stackprof.rb
    CHANGED
    
    
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            $:.unshift File.expand_path('../../lib', __FILE__)
         | 
| 2 | 
            +
            require 'stackprof'
         | 
| 3 | 
            +
            require 'minitest/autorun'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            if RUBY_ENGINE == 'truffleruby'
         | 
| 6 | 
            +
              class StackProfTruffleRubyTest < MiniTest::Test
         | 
| 7 | 
            +
                def test_error
         | 
| 8 | 
            +
                  error = assert_raises RuntimeError do
         | 
| 9 | 
            +
                    StackProf.run(mode: :cpu) do
         | 
| 10 | 
            +
                      unreacheable
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  assert_match(/TruffleRuby/, error.message)
         | 
| 15 | 
            +
                  assert_match(/--cpusampler/, error.message)
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: stackprof
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.2. | 
| 4 | 
            +
              version: 0.2.22
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Aman Gupta
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2022- | 
| 11 | 
            +
            date: 2022-10-13 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: rake-compiler
         | 
| @@ -76,10 +76,12 @@ files: | |
| 76 76 | 
             
            - ext/stackprof/extconf.rb
         | 
| 77 77 | 
             
            - ext/stackprof/stackprof.c
         | 
| 78 78 | 
             
            - lib/stackprof.rb
         | 
| 79 | 
            +
            - lib/stackprof/autorun.rb
         | 
| 79 80 | 
             
            - lib/stackprof/flamegraph/flamegraph.js
         | 
| 80 81 | 
             
            - lib/stackprof/flamegraph/viewer.html
         | 
| 81 82 | 
             
            - lib/stackprof/middleware.rb
         | 
| 82 83 | 
             
            - lib/stackprof/report.rb
         | 
| 84 | 
            +
            - lib/stackprof/truffleruby.rb
         | 
| 83 85 | 
             
            - sample.rb
         | 
| 84 86 | 
             
            - stackprof.gemspec
         | 
| 85 87 | 
             
            - test/fixtures/profile.dump
         | 
| @@ -87,6 +89,7 @@ files: | |
| 87 89 | 
             
            - test/test_middleware.rb
         | 
| 88 90 | 
             
            - test/test_report.rb
         | 
| 89 91 | 
             
            - test/test_stackprof.rb
         | 
| 92 | 
            +
            - test/test_truffleruby.rb
         | 
| 90 93 | 
             
            - vendor/FlameGraph/README
         | 
| 91 94 | 
             
            - vendor/FlameGraph/flamegraph.pl
         | 
| 92 95 | 
             
            - vendor/gprof2dot/gprof2dot.py
         | 
| @@ -96,9 +99,9 @@ licenses: | |
| 96 99 | 
             
            - MIT
         | 
| 97 100 | 
             
            metadata:
         | 
| 98 101 | 
             
              bug_tracker_uri: https://github.com/tmm1/stackprof/issues
         | 
| 99 | 
            -
              changelog_uri: https://github.com/tmm1/stackprof/blob/v0.2. | 
| 100 | 
            -
              documentation_uri: https://www.rubydoc.info/gems/stackprof/0.2. | 
| 101 | 
            -
              source_code_uri: https://github.com/tmm1/stackprof/tree/v0.2. | 
| 102 | 
            +
              changelog_uri: https://github.com/tmm1/stackprof/blob/v0.2.22/CHANGELOG.md
         | 
| 103 | 
            +
              documentation_uri: https://www.rubydoc.info/gems/stackprof/0.2.22
         | 
| 104 | 
            +
              source_code_uri: https://github.com/tmm1/stackprof/tree/v0.2.22
         | 
| 102 105 | 
             
            post_install_message: 
         | 
| 103 106 | 
             
            rdoc_options: []
         | 
| 104 107 | 
             
            require_paths:
         |