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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2a0cbc0a71a4fe3322d56efe07228bc9e9f7abc0e63f5d6449d86bcc8d7e4475
4
- data.tar.gz: a07a9184f3615a5e4da4a7d66ffae945e5da377e8cb089a0fcd1b40735c3d093
3
+ metadata.gz: 6aa488d0dd08183c2fb01c791f8c6348161e5c986ac3a77d2e70b395823330aa
4
+ data.tar.gz: 205b668f35e3abe8c52bd0cd84438dad052efa9d26432ec86b19170f0c487e3c
5
5
  SHA512:
6
- metadata.gz: de54a820d1e5674b1a0b14d2519a2bd89e28f0d7d11690cf90e83a1ace67c829a2c9f019d4487952a4d2432146a857dce6905e82513273267ba7835beff2fcaa
7
- data.tar.gz: fd56fb285f351006ac7091c24db412a96518d82771beebcbcbd16107d41e0a2a4af382b5ce2a3a719a21fb96aeea20bbd421e429eba568b3cd1d34a39ab58048
6
+ metadata.gz: 5bc44e43c8851f850dfc542b9004ebdcb3f446036d0064947006815867bb9a4ad9502d2db0dd41fcfdebd68bf100d359a1537ed81b9e5147d936e0219a1fa8c5
7
+ data.tar.gz: 706cc7f127c5004e6dc8473531b5a305809e6eab762481b3f0bbf48571668bd807d2388e4d2a621d63bdb1e0ca5972848b61175707a3b01b13888bb0bee885ba
data/.rubocop.yml CHANGED
@@ -6,7 +6,6 @@ require: rubocop-minitest
6
6
  AllCops:
7
7
  NewCops: enable
8
8
  SuggestExtensions: false
9
- TargetRubyVersion: 2.6
10
9
 
11
10
  Minitest/AssertInDelta:
12
11
  Enabled: false
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 intances) and 1.0 (enabled on all instances). Note that this does not sample reqeusts, 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.
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.
@@ -5,15 +5,13 @@ module Autotuner
5
5
  class Base
6
6
  class << self
7
7
  def enabled?
8
- supported? && !@disabled
8
+ !@disabled
9
9
  end
10
10
 
11
11
  def disable!
12
12
  @disabled = true
13
13
  end
14
14
 
15
- private
16
-
17
15
  def supported?
18
16
  raise NotImplementedError
19
17
  end
@@ -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, in Puma, add the following code into config/puma.rb:
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 adjusts the size of heap at boot time, which can improve bootup speed and reduce the time taken for the app to reach peak performance.
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 reduces 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.
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 aims 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.
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 reduces 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.
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 aims 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.
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 reduces 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.
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 aims 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.
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,
@@ -3,10 +3,10 @@
3
3
  module Autotuner
4
4
  module Heuristics
5
5
  HEURISTICS = Heuristic::Base.subclasses.freeze
6
- ENABLED_HEURISTICS = HEURISTICS.dup.keep_if(&:enabled?).freeze
6
+ SUPPORTED_HEURISTICS = HEURISTICS.dup.keep_if(&:supported?).freeze
7
7
 
8
- def enabled_heuristics
9
- ENABLED_HEURISTICS
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.enabled_heuristics.map { |h| h.new(@system_context) }
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
- heuristics.each do |heuristic|
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
- heuristics.each do |heuristic|
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
- heuristics.each do |h|
79
+ enabled_heuristics.each do |h|
72
80
  debug_states[h.name] = h.debug_state
73
81
  end
74
82
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Autotuner
4
- VERSION = "1.0.0"
4
+ VERSION = "1.0.2"
5
5
  end
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.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: 2023-09-28 00:00:00.000000000 Z
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: 2.6.0
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.4.10
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