3 日坊主日記
2007-03-03 [長年日記]
_ 再現しない
[BUG] を mingw32 で切り詰めよしよしと思って linux に持っていったら再現しない。なぜだ!
module Rake
class HaunTask
def initialize
Rake.app.define_task { p :here }
end
end
def self.app
@app ||= Rake::App.new
end
class App
def initialize
@t = Hash.new
end
def define_task(&b)
@t["hu"] ||= Rake::Task.new
t = @t["hu"]
t.enhance(&b)
t
end
def run
Rake::HaunTask.new
@t["hu"].execute
end
end
class Task
def initialize
@act = nil
end
def enhance(&b)
@act = b
end
def execute
GC.start
@act.call(self)
end
end
end
Rake.app.run
2007-03-09 [長年日記]
_ rubygems for ruby-1.9
$ ruby-1.9.0 -v ruby 1.9.0 (2007-03-05 patchlevel 0) [i386-mingw32]
RubyGems unpack が ruby-1.9 で動かないので調査中。
ERROR: While executing gem ... (Zlib::GzipFile::Error)
not in gzip format
Zlib::GzipReader がうまく動いていない。
# gzipreader_io_test.rb:
fname = "metadata.gz"
io = File.open(fname)
class Reader
def initialize(io)
@io = io
end
def read(*args)
p [:read, *args]
@io.read(*args)
end
end
io = Reader.new(io)
require "zlib"
p Zlib::GzipReader.new(io)
$ ruby-1.8.6 gzipreader_io_test.rb [:read, 2048] #<Zlib::GzipReader:0x293ef20>
$ ruby-1.9.0 gzipreader_io_test.rb
gzipreader_io_test.rb:16:in `new': not in gzip format (Zlib::GzipFile::Error)
from gzipreader_io_test.rb:16:in `<main>'
Zlib::GzipReader から io.read が呼ばれていない。
# zlib.c:
static VALUE
gzfile_read_raw_partial(VALUE arg)
{
struct gzfile *gz = (struct gzfile*)arg;
VALUE str;
str = rb_funcall(gz->io, id_readpartial, 1, INT2FIX(GZFILE_READ_SIZE));
Check_Type(str, T_STRING);
return str;
}
static VALUE
gzfile_read_raw_rescue(VALUE arg)
{
struct gzfile *gz = (struct gzfile*)arg;
VALUE str = Qnil;
if (rb_obj_is_kind_of(rb_errinfo(), rb_eNoMethodError)) {
str = rb_funcall(gz->io, id_read, 1, INT2FIX(GZFILE_READ_SIZE));
if (!NIL_P(str)) {
Check_Type(str, T_STRING);
}
}
return str; /* return nil when EOFError */
}
static VALUE
gzfile_read_raw(struct gzfile *gz)
{
return rb_rescue2(gzfile_read_raw_partial, (VALUE)gz,
gzfile_read_raw_rescue, (VALUE)gz,
rb_eEOFError, rb_eNoMethodError, (VALUE)0);
}
rb_rescue2 の r_proc は第2引数に errinfo が渡る。これを試してみる。
# zlib.diff
--- ext/zlib/zlib.c Fri Mar 9 17:14:18 2007
+++ ext/zlib/zlib.c.new Fri Mar 9 17:00:45 2007
@@ -112,7 +112,7 @@
static void gzfile_close _((struct gzfile*, int));
static void gzfile_write_raw _((struct gzfile*));
static VALUE gzfile_read_raw_partial _((VALUE));
-static VALUE gzfile_read_raw_rescue _((VALUE));
+static VALUE gzfile_read_raw_rescue _((VALUE, VALUE));
static VALUE gzfile_read_raw _((struct gzfile*));
static int gzfile_read_raw_ensure _((struct gzfile*, int));
static char *gzfile_read_raw_until_zero _((struct gzfile*, long));
@@ -1755,11 +1755,11 @@
}
static VALUE
-gzfile_read_raw_rescue(VALUE arg)
+gzfile_read_raw_rescue(VALUE arg, VALUE errinfo)
{
struct gzfile *gz = (struct gzfile*)arg;
VALUE str = Qnil;
- if (rb_obj_is_kind_of(rb_errinfo(), rb_eNoMethodError)) {
+ if (rb_obj_is_kind_of(errinfo, rb_eNoMethodError)) {
str = rb_funcall(gz->io, id_read, 1, INT2FIX(GZFILE_READ_SIZE));
if (!NIL_P(str)) {
Check_Type(str, T_STRING);
$ ruby-1.9.0 gzipreader_io_test.rb [:read, 2048] -- stack frame ------------ 0000 (00C70020): 00000004 0001 (00C70024): 00000005 0002 (00C70028): 00c28398 0003 (00C7002C): 00c281e8 0004 (00C70030): 00000004 0005 (00C70034): 00000001 0006 (00C70038): 00000004 0007 (00C7003C): 00c25c08 0008 (00C70040): 00c281e8 0009 (00C70044): 00000004 0010 (00C70048): 00000001 <- lfp <- dfp -- control frame ---------- c:0004 p:---- s:0011 b:0011 l:000010 d:000010 CFUNC :new c:0003 p:0073 s:0007 b:0006 l:000005 d:000005 TOP gzipreader_io_test.rb:16 c:0002 p:---- s:0002 b:0002 l:000001 d:000001 FINISH c:0001 p:---- s:0000 b:-001 l:000000 d:000000 ------ --------------------------- -- stack frame ------------ 0000 (00C70020): 00000004 0001 (00C70024): 00000005 0002 (00C70028): 00c28398 0003 (00C7002C): 00c281e8 0004 (00C70030): 00000004 0005 (00C70034): 00000001 0006 (00C70038): 00000004 0007 (00C7003C): 00c25c08 0008 (00C70040): 00c281e8 0009 (00C70044): 00000004 0010 (00C70048): 00000001 0011 (00C7004C): 00000004 0012 (00C70050): 00000001 0013 (00C70054): 00000004 0014 (00C70058): 00000001 0015 (00C7005C): 00000004 0016 (00C70060): 00c23b38 0017 (00C70064): 00c23c10 0018 (00C70068): 00000004 0019 (00C7006C): 00000001 0020 (00C70070): 00c23b38 0021 (00C70074): 00001001 0022 (00C70078): 00000004 0023 (00C7007C): 00000001 0024 (00C70080): 00000004 0025 (00C70084): 00000001 0026 (00C70088): 00000004 0027 (00C7008C): 00000001 <- lfp <- dfp -- control frame ---------- c:0011 p:---- s:0028 b:0028 l:000027 d:000027 CFUNC :inspect c:0010 p:---- s:0026 b:0026 l:000025 d:000025 CFUNC :write c:0009 p:---- s:0024 b:0024 l:000023 d:000023 CFUNC :read c:0008 p:0024 s:0020 b:0020 l:000019 d:000019 METHOD gzipreader_io_test.rb:10 c:0007 p:---- s:0016 b:0017 l:000016 d:000016 FINISH c:0006 p:---- s:0015 b:0015 l:000014 d:000014 CFUNC :method_missing c:0005 p:---- s:0013 b:0013 l:000012 d:000012 CFUNC :initialize c:0004 p:---- s:0011 b:0011 l:000010 d:000010 CFUNC :new c:0003 p:0073 s:0007 b:0006 l:000005 d:000005 TOP gzipreader_io_test.rb:16 c:0002 p:---- s:0002 b:0002 l:000001 d:000001 FINISH c:0001 p:---- s:0000 b:-001 l:000000 d:000000 ------ --------------------------- -- stack frame ------------ 0000 (00C70020): 00000004 0001 (00C70024): 00000005 0002 (00C70028): 00c28398 0003 (00C7002C): 00c281e8 0004 (00C70030): 00000004 0005 (00C70034): 00000001 0006 (00C70038): 00000004 0007 (00C7003C): 00c25c08 0008 (00C70040): 00c281e8 0009 (00C70044): 00000004 0010 (00C70048): 00000001 0011 (00C7004C): 00000004 0012 (00C70050): 00000001 0013 (00C70054): 00000004 0014 (00C70058): 00000001 <- lfp <- dfp -- control frame ---------- c:0006 p:---- s:0015 b:0015 l:000014 d:000014 CFUNC :method_missing c:0005 p:---- s:0013 b:0013 l:000012 d:000012 CFUNC :initialize c:0004 p:---- s:0011 b:0011 l:000010 d:000010 CFUNC :new c:0003 p:0073 s:0007 b:0006 l:000005 d:000005 TOP gzipreader_io_test.rb:16 c:0002 p:---- s:0002 b:0002 l:000001 d:000001 FINISH c:0001 p:---- s:0000 b:-001 l:000000 d:000000 ------ --------------------------- DBG> : "gzipreader_io_test.rb:16:in `new'" DBG> : "gzipreader_io_test.rb:16:in `<main>'" This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information. [BUG] cfp consistency error - call0 ruby 1.9.0 (2007-03-05) [i386-mingw32]
io.read は呼ばれたけど落ちた。
2007-03-10 [長年日記]
_ [Ruby] 可視性 (ruby-1.9)
send は public なメソッドは呼べるけど private, protected なメソッドは呼べない。
funcall は public, private なメソッドは呼べるけど protected なメソッドは呼べない。
protected が分からない。
class C
def him
end
public :him
def you
end
protected :you
def me
end
private :me
end
require 'test/unit'
class TC < Test::Unit::TestCase
def setup
@i = C.new
end
#
# send
#
def test_send_him
y { @i.send(:him) }
end
def test_send_you
n { @i.send(:you) }
end
def test_send_me
n { @i.send(:me) }
end
#
# funcall
#
def test_funcall_him
y { @i.funcall(:him) }
end
def test_funcall_you
n { @i.funcall(:you) }
end
def test_funcall_me
y { @i.funcall(:me) }
end
private
def y(&b)
assert_nothing_raised(&b)
end
def n(&b)
assert_raise(NoMethodError, &b)
end
end
Rails は send も protected も使いまくってる。うー。
_ [Rails] benchmark (rails for ruby 1.9)
最低限動くようになったので benchmark をとってみた。
# Linux can.moriq.com 2.6.12-2.3.legacy_FC3smp
まず AR のみ。AR の benchmarks を元に書いた。
# sqlite3-ruby select (n=1000) ruby-1.8.6: 2142 req/sec ruby-1.8.6: 2153 req/sec ruby-1.9.0: 2313 req/sec ruby-1.9.0: 2328 req/sec
# activerecord -> sqlite3-ruby select (n=1000) ruby-1.8.6: 1098 req/sec ruby-1.8.6: 1103 req/sec ruby-1.9.0: 801 req/sec ruby-1.9.0: 806 req/sec
次に dispatch 以降全体。railsbench を元に書いた。
gem をなるべく使わない環境を用意。
- vendor/rails (rails:freeze:gems)
- rake on site_ruby
- rubygems on site_ruby
- sqlite3-ruby on site_ruby
Music model: schema としては genre:int column だけ持つ。 実際の record はひとつもない状態で計測。
musics は scaffold Music で作った controller。 musics/index は paginate limit 20 だけど record がないのであまり影響しない。
----------------------------------------
Time: Sat, Mar 10 2007 15:27:28 +0900
Ruby version: 1.8.6
user system total real
load environment 0.730000 0.090000 0.820000 ( 0.820679)
/musics/index 0.810000 0.120000 0.930000 ( 0.928919)
----------------------------------------
Time: 2007-03-10 14:32:31 +0900
Ruby version: 1.9.0
user system total real
load environment 1.120000 0.090000 1.210000 ( 1.222148)
/musics/index 0.670000 0.120000 0.790000 ( 0.795256)
n=100 なので n/real では
1.8.6: 108 req/sec 1.9.0: 126 req/sec
次に
rake db:fixtures:load
として record を 2 個置いた (genre は null)。
----------------------------------------
Time: Sat, Mar 10 2007 16:21:56 +0900
Ruby version: 1.8.6
user system total real
load environment 0.740000 0.090000 0.830000 ( 0.825608)
/musics/index 1.040000 0.130000 1.170000 ( 1.173964)
----------------------------------------
Time: 2007-03-10 16:20:53 +0900
Ruby version: 1.9.0
user system total real
load environment 1.100000 0.120000 1.220000 ( 1.216180)
/musics/index 0.840000 0.110000 0.950000 ( 1.039765)
1.8.6: 85.2 req/sec 1.9.0: 96.2 req/sec
_ KaracriBoard
成型機監視にエスアイ創房さんの KaracriBoard を購入。
# u.rb:
require 'socket'
socket = UDPSocket.new
socket.connect('192.168.0.200', 20000)
while request = gets.chomp
socket.send(request, 0)
begin
response, addr = socket.recvfrom(128)
p response
rescue
p $!
end
end
$ ruby u.rb 1 hello "1 HELLO TK0040A v1.00 MyCpuName 192.168.0.200 0004b9xxxxxx H 1234.000" 1 din "1 DIN 000000 0000" 1 din "1 DIN 100000 0000" 1 ain "1 AIN 1023 1023 1023 1023 0 0" 1 ain "1 AIN 1023 1023 1023 2 0 0"
楽しす。
2007-03-12 [長年日記]
_ register calling convention
Delphi の register calling convention を Ruby/DL で扱いたいという話なのだけど難しいよね。
_ [Rails] benchmark: activesupport が怪しい
# sqlite3-ruby select (n=1000) ruby-1.8.6: 2142 req/sec ruby-1.8.6: 2153 req/sec ruby-1.9.0: 2313 req/sec ruby-1.9.0: 2328 req/sec
# activerecord -> sqlite3-ruby select (n=1000) ruby-1.8.6: 1098 req/sec ruby-1.8.6: 1103 req/sec ruby-1.9.0: 801 req/sec ruby-1.9.0: 806 req/sec
と興味深い結果を得たのだけど、どうも activesupport が怪しい。
# sqlite3-ruby select (n=1000) with require 'active_record' ruby-1.8.6: 1936 req/sec ruby-1.8.6: 1931 req/sec ruby-1.9.0: 1550 req/sec ruby-1.9.0: 1565 req/sec
require するだけでこのありさま。
vendor/builder/blankslate.rb で Kernel.method_added Object.method_added を書き換えてるのが効いてるのかも。
少なくとも特化命令は有効。
module Builder BlankSlate = ::BasicObject
にしてみたけど、変わらないなあ。なんだろう。
計測の結果、次のライブラリを require すると速度低下が顕著。
- builder
- core_ext
- dependencies
- reloadable
- deprecation
- multibyte
ってほとんど全部なんだけど。
でも benchmark に影響するのはなんでかなあ。 Benchmark.measure 自体が影響を受けているのだろうか。
# benchmarks/bm3.rb:
require 'benchmark'
RUNS = 1000
require 'sqlite3'
$:.unshift(File.dirname(__FILE__) + '/../lib')
require 'active_record'
$VERBOSE = nil
File.delete "test3.db" rescue nil
db3 = SQLite3::Database.open( "test3.db" )
db3.execute "create table foo (a,b)"
db3.execute "insert into foo values (1,2)"
db3.execute "insert into foo values (3,4)"
db3.execute "insert into foo values (5,6)"
puts
puts "queries"
runtime = Benchmark.measure do |x|
RUNS.times do
db3.execute "select * from foo"
end
end
puts "Rehearsal"
puts "Runs: #{RUNS}"
puts "Avg. runtime: #{runtime.real / RUNS}"
puts "Requests/second: #{RUNS / runtime.real}"
runtime = Benchmark.measure do |x|
RUNS.times do
db3.execute "select * from foo"
end
end
puts "Runs: #{RUNS}"
puts "Avg. runtime: #{runtime.real / RUNS}"
puts "Requests/second: #{RUNS / runtime.real}"
db3.close
_ 青画面
IRQL_NOT_LESS_OR_EQUAL STOP: 0x0000000A (0XCDCDCD,0x00000002,0x00000001,0x804DDC9A)
これに引っかかったのかなあ。
2007-03-15 [長年日記]
2007-03-18 [長年日記]
_ Puppet
OSC2007 (1日目) で聴講した 16-B2B-4 オープンソースによるシステム管理の自動化。 ぱぺっと。Rubyで書かれていてむちゃ流行ってるらしい。良さそう。けどストヤンは知らなかった。
こういうのは何ツールて言うんだろう。
Puppet is a system configuration tool. Puppet is an open-source next-generation server automation tool.
_ Hinemos
OSC2007 (1日目) で聴講した 16-7A-5 Hinemosでできる!今日から始める運用管理。 ひねもす。未だMRTGな人なのでNagiosとか使えるようになりたいと思っていた。興味深い。
_ [Rails] Rails 勉強会@関西 第7回
Rails for Ruby 1.9。一般受けしなさそうなネタをどうしようかと思って、ユーザから見て気になるであろう Ruby 1.9 の変更点を紹介してみた。 時間が余らなくて良かった。 発表資料。 Ruby 1.9 の売りは速度のほか何があるだろう。 組み込み breakpoint があると嬉しいかも。 rake が動かないバグは GC.stress で見つかるかもしれない (znz さんの示唆)。
氏久さんの int service は夢が広がりんぐ (上記 int.jitor.net)。
モバイル通信兵さんの発表は実用度が高い。 BackgrounDRb と組み合わせたい。
2007-03-25 [長年日記]
_ [本] 市立図書館
DB勉強会参加したい! てことでRDBMSの基礎を学ぶ一冊。
比喩が楽しい。 こんなところに萌え要素。
闘うのはオプティマイザだが、武器はユーザが事前に提供しなくてはならない。……現実には、ほとんどのユーザは自分が武器を提供しなかったにも関わらず、戦いに敗れた者だけを責めている。オプティマイザが喋れるなら、さぞかし不満を述べるに違いない。(p.83)
オプティマイザ萌えー。
今、我々は教師としてSQLを通してオプティマイザに宿題を出すのである。……しかし現実はどうであろうか? 立場は教師であるが、それにふさわしい行動をとっている人はほとんどいないのではないだろうか。あまりに多くの宿題を出すと、学生が辛いのではと心配していないだろうか? データベースが可哀想に思えて、自分が直接宿題をしていないだろうか?(p.84)
_ [Rails] BackgrounDRb
BackgrounDRb いいね。win32 でも動くし。 単純な fork を実現する定石ぽい手順を紹介する。
時間のかかる処理を行うアクションがあるとする。 この処理をユーザが待つ必要はなく、バックグラウンド処理しても構わない類のものとする。
# app/controllers/board_controller.rb:
def post
@school = School.find(params[:id])
# ここで時間のかかる処理を行う...
redirect_to :action => 'index', :id => @school
end
時間のかかる処理を BackgrounDRb のワーカスレッドに置くことができる。
# app/controllers/board_controller.rb:
def post
@school = School.find(params[:id])
# worker を作ってすぐ戻る
MiddleMan.new_worker(:class => :post_worker, :args => { :id => @school.id })
redirect_to :action => 'index', :id => @school
end
# lib/workers/post_worker.rb:
class PostWorker < BackgrounDRb::Rails
def do_work(args)
@school = School.find(args[:id])
# ここで時間のかかる処理を行う...
ensure
kill()
end
end
処理コードを切り貼りするだけである。 ワーカスレッドでの ActiveRecord の呼び出しも問題ない。
対応する test も分離しよう。 functional test での MiddleMan は mock で置き換える。
# test/mocks/test/backgroundrb.rb:
class MiddleMan
def self.new_worker(opts={})
'dummy'
end
def self.get_worker(key)
'dummy'
end
def self.delete_worker(key)
true
end
end
これは Rails 流の mock 実現法であり、 test/mocks/ が vendor/ より先に探索されることを利用している。
# vendor/plugins/backgroundrb/init.rb: require 'backgroundrb'
test 環境では この require で test/mocks/test/backgroundrb.rb が読み込まれるわけだ。
do_work に移した処理に対応する test コードを worker test に移す。
# test/functional/board_controller_test.rb:
def test_post
room = rooms(:fuzoku_school)
post 'post', :id => room.id
assert_response :redirect
assert_redirected_to :action => 'index'
#assert_equal 1, ActionMailer::Base.deliveries.size
end
# test/unit/post_worker_test.rb:
class PostWorkerTest < Test::Unit::TestCase
fixtures :rooms
def setup
@middleman = BackgrounDRb::MiddleMan.instance
@middleman.set_sleep 0.05
@middleman.start_timer
@middleman.gc! Time.now
end
def test_post
room = rooms(:fuzoku_school)
job_key = @middleman.new_worker(:class => :post_worker, :args => { :id => room.id })
sleep 0.1 while @middleman.get_worker(job_key)
# 以降に do_work の test を記述
assert_equal 1, ActionMailer::Base.deliveries.size
end
end
ここでの setup は BackgrounDRb 自体の test を参考にした。 kill() されると @middleman.get_worker が nil になるので、それまで sleep して待つ。 test では do_work(args) を直接呼んでもいいかもしれない。
2007-03-30 [長年日記]
_ BGM Driven Development Environment
ゲーム脳+TDD
red/green bar を聴覚変換してみる。
- (テスト書き)
- Red Bar: BGM=バトル
- (実装)
- Green Bar: BGM=フィールド
- (リファクタリング)
autotest だとフック書けるから簡単。
2007-03-31 [長年日記]
_ [Apollo] EInvalidPointer on ruby-1.8.6
require 'phi' Phi::Point.new(1, 2)
ruby 1.8.5 (2007-03-13 patchlevel 35) [i386-mswin32] no error
ruby 1.8.6 (2007-03-13 patchlevel 0) [i386-mswin32] EInvalidPointer
うー
_ [Apollo] わかりました
Turbo Delphi Explorer でデバッグ。
@DynArrayClear
なるほど。動的配列の解放でこける。
function Phi_new_item(argc: integer; argv: Pointer; This: Tvalue): Tvalue; cdecl; var args: array of Tvalue; begin SetLength(args, argc); args := argv; acap := dl_String(args[0]);
だとまずい。
function Phi_new_item(argc: integer; argv: Pointer; This: Tvalue): Tvalue; cdecl; var args: Pvalue; begin args := argv; acap := dl_String(args^); inc(args); dec(argc);
ださいなあ。



# MoonWolf [RSSのURLが間違っているようです。 moriq.rdfではなくindex.rdfでは?]
# moriq [おおっ間違ってますね。直します。 ご指摘ありがとうございます。]