tunemygc 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,156 @@
1
+ #include "tunemygc_ext.h"
2
+
3
+ VALUE rb_mTunemygc;
4
+ static ID id_tunemygc_tracepoint;
5
+ static ID id_tunemygc_raw_snapshot;
6
+
7
+ static VALUE sym_gc_cycle_started;
8
+ static VALUE sym_gc_cycle_ended;
9
+
10
+ /* For 2.2.x incremental GC */
11
+ #ifdef RUBY_INTERNAL_EVENT_GC_ENTER
12
+ static VALUE sym_gc_cycle_entered;
13
+ static VALUE sym_gc_cycle_exited;
14
+ #endif
15
+
16
+ /* From @tmm1/gctools */
17
+ static double _tunemygc_walltime()
18
+ {
19
+ struct timespec ts;
20
+ #ifdef HAVE_CLOCK_GETTIME
21
+ if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
22
+ rb_sys_fail("clock_gettime");
23
+ }
24
+ #else
25
+ {
26
+ struct timeval tv;
27
+ if (gettimeofday(&tv, 0) < 0) {
28
+ rb_sys_fail("gettimeofday");
29
+ }
30
+ ts.tv_sec = tv.tv_sec;
31
+ ts.tv_nsec = tv.tv_usec * 1000;
32
+ }
33
+ #endif
34
+ return ts.tv_sec + ts.tv_nsec * 1e-9;
35
+ }
36
+
37
+ static VALUE tunemygc_walltime(VALUE mod)
38
+ {
39
+ return DBL2NUM(_tunemygc_walltime());
40
+ }
41
+
42
+ /* Postponed job callback that fires when the VM is in a consistent state again (sometime
43
+ * after the GC cycle, notably RUBY_INTERNAL_EVENT_GC_END_SWEEP)
44
+ */
45
+ static void tunemygc_invoke_gc_snapshot(void *data)
46
+ {
47
+ tunemygc_stat_record *stat = (tunemygc_stat_record *)data;
48
+ VALUE snapshot = tunemygc_get_stat_record(stat);
49
+ rb_funcall(rb_mTunemygc, id_tunemygc_raw_snapshot, 1, snapshot);
50
+ free(stat);
51
+ }
52
+
53
+ /* GC tracepoint hook. Snapshots GC state using new low level helpers which are safe
54
+ * to call from within tracepoint handlers as they don't allocate and change the heap state
55
+ */
56
+ static void tunemygc_gc_hook_i(VALUE tpval, void *data)
57
+ {
58
+ rb_trace_arg_t *tparg = rb_tracearg_from_tracepoint(tpval);
59
+ rb_event_flag_t flag = rb_tracearg_event_flag(tparg);
60
+
61
+ tunemygc_stat_record *stat = ((tunemygc_stat_record*)malloc(sizeof(tunemygc_stat_record)));
62
+ stat->ts = _tunemygc_walltime();
63
+ stat->peak_rss = getPeakRSS();
64
+ stat->current_rss = getCurrentRSS();
65
+
66
+ switch (flag) {
67
+ case RUBY_INTERNAL_EVENT_GC_START:
68
+ stat->stage = sym_gc_cycle_started;
69
+ break;
70
+ case RUBY_INTERNAL_EVENT_GC_END_SWEEP:
71
+ stat->stage = sym_gc_cycle_ended;
72
+ break;
73
+ #ifdef RUBY_INTERNAL_EVENT_GC_ENTER
74
+ case RUBY_INTERNAL_EVENT_GC_ENTER:
75
+ stat->stage = sym_gc_cycle_entered;
76
+ break;
77
+ case RUBY_INTERNAL_EVENT_GC_EXIT:
78
+ stat->stage = sym_gc_cycle_exited;
79
+ break;
80
+ #endif
81
+ }
82
+
83
+ tunemygc_set_stat_record(stat);
84
+ rb_postponed_job_register(0, tunemygc_invoke_gc_snapshot, (void *)stat);
85
+ }
86
+
87
+ /* Installs the GC tracepoint and declare interest only in start of the cycle and end of sweep
88
+ * events
89
+ */
90
+ static VALUE tunemygc_install_gc_tracepoint(VALUE mod)
91
+ {
92
+ rb_event_flag_t events;
93
+ VALUE tunemygc_tracepoint = rb_ivar_get(rb_mTunemygc, id_tunemygc_tracepoint);
94
+ if (!NIL_P(tunemygc_tracepoint)) {
95
+ rb_tracepoint_disable(tunemygc_tracepoint);
96
+ rb_ivar_set(rb_mTunemygc, id_tunemygc_tracepoint, Qnil);
97
+ }
98
+ events = RUBY_INTERNAL_EVENT_GC_START | RUBY_INTERNAL_EVENT_GC_END_SWEEP;
99
+ tunemygc_tracepoint = rb_tracepoint_new(0, events, tunemygc_gc_hook_i, (void *)0);
100
+ if (NIL_P(tunemygc_tracepoint)) rb_warn("Could not install GC tracepoint!");
101
+ rb_tracepoint_enable(tunemygc_tracepoint);
102
+ rb_ivar_set(rb_mTunemygc, id_tunemygc_tracepoint, tunemygc_tracepoint);
103
+ return Qnil;
104
+ }
105
+
106
+ /* Removes a previously enabled GC tracepoint */
107
+ static VALUE tunemygc_uninstall_gc_tracepoint(VALUE mod)
108
+ {
109
+ VALUE tunemygc_tracepoint = rb_ivar_get(rb_mTunemygc, id_tunemygc_tracepoint);
110
+ if (!NIL_P(tunemygc_tracepoint)) {
111
+ rb_tracepoint_disable(tunemygc_tracepoint);
112
+ rb_ivar_set(rb_mTunemygc, id_tunemygc_tracepoint, Qnil);
113
+ }
114
+ return Qnil;
115
+ }
116
+
117
+ static VALUE tunemygc_peak_rss(VALUE mod)
118
+ {
119
+ return SIZET2NUM(getPeakRSS());
120
+ }
121
+
122
+ static VALUE tunemygc_current_rss(VALUE mod)
123
+ {
124
+ return SIZET2NUM(getCurrentRSS());
125
+ }
126
+
127
+ void Init_tunemygc_ext()
128
+ {
129
+ /* Warm up the symbol table */
130
+ id_tunemygc_tracepoint = rb_intern("__tunemygc_tracepoint");
131
+ id_tunemygc_raw_snapshot = rb_intern("raw_snapshot");
132
+ rb_funcall(rb_mGC, rb_intern("stat"), 0);
133
+ rb_funcall(rb_mGC, rb_intern("latest_gc_info"), 0);
134
+
135
+ /* Symbol warmup */
136
+ sym_gc_cycle_started = ID2SYM(rb_intern("GC_CYCLE_STARTED"));
137
+ sym_gc_cycle_ended = ID2SYM(rb_intern("GC_CYCLE_ENDED"));
138
+
139
+ /* For 2.2.x incremental GC */
140
+ #ifdef RUBY_INTERNAL_EVENT_GC_ENTER
141
+ sym_gc_cycle_entered = ID2SYM(rb_intern("GC_CYCLE_ENTERED"));
142
+ sym_gc_cycle_exited = ID2SYM(rb_intern("GC_CYCLE_EXITED"));
143
+ #endif
144
+
145
+ tunemygc_setup_trace_symbols();
146
+
147
+ rb_mTunemygc = rb_define_module("TuneMyGc");
148
+ rb_ivar_set(rb_mTunemygc, id_tunemygc_tracepoint, Qnil);
149
+
150
+ rb_define_module_function(rb_mTunemygc, "install_gc_tracepoint", tunemygc_install_gc_tracepoint, 0);
151
+ rb_define_module_function(rb_mTunemygc, "uninstall_gc_tracepoint", tunemygc_uninstall_gc_tracepoint, 0);
152
+
153
+ rb_define_module_function(rb_mTunemygc, "walltime", tunemygc_walltime, 0);
154
+ rb_define_module_function(rb_mTunemygc, "peak_rss", tunemygc_peak_rss, 0);
155
+ rb_define_module_function(rb_mTunemygc, "current_rss", tunemygc_current_rss, 0);
156
+ }
@@ -0,0 +1,21 @@
1
+ #ifndef TUNEMYGC_EXT_H
2
+ #define TUNEMYGC_EXT_H
3
+
4
+ #include "ruby/ruby.h"
5
+ #include "ruby/debug.h"
6
+
7
+ extern VALUE rb_mTunemygc;
8
+
9
+ #include <stddef.h>
10
+ /* for walltime */
11
+ #include <time.h>
12
+ #include <sys/time.h>
13
+
14
+ /* header we codegen'ed in extconf.rb from VM specific GC stats */
15
+ #include "tunemygc_env.h"
16
+
17
+ /* From getRSS.c */
18
+ size_t getPeakRSS();
19
+ size_t getCurrentRSS();
20
+
21
+ #endif
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+
3
+ require "tunemygc/tunemygc_ext"
4
+ require "tunemygc/interposer"
5
+ require "tunemygc/snapshotter"
6
+ require "logger"
7
+
8
+ module TuneMyGc
9
+ MUTEX = Mutex.new
10
+
11
+ attr_accessor :logger, :interposer, :snapshotter
12
+
13
+ def snapshot(stage, timestamp = nil, meta = nil)
14
+ snapshotter.take(stage, timestamp, meta)
15
+ end
16
+
17
+ def raw_snapshot(snapshot)
18
+ snapshotter.take_raw(snapshot)
19
+ end
20
+
21
+ def log(message)
22
+ logger.info "[TuneMyGC] #{message}"
23
+ end
24
+
25
+ def reccommendations
26
+ MUTEX.synchronize do
27
+ require "tunemygc/syncer"
28
+ syncer = TuneMyGc::Syncer.new
29
+ config = syncer.sync(snapshotter)
30
+ require "tunemygc/configurator"
31
+ TuneMyGc::Configurator.new(config).configure
32
+ end
33
+ rescue Exception => e
34
+ log "Config reccommendation error (#{e.message})"
35
+ end
36
+
37
+ extend self
38
+
39
+ MUTEX.synchronize do
40
+ self.logger = Logger.new($stdout)
41
+ self.interposer = TuneMyGc::Interposer.new
42
+ self.snapshotter = TuneMyGc::Snapshotter.new
43
+ end
44
+ end
@@ -0,0 +1,86 @@
1
+ # encoding: utf-8
2
+
3
+ require 'net/http'
4
+ require 'certified'
5
+ require 'timeout'
6
+ require 'optparse'
7
+
8
+ module TuneMyGc
9
+ class CLI
10
+ TIMEOUT = 10
11
+
12
+ attr_reader :uri, :client, :options
13
+
14
+ def self.start(args)
15
+ args = ["-h"] if args.empty?
16
+ options = {}
17
+ OptionParser.new do |opts|
18
+ opts.banner = "Usage: tunemygc [options]"
19
+
20
+ opts.on("-r ", "--register EMAIL", "Register this Rails app with the https://tunemygc.com service") do |email|
21
+ options[:email] = email
22
+ end
23
+ opts.on("-c ", "--config TOKEN", "Fetch the last known config for a given Rails app") do |token|
24
+ options[:config] = token
25
+ end
26
+ opts.on_tail("-h", "--help", "How to use the TuneMyGC agent CLI") do
27
+ puts opts
28
+ exit
29
+ end
30
+ end.parse!(args)
31
+ new(options)
32
+ end
33
+
34
+ def initialize(options)
35
+ @options = options
36
+ @uri = URI("http://#{TuneMyGc::HOST}")
37
+ @client = Net::HTTP.new(@uri.host, @uri.port)
38
+ @client.use_ssl = (uri.port == 443)
39
+ @client.read_timeout = TIMEOUT
40
+ register if options[:email]
41
+ fetch_config if options[:config]
42
+ end
43
+
44
+ def register
45
+ timeout do
46
+ registration = Net::HTTP::Post.new('/accounts')
47
+ registration.set_form_data(:email => options[:email])
48
+ response = client.request(registration)
49
+ if Net::HTTPUnprocessableEntity === response
50
+ puts "Registration error: #{response.body}"
51
+ elsif Net::HTTPSuccess === response
52
+ puts "Application registered. Use RUBY_GC_TOKEN=#{response.body} in your environment."
53
+ else
54
+ puts "Registration error: #{response.body}"
55
+ end
56
+ end
57
+ rescue Exception => e
58
+ puts "Registration error: #{e.inspect}"
59
+ end
60
+
61
+ def fetch_config
62
+ timeout do
63
+ config = Net::HTTP::Get.new("/apps/#{options[:config]}")
64
+ response = client.request(config)
65
+ if Net::HTTPNoContent === response
66
+ puts "There is no configuration for Rails app with token #{options[:config]} yet"
67
+ elsif Net::HTTPNotFound === response
68
+ puts "Rails app with token #{options[:config]} doesn't exist"
69
+ elsif Net::HTTPSuccess === response
70
+ puts "=== Suggested GC configuration:"
71
+ puts
72
+ puts response.body
73
+ else
74
+ puts "Config retrieval error: #{response.body}"
75
+ end
76
+ end
77
+ rescue Exception => e
78
+ puts "Config retrieval error: #{e.inspect}"
79
+ end
80
+
81
+ private
82
+ def timeout(&block)
83
+ Timeout.timeout(TIMEOUT + 1){ block.call }
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+
3
+ module TuneMyGc
4
+ class Configurator
5
+ attr_reader :config
6
+
7
+ def initialize(config)
8
+ @config = config
9
+ end
10
+
11
+ def configure
12
+ if Hash === config && !config.empty?
13
+ TuneMyGc.log "==== Recommended GC configs from #{config.delete("callback")}"
14
+ write_env("Speed")
15
+ end
16
+ end
17
+
18
+ private
19
+ def write_env(strategy)
20
+ config.delete(strategy).each do |var,val|
21
+ TuneMyGc.log "export #{var}=#{val}"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+
3
+ require 'active_support'
4
+ require 'tunemygc/spies/action_controller'
5
+
6
+ module TuneMyGc
7
+ class Interposer
8
+ attr_reader :spy
9
+ attr_accessor :installed
10
+
11
+ def initialize
12
+ reset
13
+ end
14
+
15
+ def on_initialized
16
+ GC.start(full_mark: true, :immediate_sweep => true)
17
+ TuneMyGc.install_gc_tracepoint
18
+ TuneMyGc.log "hooked: GC tracepoints"
19
+ TuneMyGc.snapshot(:BOOTED)
20
+
21
+ TuneMyGc.interposer.spy.install
22
+ end
23
+
24
+ def install
25
+ return if @installed
26
+ TuneMyGc.log "interposing"
27
+ ActiveSupport.on_load(:after_initialize) do
28
+ TuneMyGc.interposer.on_initialized
29
+ end
30
+ TuneMyGc.log "hooked: after_initialize"
31
+
32
+ at_exit do
33
+ if @installed
34
+ TuneMyGc.log "at_exit"
35
+ @spy.uninstall
36
+ TuneMyGc.snapshot(:TERMINATED)
37
+ TuneMyGc.reccommendations
38
+ end
39
+ end
40
+ TuneMyGc.log "hooked: at_exit"
41
+ @installed = true
42
+ TuneMyGc.log "interposed"
43
+ end
44
+
45
+ def check_uninstall
46
+ @spy.check_uninstall
47
+ end
48
+
49
+ def uninstall
50
+ @spy.uninstall
51
+ reset
52
+ end
53
+
54
+ private
55
+ def reset
56
+ @installed = false
57
+ @spy = TuneMyGc::Spies::ActionController.new
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+
3
+ require 'tunemygc/agent'
4
+ require 'rails/railtie'
5
+
6
+ module TuneMyGc
7
+ class Railtie < Rails::Railtie
8
+ initializer 'tunemygc' do
9
+ TuneMyGc.logger = Rails.logger
10
+ TuneMyGc.interposer.install
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ require 'tunemygc/subscriber'
4
+
5
+ module TuneMyGc
6
+ class StartRequestSubscriber < Subscriber
7
+ def start(name, id, payload)
8
+ TuneMyGc.snapshot(:REQUEST_PROCESSING_STARTED)
9
+ end
10
+ end
11
+
12
+ class EndRequestSubscriber < Subscriber
13
+ def finish(name, id, payload)
14
+ TuneMyGc.snapshot(:REQUEST_PROCESSING_ENDED)
15
+ TuneMyGc.interposer.check_uninstall
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ require 'thread'
4
+
5
+ module TuneMyGc
6
+ class Snapshotter
7
+ MAX_SAMPLES = 1000
8
+
9
+ attr_reader :buffer
10
+
11
+ def initialize(buf = Queue.new)
12
+ @buffer = buf
13
+ end
14
+
15
+ def take(stage, timestamp = nil, meta = nil)
16
+ _buffer([(timestamp || TuneMyGc.walltime), TuneMyGc.peak_rss, TuneMyGc.current_rss, stage, GC.stat, GC.latest_gc_info, meta])
17
+ end
18
+
19
+ # low level interface, for tests and GC callback
20
+ def take_raw(snapshot)
21
+ _buffer(snapshot)
22
+ end
23
+
24
+ def clear
25
+ @buffer.clear
26
+ end
27
+
28
+ def size
29
+ @buffer.size
30
+ end
31
+
32
+ def deq
33
+ @buffer.deq
34
+ end
35
+
36
+ def empty?
37
+ @buffer.empty?
38
+ end
39
+
40
+ private
41
+ def _buffer(snapshot)
42
+ if size < MAX_SAMPLES
43
+ @buffer << snapshot
44
+ else
45
+ TuneMyGc.log "Discarding snapshot #{snapshot.inspect} (max samples threshold of #{MAX_SAMPLES} reached)"
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+
3
+ require 'tunemygc/request_subscriber'
4
+
5
+ module TuneMyGc
6
+ module Spies
7
+ class ActionController
8
+ attr_reader :subscriptions
9
+
10
+ def initialize
11
+ @subscriptions = []
12
+ @requests_processed = 0
13
+ @requests_limit = nil
14
+ end
15
+
16
+ def install
17
+ @subscriptions << ActiveSupport::Notifications.subscribe(/^start_processing.action_controller$/, TuneMyGc::StartRequestSubscriber.new)
18
+ TuneMyGc.log "hooked: start_processing.action_controller"
19
+
20
+ @subscriptions << ActiveSupport::Notifications.subscribe(/^process_action.action_controller$/, TuneMyGc::EndRequestSubscriber.new)
21
+ TuneMyGc.log "hooked: process_action.action_controller"
22
+ end
23
+
24
+ def uninstall
25
+ TuneMyGc.uninstall_gc_tracepoint
26
+ TuneMyGc.log "uninstalled GC tracepoint"
27
+ @subscriptions.each{|s| ActiveSupport::Notifications.unsubscribe(s) }
28
+ @subscriptions.clear
29
+ TuneMyGc.log "cleared ActiveSupport subscriptions"
30
+ end
31
+
32
+ def check_uninstall
33
+ if ENV["RUBY_GC_TUNE_REQUESTS"]
34
+ @requests_limit ||= Integer(ENV["RUBY_GC_TUNE_REQUESTS"])
35
+ @requests_processed += 1
36
+ if @requests_processed == @requests_limit
37
+ uninstall
38
+ TuneMyGc.log "kamikaze after #{@requests_processed} of #{@requests_limit} requests"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+
3
+ module TuneMyGc
4
+ class Subscriber
5
+ def start(name, id, payload)
6
+ end
7
+
8
+ def finish(name, id, payload)
9
+ end
10
+
11
+ def publish(name, *args)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,91 @@
1
+ # encoding: utf-8
2
+
3
+ require 'net/http'
4
+ require 'certified'
5
+ require 'timeout'
6
+
7
+ module TuneMyGc
8
+ class Syncer
9
+ TIMEOUT = 10 #seconds
10
+ ENVIRONMENT = [ENV['RUBY_GC_TOKEN'], RUBY_VERSION, Rails.version, ENV.select {|k,v| k =~ /RUBY_GC_/ }, TuneMyGc::VERSION, GC::OPTS, GC::INTERNAL_CONSTANTS].freeze
11
+
12
+ attr_reader :uri, :client
13
+
14
+ def initialize(host = TuneMyGc::HOST)
15
+ @uri = URI("http://#{host}/ruby")
16
+ @client = Net::HTTP.new(@uri.host, @uri.port)
17
+ @client.use_ssl = (uri.port == 443)
18
+ @client.read_timeout = TIMEOUT
19
+ end
20
+
21
+ def sync(snapshotter)
22
+ response = nil
23
+ timeout do
24
+ response = sync_with_tuner(snapshotter)
25
+ end
26
+ timeout do
27
+ process_config_callback(response)
28
+ end if response
29
+ end
30
+
31
+ private
32
+ def timeout(&block)
33
+ Timeout.timeout(TIMEOUT + 1){ block.call }
34
+ end
35
+
36
+ def sync_with_tuner(snapshotter)
37
+ snapshots = 0
38
+ # Fallback to Timeout if Net::HTTP read timeout fails
39
+ snapshots = snapshotter.size
40
+ TuneMyGc.log "Syncing #{snapshots} snapshots"
41
+ payload = [ENVIRONMENT]
42
+ debug = ENV["RUBY_GC_TUNE_DEBUG"]
43
+ TuneMyGc.log "=== Snapshots ===" if debug
44
+ while !snapshotter.empty?
45
+ snapshot = snapshotter.deq
46
+ TuneMyGc.log(snapshot) if debug
47
+ payload << snapshot
48
+ end
49
+ data = ActiveSupport::JSON.encode(payload)
50
+ response = client.post(uri.path, data, TuneMyGc::HEADERS)
51
+ if Net::HTTPNotFound === response
52
+ TuneMyGc.log "Invalid application token. Please generate one with 'bundle exec tunemygc <a_valid_email_address>' and set the RUBY_GC_TOKEN environment variable"
53
+ return false
54
+ elsif Net::HTTPNotImplemented === response
55
+ TuneMyGc.log "Ruby version #{RUBY_VERSION} or Rails version #{Rails.version} not supported. Failed to sync #{snapshots} snapshots"
56
+ return false
57
+ elsif Net::HTTPUpgradeRequired === response
58
+ TuneMyGc.log "Agent version #{response.body} required - please upgrade. Failed to sync #{snapshots} snapshots"
59
+ return false
60
+ elsif Net::HTTPPreconditionFailed === response
61
+ TuneMyGc.log "The GC is already tuned by environment variables (#{response.body}) - we respect that, doing nothing. Failed to sync #{snapshots} snapshots"
62
+ return false
63
+ elsif Net::HTTPBadRequest === response
64
+ TuneMyGc.log "Invalid payload (#{response.body}). Failed to sync #{snapshots} snapshots"
65
+ return false
66
+ elsif Net::HTTPInternalServerError === response
67
+ TuneMyGc.log "An internal error occurred (#{response.body}). Failed to sync #{snapshots} snapshots"
68
+ return false
69
+ elsif Net::HTTPSuccess === response
70
+ response
71
+ else
72
+ TuneMyGc.log "Unknown error: #{response.body}"
73
+ return false
74
+ end
75
+ rescue Exception => e
76
+ TuneMyGc.log "Failed to sync #{snapshots} snapshots (error: #{e})"
77
+ return false
78
+ ensure
79
+ # Prefer to loose data points than accumulate buffers indefinitely on error or other conditions
80
+ snapshotter.clear
81
+ end
82
+
83
+ def process_config_callback(response)
84
+ config = client.get(URI(response.body).path)
85
+ ActiveSupport::JSON.decode(config.body).merge('callback' => response.body)
86
+ rescue Exception => e
87
+ TuneMyGc.log "Failed to process config callback url #{response.body} (error: #{e})"
88
+ return false
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,5 @@
1
+ # encoding: utf-8
2
+
3
+ module TuneMyGc
4
+ VERSION = "1.0.1"
5
+ end
data/lib/tunemygc.rb ADDED
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+
3
+ tunemygc_min_ruby_version = "2.1.0"
4
+
5
+ if RUBY_VERSION >= tunemygc_min_ruby_version
6
+ require "tunemygc/version" unless defined? TuneMyGc::VERSION
7
+
8
+ module TuneMyGc
9
+ HOST = (ENV['RUBY_GC_TUNE_HOST'] || "tunemygc.com:443").freeze
10
+ HEADERS = { "Content-Type" => "application/json",
11
+ "Accept" => "application/json",
12
+ "User-Agent" => "TuneMyGC #{TuneMyGc::VERSION}"}.freeze
13
+ end
14
+
15
+ if ENV["RUBY_GC_TUNE"] && defined?(Rails) && Rails.version >= "4.0"
16
+ require 'tunemygc/railtie'
17
+ else
18
+ puts "[TuneMyGC] not enabled"
19
+ end
20
+ else
21
+ puts "[TuneMyGC] requires a Ruby version #{tunemygc_min_ruby_version} or newer"
22
+ end
data/test/fixtures.rb ADDED
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+
3
+ require 'time'
4
+
5
+ module Fixtures
6
+ STAGE_BOOTED = [1420152606.1162581, "BOOTED", {"count"=>32, "heap_used"=>950, "heap_length"=>1519, "heap_increment"=>569, "heap_live_slot"=>385225, "heap_free_slot"=>2014, "heap_final_slot"=>0, "heap_swept_slot"=>101119, "heap_eden_page_length"=>950, "heap_tomb_page_length"=>0, "total_allocated_object"=>2184137, "total_freed_object"=>1798912, "malloc_increase"=>9665288, "malloc_limit"=>16777216, "minor_gc_count"=>26, "major_gc_count"=>6, "remembered_shady_object"=>5145, "remembered_shady_object_limit"=>6032, "old_object"=>230164, "old_object_limit"=>301030, "oldmalloc_increase"=>11715304, "oldmalloc_limit"=>24159190}, {"major_by"=>nil, "gc_by"=>"newobj", "have_finalizer"=>false, "immediate_sweep"=>false}, nil]
7
+
8
+ CONFIG = {"Memory"=>{"RUBY_GC_HEAP_INIT_SLOTS"=>307562,"RUBY_GC_HEAP_FREE_SLOTS"=>6151,"RUBY_GC_HEAP_GROWTH_FACTOR"=>0.07,"RUBY_GC_HEAP_GROWTH_MAX_SLOTS"=>6151,"RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR"=>0.11,"RUBY_GC_MALLOC_LIMIT"=>2000000,"RUBY_GC_MALLOC_LIMIT_MAX"=>4000000,"RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR"=>0.11,"RUBY_GC_OLDMALLOC_LIMIT"=>2000000,"RUBY_GC_OLDMALLOC_LIMIT_MAX"=>4000000,"RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR"=>0.11},"Speed"=>{"RUBY_GC_HEAP_INIT_SLOTS"=>369074,"RUBY_GC_HEAP_FREE_SLOTS"=>184537,"RUBY_GC_HEAP_GROWTH_FACTOR"=>1.2,"RUBY_GC_HEAP_GROWTH_MAX_SLOTS"=>123024,"RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR"=>2.0,"RUBY_GC_MALLOC_LIMIT"=>64000000,"RUBY_GC_MALLOC_LIMIT_MAX"=>128000000,"RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR"=>1.2,"RUBY_GC_OLDMALLOC_LIMIT"=>64000000,"RUBY_GC_OLDMALLOC_LIMIT_MAX"=>128000000,"RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR"=>1.2}, "callback"=>"https://tunemygc.com/configs/8d07e13cc5a7bba2da3510b9ca5e75f4.json"}
9
+ end