gc_hacks 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ rdoc
2
+ *.gem
3
+ .bundle
4
+ Gemfile.lock
5
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in gc_hacks.gemspec
4
+ gemspec
data/LICENCSE ADDED
@@ -0,0 +1,23 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2009 {XING AG}[http://www.xing.com/]
4
+ Copyright (c) 2009 {Stefan Kaes}[http://railsexpress.de]
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ THE SOFTWARE.
23
+
data/README.rdoc ADDED
@@ -0,0 +1,54 @@
1
+ = GC Hacks for Ruby
2
+
3
+ A plugin for Rails which allows one to obtain heap dumps from a running rails app for
4
+ example. It should work for mongrel and passenger hosted apps.
5
+
6
+
7
+ == Author
8
+
9
+ Stefan Kaes <skaes@railexpress.de>
10
+
11
+
12
+ == Usage
13
+
14
+ Obtain the processid of a rails process, then invoke one of the following commands:
15
+
16
+ * start_gc_trace pid # turns on gc tracing in the given process
17
+ * stop_gc_trace pid # stop gc tracing
18
+ * dump_heap pid # dump current heap to "#{tmp_dir}/heap.#{Process.pid}.#{@heap_dump_count}.dump"
19
+
20
+
21
+ == Prerequisites
22
+
23
+ You won't have much fun with this code unless you use a patched ruby which supports dumping
24
+ heap information, compiled with GC_DEBUG enabled.
25
+
26
+ I recommend my patched version of ruby 1.8.7, which you can get as follows:
27
+
28
+ git clone git://github.com/skaes/matzruby.git
29
+ cd matzruby
30
+ git checkout ruby187pl202patched
31
+ autoconf
32
+ ./configure --enable-gcdebug --prefix=/usr/local/ruby187pl202
33
+ make
34
+ sudo make install
35
+ sudo make install-doc
36
+
37
+
38
+ == Installation
39
+
40
+ Place it in vendor/plugins, as usual.
41
+
42
+
43
+ == Acknowledgments
44
+
45
+ Development of this plugin was sponsored by Xing (http://www.xing.com)
46
+
47
+
48
+ == TODO
49
+
50
+ * I think this code should be a gem.
51
+ * move railsbench analyze_heap_dump command into the gem.
52
+
53
+
54
+
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake'
5
+ require 'rake/testtask'
6
+ require 'rake/rdoctask'
7
+
8
+ Rake::RDocTask.new do |rdoc|
9
+ rdoc.rdoc_dir = 'rdoc'
10
+ rdoc.title = 'gc_hacks'
11
+ rdoc.options << '--line-numbers' << '--inline-source' << '--quiet'
12
+ rdoc.rdoc_files.include('README*')
13
+ rdoc.rdoc_files.include('lib/**/*.rb')
14
+ end
15
+
16
+ task :default => :rdoc
data/bin/dump_heap ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__)+'/../lib/gc_hacks'
3
+ GCHacks.send_command("HEAPDUMP", ARGV.first.to_i)
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__)+'/../lib/gc_hacks'
3
+ GCHacks.send_command("STARTTRACE", ARGV.first.to_i)
data/bin/stop_gc_trace ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__)+'/../lib/gc_hacks'
3
+ GCHacks.send_command("STOPTRACE", ARGV.first.to_i)
data/gc_hacks.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "gc_hacks/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "gc_hacks"
7
+ s.version = GCHacks::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Stefan Kaes"]
10
+ s.email = ["skaes@railsexpress.de"]
11
+ s.homepage = "https://github.com/skaes/gc_hacks"
12
+ s.summary = %q{GC tracing/Heap dumping support for Rails processes}
13
+ s.description = %q{This gem allows you to send GC related commands to a running Rails process}
14
+
15
+ s.rubyforge_project = "gc_hacks"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
data/init.rb ADDED
@@ -0,0 +1,15 @@
1
+ if defined?(PhusionPassenger)
2
+ class PhusionPassenger::AbstractRequestHandler
3
+ alias_method :original_reset_signal_handlers, :reset_signal_handlers
4
+
5
+ def reset_signal_handlers
6
+ original_reset_signal_handlers
7
+ GCHacks.install_signal_handlers
8
+ end
9
+
10
+ protected :original_reset_signal_handlers, :reset_signal_handlers
11
+ end
12
+
13
+ else
14
+ GCHacks.install_signal_handlers
15
+ end
@@ -0,0 +1,3 @@
1
+ module GCHacks
2
+ VERSION = "0.0.1"
3
+ end
data/lib/gc_hacks.rb ADDED
@@ -0,0 +1,137 @@
1
+ require "fileutils"
2
+
3
+ module GCHacks
4
+
5
+ extend self
6
+
7
+ def logger
8
+ @logger ||=
9
+ if defined?(Rails)
10
+ Rails.logger
11
+ elsif defined?(RAILS_DEFAULT_LOGGER)
12
+ RAILS_DEFAULT_LOGGER
13
+ else
14
+ Logger.new($stdout)
15
+ end
16
+ end
17
+
18
+ def root
19
+ @root ||=
20
+ if defined?(Rails)
21
+ Rails.root.to_s
22
+ elsif defined?(RAILS_ROOT)
23
+ RAILS_ROOT
24
+ else
25
+ find_rails_root
26
+ end
27
+ end
28
+
29
+ def find_rails_root
30
+ while !cwd_is_a_rails_project?
31
+ if FileUtils.pwd == "/"
32
+ $stderr.puts "could not determine rails project root. please cd into your rails project"
33
+ exit 1
34
+ end
35
+ FileUtils.cd ".."
36
+ end
37
+ FileUtils.pwd
38
+ end
39
+
40
+ def cwd_is_a_rails_project?
41
+ File.exist?("config/environment.rb") && File.directory?("tmp") && File.directory?("log")
42
+ end
43
+
44
+ def install_signal_handlers
45
+ # WINCH is the only signal we can receive without mongrel/passenger side effects
46
+ trap("WINCH"){ check_and_run_commands }
47
+ end
48
+
49
+ def send_command(cmd, pid)
50
+ File.open(CMD_FILE, "w"){|f| f.puts cmd}
51
+ Process.kill("WINCH", pid)
52
+ end
53
+
54
+ def check_and_run_commands
55
+ read_command_file.each do |cmd|
56
+ case cmd.chomp
57
+ when 'HEAPDUMP' then heap_dump
58
+ when 'STARTTRACE' then start_trace
59
+ when 'STOPTRACE' then stop_trace
60
+ else
61
+ logger.info "unknown gc command: '#{cmd}'"
62
+ end
63
+ end
64
+ ensure
65
+ remove_command_file
66
+ end
67
+
68
+ CMD_FILE = File.expand_path("#{root}/tmp/gc_command.txt")
69
+
70
+ def read_command_file
71
+ File.exist?(CMD_FILE) ? File.read(CMD_FILE) : []
72
+ end
73
+
74
+ def remove_command_file
75
+ File.exist?(CMD_FILE) && File.unlink(CMD_FILE)
76
+ end
77
+
78
+ def can_trace?
79
+ GC.respond_to?(:log_file)
80
+ end
81
+
82
+ def can_dump?
83
+ GC.respond_to?(:dump_file_and_line_info)
84
+ end
85
+
86
+ def log_dir
87
+ @log_dir ||= File.expand_path("#{root}/log")
88
+ end
89
+
90
+ def log_dir=(dir)
91
+ @log_dir = File.expand_path(dir)
92
+ end
93
+
94
+ def tmp_dir
95
+ @tmp_dir ||= File.expand_path("#{root}/tmp")
96
+ end
97
+
98
+ def tmp_dir=(dir)
99
+ @tmp_dir = File.expand_path(dir)
100
+ end
101
+
102
+ def start_trace
103
+ unless can_trace?
104
+ logger.info "cannot start GC trace. GC.enable_trace is undefined"
105
+ return
106
+ end
107
+ GC.log_file "#{log_dir}/gctrace-#{Process.pid}.log" unless GC.log_file
108
+ GC.enable_trace
109
+ logger.info "GC-tracing: enabled"
110
+ end
111
+
112
+ def stop_trace
113
+ unless can_trace?
114
+ logger.info "cannot stop GC trace. GC.disable_trace is undefined"
115
+ return
116
+ end
117
+ GC.disable_trace
118
+ logger.info "GC-tracing: disabled"
119
+ end
120
+
121
+ def heap_dump
122
+ unless can_dump?
123
+ logger.info "cannot dump heap. GC.dump_file_and_line_info is undefined"
124
+ return
125
+ end
126
+ @heap_dump_count ||= 0
127
+ filename = "#{tmp_dir}/heap.#{Process.pid}.#{@heap_dump_count}.dump"
128
+ msg = "** Dumping heap ..."
129
+ $stderr.puts msg; logger.info msg
130
+ GC.start;GC.start # two calls to get rid of finalizer created garbage
131
+ GC.dump_file_and_line_info(filename, true)
132
+ msg = "** Run 'railsbench analyze_heap_dump #{filename}' to analyze."
133
+ $stderr.puts msg; logger.info msg
134
+ @heap_dump_count += 1
135
+ end
136
+
137
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.expand_path('../../init.rb', __FILE__)
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gc_hacks
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Stefan Kaes
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-04-08 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: This gem allows you to send GC related commands to a running Rails process
23
+ email:
24
+ - skaes@railsexpress.de
25
+ executables:
26
+ - dump_heap
27
+ - start_gc_trace
28
+ - stop_gc_trace
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - .gitignore
35
+ - Gemfile
36
+ - LICENCSE
37
+ - README.rdoc
38
+ - Rakefile
39
+ - bin/dump_heap
40
+ - bin/start_gc_trace
41
+ - bin/stop_gc_trace
42
+ - gc_hacks.gemspec
43
+ - init.rb
44
+ - lib/gc_hacks.rb
45
+ - lib/gc_hacks/version.rb
46
+ - rails/init.rb
47
+ has_rdoc: true
48
+ homepage: https://github.com/skaes/gc_hacks
49
+ licenses: []
50
+
51
+ post_install_message:
52
+ rdoc_options: []
53
+
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 3
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ hash: 3
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ requirements: []
75
+
76
+ rubyforge_project: gc_hacks
77
+ rubygems_version: 1.3.7
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: GC tracing/Heap dumping support for Rails processes
81
+ test_files: []
82
+