autotuner 1.0.0 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +0 -1
- data/.ruby-version +1 -0
- data/Gemfile.lock +59 -0
- data/README.md +16 -1
- data/lib/autotuner/heuristic/base.rb +1 -3
- data/lib/autotuner/heuristic/gc_compact.rb +13 -3
- data/lib/autotuner/heuristic/heap_size_warmup.rb +1 -3
- data/lib/autotuner/heuristic/malloc.rb +2 -4
- data/lib/autotuner/heuristic/oldmalloc.rb +2 -4
- data/lib/autotuner/heuristic/remembered_wb_unprotected_objects.rb +2 -4
- data/lib/autotuner/heuristics.rb +3 -3
- data/lib/autotuner/request_collector.rb +14 -6
- data/lib/autotuner/version.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6aa488d0dd08183c2fb01c791f8c6348161e5c986ac3a77d2e70b395823330aa
|
4
|
+
data.tar.gz: 205b668f35e3abe8c52bd0cd84438dad052efa9d26432ec86b19170f0c487e3c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5bc44e43c8851f850dfc542b9004ebdcb3f446036d0064947006815867bb9a4ad9502d2db0dd41fcfdebd68bf100d359a1537ed81b9e5147d936e0219a1fa8c5
|
7
|
+
data.tar.gz: 706cc7f127c5004e6dc8473531b5a305809e6eab762481b3f0bbf48571668bd807d2388e4d2a621d63bdb1e0ca5972848b61175707a3b01b13888bb0bee885ba
|
data/.rubocop.yml
CHANGED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.3.0
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
autotuner (1.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
ast (2.4.2)
|
10
|
+
json (2.7.1)
|
11
|
+
language_server-protocol (3.17.0.3)
|
12
|
+
minitest (5.22.3)
|
13
|
+
mocha (2.1.0)
|
14
|
+
ruby2_keywords (>= 0.0.5)
|
15
|
+
parallel (1.24.0)
|
16
|
+
parser (3.3.0.5)
|
17
|
+
ast (~> 2.4.1)
|
18
|
+
racc
|
19
|
+
racc (1.7.3)
|
20
|
+
rainbow (3.1.1)
|
21
|
+
rake (13.1.0)
|
22
|
+
regexp_parser (2.9.0)
|
23
|
+
rexml (3.2.6)
|
24
|
+
rubocop (1.62.1)
|
25
|
+
json (~> 2.3)
|
26
|
+
language_server-protocol (>= 3.17.0)
|
27
|
+
parallel (~> 1.10)
|
28
|
+
parser (>= 3.3.0.2)
|
29
|
+
rainbow (>= 2.2.2, < 4.0)
|
30
|
+
regexp_parser (>= 1.8, < 3.0)
|
31
|
+
rexml (>= 3.2.5, < 4.0)
|
32
|
+
rubocop-ast (>= 1.31.1, < 2.0)
|
33
|
+
ruby-progressbar (~> 1.7)
|
34
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
35
|
+
rubocop-ast (1.31.2)
|
36
|
+
parser (>= 3.3.0.4)
|
37
|
+
rubocop-minitest (0.35.0)
|
38
|
+
rubocop (>= 1.61, < 2.0)
|
39
|
+
rubocop-ast (>= 1.31.1, < 2.0)
|
40
|
+
rubocop-shopify (2.15.1)
|
41
|
+
rubocop (~> 1.51)
|
42
|
+
ruby-progressbar (1.13.0)
|
43
|
+
ruby2_keywords (0.0.5)
|
44
|
+
unicode-display_width (2.5.0)
|
45
|
+
|
46
|
+
PLATFORMS
|
47
|
+
ruby
|
48
|
+
|
49
|
+
DEPENDENCIES
|
50
|
+
autotuner!
|
51
|
+
minitest (~> 5.0)
|
52
|
+
mocha
|
53
|
+
rake (~> 13.0)
|
54
|
+
rubocop (~> 1.21)
|
55
|
+
rubocop-minitest
|
56
|
+
rubocop-shopify
|
57
|
+
|
58
|
+
BUNDLED WITH
|
59
|
+
2.4.10
|
data/README.md
CHANGED
@@ -32,6 +32,9 @@ $ bundle add autotuner
|
|
32
32
|
# This (optional) callback is called to provide metrics that can give you
|
33
33
|
# insights about the performance of your app. It's recommended to send this
|
34
34
|
# data to your observability service (e.g. Datadog, Prometheus, New Relic, etc).
|
35
|
+
# Use a metric type that would allow you to calculate the average and percentiles.
|
36
|
+
# On Datadog this would be the distribution type. On Prometheus this would be
|
37
|
+
# the histogram type.
|
35
38
|
Autotuner.metrics_reporter = proc do |metrics|
|
36
39
|
# stats is a hash of metric name (string) to integer value.
|
37
40
|
metrics.each do |key, val|
|
@@ -61,11 +64,23 @@ While autotuner aims to comprehensively analyze your traffic to give the suggest
|
|
61
64
|
## Configuration
|
62
65
|
|
63
66
|
- `Autotuner.enabled=`: (required, unless `Autotuner.sample_ratio` is set) Sets whether autotuner is enabled or not. When autotuner is disabled, data is not collected and suggestions are not given. Defaults to `false`.
|
64
|
-
- `Autotuner.sample_ratio=`: (optional) Sets the portion of instances where autotuner is enabled. Pass a value between 0 (enabled on no
|
67
|
+
- `Autotuner.sample_ratio=`: (optional) Sets the portion of instances where autotuner is enabled. Pass a value between 0 (enabled on no instances) and 1.0 (enabled on all instances). Note that this does not sample requests, but rather samples the portion of instances that have autotuner enabled (it will be enabled for all requests on those instances). Do not configure `Autotuner.enabled=` when you use this option.
|
65
68
|
- `Autotuner.reporter=`: (required) Callback called when a heuristic is ready to give a suggestion. The callback will be called with one argument which will be an instance of `Autotuner::Report::Base`. Call `#to_s` on this object to get a string containing instructions and recommendations. You must set this when autotuner is enabled.
|
66
69
|
- `Autotuner.debug_reporter=`: (optional) Callback to periodically emit debug messages of internal state of heuristics. The callback will be called with one argument which will be a hash with the heuristic name as the key and the debug message as the value. Regular users do not need to configure this as this is only useful for debugging purposes.
|
67
70
|
- `Autotuner.metrics_reporter=`: (optional) Callback to emit useful metrics about your service. The callback will be called with a hash containing the metric names (string) as the key and integer values.
|
68
71
|
|
72
|
+
## Emitted Metrics
|
73
|
+
|
74
|
+
The following metrics are passed to the `metrics_reporter` callback after each request.
|
75
|
+
|
76
|
+
| Name | Description |
|
77
|
+
| --------------------- | ----------- |
|
78
|
+
| `diff.time` | Time spent doing garbage collection during the request. Produced by [GC::stat](https://docs.ruby-lang.org/en/master/GC.html#method-c-stat) |
|
79
|
+
| `diff.minor_gc_count` | Number of minor garbage collections that occurred during the request. Produced by [GC::stat](https://docs.ruby-lang.org/en/master/GC.html#method-c-stat) |
|
80
|
+
| `diff.major_gc_count` | Number of major garbage collections that occurred during the request. Produced by [GC::stat](https://docs.ruby-lang.org/en/master/GC.html#method-c-stat) |
|
81
|
+
| `heap_pages` | Number of heap pages in use after the request. Produced by [GC::stat](https://docs.ruby-lang.org/en/master/GC.html#method-c-stat) |
|
82
|
+
| `request_time` | Total duration of the request. |
|
83
|
+
|
69
84
|
## Contributing
|
70
85
|
|
71
86
|
Bug reports and pull requests are welcome on GitHub at https://github.com/Shopify/autotuner.
|
@@ -4,8 +4,6 @@ module Autotuner
|
|
4
4
|
module Heuristic
|
5
5
|
class GCCompact < Base
|
6
6
|
class << self
|
7
|
-
private
|
8
|
-
|
9
7
|
def supported?
|
10
8
|
true
|
11
9
|
end
|
@@ -41,12 +39,24 @@ module Autotuner
|
|
41
39
|
3.times { GC.start }
|
42
40
|
GC.compact
|
43
41
|
|
44
|
-
For example,
|
42
|
+
For example, with Puma, which runs its before fork hook once on boot (before the initial fork), add the following code into config/puma.rb:
|
45
43
|
|
46
44
|
before_fork do
|
47
45
|
3.times { GC.start }
|
48
46
|
GC.compact
|
49
47
|
end
|
48
|
+
|
49
|
+
With Unicorn, which runs its before fork hook before each fork, add the following code into config/unicorn.rb:
|
50
|
+
|
51
|
+
compacted = false
|
52
|
+
before_fork do
|
53
|
+
# avoid invalidating heap pages shared with previously forked children
|
54
|
+
unless compacted
|
55
|
+
3.times { GC.start }
|
56
|
+
GC.compact
|
57
|
+
compacted = true
|
58
|
+
end
|
59
|
+
end
|
50
60
|
MSG
|
51
61
|
end
|
52
62
|
|
@@ -4,8 +4,6 @@ module Autotuner
|
|
4
4
|
module Heuristic
|
5
5
|
class HeapSizeWarmup < Base
|
6
6
|
class << self
|
7
|
-
private
|
8
|
-
|
9
7
|
def supported?
|
10
8
|
# Ruby 3.2 uses multiple heaps but does not support the
|
11
9
|
# RUBY_GC_HEAP_%d_INIT_SLOTS environment variables, so we cannot
|
@@ -28,7 +26,7 @@ module Autotuner
|
|
28
26
|
HEAP_SIZE_CONFIGURATION_DELTA = 1_000
|
29
27
|
|
30
28
|
REPORT_ASSIST_MESSAGE = <<~MSG
|
31
|
-
The following suggestions
|
29
|
+
The following suggestions adjust the size of the heap at boot time, which can improve bootup speed and reduce the time taken for the app to reach peak performance.
|
32
30
|
MSG
|
33
31
|
|
34
32
|
def initialize(_system_context)
|
@@ -4,8 +4,6 @@ module Autotuner
|
|
4
4
|
module Heuristic
|
5
5
|
class Malloc < Base
|
6
6
|
class << self
|
7
|
-
private
|
8
|
-
|
9
7
|
def supported?
|
10
8
|
true
|
11
9
|
end
|
@@ -68,9 +66,9 @@ module Autotuner
|
|
68
66
|
|
69
67
|
Report::MultipleEnvironmentVariables.new(
|
70
68
|
<<~MSG,
|
71
|
-
The following suggestions
|
69
|
+
The following suggestions reduce the number of minor garbage collection cycles, specifically a cycle called "malloc". Your app runs malloc cycles in approximately #{format("%.2f", malloc_gc_ratio * 100)}% of all minor garbage collection cycles.
|
72
70
|
|
73
|
-
Reducing minor garbage collection cycles can help reduce response times. The following tuning values
|
71
|
+
Reducing minor garbage collection cycles can help reduce response times. The following tuning values aim to reduce malloc garbage collection cycles by setting it to a higher value. This may cause a slight increase in memory usage. You should monitor memory usage carefully to ensure your app is not running out of memory.
|
74
72
|
MSG
|
75
73
|
[LIMIT_ENV, LIMIT_MAX_ENV],
|
76
74
|
# Suggest to double the limit and max
|
@@ -4,8 +4,6 @@ module Autotuner
|
|
4
4
|
module Heuristic
|
5
5
|
class Oldmalloc < Base
|
6
6
|
class << self
|
7
|
-
private
|
8
|
-
|
9
7
|
def supported?
|
10
8
|
true
|
11
9
|
end
|
@@ -67,9 +65,9 @@ module Autotuner
|
|
67
65
|
|
68
66
|
Report::MultipleEnvironmentVariables.new(
|
69
67
|
<<~MSG,
|
70
|
-
The following suggestions
|
68
|
+
The following suggestions reduce the number of major garbage collection cycles, specifically a cycle called "oldmalloc". Your app runs oldmalloc cycles in approximately #{format("%.2f", oldmalloc_gc_ratio * 100)}% of all major garbage collection cycles.
|
71
69
|
|
72
|
-
Reducing major garbage collection cycles can help reduce response times, especially for the extremes (e.g. p95 or p99 response times). The following tuning values
|
70
|
+
Reducing major garbage collection cycles can help reduce response times, especially for the extremes (e.g. p95 or p99 response times). The following tuning values aim to disable oldmalloc garbage collection cycles by setting it to an extremely high value. This may cause a slight increase in memory usage. You should monitor memory usage carefully to ensure your app is not running out of memory.
|
73
71
|
MSG
|
74
72
|
[LIMIT_ENV, LIMIT_MAX_ENV],
|
75
73
|
[LIMIT_ENV_SUGGESTED_VALUE, LIMIT_MAX_SUGGESTED_VALUE],
|
@@ -4,8 +4,6 @@ module Autotuner
|
|
4
4
|
module Heuristic
|
5
5
|
class RememberedWBUnprotectedObjects < Base
|
6
6
|
class << self
|
7
|
-
private
|
8
|
-
|
9
7
|
def supported?
|
10
8
|
# Ruby 3.3.0 and later have support RUBY_GC_HEAP_REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO
|
11
9
|
RUBY_VERSION >= "3.3.0"
|
@@ -65,9 +63,9 @@ module Autotuner
|
|
65
63
|
|
66
64
|
Report::SingleEnvironmentVariable.new(
|
67
65
|
<<~MSG,
|
68
|
-
The following suggestions
|
66
|
+
The following suggestions reduce the number of major garbage collection cycles, specifically a cycle called "remembered write barrier unprotected" (also know as "shady" due to historical reasons). Your app runs remembered write barrier unprotected cycles in approximately #{format("%.2f", wb_unprotected_gc_ratio * 100)}% of all major garbage collection cycles.
|
69
67
|
|
70
|
-
Reducing major garbage collection cycles can help reduce response times, especially for the extremes (e.g. p95 or p99 response times). The following tuning values
|
68
|
+
Reducing major garbage collection cycles can help reduce response times, especially for the extremes (e.g. p95 or p99 response times). The following tuning values aim to disable oldmalloc garbage collection cycles by setting it to an extremely high value. This may cause a slight increase in memory usage. You should monitor memory usage carefully to ensure your app is not running out of memory.
|
71
69
|
MSG
|
72
70
|
LIMIT_RATIO_ENV,
|
73
71
|
suggested_limit_ratio,
|
data/lib/autotuner/heuristics.rb
CHANGED
@@ -3,10 +3,10 @@
|
|
3
3
|
module Autotuner
|
4
4
|
module Heuristics
|
5
5
|
HEURISTICS = Heuristic::Base.subclasses.freeze
|
6
|
-
|
6
|
+
SUPPORTED_HEURISTICS = HEURISTICS.dup.keep_if(&:supported?).freeze
|
7
7
|
|
8
|
-
def
|
9
|
-
|
8
|
+
def supported_heuristics
|
9
|
+
SUPPORTED_HEURISTICS
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
@@ -5,8 +5,6 @@ module Autotuner
|
|
5
5
|
HEURISTICS_POLLING_FREQUENCY = 100
|
6
6
|
DEBUG_EMIT_FREQUENCY = 1000
|
7
7
|
|
8
|
-
attr_reader :heuristics
|
9
|
-
|
10
8
|
def initialize
|
11
9
|
@request_count = 0
|
12
10
|
|
@@ -14,7 +12,7 @@ module Autotuner
|
|
14
12
|
|
15
13
|
@system_context = SystemContext.new
|
16
14
|
|
17
|
-
@heuristics = Autotuner.
|
15
|
+
@heuristics = Autotuner.supported_heuristics.map { |h| h.new(@system_context) }
|
18
16
|
end
|
19
17
|
|
20
18
|
def request
|
@@ -27,6 +25,16 @@ module Autotuner
|
|
27
25
|
|
28
26
|
private
|
29
27
|
|
28
|
+
def enabled_heuristics
|
29
|
+
Enumerator.new do |y|
|
30
|
+
@heuristics.each do |heuristic|
|
31
|
+
next unless heuristic.class.enabled?
|
32
|
+
|
33
|
+
y << heuristic
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
30
38
|
def before_request
|
31
39
|
@request_context.before_request
|
32
40
|
|
@@ -38,7 +46,7 @@ module Autotuner
|
|
38
46
|
|
39
47
|
@system_context.update(@request_context)
|
40
48
|
|
41
|
-
|
49
|
+
enabled_heuristics.each do |heuristic|
|
42
50
|
heuristic.call(@request_context)
|
43
51
|
end
|
44
52
|
|
@@ -48,7 +56,7 @@ module Autotuner
|
|
48
56
|
end
|
49
57
|
|
50
58
|
def emit_heuristic_reports
|
51
|
-
|
59
|
+
enabled_heuristics.each do |heuristic|
|
52
60
|
report = heuristic.tuning_report
|
53
61
|
|
54
62
|
next unless report
|
@@ -68,7 +76,7 @@ module Autotuner
|
|
68
76
|
system_context: @system_context.debug_state,
|
69
77
|
}
|
70
78
|
|
71
|
-
|
79
|
+
enabled_heuristics.each do |h|
|
72
80
|
debug_states[h.name] = h.debug_state
|
73
81
|
end
|
74
82
|
|
data/lib/autotuner/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: autotuner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Zhu
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-05-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mocha
|
@@ -60,7 +60,9 @@ extensions: []
|
|
60
60
|
extra_rdoc_files: []
|
61
61
|
files:
|
62
62
|
- ".rubocop.yml"
|
63
|
+
- ".ruby-version"
|
63
64
|
- Gemfile
|
65
|
+
- Gemfile.lock
|
64
66
|
- LICENSE.txt
|
65
67
|
- README.md
|
66
68
|
- Rakefile
|
@@ -98,14 +100,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
98
100
|
requirements:
|
99
101
|
- - ">="
|
100
102
|
- !ruby/object:Gem::Version
|
101
|
-
version:
|
103
|
+
version: 3.1.0
|
102
104
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
105
|
requirements:
|
104
106
|
- - ">="
|
105
107
|
- !ruby/object:Gem::Version
|
106
108
|
version: '0'
|
107
109
|
requirements: []
|
108
|
-
rubygems_version: 3.
|
110
|
+
rubygems_version: 3.5.3
|
109
111
|
signing_key:
|
110
112
|
specification_version: 4
|
111
113
|
summary: Get suggestions to tune Ruby's garbage collector
|