estackprof 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2fb2e9ab5ae1157f4f88c4ddf9091aba225e97036725c1641598df88a9959c91
4
+ data.tar.gz: b9b994ef293a0f97df4a1a2c72395fd2d2765e7023ce4cf4e86e19898137bf12
5
+ SHA512:
6
+ metadata.gz: 8e98f8ebe4b4051c418e6f75d7f93aab8a40b0d6a1cf9f02d24d00b0ae5909371a020c1c59d76a3de243cbe0f0b16c98d18627ac40d4977c6870cbeccc7fff63
7
+ data.tar.gz: 0e5de4a47cd8217c29b4fd8956796a14674bfab44992b7e58e9152e619d870bd20ef343cec94dc6e4865dbc1e2c534f11031b008791f416a49db712748d88b2d
@@ -0,0 +1,28 @@
1
+ version: 2.1
2
+ jobs:
3
+ build:
4
+ docker:
5
+ - image: ruby:3.0.1
6
+ steps:
7
+ - checkout
8
+ - restore_cache:
9
+ name: Restore bundle cache
10
+ keys:
11
+ - bundle-{{ arch }}-{{ checksum "Gemfile" }}-{{ checksum "estackprof.gemspec" }}
12
+ - bundle-{{ arch }}-{{ checksum "Gemfile" }}
13
+ - bundle-{{ arch }}
14
+ - bundle
15
+ - run:
16
+ name: Bundle Install
17
+ command: bundle install
18
+ - save_cache:
19
+ name: Store bundle cache
20
+ key: bundle-{{ arch }}-{{ checksum "Gemfile" }}-{{ checksum "estackprof.gemspec" }}
21
+ paths:
22
+ - vendor/bundle
23
+ - run:
24
+ name: Rubocop
25
+ command: bundle exec rubocop
26
+ - run:
27
+ name: RSpec
28
+ command: bundle exec rspec
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /vendor/bundle/
9
+ Gemfile.lock
10
+
11
+ /example/vendor/bundle/
12
+ /example/bundle/
13
+
14
+ # rspec failure tracking
15
+ .rspec_status
16
+
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,30 @@
1
+ # The behavior of RuboCop can be controlled via the .rubocop.yml
2
+ # configuration file. It makes it possible to enable/disable
3
+ # certain cops (checks) and to alter their behavior if they accept
4
+ # any parameters. The file can be placed either in your home
5
+ # directory or in some project directory.
6
+ #
7
+ # RuboCop will start looking for the configuration file in the directory
8
+ # where the inspected file is and continue its way up to the root directory.
9
+ #
10
+ # See https://docs.rubocop.org/rubocop/configuration
11
+ require:
12
+ - rubocop-rspec
13
+ - rubocop-rake
14
+
15
+ AllCops:
16
+ NewCops: enable
17
+ TargetRubyVersion: 2.5
18
+
19
+ Style/Documentation:
20
+ Enabled: false
21
+
22
+ Metrics/BlockLength:
23
+ Exclude:
24
+ - "spec/**/*.rb"
25
+
26
+ RSpec/MessageSpies:
27
+ EnforcedStyle: receive
28
+
29
+ Security/MarshalLoad:
30
+ Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.0.1
data/Gemfile ADDED
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in estackprof.gemspec
6
+ gemspec
7
+
8
+ gem 'rake', '~> 13.0'
9
+
10
+ group :development do
11
+ gem 'guard-rubocop'
12
+ gem 'pry'
13
+ gem 'rubocop'
14
+ gem 'rubocop-rake'
15
+ gem 'rubocop-rspec'
16
+ gem 'sinatra'
17
+ gem 'webrick'
18
+ end
19
+
20
+ group :test do
21
+ gem 'aruba', '~> 2.0.0'
22
+ gem 'guard-rspec'
23
+ gem 'rspec', '~> 3.0'
24
+ end
data/Guardfile ADDED
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ # A sample Guardfile
4
+ # More info at https://github.com/guard/guard#readme
5
+
6
+ ## Uncomment and set this to only include directories you want to watch
7
+ # directories %w(app lib config test spec features) \
8
+ # .select{|d| Dir.exist?(d) ? d : UI.warning("Directory #{d} does not exist")}
9
+
10
+ ## Note: if you are using the `directories` clause above and you are not
11
+ ## watching the project directory ('.'), then you will want to move
12
+ ## the Guardfile to a watched dir and symlink it back, e.g.
13
+ #
14
+ # $ mkdir config
15
+ # $ mv Guardfile config/
16
+ # $ ln -s config/Guardfile .
17
+ #
18
+ # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
19
+
20
+ # NOTE: The cmd option is now required due to the increasing number of ways
21
+ # rspec may be run, below are examples of the most common uses.
22
+ # * bundler: 'bundle exec rspec'
23
+ # * bundler binstubs: 'bin/rspec'
24
+ # * spring: 'bin/rspec' (This will use spring if running and you have
25
+ # installed the spring binstubs per the docs)
26
+ # * zeus: 'zeus rspec' (requires the server to be started separately)
27
+ # * 'just' rspec: 'rspec'
28
+
29
+ guard :rspec, cmd: 'bundle exec rspec' do
30
+ require 'guard/rspec/dsl'
31
+ dsl = Guard::RSpec::Dsl.new(self)
32
+
33
+ # Feel free to open issues for suggestions and improvements
34
+
35
+ # RSpec files
36
+ rspec = dsl.rspec
37
+ watch(rspec.spec_helper) { rspec.spec_dir }
38
+ watch(rspec.spec_support) { rspec.spec_dir }
39
+ watch(rspec.spec_files)
40
+
41
+ # Ruby files
42
+ ruby = dsl.ruby
43
+ dsl.watch_spec_files_for(ruby.lib_files)
44
+ dsl.watch_spec_files_for(%r{^(exe/.+)\.rb$})
45
+ end
46
+
47
+ guard :rubocop, cli: %w[-a] do
48
+ watch(/.+\.rb$/)
49
+ watch(%r{(?:.+/)?\.rubocop(?:_todo)?\.yml$}) { |m| File.dirname(m[0]) }
50
+ end
data/README.md ADDED
@@ -0,0 +1,150 @@
1
+ # Estackprof
2
+
3
+ Estackprof is a wrapper to make it easier to use [Stackprof](https://github.com/tmm1/stackprof) in your rack application.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'estackprof'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install estackprof
20
+
21
+ ## Usage
22
+
23
+ ### Profiling
24
+
25
+ Add the following code to your rack application to enable the rack middleware.
26
+ `Estackprof::Middleware` supports the same options as `StackProf::Middleware`.
27
+
28
+ ```ruby
29
+ require 'estackprof'
30
+
31
+ use Estackprof::Middleware
32
+
33
+ # ...your rack application
34
+ ```
35
+
36
+ ### Reporting
37
+
38
+ Use the CLI to report.
39
+
40
+ ```sh
41
+ # Report the top 3 frames
42
+ $ estackprof top -l 3
43
+ ==================================
44
+ Mode: cpu(1000)
45
+ Samples: 516 (0.00% miss rate)
46
+ GC: 77 (14.92%)
47
+ ==================================
48
+ TOTAL (pct) SAMPLES (pct) FRAME
49
+ 434 (84.1%) 434 (84.1%) Object#bubble_sort(example/app.rb:9)
50
+ 45 (8.7%) 45 (8.7%) (sweeping)
51
+ 31 (6.0%) 31 (6.0%) (marking)
52
+
53
+ # Report the top 3 cumlative frames
54
+ $ estackprof top -l 3 -c
55
+ ==================================
56
+ Mode: cpu(1000)
57
+ Samples: 516 (0.00% miss rate)
58
+ GC: 77 (14.92%)
59
+ ==================================
60
+ TOTAL (pct) SAMPLES (pct) FRAME
61
+ 439 (85.1%) 0 (0.0%) Rack::MethodOverride#call(vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/method_override.rb:15)
62
+ 439 (85.1%) 0 (0.0%) Sinatra::ExtendedRack#call(vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb:215)
63
+ 439 (85.1%) 0 (0.0%) Sinatra::Wrapper#call(vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb:1990)
64
+
65
+ # Report the top frames filtered by patten(file name).
66
+ $ estackprof top -p app.rb
67
+ ==================================
68
+ Mode: cpu(1000)
69
+ Samples: 516 (0.00% miss rate)
70
+ GC: 77 (14.92%)
71
+ ==================================
72
+ TOTAL (pct) SAMPLES (pct) FRAME
73
+ 434 (84.1%) 434 (84.1%) Object#bubble_sort(example/app.rb:9)
74
+ 438 (84.9%) 0 (0.0%) block in <main>(example/app.rb:23)
75
+
76
+ # Report the top frames filtered by patten(method name).
77
+ $ estackprof top -p bubble
78
+ ==================================
79
+ Mode: cpu(1000)
80
+ Samples: 516 (0.00% miss rate)
81
+ GC: 77 (14.92%)
82
+ ==================================
83
+ TOTAL (pct) SAMPLES (pct) FRAME
84
+ 434 (84.1%) 434 (84.1%) Object#bubble_sort(example/app.rb:9)
85
+
86
+ # Report the list in the specified file.
87
+ $ estackprof list -f app.rb
88
+ | 1 | # frozen_string_literal: true
89
+ | 2 |
90
+ | 3 | require 'sinatra'
91
+ | 4 | require 'json'
92
+ | 5 | require 'estackprof'
93
+ | 6 |
94
+ | 7 | use Estackprof::Middleware
95
+ | 8 |
96
+ | 9 | def bubble_sort(array)
97
+ | 10 | ary = array.dup
98
+ | 11 | pos_max = ary.size - 1
99
+ | 12 |
100
+ 434 (84.1%) | 13 | (0...pos_max).each do |n|
101
+ 433 (83.9%) | 14 | (0...(pos_max - n)).each do |ix|
102
+ | 15 | iy = ix + 1
103
+ 139 (26.9%) / 139 (26.9%) | 16 | ary[ix], ary[iy] = ary[iy], ary[ix] if ary[ix] > ary[iy]
104
+ 294 (57.0%) / 294 (57.0%) | 17 | end
105
+ 1 (0.2%) / 1 (0.2%) | 18 | end
106
+ | 19 |
107
+ | 20 | ary
108
+ | 21 | end
109
+ | 22 |
110
+ | 23 | get '/' do
111
+ | 24 | array = Array.new(1000) { rand(10_000) }
112
+ 438 (84.9%) | 25 | bubble_sort(array).to_s
113
+ | 26 | end
114
+
115
+ # Report the list in the specified method.
116
+ $ estackprof list -m bubble
117
+ Object#bubble_sort (/estackprof/example/app.rb:9)
118
+ samples: 434 self (84.1%) / 434 total (84.1%)
119
+ callers:
120
+ 867 ( 199.8%) Range#each
121
+ 434 ( 100.0%) block in <main>
122
+ callees (0 total):
123
+ 867 ( Inf%) Range#each
124
+ code:
125
+ | 9 | def bubble_sort(array)
126
+ | 10 | ary = array.dup
127
+ | 11 | pos_max = ary.size - 1
128
+ | 12 |
129
+ 434 (84.1%) | 13 | (0...pos_max).each do |n|
130
+ 433 (83.9%) | 14 | (0...(pos_max - n)).each do |ix|
131
+ | 15 | iy = ix + 1
132
+ 139 (26.9%) / 139 (26.9%) | 16 | ary[ix], ary[iy] = ary[iy], ary[ix] if ary[ix] > ary[iy]
133
+ 294 (57.0%) / 294 (57.0%) | 17 | end
134
+ 1 (0.2%) / 1 (0.2%) | 18 | end
135
+ | 19 |
136
+
137
+ # Display the flamegraph
138
+ $ estackprof flamegraph
139
+ #=> Open flamegraph in your browser.
140
+ ```
141
+
142
+ ## Development
143
+
144
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
145
+
146
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
147
+
148
+ ## Contributing
149
+
150
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/estackprof.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'estackprof'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/estackprof/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'estackprof'
7
+ spec.version = Estackprof::VERSION
8
+ spec.authors = ['Yuhei Okazaki']
9
+ spec.email = ['okazaki@fusic.co.jp']
10
+
11
+ spec.summary = 'We want to make stackprof easier to use.'
12
+ spec.description = 'Estackprof is a wrapper to make it easier to use Stackprof in your rack application'
13
+ spec.homepage = 'https://github.com/fusic/estackprof'
14
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0')
15
+
16
+ spec.metadata['homepage_uri'] = spec.homepage
17
+ spec.metadata['source_code_uri'] = 'https://github.com/fusic/estackprof'
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
22
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
23
+ end
24
+ spec.bindir = 'exe'
25
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
26
+ spec.require_paths = ['lib']
27
+
28
+ # Uncomment to register a new dependency of your gem
29
+ spec.add_dependency 'launchy'
30
+ spec.add_dependency 'stackprof', '~> 0.2'
31
+ spec.add_dependency 'thor', '~> 1.1.0'
32
+
33
+ # For more information and examples about making a new gem, checkout our
34
+ # guide at: https://bundler.io/guides/creating_gem.html
35
+ end
data/example/app.rb ADDED
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sinatra'
4
+ require 'json'
5
+ require 'estackprof'
6
+
7
+ use Estackprof::Middleware
8
+
9
+ def bubble_sort(array)
10
+ ary = array.dup
11
+ pos_max = ary.size - 1
12
+
13
+ (0...pos_max).each do |n|
14
+ (0...(pos_max - n)).each do |ix|
15
+ iy = ix + 1
16
+ ary[ix], ary[iy] = ary[iy], ary[ix] if ary[ix] > ary[iy]
17
+ end
18
+ end
19
+
20
+ ary
21
+ end
22
+
23
+ get '/' do
24
+ array = Array.new(1000) { rand(10_000) }
25
+ bubble_sort(array).to_s
26
+ end
data/exe/estackprof ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'estackprof'
5
+
6
+ Estackprof::CLI.start(ARGV)
data/flamegraph.html ADDED
@@ -0,0 +1,153 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1">
7
+
8
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
9
+ <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/spiermar/d3-flame-graph@2.0.3/dist/d3-flamegraph.css">
10
+
11
+ <style>
12
+
13
+ /* Space out content a bit */
14
+ body {
15
+ padding-top: 20px;
16
+ padding-bottom: 20px;
17
+ }
18
+
19
+ /* Custom page header */
20
+ .header {
21
+ padding-bottom: 20px;
22
+ padding-right: 15px;
23
+ padding-left: 15px;
24
+ border-bottom: 1px solid #e5e5e5;
25
+ }
26
+
27
+ /* Make the masthead heading the same height as the navigation */
28
+ .header h3 {
29
+ margin-top: 0;
30
+ margin-bottom: 0;
31
+ line-height: 40px;
32
+ }
33
+
34
+ /* Customize container */
35
+ .container {
36
+ max-width: 990px;
37
+ }
38
+
39
+ address {
40
+ text-align: right;
41
+ }
42
+ </style>
43
+
44
+ <title>stackprof (mode: cpu)</title>
45
+
46
+ <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
47
+ <!--[if lt IE 9]>
48
+ <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
49
+ <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
50
+ <![endif]-->
51
+ </head>
52
+ <body>
53
+ <div class="container">
54
+ <div class="header clearfix">
55
+ <nav>
56
+ <div class="pull-right">
57
+ <form class="form-inline" id="form">
58
+ <a class="btn" href="javascript: resetZoom();">Reset zoom</a>
59
+ <a class="btn" href="javascript: clear();">Clear</a>
60
+ <div class="form-group">
61
+ <input type="text" class="form-control" id="term">
62
+ </div>
63
+ <a class="btn btn-primary" href="javascript: search();">Search</a>
64
+ </form>
65
+ </div>
66
+ </nav>
67
+ <h3 class="text-muted">stackprof (mode: cpu)</h3>
68
+ </div>
69
+ <div id="chart">
70
+ </div>
71
+ <address>
72
+ powered by <a href="https://github.com/spiermar/d3-flame-graph">d3-flame-graph</a>
73
+ </address>
74
+ <hr>
75
+ <div id="details">
76
+ </div>
77
+ </div>
78
+
79
+ <!-- D3.js -->
80
+ <script src="https://d3js.org/d3.v4.min.js" charset="utf-8"></script>
81
+
82
+ <!-- d3-tip -->
83
+ <script type="text/javascript" src=https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.9.1/d3-tip.min.js></script>
84
+
85
+ <!-- d3-flamegraph -->
86
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/gh/spiermar/d3-flame-graph@2.0.3/dist/d3-flamegraph.min.js"></script>
87
+
88
+ <script type="text/javascript">
89
+ var flameGraph = d3.flamegraph()
90
+ .width(960)
91
+ .cellHeight(18)
92
+ .transitionDuration(750)
93
+ .minFrameSize(5)
94
+ .transitionEase(d3.easeCubic)
95
+ .sort(true)
96
+ //Example to sort in reverse order
97
+ //.sort(function(a,b){ return d3.descending(a.name, b.name);})
98
+ .title("")
99
+ .onClick(onClick)
100
+ .differential(false)
101
+ .selfValue(false);
102
+
103
+
104
+ // Example on how to use custom tooltips using d3-tip.
105
+ // var tip = d3.tip()
106
+ // .direction("s")
107
+ // .offset([8, 0])
108
+ // .attr('class', 'd3-flame-graph-tip')
109
+ // .html(function(d) { return "name: " + d.data.name + ", value: " + d.data.value; });
110
+
111
+ // flameGraph.tooltip(tip);
112
+
113
+ var details = document.getElementById("details");
114
+ flameGraph.setDetailsElement(details);
115
+
116
+ // Example on how to use custom labels
117
+ // var label = function(d) {
118
+ // return "name: " + d.name + ", value: " + d.value;
119
+ // }
120
+ // flameGraph.label(label);
121
+
122
+ // Example of how to set fixed chart height
123
+ // flameGraph.height(540);
124
+
125
+ d3.select("#chart")
126
+ .datum({"name":"<root>","value":278,"children":[{"name":"(garbage collection) : ","value":36,"children":[{"name":"(marking) : ","value":12,"children":[]},{"name":"(sweeping) : ","value":24,"children":[]}]},{"name":"WEBrick::GenericServer#start_thread : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/webrick-1.7.0/lib/webrick/server.rb","value":241,"children":[{"name":"WEBrick::HTTPServer#run : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/webrick-1.7.0/lib/webrick/httpserver.rb","value":241,"children":[{"name":"WEBrick::HTTPServer#service : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/webrick-1.7.0/lib/webrick/httpserver.rb","value":241,"children":[{"name":"Rack::Handler::WEBrick#service : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/handler/webrick.rb","value":241,"children":[{"name":"Sinatra::Base.call : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":241,"children":[{"name":"Sinatra::Base.synchronize : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":241,"children":[{"name":"Sinatra::Base.call : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":241,"children":[{"name":"Sinatra::Wrapper#call : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":241,"children":[{"name":"Sinatra::ExtendedRack#call : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":241,"children":[{"name":"Sinatra::ShowExceptions#call : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/show_exceptions.rb","value":241,"children":[{"name":"Rack::MethodOverride#call : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/method_override.rb","value":241,"children":[{"name":"Rack::Head#call : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/head.rb","value":241,"children":[{"name":"Sinatra::CommonLogger#call : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":241,"children":[{"name":"Rack::CommonLogger#call : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":241,"children":[{"name":"Rack::CommonLogger#call : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/common_logger.rb","value":241,"children":[{"name":"Rack::Logger#call : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/logger.rb","value":241,"children":[{"name":"Rack::Protection::FrameOptions#call : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/rack-protection-2.1.0/lib/rack/protection/frame_options.rb","value":241,"children":[{"name":"Rack::Protection::Base#call : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/rack-protection-2.1.0/lib/rack/protection/base.rb","value":241,"children":[{"name":"Rack::Protection::Base#call : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/rack-protection-2.1.0/lib/rack/protection/base.rb","value":241,"children":[{"name":"Rack::Protection::JsonCsrf#call : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/rack-protection-2.1.0/lib/rack/protection/json_csrf.rb","value":241,"children":[{"name":"Rack::Protection::PathTraversal#call : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/rack-protection-2.1.0/lib/rack/protection/path_traversal.rb","value":241,"children":[{"name":"Rack::Protection::XSSHeader#call : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/rack-protection-2.1.0/lib/rack/protection/xss_header.rb","value":241,"children":[{"name":"StackProf::Middleware#call : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/stackprof-0.2.17/lib/stackprof/middleware.rb","value":241,"children":[{"name":"Sinatra::Base#call : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":241,"children":[{"name":"Sinatra::Base#call! : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":241,"children":[{"name":"Sinatra::Base#invoke : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":241,"children":[{"name":"Kernel#catch : <cfunc>","value":241,"children":[{"name":"Sinatra::Base#invoke : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":241,"children":[{"name":"Sinatra::Base#call! : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":241,"children":[{"name":"Sinatra::Base#dispatch! : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":241,"children":[{"name":"Sinatra::Request#params : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":1,"children":[{"name":"Rack::Request#params : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/request.rb","value":1,"children":[{"name":"Rack::Request::Helpers#params : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/request.rb","value":1,"children":[{"name":"Rack::Request::Helpers#POST : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/request.rb","value":1,"children":[{"name":"Rack::Request::Helpers#form_data? : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/request.rb","value":1,"children":[{"name":"Rack::Request::Helpers#media_type : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/request.rb","value":1,"children":[{"name":"Kernel#require : <cfunc>","value":1,"children":[{"name":"<top (required)> : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/media_type.rb","value":1,"children":[{"name":"<module:Rack> : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/media_type.rb","value":1,"children":[{"name":"Class#inherited : <cfunc>","value":1,"children":[]}]}]}]}]}]}]}]}]}]},{"name":"Sinatra::Base#invoke : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":240,"children":[{"name":"Kernel#catch : <cfunc>","value":238,"children":[{"name":"Sinatra::Base#invoke : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":238,"children":[{"name":"Sinatra::Base#dispatch! : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":238,"children":[{"name":"Sinatra::Base#route! : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":238,"children":[{"name":"Array#each : <cfunc>","value":238,"children":[{"name":"Sinatra::Base#route! : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":238,"children":[{"name":"Sinatra::Base#process_route : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":238,"children":[{"name":"Kernel#catch : <cfunc>","value":238,"children":[{"name":"Sinatra::Base#process_route : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":238,"children":[{"name":"Sinatra::Base#route! : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":238,"children":[{"name":"Sinatra::Base#route_eval : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":238,"children":[{"name":"Sinatra::Base#route! : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":238,"children":[{"name":"Sinatra::Base.compile! : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":238,"children":[{"name":"Method#call : <cfunc>","value":238,"children":[{"name":"block in <main> : /Users/yokazaki/src/github.com/fusic/estackprof/example/app.rb","value":238,"children":[{"name":"Object#bubble_sort : /Users/yokazaki/src/github.com/fusic/estackprof/example/app.rb","value":237,"children":[{"name":"Range#each : <cfunc>","value":237,"children":[{"name":"Object#bubble_sort : /Users/yokazaki/src/github.com/fusic/estackprof/example/app.rb","value":237,"children":[{"name":"Range#each : <cfunc>","value":237,"children":[{"name":"Object#bubble_sort : /Users/yokazaki/src/github.com/fusic/estackprof/example/app.rb","value":237,"children":[]}]}]}]}]},{"name":"Array#inspect : <cfunc>","value":1,"children":[{"name":"Integer#to_s : <cfunc>","value":1,"children":[]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]},{"name":"Sinatra::Helpers#body : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":2,"children":[{"name":"Kernel#require : <cfunc>","value":1,"children":[{"name":"<top (required)> : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/file.rb","value":1,"children":[{"name":"Kernel#require_relative : <cfunc>","value":1,"children":[]}]}]},{"name":"Kernel#block_given? : <cfunc>","value":1,"children":[]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]},{"name":"<main> : example/app.rb","value":1,"children":[{"name":"block in <module:Sinatra> : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/main.rb","value":1,"children":[{"name":"Sinatra::Base.run! : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":1,"children":[{"name":"Sinatra::Base.start_server : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/sinatra-2.1.0/lib/sinatra/base.rb","value":1,"children":[{"name":"Rack::Handler::WEBrick.run : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/handler/webrick.rb","value":1,"children":[{"name":"WEBrick::GenericServer#start : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/webrick-1.7.0/lib/webrick/server.rb","value":1,"children":[{"name":"WEBrick::SimpleServer.start : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/webrick-1.7.0/lib/webrick/server.rb","value":1,"children":[{"name":"WEBrick::GenericServer#start : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/webrick-1.7.0/lib/webrick/server.rb","value":1,"children":[{"name":"Array#each : <cfunc>","value":1,"children":[{"name":"WEBrick::GenericServer#start : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/webrick-1.7.0/lib/webrick/server.rb","value":1,"children":[{"name":"WEBrick::GenericServer#start_thread : /Users/yokazaki/src/github.com/fusic/estackprof/vendor/bundle/ruby/3.0.0/gems/webrick-1.7.0/lib/webrick/server.rb","value":1,"children":[{"name":"Thread.start : <cfunc>","value":1,"children":[]}]}]}]}]}]}]}]}]}]}]}]}]})
127
+ .call(flameGraph);
128
+
129
+ document.getElementById("form").addEventListener("submit", function(event){
130
+ event.preventDefault();
131
+ search();
132
+ });
133
+
134
+ function search() {
135
+ var term = document.getElementById("term").value;
136
+ flameGraph.search(term);
137
+ }
138
+
139
+ function clear() {
140
+ document.getElementById('term').value = '';
141
+ flameGraph.clear();
142
+ }
143
+
144
+ function resetZoom() {
145
+ flameGraph.resetZoom();
146
+ }
147
+
148
+ function onClick(d) {
149
+ console.info("Clicked on " + d.data.name);
150
+ }
151
+ </script>
152
+ </body>
153
+ </html>
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require 'pry'
5
+ require 'estackprof'
6
+
7
+ module Estackprof
8
+ class CLI < Thor
9
+ class_option :debug, type: :boolean, aliases: '-d', desc: 'debug mode'
10
+
11
+ desc 'top [OPTIONS] [FILE...]', 'Report to top of methods'
12
+ option :limit, aliases: '-l', desc: 'Limit reports.', type: :numeric
13
+ option :pattern, aliases: '-p', desc: 'Filter reports by pattern match.'
14
+ option :cumlative, aliases: '-c', desc: 'Sort by cumulative count.', type: :boolean
15
+ def top(*files)
16
+ puts Estackprof.top(
17
+ files: files.empty? ? Dir.glob('./tmp/*.dump') : files,
18
+ options: options
19
+ )
20
+ exit
21
+ rescue StandardError => e
22
+ output_error_if_debug_mode(e)
23
+ exit(-1)
24
+ end
25
+
26
+ desc 'list [OPTIONS] [FILE...]', 'Display sample counts of each line'
27
+ option :file, aliases: '-f', desc: 'Filter by file name.'
28
+ option :method, aliases: '-m', desc: 'Filter by method name'
29
+ def list(*files)
30
+ puts Estackprof.list(
31
+ files: files.empty? ? Dir.glob('./tmp/*.dump') : files,
32
+ options: options
33
+ )
34
+ exit
35
+ rescue StandardError => e
36
+ output_error_if_debug_mode(e)
37
+ exit(-1)
38
+ end
39
+
40
+ desc 'flamegraph [OPTIONS] [FILE]', 'Generate and open flamegraph'
41
+ def flamegraph(*files)
42
+ puts Estackprof.flamegraph(
43
+ files: files.empty? ? Dir.glob('./tmp/*.dump') : files
44
+ )
45
+ exit
46
+ rescue StandardError => e
47
+ output_error_if_debug_mode(e)
48
+ exit(-1)
49
+ end
50
+
51
+ map %w[--version -v] => :version
52
+ desc 'version', 'version'
53
+ def version
54
+ puts Estackprof::VERSION
55
+ end
56
+
57
+ private
58
+
59
+ def output_error_if_debug_mode(exception)
60
+ return unless options[:debug]
61
+
62
+ warn(exception.message)
63
+ warn(exception.backtrace)
64
+ end
65
+
66
+ class << self
67
+ private
68
+
69
+ def exit_on_failure?
70
+ true
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stackprof'
4
+ require 'launchy'
5
+
6
+ module Estackprof
7
+ def flamegraph(files:)
8
+ mkdir(tmp_path = './tmp')
9
+ html_path = File.expand_path("#{tmp_path}/flamegraph.html")
10
+ File.open(html_path, 'w') { |f| Report.create([files[0]]).print_d3_flamegraph(f) }
11
+ Launchy.open(html_path)
12
+ html_path
13
+ rescue StandardError
14
+ puts 'Dump files are missing or incorrect.'
15
+ end
16
+
17
+ private
18
+
19
+ def mkdir(path)
20
+ FileUtils.mkdir_p(path) unless FileTest.exist?(path)
21
+ end
22
+
23
+ module_function :flamegraph, :mkdir
24
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stackprof'
4
+
5
+ module Estackprof
6
+ def list(files:, options:)
7
+ io = StringIO.new
8
+
9
+ print_by_options(Report.create(files), options, io)
10
+
11
+ io.rewind
12
+ io.read.to_s
13
+ rescue StandardError
14
+ puts 'Dump files are missing or incorrect.'
15
+ end
16
+
17
+ private
18
+
19
+ def print_by_options(report, options, io)
20
+ if options[:method]
21
+ report.print_method(options[:method], io)
22
+ elsif options[:file]
23
+ report.print_file(options[:file], io)
24
+ else
25
+ report.print_files(false, nil, io)
26
+ end
27
+ end
28
+
29
+ module_function :list, :print_by_options
30
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stackprof'
4
+
5
+ module Estackprof
6
+ class Middleware < StackProf::Middleware
7
+ def initialize(app, options = {})
8
+ options[:enabled] = true if options[:enabled].nil?
9
+ options[:raw] = true if options[:raw].nil?
10
+ options[:save_every] ||= 10
11
+
12
+ super(app, **options)
13
+ end
14
+
15
+ class << self
16
+ %i[enabled mode interval raw path metadata].each do |sym|
17
+ define_method(sym) do
18
+ StackProf::Middleware.send(sym)
19
+ end
20
+ define_method("#{sym}=") do |value|
21
+ StackProf::Middleware.send("#{sym}=", value)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stackprof'
4
+
5
+ module Estackprof
6
+ class Report < StackProf::Report
7
+ def self.create(files)
8
+ reports = files.map do |file|
9
+ new(Marshal.load(IO.binread(file)))
10
+ end
11
+ reports.inject(:+)
12
+ end
13
+
14
+ def print_text(limit:, pattern:, sort_by_total: false, out: $stdout)
15
+ print_summary(out)
16
+ print_header(out)
17
+
18
+ list = frames(sort_by_total)
19
+ if pattern
20
+ list = list.filter do |_frame, info|
21
+ %i[file name].any? { |s| info[s].match?(pattern) }
22
+ end
23
+ end
24
+ list = list.first(limit) if limit
25
+ print_body(list, out)
26
+ end
27
+
28
+ private
29
+
30
+ def print_summary(out)
31
+ out.puts '=================================='
32
+ out.printf " Mode: #{modeline}\n"
33
+ print_summary_samples(out)
34
+ print_summary_gc(out)
35
+ out.puts '=================================='
36
+ end
37
+
38
+ def print_summary_samples(out)
39
+ out.printf " Samples: #{@data[:samples]} (%.2f%% miss rate)\n",
40
+ 100.0 * @data[:missed_samples] / (@data[:missed_samples] + @data[:samples])
41
+ end
42
+
43
+ def print_summary_gc(out)
44
+ out.printf " GC: #{@data[:gc_samples]} (%.2f%%)\n", 100.0 * @data[:gc_samples] / @data[:samples]
45
+ end
46
+
47
+ def print_header(out)
48
+ out.printf format("%<total>10s (pct) %<samples>10s (pct) FRAME\n", total: 'TOTAL', samples: 'SAMPLES')
49
+ end
50
+
51
+ def print_body(list, out)
52
+ list.each do |_frame, info|
53
+ call, total = info.values_at(:samples, :total_samples)
54
+ out.printf(
55
+ "%<total>10d %<total_pct>8s %<samples>10d %<samples_pct>8s %<frame>s\n",
56
+ total: total, total_pct: format('(%2.1f%%)', (total * 100.0 / overall_samples)),
57
+ samples: call, samples_pct: format('(%2.1f%%)', (call * 100.0 / overall_samples)),
58
+ frame: frame(info[:name], info[:file], info[:line])
59
+ )
60
+ end
61
+ end
62
+
63
+ def frame(name, file, line)
64
+ file_path = name
65
+ begin
66
+ file_path += "(#{Pathname(file).relative_path_from(Dir.pwd)}:#{line})"
67
+ rescue StandardError
68
+ # NOP
69
+ end
70
+ file_path
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stackprof'
4
+
5
+ module Estackprof
6
+ def top(files:, options:)
7
+ io = StringIO.new
8
+ Report.create(files).print_text(**parse_options(options), out: io)
9
+ io.rewind
10
+ io.read.to_s
11
+ rescue StandardError
12
+ puts 'Dump files are missing or incorrect.'
13
+ end
14
+
15
+ private
16
+
17
+ def parse_options(options)
18
+ limit = options[:limit] || 10
19
+ pattern = options[:pattern] && Regexp.new(options[:pattern])
20
+ sort_by_total = options[:cumlative]
21
+ { limit: limit, pattern: pattern, sort_by_total: sort_by_total }
22
+ end
23
+
24
+ module_function :top, :parse_options
25
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Estackprof
4
+ VERSION = '0.1.0'
5
+ end
data/lib/estackprof.rb ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'estackprof/cli'
4
+ require_relative 'estackprof/top'
5
+ require_relative 'estackprof/list'
6
+ require_relative 'estackprof/flamegraph'
7
+ require_relative 'estackprof/version'
8
+ require_relative 'estackprof/report'
9
+ require_relative 'estackprof/middleware'
10
+
11
+ module Estackprof
12
+ class Error < StandardError; end
13
+ # Your code goes here...
14
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: estackprof
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Yuhei Okazaki
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-09-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: launchy
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: stackprof
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: thor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.1.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.1.0
55
+ description: Estackprof is a wrapper to make it easier to use Stackprof in your rack
56
+ application
57
+ email:
58
+ - okazaki@fusic.co.jp
59
+ executables:
60
+ - estackprof
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - ".circleci/config.yml"
65
+ - ".gitignore"
66
+ - ".rspec"
67
+ - ".rubocop.yml"
68
+ - ".ruby-version"
69
+ - Gemfile
70
+ - Guardfile
71
+ - README.md
72
+ - Rakefile
73
+ - bin/console
74
+ - bin/setup
75
+ - estackprof.gemspec
76
+ - example/app.rb
77
+ - exe/estackprof
78
+ - flamegraph.html
79
+ - lib/estackprof.rb
80
+ - lib/estackprof/cli.rb
81
+ - lib/estackprof/flamegraph.rb
82
+ - lib/estackprof/list.rb
83
+ - lib/estackprof/middleware.rb
84
+ - lib/estackprof/report.rb
85
+ - lib/estackprof/top.rb
86
+ - lib/estackprof/version.rb
87
+ homepage: https://github.com/fusic/estackprof
88
+ licenses: []
89
+ metadata:
90
+ homepage_uri: https://github.com/fusic/estackprof
91
+ source_code_uri: https://github.com/fusic/estackprof
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: 2.5.0
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubygems_version: 3.2.15
108
+ signing_key:
109
+ specification_version: 4
110
+ summary: We want to make stackprof easier to use.
111
+ test_files: []