scout_apm 2.0.0.pre2 → 2.0.0.pre3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.markdown +9 -0
- data/lib/scout_apm/agent.rb +14 -33
- data/lib/scout_apm/config.rb +0 -1
- data/lib/scout_apm/instruments/percentile_sampler.rb +7 -8
- data/lib/scout_apm/instruments/process/process_cpu.rb +12 -0
- data/lib/scout_apm/instruments/process/process_memory.rb +12 -0
- data/lib/scout_apm/layer_converters/slow_request_converter.rb +1 -4
- data/lib/scout_apm/slow_transaction.rb +1 -4
- data/lib/scout_apm/store.rb +24 -0
- data/lib/scout_apm/tracked_request.rb +2 -13
- data/lib/scout_apm/version.rb +1 -1
- data/lib/scout_apm.rb +0 -6
- data/test/unit/serializers/payload_serializer_test.rb +0 -1
- metadata +2 -4
- data/lib/scout_apm/stackprof_tree_collapser.rb +0 -103
- data/lib/scout_apm/utils/fake_stack_prof.rb +0 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d49313e6479d1530b66fcc237fbe105646dd33d8
|
4
|
+
data.tar.gz: bfc290ad58b83f3c3509cc81ffb14d9d08ab1237
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 420825d2d15e709e0d07209ff6d32c03fb51400123b31b880de67dd1c1890e4ab23421a05830d1821569db135aa4f30ab9e1b9b82e1112b713d0b09a797c8f5b
|
7
|
+
data.tar.gz: 21d53aadf8fbb4584e5c5a75437f6b1433f28d7792c4715435b49f7f0170b619fc38246bae2e8b64b3e6acd546c57b7eead417d8ddafaafa1a34abd3c2f8f777
|
data/CHANGELOG.markdown
CHANGED
@@ -8,6 +8,15 @@
|
|
8
8
|
* seconds_since_startup (larger memory increases and other other odd behavior more common when close to startup)
|
9
9
|
* Initial support for instant traces
|
10
10
|
* Collect 95th percentiles
|
11
|
+
* Remove unused & old references to Stackprof
|
12
|
+
|
13
|
+
# 1.6.0
|
14
|
+
|
15
|
+
* Dynamic algorithm for selecting when to collect traces. Now, we will collect a
|
16
|
+
more complete cross-section of your application's performance, dynamically
|
17
|
+
tuned as your application runs.
|
18
|
+
* Record and report 95th percentiles for each action
|
19
|
+
* A variety of bug fixes
|
11
20
|
|
12
21
|
# 1.5.5
|
13
22
|
|
data/lib/scout_apm/agent.rb
CHANGED
@@ -24,8 +24,9 @@ module ScoutApm
|
|
24
24
|
# Histogram of the cumulative requests since the start of the process
|
25
25
|
attr_reader :request_histograms
|
26
26
|
|
27
|
-
# Histogram of the requests
|
28
|
-
|
27
|
+
# Histogram of the requests, distinct by reporting period (minute)
|
28
|
+
# { StoreReportingPeriodTimestamp => RequestHistograms }
|
29
|
+
attr_reader :request_histograms_by_time
|
29
30
|
|
30
31
|
# All access to the agent is thru this class method to ensure multiple Agent instances are not initialized per-Ruby process.
|
31
32
|
def self.instance(options = {})
|
@@ -50,7 +51,7 @@ module ScoutApm
|
|
50
51
|
@slow_request_policy = ScoutApm::SlowRequestPolicy.new
|
51
52
|
@slow_job_policy = ScoutApm::SlowJobPolicy.new
|
52
53
|
@request_histograms = ScoutApm::RequestHistograms.new
|
53
|
-
@
|
54
|
+
@request_histograms_by_time = Hash.new { |h, k| h[k] = ScoutApm::RequestHistograms.new }
|
54
55
|
|
55
56
|
@store = ScoutApm::Store.new
|
56
57
|
@layaway = ScoutApm::Layaway.new
|
@@ -124,11 +125,10 @@ module ScoutApm
|
|
124
125
|
|
125
126
|
load_instruments if should_load_instruments?(options)
|
126
127
|
|
127
|
-
|
128
|
-
ScoutApm::Instruments::Process::ProcessCpu.new(environment.processors, logger),
|
128
|
+
[ ScoutApm::Instruments::Process::ProcessCpu.new(environment.processors, logger),
|
129
129
|
ScoutApm::Instruments::Process::ProcessMemory.new(logger),
|
130
130
|
ScoutApm::Instruments::PercentileSampler.new(logger, 95),
|
131
|
-
]
|
131
|
+
].each { |s| store.add_sampler(s) }
|
132
132
|
|
133
133
|
app_server_load_hook
|
134
134
|
|
@@ -242,16 +242,19 @@ module ScoutApm
|
|
242
242
|
@background_worker = ScoutApm::BackgroundWorker.new
|
243
243
|
@background_worker_thread = Thread.new do
|
244
244
|
@background_worker.start {
|
245
|
-
# First, run periodic samplers. These should run once a minute,
|
246
|
-
# rather than per-request. "CPU Load" and similar.
|
247
|
-
run_samplers
|
248
|
-
capacity.process
|
249
|
-
|
250
245
|
ScoutApm::Agent.instance.process_metrics
|
246
|
+
clean_old_percentiles
|
251
247
|
}
|
252
248
|
end
|
253
249
|
end
|
254
250
|
|
251
|
+
def clean_old_percentiles
|
252
|
+
request_histograms_by_time.
|
253
|
+
keys.
|
254
|
+
select {|timestamp| timestamp.age_in_seconds > 60 * 10 }.
|
255
|
+
each {|old_timestamp| request_histograms_by_time.delete(old_timestamp) }
|
256
|
+
end
|
257
|
+
|
255
258
|
# If we want to skip the app_server_check, then we must load it.
|
256
259
|
def should_load_instruments?(options={})
|
257
260
|
return true if options[:skip_app_server_check]
|
@@ -284,10 +287,6 @@ module ScoutApm
|
|
284
287
|
install_instrument(ScoutApm::Instruments::Redis)
|
285
288
|
install_instrument(ScoutApm::Instruments::InfluxDB)
|
286
289
|
install_instrument(ScoutApm::Instruments::Elasticsearch)
|
287
|
-
|
288
|
-
if StackProf.respond_to?(:fake?) && StackProf.fake?
|
289
|
-
logger.info 'StackProf not found - add `gem "stackprof"` to your Gemfile to enable advanced code profiling (only for Ruby 2.1+)'
|
290
|
-
end
|
291
290
|
rescue
|
292
291
|
logger.warn "Exception loading instruments:"
|
293
292
|
logger.warn $!.message
|
@@ -314,24 +313,6 @@ module ScoutApm
|
|
314
313
|
environment.deploy_integration
|
315
314
|
end
|
316
315
|
|
317
|
-
# TODO: Extract a proper class / registery for these. They don't really belong here
|
318
|
-
def run_samplers
|
319
|
-
@samplers.each do |sampler|
|
320
|
-
begin
|
321
|
-
if sampler.respond_to? :metrics
|
322
|
-
store.track!(sampler.metrics)
|
323
|
-
else
|
324
|
-
result = sampler.run
|
325
|
-
store.track_one!(sampler.metric_type, sampler.metric_name, result) if result
|
326
|
-
end
|
327
|
-
rescue => e
|
328
|
-
logger.info "Error reading #{sampler.human_name}"
|
329
|
-
logger.debug e.message
|
330
|
-
logger.debug e.backtrace.join("\n")
|
331
|
-
end
|
332
|
-
end
|
333
|
-
end
|
334
|
-
|
335
316
|
def app_server_missing?(options = {})
|
336
317
|
!environment.app_server_integration(true).found? && !options[:skip_app_server_check]
|
337
318
|
end
|
data/lib/scout_apm/config.rb
CHANGED
@@ -68,7 +68,6 @@ module ScoutApm
|
|
68
68
|
'host' => 'https://checkin.scoutapp.com',
|
69
69
|
'direct_host' => 'https://apm.scoutapp.com',
|
70
70
|
'log_level' => 'info',
|
71
|
-
'stackprof_interval' => 20000, # microseconds, 1000 = 1 millisecond, so 20k == 20 milliseconds
|
72
71
|
'uri_reporting' => 'full_path',
|
73
72
|
'report_format' => 'json',
|
74
73
|
'disabled_instruments' => [],
|
@@ -14,25 +14,24 @@ module ScoutApm
|
|
14
14
|
"Percentiles"
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
# Gets the 95th%ile for the time requested
|
18
|
+
def metrics(time)
|
18
19
|
ms = {}
|
19
|
-
|
20
|
-
|
20
|
+
histos = ScoutApm::Agent.instance.request_histograms_by_time[time]
|
21
|
+
histos.each_name do |name|
|
21
22
|
percentiles.each do |percentile|
|
22
23
|
meta = MetricMeta.new("Percentile/#{percentile}/#{name}")
|
23
24
|
stat = MetricStats.new
|
24
|
-
stat.update!(
|
25
|
+
stat.update!(histos.quantile(name, percentile))
|
25
26
|
ms[meta] = stat
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
29
|
-
# Wipe the histograms
|
30
|
-
ScoutApm::Agent.instance.
|
30
|
+
# Wipe the histograms we just collected data on
|
31
|
+
ScoutApm::Agent.instance.request_histograms_by_time.delete(time)
|
31
32
|
|
32
33
|
ms
|
33
34
|
end
|
34
|
-
|
35
|
-
private
|
36
35
|
end
|
37
36
|
end
|
38
37
|
end
|
@@ -29,6 +29,18 @@ module ScoutApm
|
|
29
29
|
"Process CPU"
|
30
30
|
end
|
31
31
|
|
32
|
+
def metrics(_time)
|
33
|
+
result = run
|
34
|
+
if result
|
35
|
+
meta = MetricMeta.new("#{metric_type}/#{metric_name}")
|
36
|
+
stat = MetricStats.new(false)
|
37
|
+
stat.update!(result)
|
38
|
+
{ meta => stat }
|
39
|
+
else
|
40
|
+
{}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
32
44
|
# TODO: Figure out a good default instead of nil
|
33
45
|
def run
|
34
46
|
res = nil
|
@@ -33,6 +33,18 @@ module ScoutApm
|
|
33
33
|
"Process Memory"
|
34
34
|
end
|
35
35
|
|
36
|
+
def metrics(_time)
|
37
|
+
result = run
|
38
|
+
if result
|
39
|
+
meta = MetricMeta.new("#{metric_type}/#{metric_name}")
|
40
|
+
stat = MetricStats.new(false)
|
41
|
+
stat.update!(result)
|
42
|
+
{ meta => stat }
|
43
|
+
else
|
44
|
+
{}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
36
48
|
def run
|
37
49
|
self.class.rss_in_mb.tap { |res| logger.debug "#{human_name}: #{res.inspect}" }
|
38
50
|
end
|
@@ -46,9 +46,6 @@ module ScoutApm
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
# Disable stackprof output for now
|
50
|
-
stackprof = [] # request.stackprof
|
51
|
-
|
52
49
|
SlowTransaction.new(uri,
|
53
50
|
scope.legacy_metric_name,
|
54
51
|
root_layer.total_call_time,
|
@@ -56,7 +53,7 @@ module ScoutApm
|
|
56
53
|
allocation_metrics,
|
57
54
|
request.context,
|
58
55
|
root_layer.stop_time,
|
59
|
-
stackprof,
|
56
|
+
[], # stackprof, now unused.
|
60
57
|
mem_delta,
|
61
58
|
root_layer.total_allocations,
|
62
59
|
@points)
|
@@ -11,7 +11,6 @@ module ScoutApm
|
|
11
11
|
attr_reader :context
|
12
12
|
attr_reader :time
|
13
13
|
attr_reader :prof
|
14
|
-
attr_reader :raw_prof
|
15
14
|
attr_reader :mem_delta
|
16
15
|
attr_reader :allocations
|
17
16
|
attr_accessor :hostname # hack - we need to reset these server side.
|
@@ -25,9 +24,7 @@ module ScoutApm
|
|
25
24
|
@allocation_metrics = allocation_metrics
|
26
25
|
@context = context
|
27
26
|
@time = time
|
28
|
-
@prof =
|
29
|
-
@raw_prof = raw_stackprof # Send whole data up to server
|
30
|
-
|
27
|
+
@prof = []
|
31
28
|
@mem_delta = mem_delta
|
32
29
|
@allocations = allocations
|
33
30
|
@seconds_since_startup = (Time.now - ScoutApm::Agent.instance.process_start_time)
|
data/lib/scout_apm/store.rb
CHANGED
@@ -6,9 +6,13 @@ module ScoutApm
|
|
6
6
|
# A hash of reporting periods. { StoreReportingPeriodTimestamp => StoreReportingPeriod }
|
7
7
|
attr_reader :reporting_periods
|
8
8
|
|
9
|
+
# Used to pull metrics into each reporting period, as that reporting period is finished.
|
10
|
+
attr_reader :samplers
|
11
|
+
|
9
12
|
def initialize
|
10
13
|
@mutex = Mutex.new
|
11
14
|
@reporting_periods = Hash.new { |h,k| h[k] = StoreReportingPeriod.new(k) }
|
15
|
+
@samplers = []
|
12
16
|
end
|
13
17
|
|
14
18
|
def current_timestamp
|
@@ -66,12 +70,32 @@ module ScoutApm
|
|
66
70
|
@mutex.synchronize {
|
67
71
|
reporting_periods.select { |time, rp| force || time.timestamp < current_timestamp.timestamp}.
|
68
72
|
each { |time, rp|
|
73
|
+
collect_samplers(rp)
|
69
74
|
layaway.add_reporting_period(time, rp)
|
70
75
|
reporting_periods.delete(time)
|
71
76
|
}
|
72
77
|
}
|
73
78
|
ScoutApm::Agent.instance.logger.debug("Finished writing to layaway")
|
74
79
|
end
|
80
|
+
|
81
|
+
######################################
|
82
|
+
# Sampler support
|
83
|
+
def add_sampler(sampler)
|
84
|
+
@samplers << sampler
|
85
|
+
end
|
86
|
+
|
87
|
+
def collect_samplers(rp)
|
88
|
+
@samplers.each do |sampler|
|
89
|
+
begin
|
90
|
+
metrics = sampler.metrics(rp.timestamp)
|
91
|
+
rp.absorb_metrics!(metrics)
|
92
|
+
rescue => e
|
93
|
+
ScoutApm::Agent.instance.logger.info "Error reading #{sampler.human_name} for period: #{rp}"
|
94
|
+
ScoutApm::Agent.instance.logger.debug e.message
|
95
|
+
ScoutApm::Agent.instance.logger.debug e.backtrace.join("\n")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
75
99
|
end
|
76
100
|
|
77
101
|
# A timestamp, normalized to the beginning of a minute. Used as a hash key to
|
@@ -22,10 +22,6 @@ module ScoutApm
|
|
22
22
|
# :queue_latency - how long a background Job spent in the queue before starting processing
|
23
23
|
attr_reader :annotations
|
24
24
|
|
25
|
-
# Nil until the request is finalized, at which point it will hold the
|
26
|
-
# entire raw stackprof output for this request
|
27
|
-
attr_reader :stackprof
|
28
|
-
|
29
25
|
# Headers as recorded by rails
|
30
26
|
# Can be nil if we never reach a Rails Controller
|
31
27
|
attr_reader :headers
|
@@ -52,7 +48,6 @@ module ScoutApm
|
|
52
48
|
@ignoring_children = false
|
53
49
|
@context = Context.new
|
54
50
|
@root_layer = nil
|
55
|
-
@stackprof = nil
|
56
51
|
@error = false
|
57
52
|
@instant_key = nil
|
58
53
|
@mem_start = mem_usage
|
@@ -158,21 +153,14 @@ module ScoutApm
|
|
158
153
|
# Run at the beginning of the whole request
|
159
154
|
#
|
160
155
|
# * Capture the first layer as the root_layer
|
161
|
-
# * Start Stackprof (disabling to avoid conflicts if stackprof is included as middleware since we aren't sending this up to server now)
|
162
156
|
def start_request(layer)
|
163
157
|
@root_layer = layer unless @root_layer # capture root layer
|
164
|
-
#StackProf.start(:mode => :wall, :interval => ScoutApm::Agent.instance.config.value("stackprof_interval"))
|
165
158
|
end
|
166
159
|
|
167
160
|
# Run at the end of the whole request
|
168
161
|
#
|
169
|
-
# * Collect stackprof info
|
170
162
|
# * Send the request off to be stored
|
171
163
|
def stop_request
|
172
|
-
# ScoutApm::Agent.instance.logger.debug("stop_request: #{annotations[:uri]}" )
|
173
|
-
#StackProf.stop # disabling to avoid conflicts if stackprof is included as middleware since we aren't sending this up to server now
|
174
|
-
#@stackprof = StackProf.results
|
175
|
-
|
176
164
|
record!
|
177
165
|
end
|
178
166
|
|
@@ -234,7 +222,8 @@ module ScoutApm
|
|
234
222
|
# Update immediate and long-term histograms for both job and web requests
|
235
223
|
if unique_name != :unknown
|
236
224
|
ScoutApm::Agent.instance.request_histograms.add(unique_name, root_layer.total_call_time)
|
237
|
-
ScoutApm::Agent.instance.
|
225
|
+
ScoutApm::Agent.instance.request_histograms_by_time[ScoutApm::Agent.instance.store.current_timestamp].
|
226
|
+
add(unique_name, root_layer.total_call_time)
|
238
227
|
end
|
239
228
|
|
240
229
|
metrics = LayerConverters::MetricConverter.new(self).call
|
data/lib/scout_apm/version.rb
CHANGED
data/lib/scout_apm.rb
CHANGED
@@ -18,11 +18,6 @@ require 'yaml'
|
|
18
18
|
#####################################
|
19
19
|
# Gem Requires
|
20
20
|
#####################################
|
21
|
-
begin
|
22
|
-
require 'stackprof'
|
23
|
-
rescue LoadError
|
24
|
-
require 'scout_apm/utils/fake_stack_prof'
|
25
|
-
end
|
26
21
|
require 'rusage'
|
27
22
|
|
28
23
|
#####################################
|
@@ -116,7 +111,6 @@ require 'scout_apm/metric_set'
|
|
116
111
|
require 'scout_apm/store'
|
117
112
|
require 'scout_apm/tracer'
|
118
113
|
require 'scout_apm/context'
|
119
|
-
require 'scout_apm/stackprof_tree_collapser'
|
120
114
|
require 'scout_apm/instant_reporting'
|
121
115
|
|
122
116
|
require 'scout_apm/metric_meta'
|
@@ -6,7 +6,6 @@ require 'scout_apm/serializers/payload_serializer_to_json'
|
|
6
6
|
require 'scout_apm/slow_transaction'
|
7
7
|
require 'scout_apm/metric_meta'
|
8
8
|
require 'scout_apm/metric_stats'
|
9
|
-
require 'scout_apm/stackprof_tree_collapser'
|
10
9
|
require 'scout_apm/utils/fake_stack_prof'
|
11
10
|
require 'scout_apm/context'
|
12
11
|
require 'ostruct'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scout_apm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.pre3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Derek Haynes
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-06-
|
12
|
+
date: 2016-06-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rusage
|
@@ -200,13 +200,11 @@ files:
|
|
200
200
|
- lib/scout_apm/slow_request_policy.rb
|
201
201
|
- lib/scout_apm/slow_transaction.rb
|
202
202
|
- lib/scout_apm/stack_item.rb
|
203
|
-
- lib/scout_apm/stackprof_tree_collapser.rb
|
204
203
|
- lib/scout_apm/store.rb
|
205
204
|
- lib/scout_apm/tracer.rb
|
206
205
|
- lib/scout_apm/tracked_request.rb
|
207
206
|
- lib/scout_apm/utils/active_record_metric_name.rb
|
208
207
|
- lib/scout_apm/utils/backtrace_parser.rb
|
209
|
-
- lib/scout_apm/utils/fake_stack_prof.rb
|
210
208
|
- lib/scout_apm/utils/installed_gems.rb
|
211
209
|
- lib/scout_apm/utils/klass_helper.rb
|
212
210
|
- lib/scout_apm/utils/null_logger.rb
|
@@ -1,103 +0,0 @@
|
|
1
|
-
module ScoutApm
|
2
|
-
class StackprofTreeCollapser
|
3
|
-
attr_reader :raw_stackprof
|
4
|
-
attr_reader :nodes
|
5
|
-
|
6
|
-
def initialize(raw_stackprof)
|
7
|
-
@raw_stackprof = raw_stackprof
|
8
|
-
|
9
|
-
# Log the raw stackprof info
|
10
|
-
#unless StackProf.respond_to?(:fake?) && StackProf.fake?
|
11
|
-
# begin
|
12
|
-
# ScoutApm::Agent.instance.logger.debug("StackProf - Samples: #{raw_stackprof[:samples]}, GC: #{raw_stackprof[:gc_samples]}, missed: #{raw_stackprof[:missed_samples]}, Interval: #{raw_stackprof[:interval]}")
|
13
|
-
# rescue
|
14
|
-
# ScoutApm::Agent.instance.logger.debug("StackProf Raw - #{raw_stackprof.inspect}")
|
15
|
-
# end
|
16
|
-
#end
|
17
|
-
end
|
18
|
-
|
19
|
-
def call
|
20
|
-
build_tree
|
21
|
-
connect_children
|
22
|
-
total_samples_of_app_nodes
|
23
|
-
rescue
|
24
|
-
[]
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def build_tree
|
30
|
-
@nodes = raw_stackprof[:frames].map do |(frame_id, frame_data)|
|
31
|
-
TreeNode.new(frame_id, # frame_id
|
32
|
-
frame_data[:name], # name
|
33
|
-
frame_data[:file], # file
|
34
|
-
frame_data[:line], # line
|
35
|
-
frame_data[:samples], # samples
|
36
|
-
frame_data[:total_samples], # total_samples
|
37
|
-
(frame_data[:edges] || {}), # children_edges [ { id => weight } ]
|
38
|
-
[], # children [ treenode, ... ]
|
39
|
-
[] # parents [ [treenode, int (weight) ], [...] ]
|
40
|
-
)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def connect_children
|
45
|
-
nodes.each do |node|
|
46
|
-
children = nodes.find_all { |n| node.children_edges.keys.include? n.frame_id }
|
47
|
-
|
48
|
-
node.children_edges.each do |(frame_id, weight)|
|
49
|
-
child = children.detect{ |c| c.frame_id == frame_id }
|
50
|
-
child.parents << [node, weight]
|
51
|
-
end
|
52
|
-
|
53
|
-
node.children = children
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def in_app_nodes
|
58
|
-
nodes.select {|n| n.app? }
|
59
|
-
end
|
60
|
-
|
61
|
-
def total_samples_of_app_nodes
|
62
|
-
in_app_nodes.reject{|n| n.calls_only_app_nodes? && !n.has_samples? }.
|
63
|
-
map{|n| { :samples => n.total_samples,
|
64
|
-
:name => n.name,
|
65
|
-
:file => n.file,
|
66
|
-
:line => n.line
|
67
|
-
}
|
68
|
-
}
|
69
|
-
end
|
70
|
-
|
71
|
-
###########################################
|
72
|
-
# TreeNode class represents a single node.
|
73
|
-
###########################################
|
74
|
-
TreeNode = Struct.new(:frame_id, :name, :file, :line, :samples, :total_samples,
|
75
|
-
:children_edges, :children, :parents) do
|
76
|
-
def app?
|
77
|
-
@is_app ||= file =~ /^#{ScoutApm::Environment.instance.root}/
|
78
|
-
end
|
79
|
-
|
80
|
-
# Force object_id to be the equality mechanism, rather than struct's
|
81
|
-
# default which delegates to == on each value. That is wrong because
|
82
|
-
# we want to be able to dup a node in the tree construction process and
|
83
|
-
# not have those compare equal to each other.
|
84
|
-
def ==(other)
|
85
|
-
object_id == other.object_id
|
86
|
-
end
|
87
|
-
|
88
|
-
def inspect
|
89
|
-
"#{frame_id}: #{name} - ##{samples}\n" +
|
90
|
-
" Parents: #{parents.map{ |(p, w)| "#{p.name}: #{w}"}.join("\n ") }\n" +
|
91
|
-
" Children: #{children_edges.inspect} \n"
|
92
|
-
end
|
93
|
-
|
94
|
-
def calls_only_app_nodes?
|
95
|
-
children.all?(&:app?)
|
96
|
-
end
|
97
|
-
|
98
|
-
def has_samples?
|
99
|
-
samples > 0
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
# A fake implementation of stackprof, for systems that don't support it.
|
2
|
-
module StackProf
|
3
|
-
def self.start(*args)
|
4
|
-
@running = true
|
5
|
-
end
|
6
|
-
|
7
|
-
def self.stop(*args)
|
8
|
-
@running = false
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.running?
|
12
|
-
!!@running
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.run(*args)
|
16
|
-
start
|
17
|
-
yield
|
18
|
-
stop
|
19
|
-
results
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.sample(*args)
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.results(*args)
|
26
|
-
{
|
27
|
-
:version => 0.0,
|
28
|
-
:mode => :wall,
|
29
|
-
:interval => 1000,
|
30
|
-
:samples => 0,
|
31
|
-
:gc_samples => 0,
|
32
|
-
:missed_samples => 0,
|
33
|
-
:frames => {},
|
34
|
-
}
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.fake?
|
38
|
-
true
|
39
|
-
end
|
40
|
-
end
|