bleak_house 3 → 3.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +26 -4
- data/LICENSE_BSD +10 -0
- data/LICENSE_RUBY +53 -0
- data/Manifest +30 -18
- data/README +66 -13
- data/Rakefile +63 -56
- data/TODO +2 -0
- data/bin/bleak +10 -0
- data/ext/bleak_house/logger/extconf.rb +4 -0
- data/ext/bleak_house/logger/snapshot.c +153 -0
- data/ext/bleak_house/logger/snapshot.h +99 -0
- data/init.rb +2 -1
- data/install.rb +2 -1
- data/lib/bleak_house/analyzer/analyzer.rb +143 -0
- data/lib/bleak_house/analyzer.rb +5 -0
- data/lib/bleak_house/logger/mem_usage.rb +13 -0
- data/lib/bleak_house/logger.rb +3 -0
- data/lib/bleak_house/{action_controller.rb → rails/action_controller.rb} +3 -2
- data/lib/bleak_house/rails/bleak_house.rb +58 -0
- data/lib/bleak_house/rails/dispatcher.rb +19 -0
- data/lib/bleak_house/rails.rb +6 -0
- data/lib/bleak_house/{support_methods.rb → support/core_extensions.rb} +24 -1
- data/lib/bleak_house/{rake_task_redefine_task.rb → support/rake.rb} +0 -0
- data/lib/bleak_house.rb +4 -10
- data/lib/vendor/lightcsv.rb +168 -0
- data/patches/gc.c.patch +27 -0
- data/patches/parse.y.patch +16 -0
- data/test/misc/direct.rb +13 -0
- data/test/unit/test_bleak_house.rb +34 -0
- data.tar.gz.sig +3 -0
- metadata +77 -50
- metadata.gz.sig +0 -0
- data/lib/bleak_house/analyze.rb +0 -139
- data/lib/bleak_house/bleak_house.rb +0 -33
- data/lib/bleak_house/dispatcher.rb +0 -23
- data/lib/bleak_house/gruff_hacks.rb +0 -56
- data/lib/bleak_house/mem_logger.rb +0 -54
- data/tasks/bleak_house_tasks.rake +0 -13
@@ -0,0 +1,143 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'yaml'
|
5
|
+
require 'pp'
|
6
|
+
require 'ruby-debug'
|
7
|
+
|
8
|
+
module BleakHouse
|
9
|
+
|
10
|
+
class Analyzer
|
11
|
+
|
12
|
+
MAGIC_KEYS = {
|
13
|
+
-1 => 'timestamp',
|
14
|
+
-2 => 'mem usage/swap',
|
15
|
+
-3 => 'mem usage/real',
|
16
|
+
-4 => 'tag',
|
17
|
+
-5 => 'heap/filled',
|
18
|
+
-6 => 'heap/free'
|
19
|
+
}
|
20
|
+
|
21
|
+
CLASS_KEYS = eval('[nil, ' + # skip 0
|
22
|
+
open(
|
23
|
+
File.dirname(__FILE__) + '/../../../ext/bleak_house/logger/snapshot.h'
|
24
|
+
).read[/\{(.*?)\}/m, 1] + ']')
|
25
|
+
|
26
|
+
# Parses and correlates a BleakHouse::Logger output file.
|
27
|
+
def self.run(logfile)
|
28
|
+
unless File.exists? logfile
|
29
|
+
puts "No data file found: #{logfile}"
|
30
|
+
exit
|
31
|
+
end
|
32
|
+
|
33
|
+
frames = []
|
34
|
+
last_population = []
|
35
|
+
frame = nil
|
36
|
+
ix = nil
|
37
|
+
|
38
|
+
puts "Examining objects"
|
39
|
+
|
40
|
+
LightCsv.foreach(logfile) do |row|
|
41
|
+
|
42
|
+
# Stupid is fast
|
43
|
+
row[0] = row[0].to_i if row[0].to_i != 0
|
44
|
+
row[1] = row[1].to_i if row[1].to_i != 0
|
45
|
+
|
46
|
+
if row[0].to_i < 0
|
47
|
+
# Get frame meta-information
|
48
|
+
if MAGIC_KEYS[row[0]] == 'timestamp'
|
49
|
+
|
50
|
+
# The frame has ended; process the last one
|
51
|
+
if frame
|
52
|
+
population = frame['objects'].keys
|
53
|
+
births = population - last_population
|
54
|
+
deaths = last_population - population
|
55
|
+
last_population = population
|
56
|
+
|
57
|
+
# assign births
|
58
|
+
frame['births'] = frame['objects'].slice(births)
|
59
|
+
|
60
|
+
if final = frames[-2]
|
61
|
+
final['deaths'] = final['objects'].slice(deaths)
|
62
|
+
bsize = final['births'].size
|
63
|
+
dsize = final['deaths'].size
|
64
|
+
final['velocity'] = bsize * 100 / dsize / 100.0
|
65
|
+
puts " Frame #{frames.size - 1} (#{final['meta']['tag]}) finalized: #{bsize} births, #{dsize} deaths, velocity #{final['velocity']}, population #{final['objects'].size}"
|
66
|
+
final.delete 'objects'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Set up a new frame
|
71
|
+
frame = {}
|
72
|
+
frames << frame
|
73
|
+
frame['objects'] ||= {}
|
74
|
+
frame['meta'] ||= {}
|
75
|
+
|
76
|
+
#puts " Frame #{frames.size} opened"
|
77
|
+
end
|
78
|
+
|
79
|
+
frame['meta'][MAGIC_KEYS[row[0]]] = row[1]
|
80
|
+
else
|
81
|
+
# Assign live objects
|
82
|
+
frame['objects'][row[1]] = row[0]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# See what objects are still laying around
|
87
|
+
population = frames.last['objects'].reject do |key, value|
|
88
|
+
frames.first['births'][key] == value
|
89
|
+
end
|
90
|
+
|
91
|
+
# Remove bogus frames
|
92
|
+
frames = frames[1..-3]
|
93
|
+
|
94
|
+
total_births = frames.inject(0) do |births, frame|
|
95
|
+
births + frame['births'].size
|
96
|
+
end
|
97
|
+
total_deaths = frames.inject(0) do |deaths, frame|
|
98
|
+
deaths + frame['deaths'].size
|
99
|
+
end
|
100
|
+
|
101
|
+
puts "#{total_births} total meaningful births, #{total_deaths} total meaningful deaths.\n\n"
|
102
|
+
|
103
|
+
leakers = {}
|
104
|
+
|
105
|
+
# Find the sources of the leftover objects in the final population
|
106
|
+
population.each do |id, klass|
|
107
|
+
leaker = frames.detect do |frame|
|
108
|
+
frame['births'][id] == klass
|
109
|
+
end
|
110
|
+
if leaker
|
111
|
+
tag = leaker['meta']['tag']
|
112
|
+
klass = CLASS_KEYS[klass] if klass.is_a? Fixnum
|
113
|
+
leakers[tag] ||= Hash.new(0)
|
114
|
+
leakers[tag][klass] += 1
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Sort
|
119
|
+
leakers = leakers.map do |tag, value|
|
120
|
+
[tag, value.sort_by do |klass, count|
|
121
|
+
-count
|
122
|
+
end]
|
123
|
+
end.sort_by do |tag, value|
|
124
|
+
Hash[*value.flatten].values.inject(0) {|i, v| i - v}
|
125
|
+
end
|
126
|
+
|
127
|
+
puts "Here are your leaks:"
|
128
|
+
leakers.each do |tag, value|
|
129
|
+
puts " #{tag} leaked per request:"
|
130
|
+
requests = frames.select do |frame|
|
131
|
+
frame['meta']['tag'] == tag
|
132
|
+
end.size
|
133
|
+
value.each do |klass, count|
|
134
|
+
count = count/requests
|
135
|
+
puts " #{count} #{klass}" if count > 0
|
136
|
+
end
|
137
|
+
end
|
138
|
+
puts "\nBye"
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
module BleakHouse
|
3
|
+
|
4
|
+
class Logger
|
5
|
+
|
6
|
+
# Returns an array of the running process's real and virtual memory usage, in kilobytes.
|
7
|
+
def mem_usage
|
8
|
+
a = `ps -o vsz,rss -p #{Process.pid}`.split(/\s+/)[-2..-1].map{|el| el.to_i}
|
9
|
+
[a.first - a.last, a.last]
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -1,14 +1,15 @@
|
|
1
1
|
|
2
|
+
# Override ActionController::Base.process and process_with_exception to make sure the request tag for the snapshot gets set as a side-effect of request processing.
|
2
3
|
class ActionController::Base
|
3
4
|
class << self
|
4
5
|
def process_with_bleak_house(request, *args)
|
5
|
-
BleakHouse.set_request_name request
|
6
|
+
BleakHouse::Rails.set_request_name request
|
6
7
|
process_without_bleak_house(request, *args)
|
7
8
|
end
|
8
9
|
alias_method_chain :process, :bleak_house
|
9
10
|
|
10
11
|
def process_with_exception_with_bleak_house(request, *args)
|
11
|
-
BleakHouse.set_request_name request, "/error"
|
12
|
+
BleakHouse::Rails.set_request_name request, "/error"
|
12
13
|
process_with_exception_without_bleak_house(request, *args)
|
13
14
|
end
|
14
15
|
alias_method_chain :process_with_exception, :bleak_house
|
@@ -0,0 +1,58 @@
|
|
1
|
+
|
2
|
+
module BleakHouse
|
3
|
+
module Rails
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def last_request_name
|
7
|
+
@@last_request_name
|
8
|
+
end
|
9
|
+
|
10
|
+
def last_request_name=(obj)
|
11
|
+
@@last_request_name = obj
|
12
|
+
end
|
13
|
+
|
14
|
+
# Avoid making four more strings on each request.
|
15
|
+
CONTROLLER_KEY = 'controller'
|
16
|
+
ACTION_KEY = 'action'
|
17
|
+
GSUB_SEARCH = '/'
|
18
|
+
GSUB_REPLACEMENT = '__'
|
19
|
+
|
20
|
+
# Sets the request name on the BleakHouse object to match this Rails request. Called from <tt>ActionController::Base.process</tt>. Assign to <tt>last_request_name</tt> yourself if you are not using BleakHouse within Rails.
|
21
|
+
def set_request_name(request, other = nil)
|
22
|
+
self.last_request_name = "#{
|
23
|
+
request.parameters[CONTROLLER_KEY].gsub(GSUB_SEARCH, GSUB_REPLACEMENT) # mangle namespaced controller names
|
24
|
+
}/#{
|
25
|
+
request.parameters[ACTION_KEY]
|
26
|
+
}/#{
|
27
|
+
request.request_method
|
28
|
+
}#{
|
29
|
+
other
|
30
|
+
}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def debug(s) #:nodoc:
|
34
|
+
s = "** bleak_house: #{s}"
|
35
|
+
RAILS_DEFAULT_LOGGER.debug s if RAILS_DEFAULT_LOGGER
|
36
|
+
end
|
37
|
+
|
38
|
+
def warn(s) #:nodoc:
|
39
|
+
s = "** bleak_house: #{s}"
|
40
|
+
if RAILS_DEFAULT_LOGGER
|
41
|
+
RAILS_DEFAULT_LOGGER.warn s
|
42
|
+
else
|
43
|
+
$stderr.puts s
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
LOGFILE = "#{RAILS_ROOT}/log/bleak_house_#{RAILS_ENV}.dump"
|
49
|
+
if File.exists?(LOGFILE)
|
50
|
+
File.rename(LOGFILE, "#{LOGFILE}.old")
|
51
|
+
warn "renamed old logfile"
|
52
|
+
end
|
53
|
+
|
54
|
+
WITH_SPECIALS = false
|
55
|
+
|
56
|
+
MEMLOGGER = Logger.new
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
# Override Dispatcher#prepare and Dispatcher#reset_after_dispatch so that each request makes before-and-after usage snapshots.
|
3
|
+
class Dispatcher
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def prepare_application_with_bleak_house
|
7
|
+
prepare_application_without_bleak_house
|
8
|
+
BleakHouse::Rails::MEMLOGGER.snapshot(BleakHouse::Rails::LOGFILE, 'core rails', BleakHouse::Rails::WITH_SPECIALS)
|
9
|
+
end
|
10
|
+
alias_method_chain :prepare_application, :bleak_house
|
11
|
+
|
12
|
+
def reset_after_dispatch_with_bleak_house
|
13
|
+
BleakHouse::Rails::MEMLOGGER.snapshot(BleakHouse::Rails::LOGFILE, BleakHouse::Rails.last_request_name || 'unknown', BleakHouse::Rails::WITH_SPECIALS)
|
14
|
+
reset_after_dispatch_without_bleak_house
|
15
|
+
end
|
16
|
+
alias_method_chain :reset_after_dispatch, :bleak_house
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -1,4 +1,6 @@
|
|
1
1
|
|
2
|
+
require 'set'
|
3
|
+
|
2
4
|
class Array
|
3
5
|
alias :time :first
|
4
6
|
alias :data :last
|
@@ -13,10 +15,28 @@ class Array
|
|
13
15
|
|
14
16
|
end
|
15
17
|
|
18
|
+
class Hash
|
19
|
+
|
20
|
+
# Similar to the ActiveSupport methods in Rails
|
21
|
+
def slice(keys)
|
22
|
+
keys = Set.new(keys)
|
23
|
+
reject do |key,|
|
24
|
+
!keys.include?(key)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def unslice(keys)
|
29
|
+
keys = Set.new(keys)
|
30
|
+
reject do |key,|
|
31
|
+
keys.include?(key)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
16
36
|
class Dir
|
17
37
|
def self.descend path, &block
|
18
38
|
path = path.split("/") unless path.is_a? Array
|
19
|
-
top = path.shift
|
39
|
+
top = (path.shift or ".")
|
20
40
|
Dir.mkdir(top) unless File.exists? top
|
21
41
|
Dir.chdir(top) do
|
22
42
|
if path.any?
|
@@ -44,4 +64,7 @@ class Symbol
|
|
44
64
|
def =~ regex
|
45
65
|
self.to_s =~ regex
|
46
66
|
end
|
67
|
+
def [](*args)
|
68
|
+
self.to_s[*args]
|
69
|
+
end
|
47
70
|
end
|
File without changes
|
data/lib/bleak_house.rb
CHANGED
@@ -1,13 +1,7 @@
|
|
1
1
|
|
2
|
-
|
2
|
+
require 'bleak_house/logger'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
require 'bleak_house/mem_logger'
|
8
|
-
require 'bleak_house/dispatcher'
|
9
|
-
require 'bleak_house/action_controller'
|
10
|
-
|
11
|
-
BleakHouse.warn "enabled (log/#{RAILS_ENV}_bleak_house.log) (#{BleakHouse.log_interval} requests per frame)"
|
12
|
-
|
4
|
+
if ENV['RAILS_ENV'] and ENV['BLEAK_HOUSE']
|
5
|
+
require 'bleak_house/rails'
|
6
|
+
BleakHouse::Rails.warn "enabled (log/bleak_house_#{RAILS_ENV}.dump)"
|
13
7
|
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
# = LightCsv
|
2
|
+
# CSV parser
|
3
|
+
#
|
4
|
+
# $Id: lightcsv.rb 76 2007-04-15 14:34:23Z tommy $
|
5
|
+
# Copyright:: 2007 (C) TOMITA Masahiro <tommy@tmtm.org>
|
6
|
+
# License:: Ruby's
|
7
|
+
# Homepage:: http://tmtm.org/ja/ruby/lightcsv
|
8
|
+
|
9
|
+
require "strscan"
|
10
|
+
|
11
|
+
# == CSV のパース
|
12
|
+
# 各レコードはカラムを要素とする配列である。
|
13
|
+
# レコードの区切りは LF,CR,CRLF のいずれか。
|
14
|
+
#
|
15
|
+
# 以下が csv.rb と異なる。
|
16
|
+
# * 空行は [nil] ではなく [] になる。
|
17
|
+
# * 「"」で括られていない空カラムは nil ではなく "" になる。
|
18
|
+
#
|
19
|
+
# == 例
|
20
|
+
# * CSVファイルのレコード毎にブロックを繰り返す。
|
21
|
+
# LightCsv.foreach(filename){|row| ...}
|
22
|
+
# 次と同じ。
|
23
|
+
# LightCsv.open(filename){|csv| csv.each{|row| ...}}
|
24
|
+
#
|
25
|
+
# * CSVファイルの全レコードを返す。
|
26
|
+
# LightCsv.readlines(filename) # => [[col1,col2,...],...]
|
27
|
+
# 次と同じ。
|
28
|
+
# LightCsv.open(filename){|csv| csv.map}
|
29
|
+
#
|
30
|
+
# * CSV文字列のレコード毎にブロックを繰り返す。
|
31
|
+
# LightCsv.parse("a1,a2,..."){|row| ...}
|
32
|
+
# 次と同じ。
|
33
|
+
# LightCsv.new("a1,a2,...").each{|row| ...}
|
34
|
+
#
|
35
|
+
# * CSV文字列の全レコードを返す。
|
36
|
+
# LightCsv.parse("a1,a2,...") # => [[a1,a2,...],...]
|
37
|
+
# 次と同じ。
|
38
|
+
# LightCsv.new("a1,a2,...").map
|
39
|
+
#
|
40
|
+
class LightCsv
|
41
|
+
include Enumerable
|
42
|
+
|
43
|
+
# == パースできない形式の場合に発生する例外
|
44
|
+
# InvalidFormat#message は処理できなかった位置から 10バイト文の文字列を返す。
|
45
|
+
class InvalidFormat < RuntimeError; end
|
46
|
+
|
47
|
+
# ファイルの各レコード毎にブロックを繰り返す。
|
48
|
+
# ブロック引数はレコードを表す配列。
|
49
|
+
def self.foreach(filename, &block)
|
50
|
+
self.open(filename) do |f|
|
51
|
+
f.each(&block)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# ファイルの全レコードをレコードの配列で返す。
|
56
|
+
def self.readlines(filename)
|
57
|
+
self.open(filename) do |f|
|
58
|
+
return f.map
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# CSV文字列の全レコードをレコードの配列で返す。
|
63
|
+
# ブロックが与えられた場合は、レコード毎にブロックを繰り返す。
|
64
|
+
# ブロック引数はレコードを表す配列。
|
65
|
+
def self.parse(string, &block)
|
66
|
+
unless block
|
67
|
+
return self.new(string).map
|
68
|
+
end
|
69
|
+
self.new(string).each do |row|
|
70
|
+
block.call row
|
71
|
+
end
|
72
|
+
return nil
|
73
|
+
end
|
74
|
+
|
75
|
+
# ファイルをオープンして LightCsv オブジェクトを返す。
|
76
|
+
# ブロックを与えた場合は LightCsv オブジェクトを引数としてブロックを実行する。
|
77
|
+
def self.open(filename, &block)
|
78
|
+
f = File.open(filename)
|
79
|
+
csv = self.new(f)
|
80
|
+
if block
|
81
|
+
begin
|
82
|
+
return block.call(csv)
|
83
|
+
ensure
|
84
|
+
csv.close
|
85
|
+
end
|
86
|
+
else
|
87
|
+
return csv
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# LightCsv オブジェクトを生成する。
|
92
|
+
# _src_ は String か IO。
|
93
|
+
def initialize(src)
|
94
|
+
if src.kind_of? String
|
95
|
+
@file = nil
|
96
|
+
@ss = StringScanner.new(src)
|
97
|
+
else
|
98
|
+
@file = src
|
99
|
+
@ss = StringScanner.new("")
|
100
|
+
end
|
101
|
+
@buf = ""
|
102
|
+
@bufsize = 64*1024
|
103
|
+
end
|
104
|
+
attr_accessor :bufsize
|
105
|
+
|
106
|
+
# LightCsv オブジェクトに関連したファイルをクローズする。
|
107
|
+
def close()
|
108
|
+
@file.close if @file
|
109
|
+
end
|
110
|
+
|
111
|
+
# 1レコードを返す。データの最後の場合は nil を返す。
|
112
|
+
# 空行の場合は空配列([])を返す。
|
113
|
+
# 空カラムは「"」で括られているか否かにかかわらず空文字列("")になる。
|
114
|
+
def shift()
|
115
|
+
return nil if @ss.eos? and ! read_next_data
|
116
|
+
cols = []
|
117
|
+
while true
|
118
|
+
if @ss.eos? and ! read_next_data
|
119
|
+
cols << ""
|
120
|
+
break
|
121
|
+
end
|
122
|
+
if @ss.scan(/\"/n)
|
123
|
+
until @ss.scan(/(?:\"\"|[^\"])*\"/n)
|
124
|
+
read_next_data or raise InvalidFormat, @ss.rest[0,10]
|
125
|
+
end
|
126
|
+
cols << @ss.matched.chop.gsub(/\"\"/n, '"')
|
127
|
+
else
|
128
|
+
col = @ss.scan(/[^\",\r\n]*/n)
|
129
|
+
while @ss.eos? and read_next_data
|
130
|
+
col << @ss.scan(/[^\",\r\n]*/n)
|
131
|
+
end
|
132
|
+
cols << col
|
133
|
+
end
|
134
|
+
unless @ss.scan(/,/n)
|
135
|
+
break if @ss.scan(/\r\n/n)
|
136
|
+
unless @ss.rest_size < 2 and read_next_data and @ss.scan(/,/n)
|
137
|
+
break if @ss.scan(/\r\n|\n|\r|\z/n)
|
138
|
+
read_next_data
|
139
|
+
raise InvalidFormat, @ss.rest[0,10]
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
cols.clear if cols.size == 1 and cols.first.empty?
|
144
|
+
cols
|
145
|
+
end
|
146
|
+
|
147
|
+
# 各レコード毎にブロックを繰り返す。
|
148
|
+
def each()
|
149
|
+
while row = shift
|
150
|
+
yield row
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# 現在位置以降のレコードの配列を返す。
|
155
|
+
def readlines()
|
156
|
+
return map
|
157
|
+
end
|
158
|
+
|
159
|
+
private
|
160
|
+
|
161
|
+
def read_next_data()
|
162
|
+
if @file and @file.read(@bufsize, @buf)
|
163
|
+
@ss.string = @ss.rest + @buf
|
164
|
+
else
|
165
|
+
nil
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
data/patches/gc.c.patch
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
*** gc.old 2007-09-25 00:27:27.000000000 -0400
|
2
|
+
--- gc.c 2007-09-25 00:27:28.000000000 -0400
|
3
|
+
***************
|
4
|
+
*** 309,314 ****
|
5
|
+
--- 309,330 ----
|
6
|
+
static int heaps_length = 0;
|
7
|
+
static int heaps_used = 0;
|
8
|
+
|
9
|
+
+ struct heaps_slot *
|
10
|
+
+ rb_gc_heap_slots()
|
11
|
+
+ {
|
12
|
+
+ return heaps;
|
13
|
+
+ }
|
14
|
+
+
|
15
|
+
+ int
|
16
|
+
+ rb_gc_heaps_used() {
|
17
|
+
+ return heaps_used;
|
18
|
+
+ }
|
19
|
+
+
|
20
|
+
+ int
|
21
|
+
+ rb_gc_heaps_length() {
|
22
|
+
+ return heaps_length;
|
23
|
+
+ }
|
24
|
+
+
|
25
|
+
#define HEAP_MIN_SLOTS 10000
|
26
|
+
static int heap_slots = HEAP_MIN_SLOTS;
|
27
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
*** parse.old 2007-09-25 00:21:43.000000000 -0400
|
2
|
+
--- parse.y 2007-09-25 00:23:02.000000000 -0400
|
3
|
+
***************
|
4
|
+
*** 6166,6171 ****
|
5
|
+
--- 6166,6176 ----
|
6
|
+
* :wait2, :$>]
|
7
|
+
*/
|
8
|
+
|
9
|
+
+ struct st_table *
|
10
|
+
+ rb_parse_sym_tbl() {
|
11
|
+
+ return sym_tbl;
|
12
|
+
+ }
|
13
|
+
+
|
14
|
+
VALUE
|
15
|
+
rb_sym_all_symbols()
|
16
|
+
{
|
data/test/misc/direct.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby-bleak-house
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bleak_house/c'
|
5
|
+
$memlogger = BleakHouse::Logger.new
|
6
|
+
File.delete($logfile = "/tmp/log") rescue nil
|
7
|
+
|
8
|
+
puts 0
|
9
|
+
$memlogger.snapshot($logfile, "file", true)
|
10
|
+
puts 1
|
11
|
+
$memlogger.snapshot($logfile, "file/one", true)
|
12
|
+
puts 2
|
13
|
+
$memlogger.snapshot($logfile, "file/two", true)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
DIR = File.dirname(__FILE__) + "/../../"
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'test/unit'
|
6
|
+
require 'yaml'
|
7
|
+
require 'ruby-debug'
|
8
|
+
Debugger.start
|
9
|
+
|
10
|
+
class BleakHouseTest < Test::Unit::TestCase
|
11
|
+
require "#{DIR}lib/bleak_house/logger"
|
12
|
+
|
13
|
+
SNAPSHOT_FILE = "/tmp/bleak_house"
|
14
|
+
SNAPS = {:c => SNAPSHOT_FILE + ".c.yaml",
|
15
|
+
:ruby => SNAPSHOT_FILE + ".rb.yaml"}
|
16
|
+
|
17
|
+
def setup
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_c_snapshot
|
21
|
+
File.delete SNAPS[:c] rescue nil
|
22
|
+
symbol_count = Symbol.all_symbols.size
|
23
|
+
::BleakHouse::Logger.new.snapshot(SNAPS[:c], "c_test", false)
|
24
|
+
assert_equal symbol_count, Symbol.all_symbols.size
|
25
|
+
assert File.exist?(SNAPS[:c])
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_c_raises
|
29
|
+
assert_raises(RuntimeError) do
|
30
|
+
::BleakHouse::Logger.new.snapshot("/", "c_test", false)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data.tar.gz.sig
ADDED