komamitsu-gc_monitor 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/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ === 0.0.1 2009-08-09
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/Manifest.txt ADDED
@@ -0,0 +1,11 @@
1
+ History.txt
2
+ Manifest.txt
3
+ PostInstall.txt
4
+ README.rdoc
5
+ Rakefile
6
+ lib/gc_monitor.rb
7
+ script/console
8
+ script/destroy
9
+ script/generate
10
+ test/test_gc_monitor.rb
11
+ test/test_helper.rb
data/PostInstall.txt ADDED
@@ -0,0 +1,7 @@
1
+
2
+ For more information on gc_monitor, see http://gc_monitor.rubyforge.org
3
+
4
+ NOTE: Change this information in PostInstall.txt
5
+ You can also delete it if you don't want it.
6
+
7
+
data/README.rdoc ADDED
@@ -0,0 +1,72 @@
1
+ = GcMonitor
2
+ GcMonitor is a Ruby module for monitoring GC.
3
+
4
+ == Examples
5
+ If you want to monitor the specific class, you may include GcMonitor into the class.
6
+
7
+ require 'gc_monitor'
8
+
9
+ class Foo
10
+ attr_accessor :dummy
11
+ include GcMonitor
12
+ end
13
+
14
+ Foo.release_hook('puts "i am released."') # This is option hook, for debug.
15
+
16
+ 15.times do
17
+ o = Foo.new
18
+ o.dummy = 'x' * 100 * 1024 * 1024 # For GC.
19
+ sleep 0.5
20
+ end
21
+
22
+ GcMonitor.list.each{|rec| p rec} # Array of the objects not garbage collected.
23
+
24
+ # You can filter the objects with using :time keyword.
25
+ GcMonitor.list(:time => 8).each{|rec| p rec} # Only older than 8 sec.
26
+
27
+ Then "i am released." will be printed when some Foo instancees are collected. At the last codes, array of the remaining objects will be dumped.
28
+
29
+ i am released.
30
+ :
31
+ i am released.
32
+ ["Foo__fdbef6946", {:time=>Sun Aug 09 00:11:49 +0900 2009, :caller=>["gc_monitor.rb:136:in `new'", "gc_monitor.rb:136", "gc_monitor.rb:135:in `times'", "gc_monitor.rb:135"]}]
33
+ ["Foo__fdbef8f52", {:time=>Sun Aug 09 00:11:50 +0900 2009, :caller=>["gc_monitor.rb:136:in `new'", "gc_monitor.rb:136", "gc_monitor.rb:135:in `times'", "gc_monitor.rb:135"]}]
34
+ ["Foo__fdbef8dfe", {:time=>Sun Aug 09 00:11:55 +0900 2009, :caller=>["gc_monitor.rb:136:in `new'", "gc_monitor.rb:136", "gc_monitor.rb:135:in `times'", "gc_monitor.rb:135"]}]
35
+ ["Foo__fdbef8c28", {:time=>Sun Aug 09 00:11:57 +0900 2009, :caller=>["gc_monitor.rb:136:in `new'", "gc_monitor.rb:136", "gc_monitor.rb:135:in `times'", "gc_monitor.rb:135"]}]
36
+ ["Foo__fdbef8912", {:time=>Sun Aug 09 00:11:59 +0900 2009, :caller=>["gc_monitor.rb:136:in `new'", "gc_monitor.rb:136", "gc_monitor.rb:135:in `times'", "gc_monitor.rb:135"]}]
37
+ ["Foo__fdbef87c8", {:time=>Sun Aug 09 00:12:00 +0900 2009, :caller=>["gc_monitor.rb:136:in `new'", "gc_monitor.rb:136", "gc_monitor.rb:135:in `times'", "gc_monitor.rb:135"]}]
38
+ ["Foo__fdbef84ee", {:time=>Sun Aug 09 00:12:02 +0900 2009, :caller=>["gc_monitor.rb:136:in `new'", "gc_monitor.rb:136", "gc_monitor.rb:135:in `times'", "gc_monitor.rb:135"]}]
39
+ ["Foo__fdbef8386", {:time=>Sun Aug 09 00:12:04 +0900 2009, :caller=>["gc_monitor.rb:136:in `new'", "gc_monitor.rb:136", "gc_monitor.rb:135:in `times'", "gc_monitor.rb:135"]}]
40
+ ["Foo__fdbef8110", {:time=>Sun Aug 09 00:12:05 +0900 2009, :caller=>["gc_monitor.rb:136:in `new'", "gc_monitor.rb:136", "gc_monitor.rb:135:in `times'", "gc_monitor.rb:135"]}]
41
+ ["Foo__fdbef7ea4", {:time=>Sun Aug 09 00:12:07 +0900 2009, :caller=>["gc_monitor.rb:136:in `new'", "gc_monitor.rb:136", "gc_monitor.rb:135:in `times'", "gc_monitor.rb:135"]}]
42
+ ["Foo__fdbef8f3e", {:time=>Sun Aug 09 00:12:09 +0900 2009, :caller=>["gc_monitor.rb:136:in `new'", "gc_monitor.rb:136", "gc_monitor.rb:135:in `times'", "gc_monitor.rb:135"]}]
43
+ ["Foo__fdbef8f34", {:time=>Sun Aug 09 00:12:10 +0900 2009, :caller=>["gc_monitor.rb:136:in `new'", "gc_monitor.rb:136", "gc_monitor.rb:135:in `times'", "gc_monitor.rb:135"]}]
44
+ ["Foo__fdbef8e76", {:time=>Sun Aug 09 00:12:12 +0900 2009, :caller=>["gc_monitor.rb:136:in `new'", "gc_monitor.rb:136", "gc_monitor.rb:135:in `times'", "gc_monitor.rb:135"]}]
45
+ i am released.
46
+ :
47
+ i am released.
48
+
49
+ You can monitor almost all of classes. Instead of "include GcMonitor" in the class definition, call GcMonitor.include_in_subclasses. But some classes are not supported, Time (sorry...) and implemented classes in ruby such as String and so on.
50
+
51
+ GcMonitor.include_in_subclasses(Object) # If you monitor IO and the sub classes, set the argument IO.
52
+
53
+ Finally, there is TCP/IP interface.
54
+
55
+ GcMonitor.tcp_server('0.0.0.0', 4321)
56
+
57
+ And using TCP/IP client, you can monitor the realtime information by 'list' command.
58
+
59
+ $ telnet localhost 4321
60
+ Trying ::1...
61
+ Trying 127.0.0.1...
62
+ Connected to localhost.
63
+ Escape character is '^]'.
64
+ list
65
+ now: Sun Aug 09 00:48:59 +0900 2009
66
+ ["Rational__fdbe7752e", {:time=>Sun Aug 09 00:48:56 +0900 2009, :caller=>["/usr/lib/ruby/1.8/rational.rb:94:in `new'", "/usr/lib/ruby/1.8/rational.rb:94:in `new!'", "/usr/lib/ruby/1.8/rational.rb:337:in `coerce'", "/usr/lib/ruby/1.8/date.rb:503:in `-'", "/usr/lib/ruby/1.8/date.rb:503:in `jd_to_ajd'", "/usr/lib/ruby/1.8/date.rb:754:in `new'", "gc_monitor.rb:155", "gc_monitor.rb:154:in `times'", "gc_monitor.rb:154"]}]
67
+ :
68
+ list 8 <== Only the remaining objects older than 8 sec ago.
69
+ :
70
+ quit <== Command for quit TCP/IP interface.
71
+
72
+
data/Rakefile ADDED
@@ -0,0 +1,26 @@
1
+ require 'rubygems'
2
+ gem 'hoe', '>= 2.1.0'
3
+ require 'hoe'
4
+ require 'fileutils'
5
+ require './lib/gc_monitor'
6
+
7
+ Hoe.plugin :newgem
8
+ # Hoe.plugin :website
9
+ # Hoe.plugin :cucumberfeatures
10
+
11
+ # Generate all the Rake tasks
12
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
13
+ $hoe = Hoe.spec 'gc_monitor' do
14
+ self.developer 'FIXME full name', 'FIXME email'
15
+ self.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
16
+ self.rubyforge_name = self.name # TODO this is default value
17
+ # self.extra_deps = [['activesupport','>= 2.0.2']]
18
+
19
+ end
20
+
21
+ require 'newgem/tasks'
22
+ Dir['tasks/**/*.rake'].each { |t| load t }
23
+
24
+ # TODO - want other tests/tasks run by default? Add them to the list
25
+ # remove_task :default
26
+ # task :default => [:spec, :features]
data/lib/gc_monitor.rb ADDED
@@ -0,0 +1,143 @@
1
+ require 'thread'
2
+
3
+ module GcMonitor
4
+ VERSION = '0.0.1'
5
+
6
+ class << self
7
+ def remaining_objects
8
+ @remaining_objects ||= {}
9
+ @remaining_objects
10
+ end
11
+
12
+ def mutex
13
+ @mutex ||= Mutex.new
14
+ @mutex
15
+ end
16
+
17
+ def include_in_subclasses(klass = Object)
18
+ ObjectSpace.each_object(class << klass; self; end) do |cls|
19
+ next if cls.ancestors.include?(Exception)
20
+ next if [GcMonitor, Time].include?(cls)
21
+ cls.__send__(:include, GcMonitor)
22
+ end
23
+ end
24
+
25
+ def key(obj)
26
+ sprintf("%s__%0x", obj.class, obj.object_id)
27
+ end
28
+
29
+ def regist(obj, caller)
30
+ mutex.synchronize do
31
+ remaining_objects[GcMonitor.key(obj)] = {:time => Time.now, :caller => caller}
32
+ end
33
+ end
34
+
35
+ def release(obj, caller)
36
+ mutex.synchronize do
37
+ remaining_objects.delete(GcMonitor.key(obj))
38
+ end
39
+ end
40
+
41
+ def list(cond = {})
42
+ mutex.synchronize do
43
+ cond.keys.inject(remaining_objects) {|objs, cond_key|
44
+ new_objs = nil
45
+
46
+ case cond_key
47
+ when :time
48
+ now = Time.now
49
+ new_objs = objs.select do |obj_k, obj_v|
50
+ obj_v[:time] < now - cond[cond_key]
51
+ end
52
+ else
53
+ raise "Invalid list option [#{cond_key}]"
54
+ end
55
+
56
+ new_objs
57
+ }.sort_by{|k, v| v[:time]}
58
+ end
59
+ end
60
+
61
+ def release_proc(proc_str)
62
+ lambda {
63
+ instance_eval(proc_str)
64
+ GcMonitor.release(self)
65
+ }
66
+ end
67
+
68
+ def included(base)
69
+ class << base
70
+ return if @gc_monitor_included
71
+ @gc_monitor_included = true
72
+ end
73
+ return unless base.private_methods.include?("initialize")
74
+ begin
75
+ base.__send__(:alias_method, :initialize_without_gc_monitor_pre, :initialize)
76
+ rescue NameError
77
+ return
78
+ end
79
+ base.__send__(:alias_method, :initialize, :initialize_with_gc_monitor_pre)
80
+
81
+ def base.method_added(name)
82
+ return unless name == :initialize
83
+ return if @made_initialize_with_gc_monitor_post
84
+ @made_initialize_with_gc_monitor_post = true
85
+ alias_method :initialize_without_gc_monitor_post, :initialize
86
+ alias_method :initialize, :initialize_with_gc_monitor_post
87
+ end
88
+
89
+ def base.release_hook(proc_str)
90
+ @@gc_monitor_release_hook = proc_str
91
+ end
92
+ end
93
+
94
+ def tcp_server(host, port)
95
+ require 'socket'
96
+
97
+ Thread.new do
98
+ s = TCPServer.new(host, port)
99
+ loop do
100
+ Thread.new(s.accept) do |c|
101
+ while command_line = c.gets.strip
102
+ next if command_line.empty?
103
+
104
+ command, *args = command_line.split(/\s+/)
105
+
106
+ case command
107
+ when 'list'
108
+ cond = args.empty? ? {} : {:time => Integer(args[0])}
109
+ c.puts "now: #{Time.now}"
110
+ GcMonitor.list(cond).each do |obj|
111
+ c.puts(obj.inspect)
112
+ end
113
+ when 'quit'
114
+ c.close
115
+ Thread.exit
116
+ else
117
+ c.puts 'unknown command'
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ private
127
+ def regist_gc_monitor(caller)
128
+ GcMonitor.regist(self, caller)
129
+ @@gc_monitor_release_hook ||= nil
130
+ ObjectSpace.define_finalizer(self, GcMonitor.release_proc(@@gc_monitor_release_hook))
131
+ end
132
+
133
+ def initialize_with_gc_monitor_pre(*args, &blk)
134
+ initialize_without_gc_monitor_pre(*args, &blk)
135
+ regist_gc_monitor(caller)
136
+ end
137
+
138
+ def initialize_with_gc_monitor_post(*args, &blk)
139
+ initialize_without_gc_monitor_post(*args, &blk)
140
+ regist_gc_monitor(caller)
141
+ end
142
+ end
143
+
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/gc_monitor.rb'}"
9
+ puts "Loading gc_monitor gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestGcMonitor < Test::Unit::TestCase
4
+
5
+ def setup
6
+ end
7
+
8
+ def test_truth
9
+ assert true
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ require 'stringio'
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../lib/gc_monitor'
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: komamitsu-gc_monitor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - komamitsu
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-08-09 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Ruby module for monitoring GC
17
+ email: komamitsu@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - History.txt
26
+ - Manifest.txt
27
+ - PostInstall.txt
28
+ - README.rdoc
29
+ - Rakefile
30
+ - lib/gc_monitor.rb
31
+ - script/console
32
+ - script/destroy
33
+ - script/generate
34
+ - test/test_gc_monitor.rb
35
+ - test/test_helper.rb
36
+ has_rdoc: true
37
+ homepage: http://github.com/komamitsu/gc_monitor
38
+ licenses:
39
+ post_install_message:
40
+ rdoc_options: []
41
+
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ version:
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ requirements: []
57
+
58
+ rubyforge_project:
59
+ rubygems_version: 1.3.5
60
+ signing_key:
61
+ specification_version: 2
62
+ summary: Ruby module for monitoring GC
63
+ test_files: []
64
+