runtime_profiler 0.4.1 → 0.4.3
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/README.md +6 -4
- data/lib/runtime_profiler.rb +5 -5
- data/lib/runtime_profiler/{instrumentation_data.rb → data.rb} +23 -23
- data/lib/runtime_profiler/events/sql_event.rb +6 -6
- data/lib/runtime_profiler/profiler.rb +11 -11
- data/lib/runtime_profiler/text_report.rb +24 -24
- data/lib/runtime_profiler/version.rb +1 -1
- data/rp_view_command.png +0 -0
- metadata +4 -4
- data/rp_view_only_methods_full_details.png +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 10844b957c031772b37b68bfe5f2c83fc98c25c40c709eea8e6920badd400b04
|
4
|
+
data.tar.gz: 52b61fe38de36b0f97fa16bbe742e3baa5e4444f22db6fa64e577deddeba491a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 289e5c785b16a2fb16ff17af9c1d7dbb02d765cf6990bac5ad1c7f4f6005042ff8589a80b79f54b7473705b5323adfb93b49cd31f4fa3e3934d9df15dbb31a6c
|
7
|
+
data.tar.gz: 5b783916251fafdf991f7a3cca98336bc329ce96ff4b1efcb4f215dc2924439c3dabe797f66502956b4169bb72bc60512f3a7b7b04740463a65cb5c60a803353
|
data/README.md
CHANGED
@@ -141,7 +141,7 @@ $ bundle exec runtime_profiler view --help
|
|
141
141
|
### Screenshot
|
142
142
|
|
143
143
|
<p align="center">
|
144
|
-
<img src="
|
144
|
+
<img src="rp_view_command.png">
|
145
145
|
</p>
|
146
146
|
|
147
147
|
### Configurations
|
@@ -149,9 +149,11 @@ $ bundle exec runtime_profiler view --help
|
|
149
149
|
All the configurable variables and their defaults are listed below. There is no one correct place where to put these configurations. It can be inside `config/initializers` folder of your Rails application. Or if you are using test to profile, it can be in the last part of `spec/spec_helper.rb`.
|
150
150
|
```ruby
|
151
151
|
RuntimeProfiler.output_path = File.join(Rails.root.to_s, 'tmp')
|
152
|
-
RuntimeProfiler.
|
153
|
-
RuntimeProfiler.
|
154
|
-
RuntimeProfiler.
|
152
|
+
RuntimeProfiler.profiled_constants = [User]
|
153
|
+
RuntimeProfiler.profiled_paths = %w(app lib)
|
154
|
+
RuntimeProfiler.profiled_sql_commands = %w(SELECT INSERT UPDATE DELETE)
|
155
|
+
# Useful when you want to exclude in profiling specific method(s) from framework/library being used
|
156
|
+
RuntimeProfiler.excepted_methods = [:attribute_type_decorations, :_validators, :defined_enums]
|
155
157
|
```
|
156
158
|
|
157
159
|
## Development
|
data/lib/runtime_profiler.rb
CHANGED
@@ -6,15 +6,15 @@ require 'method_meter'
|
|
6
6
|
module RuntimeProfiler
|
7
7
|
include ActiveSupport::Configurable
|
8
8
|
|
9
|
-
config_accessor :
|
9
|
+
config_accessor :profiled_constants do
|
10
10
|
[]
|
11
11
|
end
|
12
12
|
|
13
|
-
config_accessor :
|
13
|
+
config_accessor :profiled_paths do
|
14
14
|
%w[app lib]
|
15
15
|
end
|
16
16
|
|
17
|
-
config_accessor :
|
17
|
+
config_accessor :profiled_sql_commands do
|
18
18
|
%w[SELECT INSERT UPDATE DELETE]
|
19
19
|
end
|
20
20
|
|
@@ -43,11 +43,11 @@ module RuntimeProfiler
|
|
43
43
|
def profile!(key, konstants)
|
44
44
|
konstants = konstants.is_a?(Array) ? konstants : [konstants]
|
45
45
|
profiler = Profiler.new(konstants)
|
46
|
-
profiler.
|
46
|
+
profiler.prepare_for_profiling
|
47
47
|
|
48
48
|
MethodMeter.measure!(key) { yield }
|
49
49
|
|
50
|
-
profiler.
|
50
|
+
profiler.save_profiling_data
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module RuntimeProfiler
|
2
|
-
class
|
2
|
+
class Data
|
3
3
|
attr_reader :controller_data, :sql_data
|
4
4
|
|
5
5
|
def initialize(controller_data: nil, sql_data: nil)
|
@@ -9,7 +9,7 @@ module RuntimeProfiler
|
|
9
9
|
|
10
10
|
def persist!
|
11
11
|
File.open(output_file, 'w') do |f|
|
12
|
-
f.write JSON.dump(
|
12
|
+
f.write JSON.dump(profiling_data)
|
13
13
|
end
|
14
14
|
|
15
15
|
puts "\n"
|
@@ -26,18 +26,18 @@ module RuntimeProfiler
|
|
26
26
|
File.join(RuntimeProfiler.output_path, filename)
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
29
|
+
def profiled_api
|
30
30
|
return unless controller_data[:payload]
|
31
|
-
@
|
31
|
+
@profiled_api ||= [
|
32
32
|
controller_data[:payload][:controller],
|
33
33
|
controller_data[:payload][:action]
|
34
34
|
].join('#')
|
35
35
|
end
|
36
36
|
|
37
|
-
def
|
38
|
-
@
|
39
|
-
|
40
|
-
|
37
|
+
def profiling_data
|
38
|
+
@profiling_data ||= {
|
39
|
+
profiling: {
|
40
|
+
profiled_api: profiled_api,
|
41
41
|
summary: {
|
42
42
|
db_runtime: controller_data[:db_runtime],
|
43
43
|
view_runtime: controller_data[:view_runtime],
|
@@ -49,16 +49,16 @@ module RuntimeProfiler
|
|
49
49
|
slowest_method: method_calls_data[:slowest_method],
|
50
50
|
mostly_called_method: method_calls_data[:mostly_called_method]
|
51
51
|
},
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
profiled_sql_calls: sql_calls_data[:profiled_sql_calls],
|
53
|
+
profiled_methods: method_calls_data[:profiled_methods],
|
54
|
+
profiled_at: Time.now
|
55
55
|
}
|
56
56
|
}
|
57
57
|
end
|
58
58
|
|
59
59
|
def method_calls_data
|
60
60
|
@method_calls_data ||= begin
|
61
|
-
|
61
|
+
profiled_methods = {}
|
62
62
|
|
63
63
|
# TODO: Group methods under a key and under an object
|
64
64
|
MethodMeter.measurement.each do |measurement|
|
@@ -69,16 +69,16 @@ module RuntimeProfiler
|
|
69
69
|
|
70
70
|
d[:method] = separator + object.second
|
71
71
|
|
72
|
-
if
|
73
|
-
|
72
|
+
if profiled_methods[object.first]
|
73
|
+
profiled_methods[object.first] << d
|
74
74
|
else
|
75
|
-
|
75
|
+
profiled_methods[object.first] = [d]
|
76
76
|
end
|
77
77
|
end
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
|
-
|
81
|
+
profiled_methods = profiled_methods.inject({}) do |hash, (key, value)|
|
82
82
|
val = value.sort { |a, b| b[:total_runtime] <=> a[:total_runtime] }
|
83
83
|
hash[key] = val
|
84
84
|
hash
|
@@ -87,7 +87,7 @@ module RuntimeProfiler
|
|
87
87
|
slowest_method = {total_runtime: 0}
|
88
88
|
mostly_called_method = {total_calls: 0}
|
89
89
|
|
90
|
-
|
90
|
+
profiled_methods.each do |profiled_object_name, methods|
|
91
91
|
# sort using `total_runtime` in DESC order
|
92
92
|
_methods = methods.sort { |a, b| b[:total_runtime] <=> a[:total_runtime] }
|
93
93
|
slowest = _methods[0]
|
@@ -110,7 +110,7 @@ module RuntimeProfiler
|
|
110
110
|
end
|
111
111
|
|
112
112
|
{
|
113
|
-
|
113
|
+
profiled_methods: profiled_methods,
|
114
114
|
slowest_method: slowest_method,
|
115
115
|
mostly_called_method: mostly_called_method
|
116
116
|
}
|
@@ -119,7 +119,7 @@ module RuntimeProfiler
|
|
119
119
|
|
120
120
|
def sql_calls_data
|
121
121
|
@sql_calls_data ||= begin
|
122
|
-
|
122
|
+
profiled_sql_calls = []
|
123
123
|
|
124
124
|
slowest_sql = {total_runtime: 0}
|
125
125
|
mostly_called_sql = {total_calls: 0}
|
@@ -140,7 +140,7 @@ module RuntimeProfiler
|
|
140
140
|
slowest_sql[:source] = slowest[1]
|
141
141
|
end
|
142
142
|
|
143
|
-
|
143
|
+
profiled_sql_calls << {
|
144
144
|
sql: value[:sql],
|
145
145
|
runtimes: runtimes,
|
146
146
|
total_calls: total_calls,
|
@@ -162,9 +162,9 @@ module RuntimeProfiler
|
|
162
162
|
end
|
163
163
|
|
164
164
|
{
|
165
|
-
|
166
|
-
total_sql_calls:
|
167
|
-
total_unique_sql_calls:
|
165
|
+
profiled_sql_calls: profiled_sql_calls.sort { |a, b| b[:max] <=> a[:max] },
|
166
|
+
total_sql_calls: profiled_sql_calls.map { |sql_call| sql_call[:total_calls] }.reduce(:+),
|
167
|
+
total_unique_sql_calls: profiled_sql_calls.size,
|
168
168
|
slowest_sql: slowest_sql,
|
169
169
|
mostly_called_sql: mostly_called_sql
|
170
170
|
}
|
@@ -10,8 +10,8 @@ module RuntimeProfiler
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def recordable?
|
13
|
-
return true unless RuntimeProfiler.
|
14
|
-
|
13
|
+
return true unless RuntimeProfiler.profiled_sql_commands.respond_to?(:join)
|
14
|
+
profiled_sql_matcher =~ sql
|
15
15
|
end
|
16
16
|
|
17
17
|
def total_runtime
|
@@ -41,12 +41,12 @@ module RuntimeProfiler
|
|
41
41
|
@sql ||= @payload[:sql].dup
|
42
42
|
end
|
43
43
|
|
44
|
-
def
|
45
|
-
@
|
44
|
+
def profiled_sql_matcher
|
45
|
+
@profiled_sql_matcher ||= /\A#{RuntimeProfiler.profiled_sql_commands.join('|')}/i
|
46
46
|
end
|
47
47
|
|
48
48
|
def trace_path_matcher
|
49
|
-
@trace_path_matcher ||= %r{^(#{RuntimeProfiler.
|
49
|
+
@trace_path_matcher ||= %r{^(#{RuntimeProfiler.profiled_paths.join('|')})\/}
|
50
50
|
end
|
51
51
|
|
52
52
|
def sanitize_trace!(trace)
|
@@ -59,7 +59,7 @@ module RuntimeProfiler
|
|
59
59
|
|
60
60
|
Rails.backtrace_cleaner.remove_silencers!
|
61
61
|
|
62
|
-
if RuntimeProfiler.
|
62
|
+
if RuntimeProfiler.profiled_paths.respond_to?(:join)
|
63
63
|
Rails.backtrace_cleaner.add_silencer do |line|
|
64
64
|
line !~ trace_path_matcher
|
65
65
|
end
|
@@ -2,19 +2,19 @@
|
|
2
2
|
|
3
3
|
require 'runtime_profiler/callbacks/active_record'
|
4
4
|
require 'runtime_profiler/callbacks/action_controller'
|
5
|
-
require 'runtime_profiler/
|
5
|
+
require 'runtime_profiler/data'
|
6
6
|
|
7
7
|
module RuntimeProfiler
|
8
8
|
class Profiler
|
9
|
-
attr_accessor :
|
9
|
+
attr_accessor :profiled_constants
|
10
10
|
|
11
|
-
def initialize(
|
12
|
-
self.
|
11
|
+
def initialize(constants)
|
12
|
+
self.profiled_constants = constants
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
15
|
+
def prepare_for_profiling
|
16
16
|
subscribe_to_event_notifications
|
17
|
-
|
17
|
+
prepare_methods_to_profile
|
18
18
|
end
|
19
19
|
|
20
20
|
def subscribe_to_event_notifications
|
@@ -37,19 +37,19 @@ module RuntimeProfiler
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
def
|
41
|
-
|
40
|
+
def prepare_methods_to_profile
|
41
|
+
profiled_constants.flatten
|
42
42
|
.each { |constant| MethodMeter.observe(constant, RuntimeProfiler.excepted_methods) }
|
43
43
|
end
|
44
44
|
|
45
|
-
def
|
45
|
+
def save_profiling_data
|
46
46
|
unsubscribe_to_event_notifications
|
47
47
|
|
48
|
-
|
48
|
+
profiling_data = RuntimeProfiler::Data.new \
|
49
49
|
controller_data: @action_controller_callback.controller_data,
|
50
50
|
sql_data: @active_record_callback.data
|
51
51
|
|
52
|
-
|
52
|
+
profiling_data.persist!
|
53
53
|
end
|
54
54
|
end
|
55
55
|
end
|
@@ -95,12 +95,12 @@ module RuntimeProfiler
|
|
95
95
|
|
96
96
|
if options.details == 'full'
|
97
97
|
if only_methods?
|
98
|
-
|
98
|
+
print_profiled_methods
|
99
99
|
elsif only_sqls?
|
100
|
-
|
100
|
+
print_profiled_sql_calls
|
101
101
|
else
|
102
|
-
|
103
|
-
|
102
|
+
print_profiled_methods
|
103
|
+
print_profiled_sql_calls
|
104
104
|
end
|
105
105
|
end
|
106
106
|
end
|
@@ -130,25 +130,25 @@ module RuntimeProfiler
|
|
130
130
|
puts summary
|
131
131
|
end
|
132
132
|
|
133
|
-
def
|
134
|
-
|
133
|
+
def print_profiled_methods
|
134
|
+
profiled_methods = []
|
135
135
|
|
136
|
-
data['
|
137
|
-
|
136
|
+
data['profiling']['profiled_methods'].each do |profiled_object_name, methods|
|
137
|
+
_profiled_methods = methods.map do |method|
|
138
138
|
method['method'] = [profiled_object_name, method['method']].join
|
139
139
|
method
|
140
140
|
end
|
141
|
-
|
141
|
+
profiled_methods.concat(_profiled_methods)
|
142
142
|
end
|
143
143
|
|
144
|
-
|
145
|
-
|
146
|
-
|
144
|
+
profiled_methods = runtime_above(profiled_methods) if options.runtime_above.presence > 0
|
145
|
+
profiled_methods = calls_above(profiled_methods) if options.calls_above.presence > 0
|
146
|
+
profiled_methods = sort(profiled_methods)
|
147
147
|
|
148
148
|
table = Terminal::Table.new do |t|
|
149
149
|
t.headings = ['Method', 'Total Runtime (ms)', 'Total Calls', 'Min (ms)', 'Max (ms)']
|
150
150
|
|
151
|
-
|
151
|
+
profiled_methods.each_with_index do |row, index|
|
152
152
|
t.add_row [
|
153
153
|
row['method'],
|
154
154
|
row['total_runtime'].round(rounding),
|
@@ -156,28 +156,28 @@ module RuntimeProfiler
|
|
156
156
|
row['min'].round(rounding),
|
157
157
|
row['max'].round(rounding)
|
158
158
|
]
|
159
|
-
t.add_separator if index <
|
159
|
+
t.add_separator if index < profiled_methods.size - 1
|
160
160
|
end
|
161
161
|
end
|
162
162
|
|
163
163
|
puts
|
164
164
|
puts
|
165
|
-
puts "\e[
|
165
|
+
puts "\e[1mPROFILED METHOD(s)\e[22m"
|
166
166
|
puts
|
167
167
|
puts table
|
168
168
|
end
|
169
169
|
|
170
|
-
def
|
171
|
-
|
170
|
+
def print_profiled_sql_calls
|
171
|
+
profiled_sql_calls = data['profiling']['profiled_sql_calls']
|
172
172
|
|
173
|
-
|
174
|
-
|
175
|
-
|
173
|
+
profiled_sql_calls = runtime_above(profiled_sql_calls) if options.runtime_above.presence > 0
|
174
|
+
profiled_sql_calls = calls_above(profiled_sql_calls) if options.calls_above.presence > 0
|
175
|
+
profiled_sql_calls = sort(profiled_sql_calls, false)
|
176
176
|
|
177
177
|
table = Terminal::Table.new do |t|
|
178
178
|
t.headings = ['SQL Query', 'Count', 'Total Runtime (ms)', 'Average Runtime (ms)', 'Source']
|
179
179
|
|
180
|
-
|
180
|
+
profiled_sql_calls.each_with_index do |row, index|
|
181
181
|
chopped_sql = wrap_text(row['sql'], sql_width)
|
182
182
|
source_list = wrap_list(row['runtimes'].map { |runtime| runtime[1] }.uniq, sql_width - 15)
|
183
183
|
average_runtime = row['average'].round(rounding)
|
@@ -200,13 +200,13 @@ module RuntimeProfiler
|
|
200
200
|
end
|
201
201
|
|
202
202
|
t.add_row []
|
203
|
-
t.add_separator if index <
|
203
|
+
t.add_separator if index < profiled_sql_calls.size - 1
|
204
204
|
end
|
205
205
|
end
|
206
206
|
|
207
207
|
puts
|
208
208
|
puts
|
209
|
-
puts "\e[
|
209
|
+
puts "\e[1mPROFILED SQL(s)\e[22m"
|
210
210
|
puts
|
211
211
|
puts table
|
212
212
|
end
|
@@ -256,7 +256,7 @@ module RuntimeProfiler
|
|
256
256
|
end
|
257
257
|
|
258
258
|
def details_template_data
|
259
|
-
summary = data['
|
259
|
+
summary = data['profiling']['summary']
|
260
260
|
|
261
261
|
template_data = [
|
262
262
|
summary['total_runtime'] ? summary['total_runtime'].round(rounding) : 'n/a',
|
data/rp_view_command.png
ADDED
Binary file
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: runtime_profiler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wilfrido T. Nuqui Jr.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-01-
|
11
|
+
date: 2021-01-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -199,13 +199,13 @@ files:
|
|
199
199
|
- lib/runtime_profiler/callbacks/action_controller.rb
|
200
200
|
- lib/runtime_profiler/callbacks/active_record.rb
|
201
201
|
- lib/runtime_profiler/cli.rb
|
202
|
+
- lib/runtime_profiler/data.rb
|
202
203
|
- lib/runtime_profiler/events/process_action_event.rb
|
203
204
|
- lib/runtime_profiler/events/sql_event.rb
|
204
|
-
- lib/runtime_profiler/instrumentation_data.rb
|
205
205
|
- lib/runtime_profiler/profiler.rb
|
206
206
|
- lib/runtime_profiler/text_report.rb
|
207
207
|
- lib/runtime_profiler/version.rb
|
208
|
-
-
|
208
|
+
- rp_view_command.png
|
209
209
|
- runtime_profiler.gemspec
|
210
210
|
homepage: http://www.github.com/wnuqui/runtime_profiler
|
211
211
|
licenses:
|
Binary file
|