newrelic_rpm 3.10.0.279 → 3.11.0.283
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG +61 -0
- data/lib/new_relic/agent.rb +14 -8
- data/lib/new_relic/agent/agent.rb +43 -28
- data/lib/new_relic/agent/agent_logger.rb +21 -20
- data/lib/new_relic/agent/configuration/default_source.rb +31 -1
- data/lib/new_relic/agent/database.rb +2 -1
- data/lib/new_relic/agent/datastores.rb +177 -0
- data/lib/new_relic/agent/datastores/metric_helper.rb +85 -0
- data/lib/new_relic/agent/datastores/mongo/metric_translator.rb +11 -20
- data/lib/new_relic/agent/deprecator.rb +18 -0
- data/lib/new_relic/agent/instrumentation/active_record.rb +20 -35
- data/lib/new_relic/agent/instrumentation/active_record_helper.rb +116 -57
- data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +11 -20
- data/lib/new_relic/agent/instrumentation/data_mapper.rb +104 -172
- data/lib/new_relic/agent/instrumentation/memcache.rb +104 -52
- data/lib/new_relic/agent/instrumentation/metric_frame.rb +9 -0
- data/lib/new_relic/agent/instrumentation/middleware_proxy.rb +15 -2
- data/lib/new_relic/agent/instrumentation/mongo.rb +5 -18
- data/lib/new_relic/agent/instrumentation/sequel_helper.rb +36 -0
- data/lib/new_relic/agent/new_relic_service.rb +4 -0
- data/lib/new_relic/agent/stats_engine/metric_stats.rb +2 -17
- data/lib/new_relic/agent/threading/backtrace_service.rb +28 -5
- data/lib/new_relic/agent/transaction.rb +63 -34
- data/lib/new_relic/agent/transaction_event_aggregator.rb +0 -4
- data/lib/new_relic/agent/transaction_sampler.rb +11 -5
- data/lib/new_relic/rack/error_collector.rb +0 -1
- data/lib/new_relic/version.rb +1 -1
- data/lib/sequel/extensions/newrelic_instrumentation.rb +28 -56
- data/lib/sequel/plugins/newrelic_instrumentation.rb +28 -45
- data/newrelic_rpm.gemspec +0 -7
- data/test/agent_helper.rb +35 -16
- data/test/environments/rails31/Gemfile +1 -0
- data/test/environments/rails32/Gemfile +1 -0
- data/test/helpers/mongo_metric_builder.rb +2 -3
- data/test/multiverse/lib/multiverse/output_collector.rb +24 -9
- data/test/multiverse/lib/multiverse/suite.rb +5 -0
- data/test/multiverse/suites/active_record/Envfile +6 -4
- data/test/multiverse/suites/active_record/active_record_test.rb +32 -73
- data/test/multiverse/suites/active_record/ar_method_aliasing.rb +0 -1
- data/test/multiverse/suites/activemerchant/activemerchant_test.rb +0 -3
- data/test/multiverse/suites/agent_only/agent_run_id_handling_test.rb +0 -1
- data/test/multiverse/suites/agent_only/audit_log_test.rb +0 -1
- data/test/multiverse/suites/agent_only/collector_exception_handling_test.rb +0 -2
- data/test/multiverse/suites/agent_only/cross_application_tracing_test.rb +0 -1
- data/test/multiverse/suites/agent_only/custom_analytics_events_test.rb +0 -2
- data/test/multiverse/suites/agent_only/custom_queue_time_test.rb +0 -1
- data/test/multiverse/suites/agent_only/encoding_handling_test.rb +0 -2
- data/test/multiverse/suites/agent_only/exclusive_time_test.rb +0 -2
- data/test/multiverse/suites/agent_only/harvest_timestamps_test.rb +0 -1
- data/test/multiverse/suites/agent_only/http_response_code_test.rb +0 -1
- data/test/multiverse/suites/agent_only/keepalive_test.rb +0 -1
- data/test/multiverse/suites/agent_only/key_transactions_test.rb +54 -9
- data/test/multiverse/suites/agent_only/labels_test.rb +0 -2
- data/test/multiverse/suites/agent_only/logging_test.rb +0 -1
- data/test/multiverse/suites/agent_only/marshaling_test.rb +0 -1
- data/test/multiverse/suites/agent_only/pipe_manager_test.rb +0 -2
- data/test/multiverse/suites/agent_only/rename_rule_test.rb +5 -7
- data/test/multiverse/suites/agent_only/rum_instrumentation_test.rb +0 -1
- data/test/multiverse/suites/agent_only/set_transaction_name_test.rb +0 -2
- data/test/multiverse/suites/agent_only/ssl_test.rb +0 -2
- data/test/multiverse/suites/agent_only/synthetics_test.rb +0 -1
- data/test/multiverse/suites/agent_only/testing_app.rb +21 -0
- data/test/multiverse/suites/agent_only/thread_profiling_test.rb +1 -2
- data/test/multiverse/suites/agent_only/transaction_ignoring_test.rb +0 -2
- data/test/multiverse/suites/agent_only/utilization_data_collection_test.rb +0 -1
- data/test/multiverse/suites/agent_only/xray_sessions_test.rb +69 -34
- data/test/multiverse/suites/capistrano/deployment_test.rb +0 -1
- data/test/multiverse/suites/capistrano2/deployment_test.rb +0 -1
- data/test/multiverse/suites/config_file_loading/config_file_loading_test.rb +0 -2
- data/test/multiverse/suites/curb/curb_test.rb +0 -2
- data/test/multiverse/suites/datamapper/Envfile +26 -3
- data/test/multiverse/suites/datamapper/config/newrelic.yml +1 -0
- data/test/multiverse/suites/datamapper/datamapper_test.rb +271 -37
- data/test/multiverse/suites/deferred_instrumentation/sinatra_test.rb +0 -1
- data/test/multiverse/suites/delayed_job/Envfile +31 -8
- data/test/multiverse/suites/delayed_job/delayed_job_sampler_test.rb +0 -3
- data/test/multiverse/suites/delayed_job/unsupported_backend_test.rb +0 -3
- data/test/multiverse/suites/excon/excon_test.rb +0 -2
- data/test/multiverse/suites/grape/grape_test.rb +0 -3
- data/test/multiverse/suites/grape/grape_versioning_test.rb +0 -3
- data/test/multiverse/suites/grape/unsupported_version_test.rb +0 -3
- data/test/multiverse/suites/high_security/high_security_test.rb +0 -1
- data/test/multiverse/suites/httpclient/httpclient_test.rb +0 -2
- data/test/multiverse/suites/json/json_test.rb +0 -1
- data/test/multiverse/suites/marshalling/marshalling_test.rb +0 -1
- data/test/multiverse/suites/memcached/Envfile +52 -0
- data/test/multiverse/suites/memcached/dalli_test.rb +89 -0
- data/test/multiverse/suites/memcached/memcache_client_test.rb +25 -0
- data/test/multiverse/suites/memcached/memcache_test_cases.rb +302 -0
- data/test/multiverse/suites/memcached/memcached_test.rb +159 -0
- data/test/multiverse/suites/mongo/helpers/mongo_operation_tests.rb +26 -17
- data/test/multiverse/suites/mongo/mongo_connection_test.rb +0 -1
- data/test/multiverse/suites/mongo/mongo_instrumentation_test.rb +0 -1
- data/test/multiverse/suites/mongo/mongo_unsupported_version_test.rb +0 -1
- data/test/multiverse/suites/net_http/net_http_test.rb +0 -2
- data/test/multiverse/suites/padrino/padrino_test.rb +0 -3
- data/test/multiverse/suites/rack/http_response_code_test.rb +0 -1
- data/test/multiverse/suites/rack/nested_non_rack_app_test.rb +1 -1
- data/test/multiverse/suites/rack/rack_auto_instrumentation_test.rb +12 -12
- data/test/multiverse/suites/rack/rack_cascade_test.rb +0 -1
- data/test/multiverse/suites/rack/rack_env_mutation_test.rb +0 -1
- data/test/multiverse/suites/rack/rack_parameter_filtering_test.rb +0 -1
- data/test/multiverse/suites/rack/rack_unsupported_version_test.rb +0 -2
- data/test/multiverse/suites/rack/url_map_test.rb +3 -2
- data/test/multiverse/suites/rails/Envfile +3 -0
- data/test/multiverse/suites/rails/activejob_test.rb +0 -1
- data/test/multiverse/suites/rails/app.rb +0 -1
- data/test/multiverse/suites/rails/parameter_capture_test.rb +13 -0
- data/test/multiverse/suites/rails/rails3_app/app_rails3_plus.rb +5 -0
- data/test/multiverse/suites/rails/transaction_ignoring_test.rb +0 -2
- data/test/multiverse/suites/resque/instrumentation_test.rb +0 -2
- data/test/multiverse/suites/resque/resque_marshalling_test.rb +0 -1
- data/test/multiverse/suites/sequel/sequel_extension_test.rb +135 -0
- data/test/multiverse/suites/sequel/sequel_helpers.rb +62 -0
- data/test/multiverse/suites/sequel/sequel_plugin_test.rb +230 -0
- data/test/multiverse/suites/sidekiq/sidekiq_instrumentation_test.rb +0 -2
- data/test/multiverse/suites/sinatra/ignoring_test.rb +0 -2
- data/test/multiverse/suites/sinatra/nested_middleware_test.rb +0 -2
- data/test/multiverse/suites/sinatra/sinatra_classic_test.rb +0 -1
- data/test/multiverse/suites/sinatra/sinatra_error_tracing_test.rb +0 -2
- data/test/multiverse/suites/sinatra/sinatra_metric_explosion_test.rb +14 -12
- data/test/multiverse/suites/sinatra/sinatra_modular_test.rb +0 -1
- data/test/multiverse/suites/sinatra/sinatra_routes_test.rb +0 -2
- data/test/multiverse/suites/sinatra/sinatra_test_cases.rb +0 -2
- data/test/multiverse/suites/typhoeus/typhoeus_test.rb +0 -2
- data/test/multiverse/suites/yajl/yajl_test.rb +0 -1
- data/test/new_relic/agent/agent/start_test.rb +2 -2
- data/test/new_relic/agent/agent_logger_test.rb +6 -3
- data/test/new_relic/agent/datastores/metric_helper_test.rb +61 -0
- data/test/new_relic/agent/datastores/mongo/metric_translator_test.rb +20 -21
- data/test/new_relic/agent/datastores_test.rb +195 -0
- data/test/new_relic/agent/deprecator_test.rb +52 -0
- data/test/new_relic/agent/instrumentation/action_view_subscriber_test.rb +20 -26
- data/test/new_relic/agent/instrumentation/active_record_helper_test.rb +58 -53
- data/test/new_relic/agent/instrumentation/active_record_subscriber_test.rb +7 -20
- data/test/new_relic/agent/instrumentation/middleware_proxy_test.rb +19 -0
- data/test/new_relic/agent/instrumentation/sequel_helper_test.rb +36 -0
- data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +1 -0
- data/test/new_relic/agent/method_tracer_test.rb +3 -4
- data/test/new_relic/agent/pipe_channel_manager_test.rb +1 -1
- data/test/new_relic/agent/threading/backtrace_service_test.rb +29 -4
- data/test/new_relic/agent/transaction_event_aggregator_test.rb +0 -4
- data/test/new_relic/agent/transaction_test.rb +100 -2
- data/test/new_relic/agent_test.rb +3 -3
- data/test/new_relic/http_client_test_cases.rb +0 -1
- data/test/new_relic/multiverse_helpers.rb +7 -0
- data/test/new_relic/transaction_ignoring_test_cases.rb +0 -2
- data/test/new_relic/transaction_sample_test.rb +11 -2
- data/test/performance/README.md +37 -17
- data/test/performance/lib/performance.rb +1 -0
- data/test/performance/lib/performance/baseline_compare_reporter.rb +11 -7
- data/test/performance/lib/performance/console_reporter.rb +29 -5
- data/test/performance/lib/performance/formatting_helpers.rb +22 -0
- data/test/performance/lib/performance/instrumentation/stackprof.rb +11 -1
- data/test/performance/lib/performance/result.rb +17 -6
- data/test/performance/lib/performance/runner.rb +7 -3
- data/test/performance/lib/performance/test_case.rb +89 -21
- data/test/performance/script/runner +13 -1
- data/test/performance/suites/active_record.rb +47 -0
- data/test/performance/suites/config.rb +4 -48
- data/test/performance/suites/marshalling.rb +20 -30
- data/test/performance/suites/queue_time.rb +1 -1
- data/test/performance/suites/rack_middleware.rb +1 -1
- data/test/performance/suites/rum_autoinsertion.rb +1 -1
- data/test/performance/suites/sql_obfuscation.rb +2 -2
- data/test/performance/suites/startup.rb +1 -1
- data/test/performance/suites/stats_hash.rb +7 -11
- data/test/performance/suites/thread_profiling.rb +20 -25
- data/test/performance/suites/trace_execution_scoped.rb +2 -2
- data/test/performance/suites/transaction_tracing.rb +4 -2
- data/test/test_helper.rb +5 -1
- metadata +53 -100
- data.tar.gz.sig +0 -0
- data/gem-public_cert.pem +0 -20
- data/lib/new_relic/agent/datastores/mongo/metric_generator.rb +0 -33
- data/test/multiverse/suites/sequel/sequel_instrumentation_test.rb +0 -289
- data/test/new_relic/agent/datastores/mongo/metric_generator_test.rb +0 -69
- data/test/new_relic/agent/memcache_instrumentation_test.rb +0 -155
- metadata.gz.sig +0 -2
@@ -17,6 +17,7 @@ require 'performance/reporting'
|
|
17
17
|
require 'performance/table'
|
18
18
|
require 'performance/console_reporter'
|
19
19
|
require 'performance/json_reporter'
|
20
|
+
require 'performance/formatting_helpers'
|
20
21
|
|
21
22
|
require 'performance/hako_client'
|
22
23
|
require 'performance/hako_reporter'
|
@@ -55,12 +55,16 @@ module Performance
|
|
55
55
|
old_result = baseline.find { |r| r.identifier == identifier}
|
56
56
|
new_result = results.find { |r| r.identifier == identifier }
|
57
57
|
|
58
|
-
delta = new_result.
|
59
|
-
percent_delta = delta / old_result.
|
58
|
+
delta = new_result.time_per_iteration - old_result.time_per_iteration
|
59
|
+
percent_delta = delta / old_result.time_per_iteration * 100.0
|
60
60
|
|
61
61
|
allocations_before = old_result.measurements[:allocations]
|
62
62
|
allocations_after = new_result.measurements[:allocations]
|
63
63
|
if allocations_before && allocations_after
|
64
|
+
# normalize allocation counts to be per-iteration
|
65
|
+
allocations_before /= old_result.iterations
|
66
|
+
allocations_after /= new_result.iterations
|
67
|
+
|
64
68
|
allocations_delta = allocations_after - allocations_before
|
65
69
|
allocations_delta_percent = allocations_delta.to_f / allocations_before * 100
|
66
70
|
else
|
@@ -69,8 +73,8 @@ module Performance
|
|
69
73
|
|
70
74
|
rows << [
|
71
75
|
identifier,
|
72
|
-
old_result.
|
73
|
-
new_result.
|
76
|
+
old_result.time_per_iteration,
|
77
|
+
new_result.time_per_iteration,
|
74
78
|
percent_delta,
|
75
79
|
allocations_before,
|
76
80
|
allocations_after,
|
@@ -81,12 +85,12 @@ module Performance
|
|
81
85
|
format_percent_delta = Proc.new { |v|
|
82
86
|
prefix = v > 0 ? "+" : ""
|
83
87
|
sprintf("#{prefix}%.1f%%", v)
|
84
|
-
}
|
88
|
+
}
|
85
89
|
|
86
90
|
table = Table.new(rows) do
|
87
91
|
column :name
|
88
|
-
column :before,
|
89
|
-
column :after,
|
92
|
+
column :before, &(FormattingHelpers.method(:format_duration))
|
93
|
+
column :after, &(FormattingHelpers.method(:format_duration))
|
90
94
|
column :delta, &format_percent_delta
|
91
95
|
column :allocs_before
|
92
96
|
column :allocs_after
|
@@ -2,6 +2,8 @@
|
|
2
2
|
# This file is distributed under New Relic's license terms.
|
3
3
|
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
4
4
|
|
5
|
+
require 'pathname'
|
6
|
+
|
5
7
|
module Performance
|
6
8
|
class ConsoleReporter
|
7
9
|
include Reporting
|
@@ -18,25 +20,47 @@ module Performance
|
|
18
20
|
report_failed_results
|
19
21
|
end
|
20
22
|
|
23
|
+
def format_measurements(result)
|
24
|
+
measurements = result.measurements.merge(:iterations => result.iterations)
|
25
|
+
|
26
|
+
key_width = measurements.keys.map(&:size).max
|
27
|
+
formatted_values = measurements.values.map { |v| sprintf("%g", v) }
|
28
|
+
value_width = formatted_values.map(&:size).max
|
29
|
+
|
30
|
+
rows = measurements.map do |key, value|
|
31
|
+
if key == :iterations
|
32
|
+
" %#{key_width}s: %#{value_width}g" % [key, value]
|
33
|
+
else
|
34
|
+
per_iteration = value / result.iterations.to_f
|
35
|
+
" %#{key_width}s: %#{value_width}g (%.2f / iter)" % [key, value, per_iteration]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
rows.join("\n") + "\n"
|
40
|
+
end
|
41
|
+
|
21
42
|
def report_successful_results(results)
|
22
43
|
return if successes.empty?
|
23
44
|
|
24
45
|
puts ''
|
25
46
|
results.each do |result|
|
26
|
-
|
47
|
+
formatted_duration = FormattingHelpers.format_duration(result.time_per_iteration)
|
48
|
+
puts "#{result.identifier}: %.3f ips (#{formatted_duration} / iteration)" % [result.ips]
|
27
49
|
unless @options[:brief]
|
28
|
-
result
|
29
|
-
puts " %s: %g" % [key, value]
|
30
|
-
end
|
50
|
+
puts format_measurements(result)
|
31
51
|
end
|
32
52
|
unless result.artifacts.empty?
|
33
53
|
puts " artifacts:"
|
34
54
|
result.artifacts.each do |artifact|
|
35
|
-
puts " #{artifact}"
|
55
|
+
puts " #{make_relative(artifact)}"
|
36
56
|
end
|
37
57
|
end
|
38
58
|
puts '' if !@options[:brief] || !result.artifacts.empty?
|
39
59
|
end
|
40
60
|
end
|
61
|
+
|
62
|
+
def make_relative(path)
|
63
|
+
"./#{Pathname.new(path).relative_path_from(Pathname.getwd)}"
|
64
|
+
end
|
41
65
|
end
|
42
66
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
4
|
+
|
5
|
+
module Performance
|
6
|
+
module FormattingHelpers
|
7
|
+
def self.format_duration(d)
|
8
|
+
if d < 0.001
|
9
|
+
ds = d * 1000 * 1000
|
10
|
+
unit = "µs"
|
11
|
+
elsif d < 1.0
|
12
|
+
ds = d * 1000
|
13
|
+
unit = "ms"
|
14
|
+
else
|
15
|
+
ds = d
|
16
|
+
unit = "s"
|
17
|
+
end
|
18
|
+
|
19
|
+
sprintf("%.2f %s", ds, unit)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -12,8 +12,12 @@ module Performance
|
|
12
12
|
require 'stackprof'
|
13
13
|
end
|
14
14
|
|
15
|
+
def mode
|
16
|
+
:wall
|
17
|
+
end
|
18
|
+
|
15
19
|
def before(test, test_name)
|
16
|
-
StackProf.start(:mode =>
|
20
|
+
StackProf.start(:mode => mode)
|
17
21
|
end
|
18
22
|
|
19
23
|
def after(test, test_name)
|
@@ -32,5 +36,11 @@ module Performance
|
|
32
36
|
@artifacts << output_dot_path
|
33
37
|
end
|
34
38
|
end
|
39
|
+
|
40
|
+
class StackProfAllocationProfile < StackProfProfile
|
41
|
+
def mode
|
42
|
+
:object
|
43
|
+
end
|
44
|
+
end
|
35
45
|
end
|
36
46
|
end
|
@@ -7,7 +7,7 @@ require 'time'
|
|
7
7
|
module Performance
|
8
8
|
class Result
|
9
9
|
attr_reader :test_name, :measurements, :tags, :timer, :artifacts
|
10
|
-
attr_accessor :exception
|
10
|
+
attr_accessor :exception, :iterations
|
11
11
|
|
12
12
|
def initialize(test_case, test_name)
|
13
13
|
@test_case = test_case
|
@@ -15,7 +15,8 @@ module Performance
|
|
15
15
|
@measurements = {}
|
16
16
|
@tags = {}
|
17
17
|
@timer = Timer.new
|
18
|
-
@
|
18
|
+
@iterations = 0
|
19
|
+
@artifacts = []
|
19
20
|
end
|
20
21
|
|
21
22
|
def exception=(e)
|
@@ -58,16 +59,25 @@ module Performance
|
|
58
59
|
t.utc.iso8601
|
59
60
|
end
|
60
61
|
|
62
|
+
def ips
|
63
|
+
@iterations.to_f / elapsed
|
64
|
+
end
|
65
|
+
|
66
|
+
def time_per_iteration
|
67
|
+
elapsed / @iterations.to_f
|
68
|
+
end
|
69
|
+
|
61
70
|
def to_h
|
62
71
|
h = {
|
63
|
-
"suite"
|
64
|
-
"name"
|
72
|
+
"suite" => suite_name,
|
73
|
+
"name" => @test_name,
|
65
74
|
"measurements" => measurements_hash,
|
66
|
-
"tags" => @tags
|
75
|
+
"tags" => @tags,
|
76
|
+
"iterations" => @iterations
|
67
77
|
}
|
68
78
|
h['exception'] = @exception if @exception
|
69
79
|
h['artifacts'] = @artifacts if @artifacts && !@artifacts.empty?
|
70
|
-
h['started_at']
|
80
|
+
h['started_at'] = format_timestamp(@timer.start_timestamp) if @timer.start_timestamp
|
71
81
|
h['finished_at'] = format_timestamp(@timer.stop_timestamp) if @timer.stop_timestamp
|
72
82
|
h
|
73
83
|
end
|
@@ -81,6 +91,7 @@ module Performance
|
|
81
91
|
result.tags.merge! hash['tags']
|
82
92
|
result.exception = hash['exception']
|
83
93
|
result.elapsed = elapsed
|
94
|
+
result.iterations = hash['iterations']
|
84
95
|
result.timer.start_timestamp = Time.iso8601(hash['started_at']) if hash['started_at']
|
85
96
|
result.timer.stop_timestamp = Time.iso8601(hash['finished_at']) if hash['finished_at']
|
86
97
|
result
|
@@ -11,7 +11,7 @@ module Performance
|
|
11
11
|
DEFAULTS = {
|
12
12
|
:instrumentors => [],
|
13
13
|
:inline => false,
|
14
|
-
:iterations =>
|
14
|
+
:iterations => nil,
|
15
15
|
:reporter_classes => ['ConsoleReporter'],
|
16
16
|
:brief => false,
|
17
17
|
:tags => {},
|
@@ -90,7 +90,8 @@ module Performance
|
|
90
90
|
|
91
91
|
def create_test_case(cls)
|
92
92
|
test_case = cls.new
|
93
|
-
test_case.
|
93
|
+
test_case.target_iterations = @options[:iterations] if @options[:iterations]
|
94
|
+
test_case.target_duration = @options[:duration] if @options[:duration]
|
94
95
|
add_progress_callbacks(test_case) if @options[:progress]
|
95
96
|
add_instrumentor_callbacks(test_case)
|
96
97
|
add_metadata_callbacks(test_case)
|
@@ -139,7 +140,10 @@ module Performance
|
|
139
140
|
test_case_name = test_case.class.name
|
140
141
|
test_identifier = "#{test_case_name}##{method}"
|
141
142
|
runner_script = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'script', 'runner'))
|
142
|
-
cmd = "#{runner_script} -T #{test_identifier} -
|
143
|
+
cmd = "#{runner_script} -T #{test_identifier} -j -q -I"
|
144
|
+
cmd << " -A #{@options[:agent_path]}"
|
145
|
+
cmd << " -N #{@options[:iterations]}" if @options[:iterations]
|
146
|
+
cmd << " -d #{@options[:duration]}" if @options[:duration]
|
143
147
|
output = nil
|
144
148
|
IO.popen(cmd) do |io|
|
145
149
|
output = io.read
|
@@ -4,6 +4,10 @@
|
|
4
4
|
|
5
5
|
module Performance
|
6
6
|
class TestCase
|
7
|
+
DEFAULT_WARMUP_DURATION = 2
|
8
|
+
DEFAULT_DURATION = 5
|
9
|
+
BATCH_TIME = 0.1
|
10
|
+
|
7
11
|
@subclasses = []
|
8
12
|
|
9
13
|
def self.inherited(cls)
|
@@ -14,13 +18,12 @@ module Performance
|
|
14
18
|
@subclasses
|
15
19
|
end
|
16
20
|
|
17
|
-
attr_accessor :
|
21
|
+
attr_accessor :target_iterations, :target_duration
|
18
22
|
|
19
23
|
def initialize
|
20
24
|
@callbacks = {}
|
21
|
-
@
|
22
|
-
|
23
|
-
on(:after_each, &method(:teardown))
|
25
|
+
@target_iterations = nil
|
26
|
+
@target_duration = DEFAULT_DURATION
|
24
27
|
end
|
25
28
|
|
26
29
|
def setup; end
|
@@ -56,29 +59,94 @@ module Performance
|
|
56
59
|
results
|
57
60
|
end
|
58
61
|
|
59
|
-
def with_callbacks(name)
|
60
|
-
fire(:before_each, self, name)
|
61
|
-
|
62
|
-
fire(:after_each, self, name, result)
|
62
|
+
def with_callbacks(name, warmup=false)
|
63
|
+
fire(:before_each, self, name) unless warmup
|
64
|
+
yield
|
65
|
+
fire(:after_each, self, name, @result) unless warmup
|
66
|
+
end
|
67
|
+
|
68
|
+
# This is used to get a rough approximation of the amount of time required
|
69
|
+
# to call action once. We do this so that we will be able to run the actual
|
70
|
+
# timing loop in chunks of iterations, rather than calling Time.now in
|
71
|
+
# between every iteration.
|
72
|
+
def estimate_time_per_iteration(action, duration)
|
73
|
+
start_time = Time.now
|
74
|
+
deadline = start_time + duration
|
75
|
+
|
76
|
+
iterations = 0
|
77
|
+
while Time.now < deadline
|
78
|
+
action.call
|
79
|
+
iterations += 1
|
80
|
+
end
|
81
|
+
|
82
|
+
(Time.now - start_time) / iterations
|
83
|
+
end
|
84
|
+
|
85
|
+
def estimate_iterations_per_unit_time(time_per_iteration, desired_duration)
|
86
|
+
(desired_duration / time_per_iteration).ceil
|
87
|
+
end
|
88
|
+
|
89
|
+
def batch_size_in_iterations(blk)
|
90
|
+
approx_time_per_iteration = nil
|
91
|
+
approx_time_per_iteration = estimate_time_per_iteration(blk, DEFAULT_WARMUP_DURATION)
|
92
|
+
estimate_iterations_per_unit_time(approx_time_per_iteration, BATCH_TIME)
|
93
|
+
end
|
94
|
+
|
95
|
+
def run_block_in_batches(blk, duration, batch_size)
|
96
|
+
deadline = Time.now + duration
|
97
|
+
total_iterations = 0
|
98
|
+
while Time.now < deadline
|
99
|
+
batch_iterations = 0
|
100
|
+
while batch_iterations < batch_size
|
101
|
+
blk.call
|
102
|
+
batch_iterations += 1
|
103
|
+
end
|
104
|
+
total_iterations += batch_iterations
|
105
|
+
end
|
106
|
+
total_iterations
|
107
|
+
end
|
108
|
+
|
109
|
+
def run_block_n_times(blk, n)
|
110
|
+
iterations = 0
|
111
|
+
while iterations < n
|
112
|
+
blk.call
|
113
|
+
iterations += 1
|
114
|
+
end
|
115
|
+
iterations
|
116
|
+
end
|
117
|
+
|
118
|
+
def measure(&blk)
|
119
|
+
total_iterations = 0
|
120
|
+
start_time = nil
|
121
|
+
elapsed = nil
|
122
|
+
|
123
|
+
batch_size = batch_size_in_iterations(blk) unless target_iterations
|
124
|
+
|
125
|
+
with_callbacks(@result.test_name, false) do
|
126
|
+
start_time = Time.now
|
127
|
+
if target_iterations
|
128
|
+
total_iterations = run_block_n_times(blk, target_iterations)
|
129
|
+
else
|
130
|
+
total_iterations = run_block_in_batches(blk, target_duration, batch_size)
|
131
|
+
end
|
132
|
+
elapsed = Time.now - start_time
|
133
|
+
end
|
134
|
+
|
135
|
+
@result.iterations = total_iterations
|
136
|
+
@result.timer.start_timestamp = start_time
|
137
|
+
@result.timer.elapsed = elapsed
|
63
138
|
end
|
64
139
|
|
65
140
|
def run(name)
|
66
|
-
result = Result.new(self.class, name)
|
141
|
+
@result = Result.new(self.class, name)
|
67
142
|
begin
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
self.send(name)
|
72
|
-
end
|
73
|
-
else
|
74
|
-
self.send(name, result.timer)
|
75
|
-
end
|
76
|
-
result
|
77
|
-
end
|
143
|
+
setup
|
144
|
+
self.send(name)
|
145
|
+
teardown
|
78
146
|
rescue StandardError, LoadError => e
|
79
|
-
result.exception = e
|
147
|
+
@result.exception = e
|
80
148
|
end
|
81
|
-
result
|
149
|
+
@result
|
82
150
|
end
|
83
151
|
end
|
84
152
|
end
|
@@ -30,6 +30,11 @@ parser = OptionParser.new do |opts|
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
+
opts.on("-a", "--profile-alloc", "Do profiling around each test for object allocations") do
|
34
|
+
options[:inline] = true
|
35
|
+
options[:instrumentors] = [Performance::Instrumentation::StackProfAllocationProfile.to_s]
|
36
|
+
end
|
37
|
+
|
33
38
|
opts.on("-l", "--list", "List all available suites and tests") do
|
34
39
|
options[:list] = true
|
35
40
|
end
|
@@ -51,10 +56,17 @@ parser = OptionParser.new do |opts|
|
|
51
56
|
options[:reporter_classes] = ['BaselineCompareReporter']
|
52
57
|
end
|
53
58
|
|
54
|
-
opts.on("-N", "--iterations=NUM",
|
59
|
+
opts.on("-N", "--iterations=NUM",
|
60
|
+
"Set a fixed number of iterations for each test.",
|
61
|
+
"Overrides the -d / --duration option.") do |iterations|
|
55
62
|
options[:iterations] = iterations.to_i
|
56
63
|
end
|
57
64
|
|
65
|
+
opts.on("-d", "--duration=TIME",
|
66
|
+
"Run each test for TIME seconds. Defaults to 5s.") do |duration|
|
67
|
+
options[:duration] = duration.to_f
|
68
|
+
end
|
69
|
+
|
58
70
|
opts.on("-I", "--inline", "Run tests inline - do not isolate each test into a sub-invocation") do |i|
|
59
71
|
options[:inline] = true
|
60
72
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
4
|
+
|
5
|
+
require 'new_relic/agent/instrumentation/active_record_helper'
|
6
|
+
|
7
|
+
class ActiveRecordTest < Performance::TestCase
|
8
|
+
|
9
|
+
ActiveRecordHelper = NewRelic::Agent::Instrumentation::ActiveRecordHelper unless defined?(ActiveRecordHelper)
|
10
|
+
|
11
|
+
def setup
|
12
|
+
if ActiveRecordHelper.respond_to?(:metrics_for)
|
13
|
+
@run = ActiveRecordHelper.method(:metrics_for)
|
14
|
+
else
|
15
|
+
# Mimics what was buried in the instrumentation that we replaced with
|
16
|
+
# calls to metrics_for in the new instrumentation. Can run against SHA
|
17
|
+
# 399d8ed for baselining (3.10 tags won't work since the perf testing
|
18
|
+
# changed on dev post 3.10)
|
19
|
+
@run = proc do |name, sql, adapter, *_|
|
20
|
+
metric = ActiveRecordHelper.metric_for_name(name) ||
|
21
|
+
ActiveRecordHelper.metric_for_sql(sql)
|
22
|
+
remote_service_metric = ActiveRecordHelper.remote_service_metric("host", adapter)
|
23
|
+
|
24
|
+
metrics = [metric, remote_service_metric].compact
|
25
|
+
metrics += ActiveRecordHelper.rollup_metrics_for(metric)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
NAME = "Model Load"
|
31
|
+
SQL = "SELECT * FROM star"
|
32
|
+
ADAPTER = "mysql2"
|
33
|
+
|
34
|
+
def test_helper_by_name
|
35
|
+
measure do
|
36
|
+
@run.call(NAME, SQL, ADAPTER)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
UNKNOWN_NAME = "Blah"
|
41
|
+
|
42
|
+
def test_helper_by_sql
|
43
|
+
measure do
|
44
|
+
@run.call(UNKNOWN_NAME, SQL, ADAPTER)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|