K.Sasada's Home Page

Diary - 2004 November

研究日記

霜月

_30(Tue)

あかん、寝てしまった。


class C
  def initialize
    p :C
  end
end

C.new

が通った。やれやれ。


class C
  def initialize
    p :C
  end

  def to_s
    "hoge"
  end
end

p "ab#{C.new}cd"

もとおった。やれやれ。

ちなみに、rb_yield はまったく考慮していない。どうしようかなあ。


(1..1000000).each{|e|
  # e
}

--
      user     system      total        real
ruby  0.406000   0.000000   0.406000 (  0.407000)
yarv  0.359000   0.000000   0.359000 (  0.359000)
(1..1000000).each{|e|
  e
}

--
      user     system      total        real
ruby  0.500000   0.000000   0.500000 (  0.516000)
yarv  0.359000   0.000000   0.359000 (  0.359000)

やっぱ遅いっすよ、現在のブロックローカル変数参照方法。

しかし、yield 遅いなー。今回はこの高速化諦めようかなあ。あんまり意味の無さそうな基本命令列の最適化で勝負するか。


#!/usr/bin/ruby
# -*- mode: ruby -*-
# $Id: nestedloop-ruby.code,v 1.4 2004/11/13 07:42:22 bfulgham Exp $
# http://www.bagley.org/~doug/shootout/
# from Avi Bryant

n = 16 # Integer(ARGV.shift || 1)
x = 0
n.times do
    n.times do
        n.times do
            n.times do
                n.times do
                    n.times do
                        x += 1
                    end
                end
            end
        end
    end
end
# puts x

      user     system      total        real
ruby 11.985000   0.000000  11.985000 ( 12.298000)
yarv  4.578000   0.000000   4.578000 (  4.753000)

うーむ。速くなんない。python は現状の ruby の 5倍は速いんだが。うーん。yield 遅すぎ。


super どうしようかなぁ。大切だよなぁ。でも、付けるの面倒だよなぁ・・・。うーん。


やられた。hoge = huga で、hoge=(huga) だった場合、hoge= の返り値じゃなくて huga が返り値になるのか。a[x]=y では、必ず y が返る。代入だと思えば、自然な仕様だが、脳内でメソッド呼び出しに変換している自分には、必ずしも嬉しい仕様ではない。

class C
  def a=(x)
    nil
  end
end

p(C.new.a= 3)
#=> 3

というか、どうやって実装すればいいんだこんなの。スタックマシンで。

見ないふりをするってのはどうかなぁ。どうせ殆どの場合、引数がそのまま返り値になるんだしー。・・・駄目かなぁ、やっぱり。

現状は

a[x] (op)= y

eval a    # a
eval x    # a x
dupn 2    # a x a x
send :[]  # a x a[x]
eval y    # a x a[x] y
send op   # a x a[x]+y
send []=  # a x a[x]+y

なんだけど、

a[x] (op)= y

putnil    # _
eval a    # _ a
eval x    # _ a x
dupn 2    # _ a x a x
send :[]  # _ a x a[x]
eval y    # _ a x a[x] y
send op   # _ a x a[x]+y
copyto 3  # a[x]+y a x a[x]+y
send []=  # a[x]+y ?
pop       # a[x]+y

みたいにしないと駄目かなあ。うーん、かっこ悪いなあ。

とりあえず現状は何もしないでおこう。


Language ShootOut を見ていて思ったんだけど matrix benchmark | The Computer Language Shootout Benchmarks の Python と Ruby の比較は明らかに不当だろう。ruby も narray 使わせて欲しいなあ。標準じゃないから駄目ってことだろうか。これに勝つためだけにでも入れて欲しいなあ(無茶)。

_まつもと(Wed Dec 01 00:24:10 JST 2004)

 numarrayは標準添付じゃないですよ。

_ささだ(Wed Dec 01 17:45:26 JST 2004)

 そうなのですか。contribute する人の数の違いということでしょうかね。

_まつもと(Wed Dec 01 19:33:20 JST 2004)

 だれかがsubmitすればいいのだと思います

_29(Mon)

自己嫌悪。


このパッチは失敗。

Index: eval.c
===================================================================
RCS file: /src/ruby/eval.c,v
retrieving revision 1.733
diff -u -r1.733 eval.c
--- eval.c	26 Nov 2004 04:50:36 -0000	1.733
+++ eval.c	29 Nov 2004 02:35:54 -0000
@@ -18,6 +18,27 @@
 #include "util.h"
 #include "rubysig.h"
 
+
+/******************************************
+/* for YARV
+ ******************************************/
+int yarvIsWorking = 0;
+VALUE (*yarvFuncPtr_yarv_yield)   _((VALUE val));
+VALUE (*yarvFuncPtr_yarv_funcall) __((VALUE recv, ID mid, int n, ...));
+int   (*yarvFuncPtr_yarv_block_given_p) ();
+
+void yarv_setup(void *p1, void *p2, void *p3){
+  yarvFuncPtr_yarv_yield         = p1;
+  yarvFuncPtr_yarv_funcall       = p2;
+  yarvFuncPtr_yarv_block_given_p = p3;
+}
+
+#define IS_YARV_WORKING()  (yarvIsWorking)
+#define YARV_YIELD         (*yarvFuncPtr_yarv_yield)
+#define YARV_FUNCALL       (*yarvFuncPtr_yarv_funcall)
+#define YARV_BLOCK_GIVEN_P (*yarvFuncPtr_yarv_block_given_p)
+
+
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
@@ -901,7 +922,8 @@
     struct tag *prev;
     int blkid;
 };
-static struct tag *prot_tag;
+struct tag *ruby_prot_tag;
+#define prot_tag ruby_prot_tag
 
 #define PUSH_TAG(ptag) do {		\
     struct tag _tag;			\
@@ -4448,9 +4470,14 @@
 int
 rb_block_given_p()
 {
+  if(IS_YARV_WORKING()){
+    return YARV_BLOCK_GIVEN_P();
+  }
+  else{
     if (ruby_frame->iter == ITER_CUR && ruby_block)
-	return Qtrue;
+      return Qtrue;
     return Qfalse;
+  }
 }
 
 int
@@ -4806,7 +4833,12 @@
 rb_yield(val)
     VALUE val;
 {
+  if(IS_YARV_WORKING()){
+    return YARV_YIELD(val);
+  }
+  else{
     return rb_yield_0(val, 0, 0, 0, Qfalse);
+  }
 }
 
 VALUE
@@ -5810,25 +5842,35 @@
     va_dcl
 #endif
 {
-    va_list ar;
-    VALUE *argv;
-
+  va_list ar;
+  VALUE *argv;
+  VALUE ret;
+  
+  if(IS_YARV_WORKING()){
+    VALUE val;
+    va_init_list(ar, n);
+    val = YARV_FUNCALL(recv, mid, n, ar);
+    va_end(ar);
+    return val;
+  }
+  else{
     if (n > 0) {
-	long i;
+      long i;
 
-	argv = ALLOCA_N(VALUE, n);
+      argv = ALLOCA_N(VALUE, n);
 
-	va_init_list(ar, n);
-	for (i=0;i<n;i++) {
-	    argv[i] = va_arg(ar, VALUE);
-	}
-	va_end(ar);
+      va_init_list(ar, n);
+      for (i=0;i<n;i++) {
+        argv[i] = va_arg(ar, VALUE);
+      }
+      va_end(ar);
     }
     else {
-	argv = 0;
+      argv = 0;
     }
 
     return rb_call(CLASS_OF(recv), recv, mid, n, argv, 1);
+  }
 }
 
 VALUE

え、eval ってよく使うの?


うーん、7 reduce/reduce conflict。どうしたもんだか。


結局 conflict 回避はあきらめた。


Cell キター。

_28(Sun)

というわけで、やっと

def getproc &b
  b
end

def m
  yield
end


pr1 = pr2 = nil
l = 0
m{
  i = 1
  m{
    j = 2
    m{
      k = 3
      pr1 = getproc{
        [l, i, j, k]
      }
    }
    
    m{
      k = 4
      pr2 = getproc{
        [l, i, j, k]
      }
    }
    j = :block_2
  }
  i = :block_1
}

l = :loc
pr1.call.concat pr2.call

が通るようになりました。いや、とても単純なミスだったわけですが。


def m &b
  
end

p m{}
#=> #<Proc:0x00000000@t.rb:7>

バグ?


def m &b
  b.call
end

i = 0
while i<100000
  i+=1
  m{}
end



--
      user     system      total        real
ruby  3.063000   0.156000   3.219000 (  3.453000)
yarv  0.421000   0.000000   0.421000 (  0.438000)
def m &b
  yield
end

i = 0
while i<100000
  i+=1
  m{}
end



--
      user     system      total        real
ruby  2.047000   0.157000   2.204000 (  2.344000)
yarv  0.344000   0.000000   0.344000 (  0.375000)

eval.c にパッチあてて、直接 yarv メソッド呼べるようにしてるんだけど、どうにもうまくいかない。素rubyメソッドとyarvメソッドとかがいろいろ混ざってるから。それから、似たような全然違う処理もいろいろ必要。困ったもんだなあ。

_27(Sat)

# ruby/fileutils/test_fileutils.rb
test_pwd:
if have_drive_letter?
    cd('C:/') {
      assert_equal 'C:/', pwd()
    }
    assert_equal cwd, pwd()

自宅には c:\ が無いんです。残念。


るびま、って「Rubyを啓蒙」とか「世に知らしめる」とかいうことを目的としなきゃいけんかったのか? うーん、困ったな、そういうことは全然考えてなかったんだよな。るびまに変な記事を書くと、「Rubyってキモイ」とか言われるのかもしれない、ということか。まぁ、露出している部分(目立つ部分)で評価が決まるのは、しょうがないのかもしれないなぁ。

困ったなぁ。


何が言いたかったかというと「キモイ」の判断(要するに「何が会の目的に添っており、何が沿っていないか」とか、「内輪」である、という判断とか)は、人によっていろいろあるので、厳密にするには、お遊び要素を入れることは不可能になるんじゃないかと。


sheepman さんのとこで知った好き好きLaTeX2e は凄いいいですね。


添え字が萌え時に見えてしまった。もうだめだだめだ。


本屋にげんしけん(5)を買いにいったんだけど売ってなかった。残念。


どうにも、世間一般で言われている(らしい)ほどギター侍は面白くないと思うんだよな。切腹って言われても、先に言っていたネタとリンクしてないし。まぁ、あの形態ならしょうがないかもしれないけど。


そういえば今日は SICP読書会だったんだ。いろいろ終わっていないので行かなかったんだけど、行きたかったなあ。

_お節介な人(Sat Nov 27 13:43:00 JST 2004)

「日本Rubyの会」が発行しているのだから、会の目的に添ったそれなりの配慮は必要ですよね。啓蒙は会の目的にないのでいいとして、発行するものが利用者や開発者の支援になっているかどうかは 気にすることが期待されている と思います。

「変な記事」については、たとえ記名記事であっても、編集部がその筆者にそういう趣旨で記事を依頼して、上がってきた原稿を編集して記事として載せた時点で、「その媒体がその記事をよしとして載せる判断をしたのだ」と読者は考えますよね。それではうまくないような記事は、編集時に特に断り書きを付けて載せたり、筆者が個人のウェブサイトで公開したりすればいいんじゃないでしょうか。

Ruby Magazineには、そして日本Rubyの会にも、長い目で見て期待しています。スタッフのみなさんは優秀な方ばかりなので、編集部、発行所という立場とその役目について今以上に意識されると、さらに良い結果につながると思います。

_たかはし@今日も職場(Sat Nov 27 14:56:10 JST 2004)

 あんまり変な記事やキモい記事があるのは困りますが、いまくらいの分量だと1号に1つくらいは毛色の違う記事があった方がいいんじゃないでしょうか。私見では、あんまり立場を意識しすぎると必要以上に萎縮してつまんなくなったり、発行自体が自己目的化しそうなので、しばらくは「天然」で作っていくのもいいかと考えています。

_ささだ(Sat Nov 27 15:48:21 JST 2004)

 Rubyist Magazine です。「編集部がその筆者にそういう趣旨で記事を依頼して」依頼はしてますけど、どちらかというと「これ載せようぜ」という提案頂くことが多いです。まぁ、そういう提案されたものは変なものであることは(まだ)ないんですが。でも、せっかく書いてくれたものを reject するのは大変心苦しいですね。

_ささだ(Sat Nov 27 15:50:07 JST 2004)

 今のところ発行自体が目的ですねえ。少なくとも私の中では。

_26(Fri)

yarv の現状ですが、

def getproc &b
  b
end

def m
  yield
end

m{
  i = 1
  m{
    j = 2
    m{
      k = 3
      getproc{
        p [i, j, k]
      }
    }
  }
}.call

こんなコードで腐ります。つまり、環境の切り替え(スタック -> ヒープ)が全然うまくいっていないのです。

で、直った。


yarv の現状ですが、

def getproc &b
  b
end

def m
  yield
end

pr1 = nil
pr2 = nil

m{
  i = 1
  m{
    j = 2
    m{
      k = 3
      pr1 = getproc{
        p [i, j, k]
      }
    }
    m{
      k = 4
      pr2 = getproc{
        p [i, j, k]
      }
    }
  }
}

pr1.call
pr2.call

こんなコードで腐ります。つまり、環境の切り替え(スタック -> ヒープ)が全然うまくいっていないのです。


ちなみに、こんなコードは Ruby2.0 では動きません。いや、動くんだけど意味が変わります。


一時限目というのは眠い。眠すぎ。


なんというか、先生の授業がつまらん、という話は聞くが。学生の反応がつまらん。なんというか、正直聞く気がない人に教えるのはつまらんなぁ。


経費を計算しろ、という指令があったのでしてみると、30万強。これだけ立て替えてるんだから貯金もなくなるよな。

さて、この金額は高いのか安いのか。本当はもっと使って作業を効率化したほうがよかったのかも。新しいノートPC とかね。


歯を磨きながら溜まっている ruby-talk を眺める。たくさんあるなあ。


self を使わない、ローカル変数を使わない、などの条件があれば、フレーム作る必要ないんだなあ。どれくらい適用できるんだろうか。

_25(Thu)

nokadaさん鮮やかだなぁ。私はスレッドとか考えてたよ。


ライセンスなんて嫌いだうわーん。

いや、俺が馬鹿なだけです orz


もう、るびまは一日一時間、だなぁ。ああ、もう俺の馬鹿。

るびまについて、真剣に考えてくれる人が、結構いる。大変ありがたい。私はそれに答えることができるんだろうか。


まつけんすごいなー。


ちょっと気分がクサクサしてるので(カレンダーを眺めて orz)、昨日の A Study of Exception Handling and Its Dynamic Optimization in Java を見る。IBM 東京基礎研だろうか。2001 年だから、古い。というか、前見たことがあるような気がしなくもないけれど、まぁいいや。

概要:言語処理系の例外処理機構(スタックまき戻し型言語を考える)の最適化には、stack unwinding 最適化と stack cutting 最適化があり、それぞれ例外のないパスを最適化するか、例外があったときの処理を最適化するか、である(現在の Ruby は後者・YARV は前者)。どちらも最適化するような方式はなかったので、彼らは Exceeption-Directed Optimization (EDO) を提案した。フィードバックによる最適化で、(1) 例外パスプロファイリングによる hot exception の検知 (2) hot exception の catch 処理をインライン化 (3) hot exception の throw 命令にあたるものを明示的な制御命令 (jmp?) に変更する、という 3 つの仕組みにより提供される。これにより、例外の発生しないプログラムでも速度低下は起こらず、例外が頻発するプログラムでは 18.3 % の速度向上が達成できた。

概要だけ見て中身が大体わかるってのは、いい論文だなぁ。こうありたいものだ。

で、Java で例外ってのはどうやって使っているのかっていう統計のまとめ、か。SPECjvm98 ってどれくらい一般的なんだろう。


ところで、Ruby って例外どの程度頻発するものなんでしょうか。再帰と例外でループ書く人って居る?


prolog って prologue の意味になるのね。知らなかった。誤植だと思ったのに。


インタプリタをプロファイルしてインタプリタ構成を最適化する(手法は Schemeインタプリタにおける仮想マシンアーキテクチャの最適化 で述べられている方法を自動化するなど)の行い、別インタプリタとして保存するようなインタプリタ生成系は無いんだろうか。

たとえば、どっかの JAVA サーバシステムは、コードを一度全部数時間かけて全部コンパイル(JIT? AOT?) してから運用するらしいけれど。

たとえば、YARV でそれらの最適化が自動化できるようにした場合、数日 tDiary を動かしてプロファイル作って、そいつで ruby 自体を作り直して(命令融合などで、基本ブロックが全部一命令になったり)して、tDiary 専用 ruby ができたとして、そいつを動かすと、とっても速くなるんじゃないかと思うんだけれど。

・・・思うほど速くなんないかも知んないな。tDiary だと。結局文字列処理がボトルネックで。でも、C 言語ほどには速くなると思うんだけど。

まぁ、でもそういうインタプリタ自動生成系はあってもいいと思うんだけれど、誰かやってたりするんだろうか。やってなかったら、とりあえずやってみよう。プロシンにアイデアだけ書いておくか。

でも、誰でも思いつきそうだよなあ。

東工大の内山さんがそんな話をしていたような気がするけれど、趣旨は検証のほうに寄っていたし、なんか違うような気がする。ところで、PRO の発表ってどんな内容だったんだろう。聞きたかったなあ。発表資料欲しいなあと呟いてみるテスト。


って、それは AOT とどう違うんだ? といわれそう。どう違うんだろうな。なんとなく、こうやったほうが速そう、という勘なだけなんだけど。

実際、例外が絡むと AOT で本当にうまくいくのか不安ではあります。実験的って付けておいてよかった。


意外となにそれが少ない。いいなぁ いいことですね。


わーい、どうもありがとうございます。さぁ読むぞ。


PTT で見た奴とあんまり変わらないような・・・。


全国大会で YARV でなんか出せ、という指令が。何をネタにしよう。明日まで。YARV で Scheme 作りました、っていったら受けるかな。ごく一部に。

YARV で callcc の実現手法なんてどうだろう。どう考えても1月中に終わりそうにない。無難なところで「プログラミング言語 Ruby におけるメソッドキャッシング手法の検討」、ってところに落ち着けてみるか。

2ページだと、なんか書こうとしても足りんなあ。


そういえば、明日までにポインタについてなんか考えないといけないのだった。どうしようかな。嘘教えちゃまずいから、JIS X3010 でも読むか・・・。何かレジュメでも用意したほうがいいかな。

struct tag(*[5])(float)

なんて例が出ている。一生使わないんだろうなあ。

というわけで、これの解説からはじめようかな(無理)。

/* JIS X3010 P-31 */
int f(int (*)(), double (*)[3]);

どうやって読むんでしょうか、わからん。

declare f as function (pointer to function returning int, pointer to array 3 of double) returning int

sheepmanさんに教えてもらいました。世の中って便利ですね。


さて問題です。

int x, y;
x = 1;
y = 2;
/* ... */
change(&x, &y);
printf("%d, %d", x, y);

1. この結果が「2, 1」と表示されるような関数 change を作成せよ。

ヒント:

void change(int *x, int *y){
  /* ここになんか書く */
}

*名前を間違いました。change じゃなくて swap を意図してました。というわけで、swap 処理ね。

2. この問題の本学4人の学生の答案の正答率を答えよ。


しくしく。


というわけで、YARV の何をネタにしようかなー。

_shiro(Thu Nov 25 11:55:41 JST 2004)

 インタプリタ最適化、おもしろいと思うけど、そこまで手間かけるならコンパイルしちゃってもいいんじゃないってのがありそうな反応のような気もする。命令セットからかわっちゃったらもう中間コードの共有はできないし。

敢えてインタプリタにするメリットといえば、その改善されたインタプリタはテストセット以外のプログラムも走らせることができる (最適化コンパイルの場合、生成物はテストセットしか実行できないのに対して) ってことかな。だとすれば、自動最適化に使うプロファイルデータを開発元にフィードバックしてもらって、開発元でその蓄積されたデータを元に最適化かけたインタプリタを配布するようにする、っていうループを作っておくと、使う人が増えれば増える程最適化されてゆくインタプリタができるかもしれない。

ついでに、適当な確率でランダムに最適化戦略を適用した亜種を作っておいてそれもばらまき、統計的に一番良かったやつを次のリリースで採用してゆく。すると、処理系はどんどん進化していって、しまいには生成されたインタプリタが何やってるんだか作った人にもわからないのだけれど何故か速いってのができたりして。

_ささだ(Thu Nov 25 12:42:03 JST 2004)

 命令セットを拡張していくだけなので、他のが動かなくなるわけじゃないと思っています。しかし、これで「cgi用ruby」「shell script の代わりの ruby」とか、特徴づいたら面白いですねえ。

_shiro(Thu Nov 25 14:56:17 JST 2004)

 あ、命令セット云々というのは、新しいインタプリタのメリットを享受できる中間コードが元のインタプリタのコードと共有できないってことです。ソースから食わせないとならなくて、それならネイティブコードにまでコンパイルして速くしてもいいんじゃない、という意図ですな。

_ささだ(Thu Nov 25 15:02:28 JST 2004)

 なるほど、失礼しました。中間コードって書いてありますね。「コンパイルすればいいじゃん」は非常に説得力があります。で、しょーじきどうなのかよくわからない(コンパイルしたら本当に速くなるのか?)ので結構楽しみにしてます。

_24(Wed)

http://slashdot.jp/comments.pl?sid=224505&cid=656225 を読んで知ったんですが。

ScanSnap - FUJITSU Japan すげぇ。今はこんなにスキャナー速いんですね。1枚4秒・・・。速すぎる。欲しいなぁ。

MediaDrive:やさしくPDF OCR 世の中にはこんなソフトもあるんだ。いいなぁ。


うささんも言っていたけど、これだけ速くスキャンできると、いろいろと考え方が変わるような気がする。

TWAIN 非対応ということで、評判がちょっとよくないっぽいな。


しかし、これで何をスキャンするのがいいんだろうな。あんまり見ないけど、無いと困る資料。


今日のはまり。

#define PER_VALUE(type) (sizeof(type) / sizeof(VALUE))

...

OK:
#define GET_FRAME_CONTROL_BUFF_WC() (sizeof(struct vm_env_control)/sizeof(VALUE) + 1)

NG:
#define GET_FRAME_CONTROL_BUFF_WC() (PER_VALUE(sizeof(struct vm_env_control)) + 1)

PER_VALUE の定義を間違えた orz

こういうことってよくありませんか? え、俺だけ?


最近やっと gdb が便利だなあと思いはじめる。ヘルプはもっぱら http://www.asahi-net.or.jp/~wg5k-ickw/html/online/gdb-5.0/gdb-ja_toc.html などを見せてもらっていたのだけれど、自分で chm にコンパイルしていたのをたった今思い出した。

やれやれ。


さて、とりあえずバグは取れた(動いた)んだけど、実はきちんと動かない。設計のミス。さて、どうしたものやら。

具体的には、クロージャにしたときの環境の差し替え。Ruby レベルではだいたいうまくいく(まだ未実装な部分もある)のだけれど、C 関数中に yield (rb_yield)するとうまくいかない。

現在の実装では、クロージャを作る場合、環境をヒープに保存するため、スタックをさかのぼってヒープに移した環境を参照しているもののポインタを差し(指し)替えていくんだけれど、その処理が、C 関数起動のために作るスタックフレームと Rubyメソッドのために作るスタックフレームの形式が違う(caller/callee save が逆、というか、スタックにセーブしない)なので、その部分がうまくいっていない。

はてな。どうしたもんだか。

pr = nil
x.times{
  pr = proc{

  }
}

がうまくいかない。多分。

じゃぁ、といって、Ruby メソッドと同様のフレームを、C 関数を呼ぶために作ろうとすると、その構築コストがかかるので嫌。殆どの C 関数呼び出し時には、そんなフレームは要らない(たとえば、Integer#+ にはスタックフレームなんて要らない)。遅延生成にして、それ系が必要になったら(rb_yield されたりしたら)作るようにしたらいいんだろうか。まぁ、そうすれば悩まないでいいんだが。うーん。

てゆか、やっぱりきちんと揃えないと駄目か。C method-> yield -> method with block がうまくいかない。うわーん。


うーむ、yarv ではどうやっても while loop のほうが速くなりそうだなあ。困ったなぁ。


rpm とか deb とかを吐いてくれる中間表現はないのかなぁと IRC で聞いてみたところ、「そんなもん要らん」と言われた。そんなもんでしょうか。


先生におめでたい話が来たらしい。でも、私にはあんまりおめでたくない予感がする。


IPSJ 論文誌 Vol.45 No. SIG 12 (PRO 23) がきたので読む。著者省略。

■セキュリテプロトコルの略式記法から spi 計算への変換

よくわかんないのでパス。

■抽象化と精密化による実時間モデル検査の改善

よくわかんないのでパス。

しかし、これ実際のシステムで使うとして、そのパラメータの入力ってどういう形で行うんだろう。

■オブジェクト指向に基づいた構文解析機構成法の提案

よくわかんないのでパス。

構文解析機クラスの構成法、ってことか。実際、yacc などもろくに使えない私なのでわかんないんだけど、たとえば「Ruby らしい」構文解析機とか作るとしたら、どうなるんだろうね。

■曖昧な文法を扱うコンパイラ・コンパイラ

よくわかんないのでパス。

notavaCC の次論文ですか。凄いなあ。「曖昧な」という意味を知らないんですが、どういう意味になるんだろう。う、中田先生の本に書いてあるのか(参考文献)。今度調べてみよう。

opt という要素が付くか付かないか、というだけ? 基礎知識が足りなさ杉。

■型安全でない C プログラムのポインタ解析

よくわからないのでパス。

整数値をポインタ型へキャストする場合も、きちんと解析してみましょうね、ということか。組み込みっていうキーワード便利だなあ。

そういえば、先日こういうことは処理系は保証しないよね、という話をしたばっかりだった。そういえば、B1 にポインタの授業をしろ、という話があったんだけど、こんな話をするときっと大変なことになりそうだ。

形式的な解析とかの話になると、てんでわからなくなるのは駄目駄目だな。何を読んだらわかるようになるんでしょうか。

■例外処理機構を備えた命令型言語のCPS変換とその定式化

よくわからないのでパス。

しかし、たとえば Ruby を CPS に変換したとしたら、何か嬉しいことはあるんだろうか。まぁ、callcc の実装は簡単になるだろうなぁ。

こういうプログラム変換の弊害って、スタックトレースとか、デバッグとかがやりづらくなることなんじゃないかと思うんだけれど、どうなんだろう。そもそもスタックトレースなんて概念無いよな。

メッセージの send って、どうなるんだろう。特に変わりそうに無いな。例外発生の時点で、飛び先をディスパッチャでなんかするのが増えるくらいか。

そして、形式化されたプログラムの表現とか見た時点でもうダメダメなのであった。ダメダメ。なんでこういうことが考えられるのかな。もうさっぱりわかんねぇ(という苦手意識が最大の問題なような気もする)。

参考文献の A Single Intermediate Language That Supports Multiple Implementations of Exceptions と A study of exception handling and its dynamic optimization in Java は面白そう。読んでみよう。

try のコストをかけてもいいくらい、raise のコストを下げるべきだ、という論調は、いくらなんでもあんまりだと思うんだけれど。

■実行環境の変化に即応する圧縮型ガーベッジコレクション

よくわからないのでパス。

まぁ、Ruby では保守的GCにしないといけないわけだから、利用できないのではあるけれど。しかし、圧縮型って、copy GC だと思ってたけど、なんか違うっぽい。はて。copy は mark が無いから違うかな。前に理解したつもりになってたんだけど忘れてる。駄目だな、使ってない脳みそは。

ところで、世代別GCってどうなるんだろう。1.9 で入るって噂は・・・。

対象の言語を規定してるところがあるなぁ。setf って言われて最初なんのことだかわからなかった。

GC の時間を縮小することを目的としているので、compaction によるメモリ利用効率の増加は、そもそも comcaction GC の機能だから評価項目には入っていない、のか。


発表概要:

■fork システムコールを用いた並列ガーベジコレクション

これ読みたかったなぁ。ページ管理をうまく利用した GC ってことだよね。新規性が無かったのかな。

■実時間処理に適したメモリ管理を行うLisp処理系の設計と実装

気になるなあ。

■π計算に基づくプログラミング言語 Nepi のための GUI 機能

よくわからないのでパス。並列計算のどうの、だったっけ。岸本さんに聞いたような記憶が。

■ボードゲーム BAO の CCS による記述と解析

ゲーム?

■Python・Ruby 記述の分散多重スレッドプログラム用部分停止型デバッガの開発

なんか、タイトルには見覚えがあるんだけれど。概要だけ見ると、まぁできそうな気はするが、いったいどんなシチュエーションで使うのか気になる。

■ASB: A Framework for Implementating Extensible Aspect-oriented Programming Languages

英語なのでパス。元の議論もよくわかっていないので。

■不定元をを含むストリーム計算の実現

あーもー全然わかんないのでパス。

無限ストリームの計算を・・・うーん? gamb というのを用いるのがなんか凄いの?


というわけで、今回も私の無知を晒すだけになってしまった。


今切実にほしいと思うもの。

  • 彼女

は、あまりにベタなので、

  • 論文を読んで議論する場

本当に切実にほしい。たとえば、研究会に行っても、なかなかそういう機会はないし。そもそも、海外だと行けないし、英語の論文を読んでもこっちも質問できないしな。

だから、yarv-dev はなんというか、とてもすばらしいところ。

世の博士課程の人々は、どうやってんだろう。やっぱり一人で頑張ってるんだろうか。

コンパイラは俺一人だからなぁ・・・。俺が後輩の育て方を間違えたか。でも、無理やりやってもしょうがないしなぁ。そもそも、SMT + compiler という人は日本人で居るんだろうか。

_おだか(Wed Nov 24 00:34:53 JST 2004)

 とりあえず書類は全部電子化してペーパーレスに…便利そうだけど大量にスキャンしちゃうと管理が面倒くさそう。

_23(Tue)

朝起きたらもう歯痛は治っていた。健康って素晴らしい。歯医者さんありがとう。


block 受け渡しのためになんか変なことするのをやめようかなぁ、と考えている。一個 if文が増えるけど、現状ではそんなところは気にする人居ないような気がするので。

・・・と思ったけど、5% の性能低下。こりゃまずいなぁ。


rb_funcall に直接手を加えない、と昨日書いたけど、やっぱり手を加えることにする。initialize が呼べないってあり得ないし。

  1. ruby/eval.c が yarvcore.so に依存
  2. ruby/eval.c にパッチつけると面倒
  3. デバッグが面倒(いちいち ruby 作り直さないといけない)

なのを気にしていたんだけど、まぁしょうがないのでなんとかすることにする。

_22(Mon)

1000000.times{|i|
  i
}


--
      user     system      total        real
ruby  0.547000   0.000000   0.547000 (  0.547000)
yarv  0.390000   0.000000   0.390000 (  0.391000)

while loop よりも遅くなっちゃった orz。

どうしたもんかな。


むぅ。PUSH_TAG が時間かかっとる。全体の実行時間の 10%。どうしたもんかな。


しかし、やっぱり eval loop の再帰は遅いなー。スタックのセットアップに凄い時間かかってる。


1000000.times{|i|
  i
}


--
      user     system      total        real
ruby  0.562000   0.000000   0.562000 (  0.562000)
yarv  0.250000   0.000000   0.250000 (  0.266000)

なんとかインチキして速くしてみた。インチキって言っても別に何かさぼってるわけじゃないけど。いや、正確にはさぼってるな。ブロックパラメータがないブロックに引数つきで yield するとこける。上の例では、times{...} だとこける。まぁ、それはとりあえずいっか。

あと、これは yield する側の協力が必要。具体的には、Integer#times はこんな感じ。

/* Integer#times */
VALUE yarv_Integer_times(VALUE num){
  if (FIXNUM_P(num)) {
    long i, end;
    
    end = FIX2LONG(num);

    if(yarv_is_working()){
      /* yarv specific speedup tech */
      VALUE th = yarv_get_current_running_thread();
      VALUE val;
      thread_yield_light_prepare(th, 1, &val);
      for(i=0; i<end; i++){
        val = LONG2FIX(i);
        thread_yield_light_invoke(th, 1, &val);
      }
    }
    else{
      for (i=0; i<end; i++) {
        rb_yield(LONG2FIX(i));
      }
    }
  }
  else {
    VALUE i = INT2FIX(0);

    for (;;) {
      if (!RTEST(yarv_funcall(i, '<', 1, num))) break;
      yarv_yield(i);
      i = yarv_funcall(i, '+', 1, INT2FIX(1));
    }
  }
  return num;
}

ホットスポットになりそうな処理には、こんなふうに書けば速くなりますよ、という感じ。記述はちょっと複雑になってるけど、ちょっと速くなるから、ホットスポットだけ我慢してね、というスタンス。yarv_yield も用意したけど。だから、open なんかは yarv_yield をそのまま使う。組み込みライブラリのイテレータ系はこういうの使えばいいんじゃないかしらん。


ちなみに、rb_funcall 自体は遅い(yarv_yield くらい)ので、これは高速化しようが無いような気がする。どうしよう。なんとかならないものか。まぁ、全部 yarv になれば、PUSH_TAG が速くなるような気がするので、全体的にもうちょっと速くなる気はする。まぁ、rb_funcall なんて(ホットスポットで)あんまり呼ばないよね。そういうことにしておこう。


歯が痛い歯が痛い歯がまた痛い・・・。


とりあえず、基本っぽいことはやったことにして、次はお楽しみの最適化をもっと考えていこう。というわけで、統計情報を取ろうと思うのだけれど、どうやって取ろうかなあ。結構困る。

命令の使い方の統計は、まぁいいとして、とりあえず命令順序をバイグラムで取ってみようか。

で、あとベンチマークだよな。shootout からもう少し拝借するか。


現状では、自分で YARV 用に拡張ライブラリを作り直さないと、いろんなプログラムが動かない。eval.c の rb_yield などにパッチをあててしまえば一気に動く(かもしれない)のだけれど、面倒なのでしない。

これで、prot_tag が公開されれば、ruby にパッチあてないでもいいんだけど。


バグバグー。どうしようかなあ。


歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い歯が痛い。

朝起きたらとても痛い。


考えてみると、initialize は rb_funcall から呼ばれるじゃないか。うーん。


幸い歯医者さんに診てもらえたんだけど、麻酔が抜けてきてまた痛む・・・。あーうー・・・。


歯が痛くて、何もできない。何にも集中できない。やばいなー。


yarv の設計上のミス発見。とてもやばい。どうしたもんだか。なんというか、全体に複雑すぎるんだよな。

_び(Mon Nov 22 21:34:45 JST 2004)

 歯医者へ行くべし。歯はちゃんとしないと、入れ歯になるぞ、若い身空で。

_しゅどう(Tue Nov 23 00:06:12 JST 2004)

 複雑さは根性でゴリゴリ克服だー! :-P

_ベ(Tue Nov 23 10:28:05 JST 2004)

 「どんな複雑なものでも必ず単純になる。単純なものこそ本質的だ」 by 高橋秀俊

_21(Sun)

やはり、あれだけ長いと反応がない。反応のしようがない、というか。


キャッシュ効率を上げるために、constant pool みたいなものを用意したほうがいいのかなぁ・・・。うーん、凝りすぎて駄目な気がする。


mswin32 で例外が動かなくなった。なんでだろう。わからん。

rb_inspect までもがエラーを吐くようになった。で、cygwin-gcc では平気。

どうやってデバッグすればいいんだこんなの・・・。


cygwin gdb すげぇ。VC の吐いたコードをきちんとデバッグできる。行番号とかは出ないけど、関数名がバックトレースに出てくれた。


例外が発生した後、rb_funcall を呼ぶと死ぬらしい。なんでじゃー。せめて、例外発生の行数が出ればいいんだけど。


なんというか、例外は無理やりやってるんでこうなるよなぁ、というバグ。結局 VC の IDE でデバッグしました。リンク時、ruby に -debugtype:both を付けたらデバッグ情報出た。

#define PUSH_TAG(ptag) do {            \
  _tag = *ruby_prot_tag;               \
  _tag.prev = ruby_prot_tag;           \
  _tag.frame = ruby_frame;             \
  _tag.tag  = ptag;                    \
  ruby_prot_tag = &_tag;               \
} while(0)

なんか、ますますダメダメに。混ぜるな危険。


やっと closure が動いた orz 手間取りすぎ。

def m &b
  b
end

pr = m{
  a = 1
}
i=0
while i<1000000
  i+=1
  pr.call
end

--
      user     system      total        real
ruby  4.313000   0.015000   4.328000 (  4.500000)
yarv  0.953000   0.000000   0.953000 (  0.984000)

参考:
def m &b
  b
end

pr = m{
  a = 1
}
i=0
while i<1000000
  i+=1
#  pr.call
end

--
      user     system      total        real
ruby  0.844000   0.000000   0.844000 (  0.860000)
yarv  0.312000   0.000000   0.312000 (  0.312000)

いろんなチェックを抜かしてるから、まだまだどんどん遅くなるはず。

というわけで、proc のテスト作るか。バグバグぽ・・・。


ちょっと 本棚.org を見てみる。荻野さんあの量は凄いよブラクラだよ。

しかし、この仕組みは面白いよねえ。

ということで、二匹目のどじょうを探してみる。

  • 冷蔵庫.org 冷蔵庫の中身を公開。誰かがオススメレシピを紹介してくれたりくれなかったり
  • 物置.org 地域ベースで公開することで、「あれを持っているのはあの人だ、借りに行こう」とかできたり
  • 食器棚.org 銀食器とかの自慢?
  • キッチン.org 包丁自慢?
  • 引き出し.org 文房具一覧とかになるんだろうか。
  • 玄関.org 何を載せるんだ、何を。
  • 押し入れ.org 布団自慢?
  • 郵便箱.org メール関連サービスと間違えられそうだ。そもそも何を載せるんだろう。
  • 靴箱.org あんまり量はできそうにないよな。靴マニアってどれくらい要るんだろう。
  • 箪笥.org 洋服自慢。コスプレ衣装自慢になりそうな予感。

箪笥はよさそうなので、ちょっと作ってみようかなあ。でも、amazon ではやってないので、あさましくなれなさそう。


def iter
  yield
end

def getproc &b
  b
end

loc1 = 0
pr1 = iter{
  bl1 = 1
  getproc{
    loc1 += 1
    bl1  += 1
    loc1 + bl1
  }
}

pr2 = iter{
  bl1 = 1
  getproc{
    loc1 += 1
    bl1  += 1
    loc1 + bl1
  }
}


i=0
while i<1000000
  i += 1
  pr1.call
  pr2.call
end

--
      user     system      total        real
ruby 10.453000   0.172000  10.625000 ( 11.141000)
yarv  2.203000   0.000000   2.203000 (  2.235000)

まぁまぁ速い。いや、ただ単に足し算が速くなっただけかな・・・。

def iter
  yield
end

def getproc &b
  b
end

def m a
  a
end

loc1 = 0
pr1 = iter{
  bl1 = 1
  getproc{
    m loc1
    m bl1
  }
}

pr2 = iter{
  bl1 = 1
  getproc{
    m loc1
    m bl1
  }
}


i=0
while i<1000000
  i += 1
  pr1.call
  pr2.call
end

--
      user     system      total        real
ruby 10.422000   0.031000  10.453000 ( 10.922000)
yarv  2.625000   0.000000   2.625000 (  2.703000)

うーむ。

そういえば、Proc からの return の話は考えてなかったな。どうしよう。

Cメソッド呼び出しにブロックが渡せないので、その辺が壊滅的な予感。どうしようかなあ。うーん、どこに積めばいいんだろう。うーん・・・。


そういえば、super やってないな。まぁ、いいか。

とりあえず Array#each と Fixnum#times ができるようにしよう。yarv 版と取り替えたいような気もするんだけど、なんとかならないかなあ。うーん。

_shiro(Sun Nov 21 20:04:32 JST 2004)

 Cメソッド内でのブロックの評価はトランポリンでやるの?

_ささだ(Sun Nov 21 21:06:52 JST 2004)

 結局面倒なんで、eval の再帰でやります。そうしないと拡張ライブラリ作るの面倒になっちゃうので。

_20(Sat)

池田さん主催飲み会。大変たのしゅうございました。

西田さん(OpenCobol)、川合さん(OSASK)、守口さん(去年ユース)、Zebさん(Ruby好き)、奈良さん(LDAPとか)、増田さん(元中川研)など。


日高さんの指摘は非常にもっともですね。どうしやう。

recv.m1(b, c, d).m2(e, f, g)
#=>
b
c
d
e
f
g
recv
send m1
send m2

って、順番違うじゃん。やっぱり、

e
f
g
b
c
d
recv
send m1
send m2

になるかー。さて、「気持ち悪い」という感覚はわかるけれど、これで困るケースは書くだろうか。

hit = ''
"str".gsub(/.../){|hit| ...}.
      gsub(/...#{hit}.../){...}

みたいな時に困る・・・かなあ。

やっぱ優先順位気にするようなコーディングはまずいんじゃないかなあ。


(c = C.new).m = c

こんなコードがかけなくなる(c は nil)んだけれど、さてこれは許していいんだろうか(いいんだろうなぁ、Ruby 的には)。

(a = 1).times{|i|
  ...
}

なんてのも、探せば出てきそうだなあ。って、これはいいのか。


まぁ、机上の空論なんで、速くなってからもう一度考えよう。

とりあえず駄目そうな例引き続き募集中です。まつもとさんが言語仕様を説明するときに嫌な気分になる、というのは結構説得力のある反論ですが、実際問題どうだろうな、と。前者のみならば、高速化の度合いによっては許してくれそうな雰囲気なので。

そうか、俺が積まなければとても遅くなる VM を作ればいいのか!(駄目だってば)


速くなる理由だが、スタックキャッシュをすると、recv がレジスタに乗ることになるから、速くなる。

メソッド呼び出しには、必ず self を必要とするが、そのためにはレジスタに乗っていたほうがアクセスは速そうだ。キャッシュ効率もよさそうだし。

他にも細々とした理由はあるんだけど省略。case/when で swap が要らなくなるとか。でも、これは手間の問題で、あんまり本質的じゃないな。


現在VMのレジスタは、pc, sp, lfp, dfp, cfp という5つを用意しています。で、これは callee save。あんまり具体的には違わない(レジスタ退避は send 命令中で行うので)のだけれど、c function を呼び出すときには明示的にセーブするわけではないので callee ということにしておく。

(仮想)レジスタにしておくメリットは、そのレジスタが必要になったときに高速にアクセスできるかもしれないということ。コンパイルの結果によっては、高速じゃなくなるときもある。

デメリットは、メソッド呼び出し、復帰時にその値の保存、復帰が必要になる、ということ。たいてい、メソッドの呼び出し時には、新しい値をどこかに書き込まなければならないため、レジスタでもそうでなくてもあんまり変わらないのだけれど(マシンレジスタにその仮想レジスタが割り当てられた場合は書き込みは速い)、メソッドから返る時、つまり C言語風に言うと return 、yarv の命令だと end 時にそのレジスタの値の復帰が必要になる。

そのため、どちらにするかは注意深く決めるべき課題であるような気がする(スタックフレームの作り方もこれに強く依存するため)。つまり、よくアクセスする値ならば、多少の復帰のコストを考えないで仮想レジスタとして用意してやるほうが有利で、そんなにアクセスしなさそうなら、仮想レジスタにする意味はない。というか、有害。

現状の5つは、多すぎるんだろうか。ちなみに、見てわかるように、self をあらわす値は無さそうである。というか、無い。これは、上記用意したレジスタよりも、self のアクセス頻度が少ない、と私が見積もったから。

さて、これは本当だろうか? きちんと統計とって見ないとなぁ。

あと、本当に速くなるか、という問題。

lfp はローカル変数にアクセスするために使う。lfp[x] で、x番目の Ruby のローカル変数にアクセスする(本当は lfp[-x])。アセンブラに落としたものを考えてみると、lfp は C のローカル変数にアクセスされていたとして、

mov ebx, sp[どっか]
mov eax, ebx[-x]

なんてコードになりそう(オペランドとかすげーいい加減)。

ここで、cfp によって間接アクセスさせてみる。lfp = cfp[lfp_idx]; local(x) = lfp[-x] となるわけだ。

mov eax, sp[どっか]   # cfp
mov ebx, eax[lfp_idx] # lfp
mov eax, ebx[-x]      # local(x)

こんな感じ(またいい加減)。

さて、lfp, dfp を削ることによって、cfp がレジスタに割り当てられてたらどうなるだろう。esi あたり?

mov ebx, si[lfp_idx] # lfp
mov eax, ebx[-x]     # local(x)

となる。

もちろん、レジスタのタクサンタクサンなマシンを使えば、仮想レジスタ全部を物理レジスタに割り付けてくれたようなコードを吐いてくれるかもしれないけれど、メインターゲットの x86 を考えると・・・。まぁ、cfp を物理レジスタ割り当てしてくれるかっつうと結構疑問なんだけどさ。

スタックキャッシングのために、これから仮想レジスタは2個増える予定なので、悩まないといけない事柄ではあります。まぁ、少なくとも dfp (ブロックローカル変数へアクセスするためのポインタ)は self よりアクセス回数少なそうだよな。


sp じゃなくて、bp なような気もするなぁ。で、e が抜けてる。


スタックキャッシングのための仮想レジスタ2つも退避する必要があるのは大変だなぁ。どうしよう。

parrot は 32個の仮想レジスタセットが複数セットあったと思ったけど、どうやってんじゃろうなあ。まぁ、必要なのだけ退避、なんだろうけど。

yarv では、仮想レジスタ退避のために一命令動かしたら、そっちのディスパッチコストのほうがかかりそうだし。


  1. プログラムはループを高速化するべきである。
  2. ループの中では変数アクセス(ローカル・ブロックローカル)を多発しそう
  3. これらをできるだけ高速にする必要がある

という話は、ありそうではありますが・・・。ループの中でもメソッド起動は多発しそうなんだよなぁ。

やっぱ、計ってみないとわかんねーや。


そういえば、四捨五入して30になりました。


VC でのコンパイル結果。getlocal(i) (i 番目のローカル変数を得る)。

   VALUE val; /* return variable */
   ulong idx = GET_OPERAND(1);
thread_eval_body+f2:   mov      ecx, DWORD PTR [ebp-24]
                       mov      edx, DWORD PTR [ecx+04h]
                       mov      DWORD PTR [ebp-136], edx
   DEBUG_ENTER_INSN(""getlocal"");
   ADD_PC(1+1);
                       mov      eax, DWORD PTR [ebp-24]
                       add      eax, 0x8h
                       mov      DWORD PTR [ebp-24], eax
 {
   val = *(GET_LFP() - idx);
                       mov      ecx, DWORD PTR [ebp-136]
                       shl      ecx, 0x2h
                       mov      edx, DWORD PTR [ebp-4]
                       sub      edx, ecx
                       mov      eax, DWORD PTR [edx]
                       mov      DWORD PTR [ebp-140], eax
   /* footer */
   PUSH(val);
                       mov      ecx, DWORD PTR [ebp-20]
                       mov      edx, DWORD PTR [ebp-140]
                       mov      DWORD PTR [ecx], edx
                       mov      eax, DWORD PTR [ebp-20]
                       add      eax, 0x4h
                       mov      DWORD PTR [ebp-20], eax
   END_INSN();
                       jmp      thread_eval_body+2dcb

うえぇ、全部マシンスタックに変数など退避してるよ・・・。

gcc。

   VALUE val; /* return variable */
   ulong idx = GET_OPERAND(1);
thread_eval_body+1ae9: mov      ebx, DWORD PTR [ebp-276]
                       mov      eax, DWORD PTR [ebx+04h]
   DEBUG_ENTER_INSN(""getlocal"");
   ADD_PC(1+1);
                       add      ebx, 0x8h
                       mov      DWORD PTR [ebp-276], ebx
 {
   val = *(GET_LFP() - idx);
                       shl      eax, 0x2h
                       mov      edi, DWORD PTR [ebp-284]
                       sub      edi, eax
                       mov      eax, DWORD PTR [edi]
   /* footer */
   PUSH(val);
                       jmp      thread_eval_body+19ee

...
thread_eval_body+19ee: mov      edx, DWORD PTR [ebp-280]
                       mov      DWORD PTR [edx], eax
                       add      edx, 0x4h
                       mov      DWORD PTR [ebp-280], edx
   END_INSN();
                       jmp      thread_eval_body+210

あんまり変わんないけど、gcc だときちんと局所最適化(レジスタの使い回しとか)やってるなぁ。

cl:  CFLAGS   =  -MD -Zi -O2b2xg- -G6 
gcc: CFLAGS   =  -g3 -O2  

cl でも、Og- が付いてるくらいで、こんなような最適化を阻害することはやってないんだけどな。というわけで、cl はそもそも性能が悪い、ということか。cl は VC6.0 のやつです。そもそも、こんなでっかい関数のコンパイルはもともと苦手ということかも。八杉さんがそんなこと言ってたなあ・・・。

icc でも動いたりするのかなあ。

_19(Fri)

Ruby でレシーバを先に評価しないと困る、という自然な例を募集。無理やり作ればいくらでも出てくるが、そんなの誰もシネーヨ! という気がするので。

recv.method(arg1, ..., argN, *arg_splat, &arg_block)

の場合、

arg1, ..., argN, *arg_splat, &arg_block, recv

の順、というわけです。

いくら考えても、思いつかない。あ、2項演算子はなしで。


VTune、Linux プログラムのリモート解析を確認。cygwin gcc でできることを確認(gcc -s ではまった)。


http://www.scirus.com/srsapp/ 知らなかったのでメモ。


lfp, dfp について再考。もしかしたら、dfp は全然使わない(アクセスしない)のかもしれんなぁ・・・。

それよりも self をレジスタにしたほうがいいんだろうか・・・。


なーんか、偉い時間かかったけど、やっと Proc オブジェクトが作れたような気がする。気だけ。

Proc#call できるようにしないと。

_hdk(Fri Nov 19 18:11:30 JST 2004)

 メソッドチェインすると評価順序に困りませんか?

_18(Thu)

わーい、Matz にっきにるびまの紹介が載った。でも、「るびまっ」ではないです。

で、一番必要なのは全体の進捗管理だったりする。ゴメン、俺が不甲斐ないばっかりに・・・。

ちなみに、順調に遅れつづけてはいるのだけれど、想定範囲。


ET2004 行ってきたんだけど、あんまり得るものはなし。言語処理系の話は全然ないしな。営業ばっかりで、技術的な話は聞けなかったし(聞かなかった、というのもある)。


そういえば、コンパイラとバーチャルマシンを読み終わり。日本語ってのはイイネ。内容はたいしたこと書いてないけど、まぁ最初の一冊にはいいんじゃないでしょうか。日本語は堅いけど、内容が詰め込んで「ない」ので読みやすいし。

最後の章がひじょーーーに中途半端、というか消化不良。その辺は期待しちゃいけない(論文読め、でいいんですか・・・)。

まぁ、いろいろ復習にはなりました。データフローグラフの作り方とか。

でも、ruby でデータフローグラフを作って最適化って出来るんだろうか。副作用の可能性があるので、ループ不変式抽出なんてあんまりできそうにないし・・・。たとえば、

while i < max + 3
  ...
  i+=1
end

なんてのがあったとき、max+3 は不変式なのか?


ついでに(なんの) VTune を買う。けっこう清水の舞台から飛び降りる感じで。木山さんにだまされました。


凄いのだけれど、危険ソフトウェア指定だ。これは。ベンチマーク猿になる(それだけで一年終わってしまう)。


ちょっと動かしてわかったのは、結構処理時間がかかっていたのは、実は operand のフェッチは結構重かった、ということ。おっもしろいなぁ。命令ディスパッチは結構重い。


う、これ Celeron だから Pen4 の PMC ないんだ orz 。キャッシュのヒット率とかわかるのかなー・・・。わかんねーだろうなぁー。でも、そのためにプロセッサ変えるのも癪だな。


わかったらしい。凄いぞ Celeron 1.4GHz。


しかし、BTB miss を、なんで mov 命令がやってんだ? マイクロオペコードがそういうのなのか、バグなのか(そもそもそんなパフォーマンスカウンタねーよ、だったりして)。

_17(Wed)

require 'win32ole'
obj = WIN32OLE.new('com.sun.star.ServiceManager')
puts obj.ole_methods

#=>
Exception `RuntimeError' at t.rb:6 - Failed to GetTypeInfo
    HRESULT error code:0x80004001
      実装されていません
t.rb:6:in `ole_methods': Failed to GetTypeInfo (RuntimeError)
    HRESULT error code:0x80004001
      実装されていません	from t.rb:6

どうしろと。

require 'win32ole'
srv = WIN32OLE.new('com.sun.star.ServiceManager')
ref = srv.createInstance('com.sun.star.reflection.CoreReflection')
dtp = srv.createInstance('com.sun.star.frame.Desktop')
args = []
doc = dtp.loadComponentFromURL("private:factory/swriter", "_blank", 0, args)
txt = doc.getText
cur = txt.createTextCursor
txt.insertString cur, "Hello OOo with Win32OLE", false

おお、なんか動いたぞ。

しかし、impress で ppt を pdf に変換するにはどうすればいいんだろう。


dim args1(1) as new com.sun.star.beans.PropertyValue
args1(0).Name = "URL"
args1(0).Value = "file:///F:/Documents%20and%20Settings/ko1/My%20Documents/hoge.pdf"
args1(1).Name = "FilterName"
args1(1).Value = "writer_pdf_Export"

dispatcher.executeDispatch(document, ".uno:ExportToPDF", "", 0, args1())

こんな感じらしいんだが。はて。どうやるんじゃろ。

なんか、頑張れば出来そうな気はする。


明日 ET2004 に行きます。農工大で探して見つかるブースに居ると思います。でも髭はありません。


Proc#call の実装が思い浮かばない。ふつーの、VM loop の再帰でいいんだろうか。もちろん、それは必要だから、やらなければならないんだが、Proc#call も同じ仕組みでいいんだろうか。うーん。

C call から帰ってくると、その返り値をスタックに push するので、この動作が余計、ということになる。しかし、他のパスを用意しようとすると、分岐が一個増えることになる。

def m(&b)
  b.call
end

#=>
案1:

eval_loop:
  C function call:
    eval_loop:

案2:
eval_loop:
  C function call:
  exec next PC

スタックトップの値として、本来環境として設定しなければいけないものを返すってのも手だな。なんかそれが良さそうな気がしてきた。これで行くか。あー、しかし、ローカル変数とかのリストアなどを全部行わなければならないんだなぁ。面倒だなあ。まぁ、しょうがないかなぁ。

send insn:
  if(method is C function){
    call_C_function(method)
    restore_regs()
  end

1+1 のたびにレジスタをリストアするのはなんかイヤン。

send insn:
  if(method is C function)
    call_C_function(method)
    if(thread_info->require_regs_restore?)
      restore_regs()
    end
  end

メモリアクセスが2回に分岐が一回。1+1 のたびにこれをやるのか。どうしようかなあ。


C で実装されたメソッドを呼び出すとき、VM の状態について気にしなければならないのは以下の場合。

  1. C のメソッドが ruby メソッドを呼ぶ場合
  2. C のメソッドが VM の状態を変化させたい場合

前者は呼び出し前に環境の退避しなければならない。後者は、変化した環境に追随しなければならない。

さて、どうしたもんかな。

そもそも、VM のレジスタの値は、すべてメモリに書き込まなきゃいけないのかもなぁ、とは考えている。例外の関係で、いつ longjmp されるかわからんから。ただし、PC と SP だけは頻繁に変わるのでしない。

ちなみに、VM loop をもう一度呼ぶというのは、結構コストがかかる。でも、面倒だからとりあえずこれを可能にしておくか。

でも、結局メモリアクセスを10回くらいするだけで済みそうだな(setjmp 一回と、その他)。

あー、setjmp 嫌だなぁ。

でも、rb_yield もきっとそんなような処理になりそうなので、きちんと作っておかないと駄目か。うーむ。


とりあえずコストのことは後で考えて、どんなに遅くても動くものを先に作ってしまうほうがいいか。

とか言うと、ずっとそのままの実装になってしまったり。でも、もっと他の部分で高速化したほうがいいような気もする。


control_frame という名前と continuation_frame という名前を使っているので、cont と略せません。どうしましょう。


やってしまった orz

コミットせずに家に帰ってしまった・・・orz

なんてこった・・・。明日は学校行かないのに。


三角形 ABC(左回りに頂点を振る)があって、角Bを表現したいとき、角ABC とは書くが、角CBA と書くのは駄目なような気がする。

さて、これは must not なのか、should not なのか? 中学一年生の数学らしい。ネットで探しても見つからなかった。駄目だったような気がするんだけどなあ。

_kjana(Wed Nov 17 21:52:37 JST 2004)

 ctrl と cont?

_shiro(Thu Nov 18 06:22:57 JST 2004)

 ベンチ重要。メモリアクセスはキャッシュに載ってるかどうかで数十倍違うから、回数だけ数えてもあれだし。

_16(Tue)

      a = 
c	hogehoge
     *1 + 2

	print *, a
	end

valid かー・・・。

_15(Mon)

Rubyist Magazine 0003号 リリースしました。

お楽しみください。


ジョナサンでコードをある程度書いた。ちょっと進んだ。

2時ごろ行ったんだけど、近所の奥様方なのか、集団で居た。そうか、平日のこの時間のファミレスってのはこういう光景なんだな。


それなりに頑張ってるんで、るびまはもっと宣伝したいんだけど、どうやればいいんだろうか。

スラッシュドットに載った創刊号は凄かったんだけど、スラドに出るたびに垂れ込むのもアレだしなぁ。

何かいい手はないものか。下手に考えるよりも、Matz にっきが一番影響力がありそうな気もする。

_shiro(Mon Nov 15 14:30:17 JST 2004)

 C十字軍。C十字軍。C十字軍。

_14(Sun)

まつもとさん綺麗にまとめてるなぁ。この能力が Ruby が長く続いた秘訣じゃなかろうか。


やらなきゃいけないことは明確になったので、それをどうやって進めていくか、の具体的な検討に入れるわけですね。


if(cond){
  なにか1
}
なにか2
if(cond){
 なにか3
}

なにか1,2,3もそれぞれ10行以上。cond の比較がこれだと2回。

if(cond){
  なにか1
 なにか2
 なにか3
}
else{
 なにか2
}

これだと分岐は少ないけど、冗長(なにか1,2,3はそれぞれ10行以上)。

さて、どう書くのが綺麗か。

いや、method 起動の部分なので、これだけ気を使ってるんだけど、そもそも他にもっともっと重い処理をしているんで、こんなところで悩んで進まないのは何か負けっぽい。とりあえず動くようにしてから考えるか。


どーにもバグが消えない。メソッド起動の部分なんだけどね。どうしたもんだか。もう一度最初から作り直してみるかなあ。

あと、yield と super と zsuper と、結構重複する部分があるんだけど、それをどうするか、ってのも面倒な問題なのだよね。関数分ければ簡単だけど、関数コールのコストは嫌だし、コンパイラのインライン化に期待するのも、期待できないプラットホーム(具体的には開発に使っている VC6)にはきついし。

別ファイルに書いて include するかなぁ。汚いなあ。

マクロにすると、面倒だしなあ。


そういえば、super の arity を知るにはどうすればいいか、気になってたんだよな。list がもうちょっと落ち着いたら聞いてみよう。

_向井(Sun Nov 14 23:55:54 JST 2004)

 なにか1〜3を関数として書いて後者とか。で、そういう時に関数内関数とかを使いたくなったりしませんか。

_ささだ(Mon Nov 15 00:02:26 JST 2004)

 関数にすると速度がどうの、って話を後ろに。

_向井(Mon Nov 15 01:24:11 JST 2004)

 ありゃ、失礼しました。

_ynakata(Mon Nov 15 14:47:56 JST 2004)

 どうしても速度に拘るんでなければメンテナンス性を考えて当然前者なんでしょうけどねえ。

_ささだ(Mon Nov 15 18:43:15 JST 2004)

 それは、当然だと思います。でも、速度にこだわる部分なんですよねぇ。

_13(Sat)

callcc について、30秒くらい考えてみた。ネイティブスレッド付き。

あるスレッドでキャプチャした継続を、他のスレッドで kick した場合、どうなるだろうか。

Ruby では、C の関数から Ruby のメソッドを呼ばなければならないため、継続を保存するには、マシンスタックの保存を行うことでこれを実現している。しかし、これはカーネルスレッドが一個の状況で行っているため、問題は(あんまり)起きてない。

他のネイティブスレッドになると、なんかとってもまずいようになる気がする。つまり、他のカーネルスレッドに他のマシンスタックの状態をべたっと貼り付けることになるから。さて、どうすればいいんでしょうか。

継続の再開は、実行していたマシンスタックじゃないといけない、などの制限を付ける、というのが妥当か。しかし、そのカーネルスレッドがすでに死んでたらどうなるんだろう。リファレンスカウンタでも付けて、死なないようにするのかなあ。


今週の ruby quiz を考えてみていたんだけど、数式の正規化がきちんとできるかどうか、なんだと思う。で、それをやるのはなんか面倒だったので放置。

あ、memoir をちゃんとやるにはって話で。

数値の集合をちょっとずつ大きくしていって、すべての組み合わせを保存していけばいいのかなあ。

実は、計算結果でハッシュしていったほうがいいんだろうか。

あー、それだと近似値は出ないな。


[ruby-dev:24805] の akr さんへの返信に、「だからこれから検討していくべきでは」というような内容の返信を書こうとしていただけれど、それならどうする、という内容を提案しないと、あんまり意味の無いような内容になってしまうと思うので、削除。

そもそも、いきなり「組織化」ということを言っている卜部君に対して、「そもそも何を目的として組織化するのか。目的をはっきりしないと危険である」という警鐘を akr さんが鳴らしているのではないかと思うので、私が何か言っても蛇足にしかなさそうである。

では、どうすればいいか、はもっとじっくり考えないと(私は馬鹿なので)なかなか思いつかないので、当分 dev には返信できません。

こんなところでダラダラ書いているのは、dev とかに投げないのは無視しているから、じゃなくて考えてるけど妙案が出ないのよゴメン、という言い訳。


しかし、上の継続の話、寝る前に書いたので文章ぐちゃぐちゃなのに、よく読んで頂いてもらって。大変感謝しております。

いや、感謝しててもアレなので、もっとまともな文章書けるようにならないと。


最近 ruby 板をよく読むようになったんだけど、そんなさっさと物事が進むわけないじゃん。急ぎすぎるのも考えものだとおもうんだけど。

話題がホットな間にすべて片付けなければならないわけではないし、落ち着いてる間もしっかりと続けていくほうが重要だし大変だし。もちろん熱いうちのほうが意見が集まったりすることもあるけれど。

そして、それを続けてきた、たくさんの Ruby に関わる(表に出て来ない人も含め)多くのボランティアの人たちをただ単に否定するような話になっちゃったりしたので(以下略)。

たとえば、「何かをしよう」と人を集めると(その話題がホットだと)それなりの人数が手を挙げてくれるんだけど、実際に長く続けてくれる人はあんまり居ないのよね。人のこと言えないんだけど。


yarv のほうが全然進まない。スランプ。コードが書けない。全然書けない。書いては消し、書いては消し、をかれこれ一ヶ月続けている。

現状の Ruby 開発よりも、こっちをやるほうが先決だった・・・。

_shiro(Sat Nov 13 08:22:07 JST 2004)

Cスタック保存による継続では、Cコードレベルで複数回リターンしてくることになるので、無制限に許すことはできないはず。継続の再開が可能かどうかをチェックするコードがあるはずなんで、その時に同一スレッドかどうかも確認したらいいんじゃない? スレッドが死なないと保証することはできないんで(予想外の事態でcancelされる場合もあるし、別スレッドからforkされると子プロセス側にはそれ以外のスレッドは存在しなくなる)、チェックはどうしても必要でしょう。

_まつもと(Sat Nov 13 11:38:28 JST 2004)

 今でも同一スレッドでしか再開できません。制限が増えるわけじゃないんじゃないかと

_ささだ(Sat Nov 13 11:43:04 JST 2004)

 continuation called across threads を確認しました。

_12(Fri)

ごめんなさいごめんなさいごめんなさい。


「日本Rubyの会」を利用する、というのはどうすればいいんだろう。

いろいろ考えてみたんだけど、「日本Rubyの会」だからできる、あるからできる、ということは思いつかなかった。

実際に、人的リソースとして機能することはできるんだろうか? 呼びかけることはできるのかな。その後に続く行動・期待される成果に結びつくのだろうか。


あて先間違えた。あぁぁ、かっこわるぃ・・・。

というか、書き途中で送っちゃったんだよな。慣れてないめーらはつらい。


"the" という単語をプログラミング言語の予約語にするとしたら、どんな使い方をするんだろうか?(http://slashdot.jp/comments.pl?sid=222579&cid=651447

  • self の代わり(うささん案)
  • グローバル変数修飾子
  • 定数修飾子

今までなんか書いてて、the という単語を使ったことがない気がするなあ。(気がするだけで、忘れてるだけかも)

_maeda(Fri Nov 12 14:37:38 JST 2004)

 Common Lispにはtheというspecial formがありますよ。(the integer x)とか。

_shiro(Fri Nov 12 19:19:03 JST 2004)

 CLのtheは書かれちゃった。個人的なプログラムレベルでは、シングルトンインスタンスを格納する変数にtheなんとかという名前を付けることがあります。(conquer *the-world*)

_11(Thu)

lock free synchoronization って何かと思って色々調べてみたら、test and set だったんだね。気づかなかった。しかし、本当にソフトウェアだけで実装できるんだろうか。


さて、私に何ができるか、考えてみないと。


うぅ、長い。


お昼ごはんを買いに行ったら、お金が足りなかった orz

_10(Wed)

今回はいろいろと遅れてしまってごめんなさい orz。

Ruby の偉い人に負担かけまくってるよ。これじゃぁ、Rubyist の支援じゃなくて、Rubyist の邪魔だよ>るびま

人的リソースは有限で、とても貴重なものだから、やはりその管理というのは大変だなぁ。管理職やっている人は、やはり凄い人たちだ。そして、無能なのがそこにいると、凄く大変だ。ごめん orz


記事の数13!(編集後記除く)

多すぎ、多すぎ。とっても嬉しくてありがたいんだけれど。

いや、記事の数が問題なのではなく、記事を書いてもらう体制が整っていないのが問題なんだなぁ。ごめん orz


人に任せるには

  • 任せられる人を探す
    • やりたい人を探す
    • やれるかどうか確認する
      • 能力は十分か?
      • 継続できるか?(これが一番重要)
  • 任せたタスクを管理する

という、また大変な作業が増えるわけで、やっぱ何かするというのは大変なんだなぁ、とか思う。

るびま程度なら、やりたい、という人に振ればあんまり問題ないけど(あんまり)、ruby 開発だと、そうはいかないんだろうなぁ。

でも、ある程度の規模を超えると、必ずしなければいけない問題なわけで。


http://slashdot.jp/comments.pl?sid=222059&cid=650406 ちょっと誤解。


検索技術に詳しい人に質問なんですが。検索対象のインデックスがあって、データを追加するごとに、インデックスをインクリメンタルに追加していくのはできそうな気がするんですが、それをある指定のデータ分だけ取り消す、というのは可能なんでしょうか。

例1:メールの検索

メールのDBがあって、検索インデックスも作った。あるメールを追加した(して、検索インデックスも更新した)が、どうやらこれは SPAM らしい。消してしまおう。インデックスから消すことはできるか?


学習技術に詳しい人に質問なんですが。学習したデータがあって、あるデータを追加するごとに、学習データをインクリメンタルに追加していくことはできそうな気がするんですが、それをある指定のデータ分だけ取り消す、というのは可能なんでしょうか。

例2:SPAM の判定

あるメールを SPAM と学習させてみたが、実はそれは SPAM じゃなかった。その学習を取り消すことができるか?


いや、IMAP の検索を、適当な速い検索システムをバックにしてやった場合、こういうのが問題になるんじゃないかなあ、と思ったもんで。


化学系やってる人に会って話をする。なんか、スゲー研究者っぽい。それに比べておれはフリーター。橋の下で暮らしてるのかといわれた。

orz

_babie(Wed Nov 10 10:38:08 JST 2004)

 ささださんがyarvに専念できるように精進します。

_shiro(Wed Nov 10 20:59:58 JST 2004)

 インデックスの作り方、学習データの作り方によるのでは? ナイーブなbayesian spam filterだと保存してるのはメッセージ数と単語の生起回数なので、特定のメッセージのみ取り除くことは可能ですね。どこかで情報の圧縮がかかるとだめなんじゃないかな。SVMとか。

_まつもと(Wed Nov 10 21:36:10 JST 2004)

 検索の方、Estraierならできます。使ってます。

_ささだ(Thu Nov 11 03:09:46 JST 2004)

 ありがとうございます。検索はちょっと思いつかないんですが、Estraier 凄いですね。

 時間ができたら、それで imapd でもちょっと作ってみたいと思ってます。

_9(Tue)

うわー、gonzui ですか。

go ではじまる魚、ってことかなぁ。

ソースコードを自分で解析するのはなんでだろう。言語ごとに既存の専用のものを使うべきな気がするんだけど。ちょっと、どうやってお金を使うか感が。

田中さんは flex が好きだったのか。

WEBRick べったりで作るとあとで困ったりしないだろうか。

西田さんのScheme の VM ってなんだっけ。前聞いたような気がするな。

ランキングってどうするんだろう?

そういえば、ソースコードをまたぐ検索をするんだっけ。そうすると、あるアプリケーションについて調べたいとき、どうするんだろう。って、書いてあるな。どうすんだろ。

多分、google.com/mac とかみたいに、アプリケーションごとの検索窓を出すとか、そうやるんだろうな。gonzui.com/ruby で rb_call0 を検索。コールグラフをうまいこと表示してくれれば便利だろうなぁ。

C++ は doxygen を使うのはどうでしょうか(釈迦に説法だな)。

検索結果は、各エントリはソースコードへのリンクで、リファレンスマニュアルなどにひっかかれば、google の右に出る広告の部分に出すといいんじゃなかろうか。


お、Fedora Core 3 が出たのか。2からアップデートってできるのかな。

まぁ、別にとくに困ってないからどうでもいいか。


quickml が出すメールが駄目駄目なのを直すのはどうするかなぁ、と思っていたんだけど、quickml が使う smtp を ofmipd にすればいいのか。以前、前田さんに紹介されたやつだけれど。

しかし、debian には mess822 のパッケージが無い。

あと、不思議だったのは、mess822 には、しょぼい 822形式のメールテキストを食わせて、ちゃんとしたものを吐く、というのが無いのね。なんでだろう。あれば便利そうなのに。

しかし、mess822 は debian では配っていない。どうしようかな。

quickml は smtp でなんかやってるから、qmail-inject を通すのは面倒だなあ、と思っていたのだけれど、一度どっかのユーザにまわして、そいつが qmail-inject すればいいのか(http://www.emaillab.org/essay/message-id.html)。でも、遅そう。ML の配送にそれはちょっと。


本当は、QuickML が valid なのを吐いてくれれば問題ないんだけど。

TMailってそこまでやったっけ。


さて、ファイルシステムは何にしようかな。


imap over ssl にしていたんだけど、いろいろと面倒なので、imap だけにして、imap over ssh にすることにする。


フォルダがたくさんあると、縦に長くてアクセスがしづらい。den8 の自由なレイアウトは、やっぱりちょっとよかったかも。


C の preprocessor は便利なのだけれど、複数行でなんかやるには向いてない。どうしようかな。ちょこっと書くかなぁ。


  • 万能FIFOL機械 和田 英一

ってなんだー。


Thunderbird、Ctrl+W で終了しちゃうのなんとかしてほしい。他のWindow なら別にいいんだけど。


MoonWolf さんのあのリストはすばらしい。どんどん議論するべきかと。

_まつもと(Tue Nov 09 12:59:47 JST 2004)

 西田くんのVMはGuile用です。完成したという話は聞いてないけど

_び(Tue Nov 09 16:50:30 JST 2004)

 FIFOL: H13年度夏のプロシン「プログラミングの鉄人」(http://www.tanaka.ecc.u-tokyo.ac.jp/prosym01/)を参照。インタプリタは http://www.sat.t.u-tokyo.ac.jp/~hideyuki/Ghostscript/fifol.html

_ささだ(Tue Nov 09 17:01:47 JST 2004)

 すみません。書き方がまずかったかもしれません。FIFOL自体は知ってるんですが、なんでこのネタを、とか、なんで和田先生が、とか。和田先生だから、かもしれませんが・・・。

_8(Mon)

そろそろ、スレッドとかシグナルとかを考えなきゃいけないのかしらん。

signal のトラップは、たとえば全ての VM loop の先頭でやると多分遅いので、バックエッジだけでやるとか、そういう工夫が要るんじゃなかろうか。

スレッドは、native thread にすればいいから問題ない。

・・・というのは多分当分先なので、同じタイミングでやればいいや。

  • pc をマイナスにするジャンプ
  • スタックフレームを積む動作

のときに、これらをチェックすればいいでしょう。多分。

で、これの簡単な実装方法だよな、問題は。いや、別にそんなに大変なものでもないんだけどさ。


前方参照とか後方参照とか書こうかと思ったんだけど、どっちが前で後ろかわからなくてやめた。


差分とか、多分、それを before/after でやるんだと思うんですが、こんなところに書いてもしょうがないか。


Celeron 2.6GHz (4万円マシン) なんて無駄だなぁ、とか思ってたら、imap 使ってると足りない足りない。まぁ、メモリがしょぼすぎるってのもあるけど。


メールストレージのバックエンドに何かDBを使うような実装ってないんだろうか。誰でも考えそうだから、多分あると思うんだけど。

無ければちょっと作ってみようかな。


はて、x86_64 な gcc で、32bit な ruby をコンパイルすることは可能だろうか。可能なような気はするんだけど、どうやるんだろう。


x86_64 上の FedoraCore2 で i386 な ruby をコンパイルする方法:

  • yum install glibc-dev.i386
  • ../ruby-1.8.2/configure --disable-install-doc --program-suffix=182-32 --prefix=/home/ko1/tmp/ruby32-install --target=i386-linux CFLAGS=-m32 LDFLAGS=-m32 DLDFLAGS=-m32
  • make

DLDFLAGS がわからずにはまった。


なんか、マジで一日中 drb を追ってた。下手なことに首突っ込むもんじゃないな。しかも、全然解決してないし orz。


あー、もうだめだ。だめだ。

dRb がトラウマになりそう。もっと最初から気合を入れて読めばよかった。該当箇所だけ見ててもこれ絶対わからん。


m2nとりあえず公開。求む人柱。

■このソフトについて

procmail とか sieve とか書き方わかんねーなー。scmail 入れるにしても、 scheme もわかんねーしなー、という人のために、Ruby でメール振り分けとかす るためのソフトウェアです。

Lens もあるんですが、私には使い方がよくわか らんかったのと、もしかしたら機能が足りないかしらん、とか思って車輪を再発 明しました。


drb 凄いんだけどなあ。デバッグ死ぬってこれ。


そうか、SC やってるのか。いいなぁ・・・。


今日も yarv に手が付かなかった。そろそろ本気でヤバイ。

_青木(Mon Nov 08 17:31:06 JST 2004)

 CC="gcc -m32" ?

_ささだ(Mon Nov 08 18:06:32 JST 2004)

 うあ、そうやるのが正しいのですか。

_こーのいけ(Tue Nov 09 06:08:11 JST 2004)

 とりあえずApache James。<DB

_ささだ(Tue Nov 09 07:11:58 JST 2004)

 imap がないですね。popd だったら db に突っ込んであってもあんまり嬉しくないような。

_こーのいけ(Wed Nov 10 02:57:29 JST 2004)

 ずぅーっと「開発中」 http://wiki.apache.org/james/JamesIMAP ってちょっと見たらDBMailなんてのもあるようで。MDAとMRAの両方ワンセットにしなきゃならないから広まらないんじゃないかな,と。

_咳(Sat Nov 13 22:56:53 JST 2004)

 DRbのデバッグは凄いですか。反応がにぶくてごめんなさい。解決してよかった。

_び(Sat Nov 13 23:38:18 JST 2004)

 "そうか、SC やってるのか。いいなぁ・・・。"<発表するならいくらでも...

_7(Sun)

サーバ弄るのは楽しいな。

ThunderBird の、新規フォルダ、新規メッセージ巡回の基準がさっぱりわからん。

courier-imap で、日本語の検索ができないのはバージョンが古いかららしい。どうやってアップデートしたもんだか。


  • testing から持ってくる
    • 他のいらんもんまでいろいろとアップデートしてしまって怖い
  • 自分でコンパイル
    • 楽だけと、アップデートが面倒
  • あきらめる
    • 日本語検索ができないままは困る気がする
  • いっそ stable をやめて testing にする
    • 公開用サーバだしなあ
  • 自分で imapd を作る
    • 出来るかそんなもん
ko1@atdot2:~$ sudo apt-get install courier-imap-ssl/testing -s
Reading Package Lists... Done
Building Dependency Tree... Done
Selected version 3.0.8-3 (Debian:testing) for courier-imap-ssl
Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.

Since you only requested a single operation it is extremely likely that
the package is simply not installable and a bug report against
that package should be filed.
The following information may help to resolve the situation:

Sorry, but the following packages have unmet dependencies:
  courier-imap-ssl: Depends: courier-ssl (>= 0.47) but 0.37.3-3.3 is to be installed
E: Sorry, broken packages

...
  courier-ssl: Depends: libc6 (>= 2.3.2.ds1-4) but 2.2.5-11.5 is to be installed
               Depends: libssl0.9.7 but it is not going to be installed
               Depends: courier-base (>= 0.47) but 0.37.3-2.5 is to be installed
...
  libssl0.9.7: Depends: libc6 (>= 2.3.2.ds1-4) but 2.2.5-11.5 is to be installed
...

libc6 を変えたら、いろいろ動かなくなりそうでイヤン。

自分でビルドするかなぁ。外に晒すサービスなので、定期的なチェックが必要だけれど、そんなのしたくないしなぁ。

どうしたもんかなあ。


結局、ビルドした。日本語検索オッケー。


unix系OSでねっとわーくでふぁいるをきょうゆうする、と言うことを私はやったことがないんですが、何が簡単かなぁ。

ネットワークファイル共有ってSMB用語なのかしらん。

nfs 系のサービスは何やってるか怖いから全部落としてたんだけど、どうしようかな。きちんと設定すれば、怖いことはないんだろうけど。

やりたいことは、ファイルの転送なので、scp でも使うか・・・。でも数とかタイミングとか大変そうなんだよな・・・。

smbmount ってできるんだろうか。


はて。smbclient はできるのに、smbmount はできない。なんでだろう。

・・・sudo してたから、username=root だったのか orz

というわけで、samba が一番楽だったと言うオチ。性能は知らん。

パーミッションがみんなおんなじで、owner がマウントした人になるのかー。なるほどなぁ。uid 指定してもかわらん・・・。まぁ読めればいいか。

というわけで、マウントできた。いっきにどかっとメール転送可能。4万通きちんとさばけるだろうか>imapd, tb


むぅ。大量に junk と認識しちゃってるな、これ。どうしたもんだか。

不思議なのは、junk マークされてないのに、junk に移動するやつ。何やってんだ? これ。


ジャンクメールの振り分けは、クライアントでやればいいや、と思ったけど、それだと複数のマシンで簡単に扱えるように imap を導入した意味がないじゃん。

というわけで、サーバになんか付けるか。ちょっと面倒くさい。


そもそもそんなに学習させてないのにフォルダ振り分けやったから駄目な気がするけどな。


  • 偉そうなことばっかり言って、何もしてねーじゃんか
  • 何も考えず行動して、やっぱり後で後悔してるんじゃねーか

やっぱり、両方必要だよな。なかなか難しい。


久しぶりに 2ch の ruby スレを見たら、ruby の速さについてなんか書いてある。

python のバイトコード処理系は、とても綺麗です。その代わり、最適化とか、あんまりやってない。

python では、Fixnum みたいなのを特別扱いしてるので、pure な部分をなくして速くしてるんだけど、それで困ったと言う話は聞かないし、多分それで問題ないんだろうなぁ、とか。

複雑な例だと速いっていうのがあったんだけど、どういう例なんだろう。ちょっと想像が付かないな。たとえば、正規表現エンジンの出来は、あるプログラムではとても効く部分ではあるけれど、そういうことを言いたいんだろうか。


自己末尾再帰の除去くらい出来ないかと考えてみる。単純に考えれば、

def fact(n, ans)
  if n <= 1
    ans
  else
    fact(n-1, ans * n)
  end
end

#=>

def fact(n, ans)
label:
  if n <= 1
    ans
  else
    n = n - 1
    ans *= n
    goto label # まぁ、C の goto があったとして
  end
end

こんなふうにしてやればよい。ような気がする。

でも、単純じゃない場合、

class Fact
  def fact(n, ans)
    if n <= 1
      ans
    else
      fact(n-1, ans * n)
    end
  end
end

class SubFact < Fact
  def fact(n, ans)
    p [n, ans]
    super
  end
end

SubFact.new.fact(10, 1)

なんてなっていた場合、困る。

メソッドコンビネーションなんてのも入れましょー、とか言っている昨今、それも困る。

さて、どうすればいいでしょう。


RHG読書会で、

def iter(&block)
  @obj.each(&block)
end

見たいなコードが速くなって欲しい、という話を聞いた。

いっそのこと、attr みたいな最適化でもいいのかもしれないな、これだったら。


手続き内限定手続きが欲しいとき、Ruby では Proc を使うけれど、Proc は遅いかもしれない。

def m
  def inner
    ...
  end
end

をすると、innerはmと同じレベルで定義されるけれど、そうじゃないほうがいいような気がするんだけど。

_shiro(Mon Nov 08 07:37:31 JST 2004)

 「自己末尾」に限定なんてやるから困るんで、tail callならとにかくフレーム廃棄ってすればいいんじゃない、と思うけど。superを呼んだ後でもフレームを削除出来ない理由があるのかしらん。

_ささだ(Mon Nov 08 07:49:38 JST 2004)

 自己末尾再帰の、「goto に変換する最適化」を考えていました。フレームの構成とは、また別ってことで。

 一般的な末尾再帰の最適化中に、自己末尾再帰のチェックを入れて、もしそうなら goto してしまう、というのが現実的か。

_shiro(Mon Nov 08 09:50:07 JST 2004)

 いや、関数コールって継続push + 引数フレームpush + gotoでしょ。で、末尾callのコンテキストでは継続pushのところがカレントフレームの破棄になるだけ。自分自身に飛ぶ場合も他人に飛ぶ場合も全く同じ。

 第一級の継続が無い言語なら、自己末尾再帰の場合は引数フレームを改めて積まないで破壊的に自分の引数フレームを更新することで若干速度が稼げるかもしれない。ただ、継続がある言語だと、末尾再帰呼び出しの引数評価の中で継続が捕捉された場合、引数フレームの破壊的変更をしていると矛盾が出る。(上のfactの例だと、nとansを破壊的に変更してるけど、例えばメソッド* の中で継続が捕捉されてて、factを抜けた後にまたその継続から実行が再開されると困る)

_ささだ(Mon Nov 08 11:23:23 JST 2004)

 はい。「一般的な末尾再帰の最適化」として、それを言っていたつもりでした。

_6(Sat)

すみません、cvs 版じゃなくて、0.8.1 でした> Gauche

scmail が cvs 版。

Testing numbers ...                                              failed.
discrepancies found.  Errors are:
test complex division: expects 0.0 => got 1.3877787807814457e-17

以外は全部パスしました>make install check

*** ERROR: unbound variable: test* というのがとてもとても謎なんですが、よくわからないので放置します。

scmail/test/scmail.scm が駄目らしいので、テストしてみると、

ko1@atdot2:~/tmp/cvs/scmail/tests$ gosh scmail.scm
Testing scmail ...
testing bindings in #<module scmail> ... ERROR: found dangling autoloads: (mail-is-spam?)
*** ERROR: unbound variable: test*
Stack Trace:

こんなふうになります。


当然、

// Download mail from all accounts on startup
user_pref("mail.check_all_imap_folders_for_new", true);

は付けてます。起動時に全てのフォルダ一覧の表示まではするんですが、新着のチェックをしてくれません。imap-ssl だから?

そのフォルダのアイコンをクリックすると、きちんと表示されるんだけれど。


ぐ、ThunderBird で、同じサーバ・同じユーザに対して複数アカウント作れないのか。なんてこった。


ssl じゃなくてもおんなじだなぁ。


すまん、user.js じゃなくて users.js にしてた orz

疑ってすまんかった>TB


起動時にしか、全部見てくれない?


(p(0); STDOUT).print(p(1), *(p(2); []), &(p(3); nil))

#=>
3
0
1
2
nil

結構辛い・・・。

_5(Fri)

thunderbird ではじめて rss を見て、駄目っぽいという感じだったので、しょうがないからちょっと対応した。


scmail を使おうとしたのだけれど、make check でエラーが出る。

しょうがないので、lens を使わせてもらうことにする。

自分でやった奴は、自分で言うのもなんだがメンテナンス大変だし。


mailread.rb というのがあるのを初めて知った。

うーん。

よくわからない。これ、本当に valid なの?


ruby-list の記事を読んで、やっと理解。でも、どこにもそんな注意書き書いてないよ・・・。

tmail 標準添付してくれればいいのに。


と思って、lens のソースを眺めていたのだけれど、ちょっと機能が足りないっぽい。

しょうがないから自作、この前まで作っていたのをもうちょっと真剣に作ってみることにする。


書いとくべきでしたね。

Testing syntax ...                                               passed.
Testing scmail.mail ...                                          passed.
Testing scmail.util ...                                          passed.
Testing scmail.config ...                                        passed.
Testing scmail.progress ...                                      passed.
Testing scmail ...                                               
*** ERROR: unbound variable: test*
Stack Trace:
_______________________________________
Testing scmail.bayesian-filter ...                               
*** ERROR:
 cannot find file "dbm/gdbm.scm" in *load-path* 
(".." "/usr/local/share/gauche/site/lib" "/usr/local/share/gauche/0.8.1/lib")
Stack Trace:
_______________________________________
  0  (%require feature)
        At line 52 of "/usr/local/share/gauche/0.8.1/lib/gauche-init.scm"
  1  (%require feature)
        At line 52 of "/usr/local/share/gauche/0.8.1/lib/gauche-init.scm"
Testing scmail.mailbox ...                                       passed.
Testing scmail-refile --dry-run ...                              passed.
Testing scmail-refile/scmail-deliver for MH ...                  make[1]:
*** [check] Error 1
make[1]: Leaving directory `/home/ko1/tmp/cvs/scmail/tests'
make: *** [check] Error 2

gauche cvs版です。

んなこたないだろう、と思ってごちゃごちゃやってみたんですが、わかりませんでした。


なかなかよいものができた。

・・・のか?

#-*-ruby-*-

##
## m2n configuration file
##
##
## This file should be copied to ~/.m2nrc.
##

##
MaildirPath = '/home/ko1/Maildir'
DefaultFolderName = nil

##
=begin

= default rules

  # move to folder
  rule(header, pattern) # folder => "${h}"
  rule(header, pattern, folder)
  rule(header, pattern, folder, <option>)

  # invoke block instead of moving to folder
  rule(header, pattern)           do |mail| ... end
  rule(header, pattern, nil, <option>) do |mail| ... end
  rule(header, pattern, folder)   do |folder, mail| ... end

  # do nothing
  rule_no_action(header, pattern)

* rule(nil, nil, ...) matchs any mail


== folder name

* 'folder' parmeter can include ${<c>} format 


<c>:
* h  : mail['header']
* 0-9: (pattern =~ mail['header']; $~[c])


== option

  :through => true or false

  

=end

Rules = [
  #
  rule('X-ML-Name', /ruby/, "ruby/${h}"),
  rule('List-Id',   /ruby/, "ruby/${h}"),

  rule('X-ML-Name',  /.+/, "${h}"),
  rule('List-Id',    /.+/), # folder => "${h}"
  rule('X-Sequence', /\S+/, "${0}"),
  rule('List-Post',  /<<CONT>>lt;mailto:(.+)<<CONT>>gt;/, "${1}"),
]


で、結局 imap のためのメール振り分け機能がほしかっただけだったりする。


ThunderBird、IMAP サブフォルダの新着チェックしてくれない。どうしようかな。

誰かいい手知りませんか。

_shiro(Fri Nov 05 19:03:06 JST 2004)

 make checkで出るエラーって、もしかしてローカルのsmtpにつなぐところ? あそこはローカルでsmtpdを喋るデーモンが立ち上がってないとfailするっす。

_shugo(Sat Nov 06 00:54:44 JST 2004)

user.jsに

user_pref("mail.check_all_imap_folders_for_new", true);

って書いたらOK、とかそういう話?

_shiro(Sat Nov 06 05:09:16 JST 2004)

 あれれ? installに失敗してるか、古いGaucheがどこかに残ってる? installがうまくいってるかどうかは、Gaucheでmake installしたツリーが残ってたら、そのトップでmake install-checkってやると確認できます。あとgdbmが無い?

_nobsun(Sat Nov 06 06:48:18 JST 2004)

Debian だったら、パッケージ libgdbm はインストールされているけど、 libgdbm-dev がインストールされていないという状態じゃないかなぁ。 libgdbm-dev をインストールしないと、headerファイルがインストールされなかったと思う。

_4(Thu)

話の発端はね、Common Lisp で、loop を使ったほうがわかりやすいか、再帰をつかったほうがわかりやすいか、という話。

もちろん、両極端に位置する問題はあると思う。これは再帰で解くだろう、とかそんなの。

でも、グレーって言うか、悩むところがあるよね、って話。

集める、じゃなくて 1 から 10 までの和を取る、のほうがわかりやすかったかな。

C だったら誰も再帰でそんなことしないけど、とか、色々。

で、その線(繰り返しか再帰)ってのは、一般的にどんなもんなのかねってのが、アンケートの趣旨。

あんまり問題は考えてないけど。


wxRuby をふと試してみたくて、試してみたら、samples/controls/controls.rbw は死亡。

カレンダーは動いた。

まだ安定してないってことだろうか。

しかし、インストールが大変だった。


しかし、amd64マシンはえー。gauche のコンパイルが一瞬(は言い過ぎ)だ。


ふと、wxruby/samples/listctrl/listtest.rbw をみてみたら、こんなソースが。

# IDs for the menu commands
LIST_ABOUT,
LIST_QUIT,

LIST_LIST_VIEW,
LIST_ICON_VIEW,
LIST_ICON_TEXT_VIEW,
LIST_SMALL_ICON_VIEW,
LIST_SMALL_ICON_TEXT_VIEW,
LIST_REPORT_VIEW,
LIST_VIRTUAL_VIEW,

LIST_DESELECT_ALL,
LIST_SELECT_ALL,
LIST_DELETE_ALL,
LIST_DELETE,
LIST_ADD,
LIST_EDIT,
LIST_SORT,
LIST_SET_FG_COL,
LIST_SET_BG_COL,
LIST_TOGGLE_MULTI_SEL,
LIST_TOGGLE_FIRST,
LIST_SHOW_COL_INFO,
LIST_SHOW_SEL_INFO,
LIST_FOCUS_LAST,
LIST_FREEZE,
LIST_THAW = (0 .. 24).to_a

最初、何やってんだかわかんなかった。

enum かー。


%w{
LIST_ABOUT
LIST_QUIT
LIST_LIST_VIEW
LIST_ICON_VIEW
LIST_ICON_TEXT_VIEW
LIST_SMALL_ICON_VIEW
LIST_SMALL_ICON_TEXT_VIEW
LIST_REPORT_VIEW
LIST_VIRTUAL_VIEW
LIST_DESELECT_ALL
LIST_SELECT_ALL
LIST_DELETE_ALL
LIST_DELETE
LIST_ADD
LIST_EDIT
LIST_SORT
LIST_SET_FG_COL
LIST_SET_BG_COL
LIST_TOGGLE_MULTI_SEL
LIST_TOGGLE_FIRST
LIST_SHOW_COL_INFO
LIST_SHOW_SEL_INFO
LIST_FOCUS_LAST
LIST_FREEZE
LIST_THAW
}.each_with_index{|e, i|
  eval("#{e} = #{i}")
}

とかかなぁ。eval はまぁ置いといて。

class Module
  def enum consts, start = 0
    consts.each_with_index{|e, i|
      const_set(e.to_s, i + start)
    }
  end
end

class C
  enum %w{
    C1
    C2
    C3
  }
end

C.constants.each{|e|
  str = "C::#{e}"
  puts "#{str} => #{eval(str)}"
}

こんな感じかなぁ。


d ruby

d_ruby って何事かと思った。ちょうど D言語の話を見ていたところだったので。

しかし、ハッシュを言語サポートって、どういうことだろうね。式にリテラルが書ける=サポート、なんだろうが。

最適化、は処理系の話で言語の話じゃないだろうしな。


1 から x までの和をもとめましょー。

下から読んでね。


# CPS をループに
sum = lambda{|x, cont|
  if x == 0
    lambda{cont.call(0)}
  else
    lambda{sum.call(x-1, lambda{|s| lambda{cont.call(x+s)}})}
  end
}

cont = sum.call(100000, lambda{|s| p s; nil})
while cont = cont.call
end

__END__

# ちょっと ruby らしく

def sum x
  if x == 0
    yield 0
  else
    sum(x-1){|s|
      yield(x+s)
    }
  end
end

sum(10){|s|
  p s
}

__END__

# CPS
sum = lambda{|x, cont|
  if x == 0
    cont.call(0)
  else
    sum.call(x-1, lambda{|s| cont.call(x+s)})
  end
}

sum.call(10, lambda{|s| p s})

=begin
;; scheme
(define (sum x cont)
  (if (= x 0)
    (cont 0)
    (sum (- x 1) (lambda (s) (cont (+ x s))))))

(sum 10 display)
=end

__END__

# 末尾再帰
sum = lambda{|x, s|
  if x == 0
    s
  else
    sum.call(x-1, s+x)
  end
}

p sum.call(10, 0)

__END__

# ふつー再帰
sum = lambda{|x|
  if x == 0
    0
  else
    x + sum.call(x-1)
  end
}

p sum.call(10)

CPS をループにしたものは、この桁だとエラーになる(segv)。なんでだろう?

でも、コアを吐いてくれないので、コアを吐きます、とは言えない。残念(コアをはくのはどういうときなのか、知らない)。

って、ただ単に ulimit だけか。というわけで、コアを吐きました。やった。


なるほど、gc のマークが深すぎて、そこでスタックオーバーフロー起こしちゃったんだ。

a = []
while true
  a = [a]
end

で駄目なのと一緒。つまんないなぁ。

マシンスタックを使わない gc にする、とか? (こんなことしないから大丈夫か・・・)


拡張ライブラリを考えると、rb_gc_mark は外せないのか。

rb_gc_mark をどっかに記録を保存するものにしておいて、それのイテレーション、とか。 うわ、ツラ。


Gauche は (let loop ((x 1)) (loop (cons x '()))) やっても死なないなあ。

boehm gc 偉い。


python 2.3 は、

>>> a = 1
>>> while 1:
...     a = [a]

しても死なない。リファレンスカウンタだったら、そりゃそうか。


ほかにどんな言語があったっけ?

class GC{
  static public void main(String args[]){
    Object [] obj = null;
    while(true){
      Object [] tmp = new Object[1];
      tmp[0] = obj;
      obj = tmp;
      // System.out.println("" + obj);
    }
  }
}

Java version "1.4.2_04" では死亡。結構あっけないな。


ちなみに、safe level やセキュリティの機構でこんなものはサポートできるはずなどないので、こんなコード書かれたらさくっとやられるって話ですね。あ、サンドボックス上で利用可能なメモリ制限などがあればいいのか。


ちなみに、ruby にコアを吐かせるのは結構簡単で、ruby -e 'm(*Array.new(100000000))' ですぐ死にます。

ちなみに、yarv では死にま・・・死にますた orz。

C からの例外に対応していないから、か。 きちんと配列が生成されてれば対応(多分)。


core を吐きます。


ThunderBird がよさそう、と判断できそうなので、切り替えることにしよう。そろそろ den8 じゃ辛くなってきた。


もうちょっと書いておくと、末尾再帰が見づらい、ということで loop を使いました。というのが発端。

_shiro(Thu Nov 04 06:28:42 JST 2004)

 あー、CLはSchemeに比べて再帰が書き難くて、嫌々ながらloopを使っちゃいます。再帰が書き難いのは、(1)named letが無い (2)internal defineが無いし、letとlabelsを別々に書かないとならないしでネストが深くなる、からかなあ。

_まつもと(Thu Nov 04 08:35:44 JST 2004)

GCはもともと自前でスタックを管理してて、この種の問題には対応しているはずでしたが、バグってました。直しておきますので、SEGVはしなくなります。ただ、GCがSEGVしなくても、いつかはメモリを使い切って落ちるでしょうけどね。

_ささだ(Thu Nov 04 08:58:39 JST 2004)

なるほど。きちんとサポートがあったんですね。よくソースをみずに、失礼しました。

ところで、修正版では次の例はどうでしょうか(まだ公開cvsで見れないらしい)。

oth = nil

while true
  th = Thread.new{
    oth
  }
  oth = th
end
_maeda(Thu Nov 04 13:44:13 JST 2004)

 1から10までの和: (reduce + 0 (iota 10 1))

_新潟のS(Thu Nov 04 21:46:01 JST 2004)

 Σ k=1 n k = 1/2n(n+1) 必要なら数学的帰納法で証明。 (まじめに)最近40歳過ぎにもかかわらず受験生活しています。

_3(Wed)

module を追加しても、eth1 が動かない。

1> update-modules をやっていない orz

2> alias hogehoge eth1 と書いていた orz

3> etc/network/interfaces に auto eth1 を書いていなかった orz

うわーん


qmail 入れる。exim とか、remove するのを忘れてたなぁ、とか色々やってたらなんかにっちもさっちもいかなくなった。qmail remove して、全部最初からやり直し。やれやれ。しかし、なんで samba も remove されるんだ。


すみません、

[yarv-dev:285] Re: multivple values (Re: multiple assgin return value)

そうです。多重代入、多値returnなどと配列の関係がごちゃごちゃ しているのを整理するのに多値が一番きれいに実現できそうだとい うのがその理由です。

多値 return 、ときっちり明記されていますね。見落としてました orz。


文法要素として、多値を用意するか、データ構造(list や tuple、Array)だけで解決するか、ということの本質的な違いは、

val = mv

と書いたとき、どうなるか、ということか。

つまり、これを実行したとき、取り得る選択肢が、

1. val には mv[0] が入る
2. val には mv が入る(データ構造などに変換)
3. エラー

などが選べる。

データ構造だと、選べない(ふつーに考えれば 2 しかなくなる)。

こんな単純なことに、やっと気づいた。


今回のあんけーとは昨日話題になったことです。

題意として厳密じゃないんですが、まぁこんなもんかとてきとーに解釈してください。

要するに、「何が再帰で、何が繰り返しで解くことが妥当か」という話です。


研究室にマシンが二つ(私にかかわりがあるものだけ。他にもいろいろきてるけど)来た。

processor       : 0
vendor_id       : AuthenticAMD
cpu family      : 15
model           : 14
model name      : AMD Athlon(tm) 64 Processor 3400+
stepping        : 0
cpu MHz         : 2400.174
cache size      : 512 KB
fpu             : yes
fpu_exception   : yes
cpuid level     : 1
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov
                  pat pse36 clflush mmx fxsr sse sse2 syscall nx mmxext lm
                  3dnowext 3dnow
bogomips        : 4718.59
TLB size        : 1088 4K pages
clflush size    : 64
cache_alignment : 64
address sizes   : 40 bits physical, 48 bits virtual
power management: ts fid vid ttp

yarv の 64bit テストマシン(嘘)。

processor       : 0
vendor_id       : GenuineIntel
cpu family      : 15
model           : 2
model name      : Intel(R) Celeron(R) CPU 2.60GHz
stepping        : 9
cpu MHz         : 2600.517
cache size      : 20 KB
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 2
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca
                  cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm
bogomips        : 5190.45

atdot.net の代替マシン(ほんと)。

・・・キャッシュサイズが 20KB って、何?


というわけで、Fedora Core2 x86_64 を入れたんだけど。

間違えて workstation を入れてしまって X がたちあがってさぁ大変。で、X 上で端末を起動しようとすると「エラーが起きました」。端末くらい触らせてくれよ。

ほかにも、GUI での管理ツール、エラーばっか出てきて使えない。amd64 が悪いのか、俺のインストールの方法が悪かったのか(でも、何もいじってないんだけどなぁ)。

ssh は開いてたので、そいつで色々。


とりあえず ruby HEAD をビルド。さくっと終わる。速い。

test-all で、

[ko1@amd64 build-ruby]$ make test-all
./miniruby ../ruby/runruby.rb --extout=.ext -- -C "../ruby/test" runner.rb --runner=console
Loaded suite .
Started
...(中略)...
(druby://amd64:33104) /home/ko1/cvs/ruby/lib/drb/drb.rb:1375:in 
`check_insecure_method': undefined method `regist' called for  (NameError)
        from (druby://amd64:33104) /home/ko1/cvs/ruby/lib/drb/drb.rb:1417:in `check_insecure_method'
        from (druby://amd64:33104) /home/ko1/cvs/ruby/lib/drb/drb.rb:1422:in `setup_message'
        from (druby://amd64:33104) /home/ko1/cvs/ruby/lib/drb/drb.rb:1391:in `perform'
        from (druby://amd64:33104) /home/ko1/cvs/ruby/lib/drb/drb.rb:1468:in `main_loop'
        from (druby://amd64:33104) /home/ko1/cvs/ruby/lib/drb/drb.rb:1464:in `loop'
        from (druby://amd64:33104) /home/ko1/cvs/ruby/lib/drb/drb.rb:1464:in `main_loop'
        from (druby://amd64:33104) /home/ko1/cvs/ruby/lib/drb/drb.rb:1460:in `start'
        from (druby://amd64:33104) /home/ko1/cvs/ruby/lib/drb/drb.rb:1460:in `main_loop'
         ... 20 levels...
        from (druby://amd64:33104) runner.rb:8
        from /home/ko1/cvs/ruby/lib/drb/extserv.rb:16:in `initialize'
        from /home/ko1/cvs/ruby/test/drb/ut_array.rb:12:in `new'
        from /home/ko1/cvs/ruby/test/drb/ut_array.rb:12

で、刺さる。


x86_64 でせっかくなので yarv をコンパイルしてみる。

動かない動かない。なんてこった。

どれだけ自分がいい加減なソース書いてたってことだね。


gdb でデバッグしていると、ruby の例外で終了しちゃって、その例外の要因がつかめない。

なんかいい手はないものか。


rb_raise を break point にすればいいのか。便利すぎる。


        case 'U':          /* ulong */
          iseq[pos+1+j] = FIX2INT(operands[j]);
          break;

(中略)
      
        case 'I':          /* ID */
          iseq[pos+1+j] = FIX2INT(operands[j]);

こんなソースがあった。どう考えても 'U' が実行されるはずなのに、'I' でエラーだと gdb は言い張る。

・・・最適化の結果なのね。よくやるなあ。

これに気づくのに死ぬほど時間がかかった。


やっと全部通った。疲れた orz。

でも、テスト作っといて本当によかった。


x86_64 で、どんなコードが動かなかったか:

  • FIX2INT で、Fixnum 以外が入っていた(なんで 32bit版では平気だったんだろう?)
  • ポインタを unsigned int でキャストしていた、unsigned int な変数に代入していた、(unsigned) int な返り値の関数で、ポインタを返していた。とくに、プロトタイプ宣言を忘れているソースでそれが起こった

プロトタイプ宣言重要。


#define FIX2LONG(x) RSHIFT((long)x,1)

...

#if SIZEOF_INT < SIZEOF_LONG
  long rb_num2int _((VALUE));
  #define NUM2INT(x) (FIXNUM_P(x)?FIX2INT(x):rb_num2int((VALUE)x))
  long rb_fix2int _((VALUE));
  #define FIX2INT(x) rb_fix2int((VALUE)x)
  unsigned long rb_num2uint _((VALUE));
  #define NUM2UINT(x) rb_num2uint(x)
  unsigned long rb_fix2uint _((VALUE));
  #define FIX2UINT(x) rb_fix2uint(x)

#else
  #define NUM2INT(x) ((int)NUM2LONG(x))
  #define NUM2UINT(x) ((unsigned int)NUM2ULONG(x))
  #define FIX2INT(x) ((int)FIX2LONG(x))
  #define FIX2UINT(x) ((unsigned int)FIX2ULONG(x))
#endif

うーん、そういうことか。なるほど。

拡張ライブラリのデバッグでは、rb_num2int を使うようにしたほうがいいのかもしれないなぁ。

性能を考えると、FIX2LONG を使うようにしたほうがいいのか。とくに int に拘ってるわけじゃないので。

_ぶ(Wed Nov 03 20:02:44 JST 2004)

 「というわけで、Fedora Core2 x86_64 を入れたんだけど...」結局、慣れてないだけかもね。(grubの起動オプションrun levelを1にして(場合によってはそのまま起動して))、/etc/inittab の起動時のランレベルを変更すれば、Xのlogin画面なんかで立ち上がらんのに。どんなdistでも共通の対処法。

_ささだ(Wed Nov 03 20:04:27 JST 2004)

 さすがにそれくらいは知ってるんですが、GUI が立ち上がったのでそれでどこまでできるかなー、とやって惨敗した結果です。GUI の反応がなくなって、結局コンソール開いてなんかやってしのいだ次第。

_2(Tue)

イベント情報 - Mozilla Japan 第 1 回 セミナーのご案内 に行ってきた。

どう考えても退屈な話だけだろう、と思ったんだけど、そういう退屈なセミナーの勉強をする必要があったので、行ってきた。

会場はホテル。すげぇ。

ちょっと遅れて入った。客層は、スーツが大半。

「13:30 - 15:00 「Mozilla Firefox 1.0 / Mozilla 最新動向」」は、同時通訳付き。すげぇ。初めて同時通訳を生で見たが、すげぇ。あの人すげぇ。日本語 - 日本語 でもあれは出来ない。

内容は特筆するところはない。でも、オープンソースプロダクトを、ここまで喧伝し、広めよう、という態度、および行動は素晴らしい。いろいろと見習わなければならないところがあると思う。

質疑応答はしょぼい。

「15:15 - 16:15 オープンソースソフトウェア開発と大学教育 〜東京工科大学 Linux オープンソースソフトウェアセンター〜」は、否定的な感想しかなかった。たとえば、なんで Linux で、オープンソースソフトウェアなの? とか。だから、省略。内容についても反論ばかり思いつくので省略。NFS は少なくとも無いと思うんだけど。

「16:15 - 17:00 「Mozilla Japan 活動概要」」日本での活動について。組織の体制の話などを聞いて興味深かった。

いろいろと聞きたかったことはあったのだが、忙しそうなので断念。たとえば、お金の使い方とか聞いてみたかった。

期待どおり、(私にとっては)とても眠いセミナーだった。だが、眠くなるセミナーとは、という勉強にはなった。これに、人が大勢押しかけているのだから、世の中わからないものである。

さて、どうしたものかな。


別に、眠い眠い、といっているのは、技術的につまらない話ばかりだった、という意味で、要するに私の興味の対象外のことばかり言っていた、ということなので、だから無意味だとか、そういうことを言いたいわけではありません。きっと重要なことで、その重要さを私が理解できていないんだろうな、と思う。

そういうののための勉強でもあったんだけど。

まぁ、徹夜明けだったから眠かった、というのもあるんですが。


今日は別のセミナー。


そういえば、銀行にいったら、全然入ってなかった orz。

引き出し貯金も、そろそろ限界が・・・。


ウェブアプリケーションフレームワークが、なんでこんなに沢山あるのか、やっとわかったような気がする。

  • P1. URL とアクションのマッピング
  • P2. View と Model のマッピング
  • P3. Control の方法

をどうするか、が問題、ってことでいいんだろうか。

つまり、[あるウェブアプリケーションフレームワーク] = ウェブアプリケーションフレームワーク(P1, P2, P3) という式になるんだろうか。

パラメータが3つもあったら、そりゃ有象無象たくさんできるわな。

ちなみにプログラミング言語はどれくらいパラメータがあるんだろう。


多値、よくわからない。

うーん。

gauche では、

(cons (values 1 2) 3)
;;=> (1 . 3)

多値が必要ない場合には最初の値が入るらしい。

call-with-values は、なんで producer が closure なんだろう。そこに多値を渡したら駄目なんだろうか。

って、前も同じようなこと(closure で渡すか、そうじゃないか)を教えてもらった気がするけど、忘れてしまった。orz

(call-with-values (lambda () 1) +)
;;=> 1

atdot マシンのリプレース準備。

HDD 40GB のパーティション分け:

  • 512MB swap
  • 8GB /
  • 1GB /tmp
  • 1GB /var
  • 30GB /home

MOP セミナーに行ってきた。いきなり CLOS の作り方をしだすとは思わなかった。

クラスはメタオブジェクトなんだね。このこと自体が、非常にインパクトがある発見だったというか。メタオブジェクトとかメタクラスとかの定義があいまいだったから、とても役立った。

まぁ、あとはこうやるよなぁ、という感じ。でも、これをどうやって最適化するかは謎。少なくとも、各 arg の class-of はしないと駄目っぽい。

いや、コンパイル時の解析でできるだけいろいろやるんでしょうが。

客層は、スーツが少なかった。

その後、SICP面子と昼飯。中華。700円でこれはおいしい。

で、「やっぱりLispだね」と、「Lispの動的特性を生かしたソフトウェア保守」という二つの bit の記事のコピーがあったのでもらってきた。

「Lisp はプログラムとデータの形式が一緒である」というのは、それが本質であるというと疑問なんだけれど、どうなんだろうなぁ。パースしやすいし、マクロも作れるってのはわかるんだけれど。それは本質なんだろうか。

後者は、実務についてなので、大変興味深い。


debian インストール。

NIC を認識しない orz (broadcom 5705)。

というわけで、NIC を入れなおして再開。しょぼん。


とりあえず入った。kernelを再構築して再起動。

・・・ネットワークデバイスが見つからない orz。

多分、オンボードのドライバが無いからとか、そういうんじゃないかな、と思うんだけど。

オンボードを殺しても駄目。どうしよう。

Configuring network interfaces: eth0: ERROR while getting interface flags: No such device

modprove したらいけた。

このあたりの仕組みがよくわからない orz。

_shiro(Tue Nov 02 11:46:04 JST 2004)

 仕様に書いてないものは「偶然そうなっている」場合があるので、「動かしてみたらそうなったから」という理由でコードを書いてはいけません(少なくとも仕事で使うコードは)。次のバージョンでは変わるかもしれず、それに対する検証や対応は高くつくからです。Gaucheでは、ドキュメントに書いてあれば黙って変わることは無いと思って下さい。止むを得ず変える時は予告します。

 で、複数の値が一つの値を期待している継続に渡された場合の動作は処理系依存で、エラーにするのもあるでしょうし、CommonLisp風に最初の値だけ取るのもあるでしょうし、内部的にタプルを用いて多値を表現している場合はそれが見えるかもしれません。

 このうち、内部的にタプルを使っている処理系の場合は、「多値」を一級オブジェクトとして引数として渡すことができますが、一般的にはそれは期待できません (例えば、多値の最初の2つの値はレジスタ渡しで、それ以上はスタック渡し、とか。Gaucheでは多値はVMのレジスタで返します)。ということは、「多値」を引数として手続きに渡すことはできないのです。それが、call-with-valuesでclosureを取ることが必要な理由です。手続きでなく構文ならば多値を生成する式を直接書けて、それをやっているのがreceiveですね。

_ささだ(Tue Nov 02 17:08:02 JST 2004)

 あ、いや、Scheme の仕様を確認したつもりではなく、「多値(Gauche の場合)」というつもりでした。

_maeda(Tue Nov 02 21:24:44 JST 2004)

 shiroさんも書いてますが、closureをとる理由は「ライブラリ関数を増やすのは良いが、primitiveな構文を増やすのは嫌だ」というSchemeコミュニティの(私見では健全な)メンタリティによるものです。call-with-current-continuationもcall-with-valuesも、ただのライブラリ関数であって構文でないのはそういうわけ。

_かずぴこ(Wed Nov 03 10:57:52 JST 2004)

 s/modprove/modprobe/

_1(Mon)

mswin32 で、test_open_pipe(TestReadPartial) が刺さる。

cygwin で、ruby/test/inlinetest.rb:7:in `eval_part': undefined local variable or method `filename' for InlineTest:Module (NameError)

test/inlinetest.rb の filename ってのは、間違いってのは明らかだけれど(多分 path)、

ruby/test/inlinetest.rb:7:in `eval_part': No __END__ part in the library '/cygdrive/f/ko1/rubycvs/ruby/lib/generator.rb' (RuntimeError)

はて。

cygwin の改行コードがアレで、/^__END__$/ が駄目らしい。

cvs を、WinCVS + 日本語パッチ使っているのでファイルが全部 CR+LF になっているのが駄目らしいと指摘いただいた。\r? 加えて対処。


TestReadPartial が全然通らないので、mswin32 だったら skip するようにした。

cygwin では 1486 tests, 10206 assertions, 3 failures, 0 errors だった。

  1) Failure:
test_endblockwarn(TestBeginEndBlock) [./ruby/test_beginendblock.rb:53]:
<"endblockwarn.rb:2: warning: END in method; use at_exit\n(eval):2: warning: END
 in method; use at_exit\n"> expected but was
<"/cygdrive/f/DOCUME~1/ko1/LOCALS~1/Temp/TestBeginEndBlock1800.0:6: warning: Ins
ecure world writable dir /cygdrive/f/ko1/rubycvs, mode 040777\nendblockwarn.rb:2
: warning: END in method; use at_exit\n(eval):2: warning: END in method; use at_
exit\n">.

  2) Failure:
test_ruby_talk_116455(TestRegexp) [./ruby/test_regexp.rb:9]:
<"Hallo Welt"> expected to be =~
</^(\w{2,}).* ([A-Za-z\xa2\xc0-\xff]{2,}?)$/>.

  3) Failure:
test_file(SOAP::SWA::TestFile) [./soap/swa/test_file.rb:59]:
<"require 'test/unit'\r\nrequire 'soap/rpc/driver'\r\nrequire 'soap/rpc/standalo
neServer'\r\nrequire 'soap/attachment'\r\n\r\n\r\nmodule SOAP\r\nmodule SWA\r\n\
r\n\r\nclass TestFile < Test::Unit::TestCase\r\n  Port = 17171\r\n  THIS_FILE =
File.expand_path(__FILE__)\r\n\r\n  class SwAService\r\n    def get_file\r\n
  return {\r\n     \t'name' => $0,\r\n\t'file' => SOAP::Attachment.new(File.open
(THIS_FILE)) # closed when GCed.\r\n      }\r\n    end\r\n  \r\n    def put_file
(name, file)\r\n      <<CONT>>quot;File '#{name}' was received ok.<<CONT>>quot;\r\n    end\r\n  end\r\
n\r\n  def setup\r\n    @server = SOAP::RPC::StandaloneServer.new('SwAServer',\r
\n      'http://www.acmetron.com/soap', '0.0.0.0', Port)\r\n    @server.add_serv
ant(SwAService.new)\r\n    @server.level = Logger::Severity::ERROR\r\n    @t = T
hread.new {\r\n      @server.start\r\n    }\r\n    while @server.status != :Runn
ing\r\n      sleep 0.1\r\n      unless @t.alive?\r\n\t@t.join\r\n\traise\r\n
  end\r\n    end\r\n    @endpoint = <<CONT>>quot;http://localhost:#{Port}/<<CONT>>quot;\r\n    @client
 = SOAP::RPC::Driver.new(@endpoint, 'http://www.acmetron.com/soap')\r\n    @clie
nt.add_method('get_file')\r\n    @client.add_method('put_file', 'name', 'file')\
r\n    @client.wiredump_dev = STDERR if $DEBUG\r\n  end\r\n\r\n  def teardown\r\
n    @server.shutdown\r\n    @t.kill\r\n    @t.join\r\n    @client.reset_stream\
r\n  end\r\n\r\n  def test_file\r\n    assert_equal(\r\n      File.open(THIS_FIL
E) { |f| f.read },\r\n      @client.get_file['file'].content\r\n    )\r\n    ass
ert_equal(\r\n      <<CONT>>quot;File 'foo' was received ok.<<CONT>>quot;,\r\n      @client.put_file('
foo',\r\n\tSOAP::Attachment.new(File.open(THIS_FILE)))\r\n    )\r\n    assert_eq
ual(\r\n      <<CONT>>quot;File 'bar' was received ok.<<CONT>>quot;,\r\n      @client.put_file('bar',\
r\n\tSOAP::Attachment.new(File.open(THIS_FILE) { |f| f.read }))\r\n    )\r\n  en
d\r\nend\r\n\r\n\r\nend\r\nend\r\n"> expected but was
<"require 'test/unit'\r\nrequire 'soap/rpc/driver'\r\nrequire 'soap/rpc/standalo
neServer'\r\nrequire 'soap/attachment'">.

mswin32

  1) Failure:
test_kernel_open(PathnameTest)
    [F:/ko1/rubycvs/ruby/lib/pathname.rb:1195:in `test_kernel_open'
     F:/ko1/rubycvs/ruby/lib/pathname.rb:1193:in `open'
     F:/ko1/rubycvs/ruby/lib/pathname.rb:1193:in `test_kernel_open']:
<5> expected but was
<0>.

  2) Failure:
test_truncate_wbuf(TestFile) [./ruby/test_file.rb:235]:
<"<<CONT>>00<<CONT>>00<<CONT>>00<<CONT>>00def\n"> expected but was
<"<<CONT>>00<<CONT>>00<<CONT>>00<<CONT>>00<<CONT>>00def\n">.

  3) Failure:
default_test(TestReadPartial) [runner.rb:8]:
No tests were specified.

  4) Failure:
test_ruby_talk_116455(TestRegexp) [./ruby/test_regexp.rb:9]:
<"Hallo Welt"> expected to be =~
</^(\w{2,}).* ([A-Za-z\xa2\xc0-\xff]{2,}?)$/>.

  5) Error:
test_74(TestIOScanf):
IOError: ungetc failed
    F:/ko1/rubycvs/ruby/lib/scanf.rb:651:in `ungetc'
    F:/ko1/rubycvs/ruby/lib/scanf.rb:651:in `soak_up_spaces'
    F:/ko1/rubycvs/ruby/lib/scanf.rb:638:in `scanf'
    ./scanf/test_scanf.rb:304:in `test_74'
    ./scanf/test_scanf.rb:303:in `open'
    ./scanf/test_scanf.rb:303:in `test_74'
    ./scanf/test_scanf.rb:301:in `test_74'

最近、GC のテストをしていなかったんだけれど、したらサクサク落ちる。

orz

というわけで、デバッグ地獄。

まぁ、大体想像していたところだったのが救いか。


何を思ったか、Xserver on Cygwin を使ってみたいと思い、インストールしてみたのだけれど、期待する動作をしてくれない。デュアルディスプレイが駄目なんだろうか。


GC でバグ〜、ということで、3時間くらい探索。これで、多分バグは取れただろう。結局はコンパイラのバグ。volatile とか付けなきゃいけないかと思ってしまったけれど。


というわけで、やっと最新版に追いついた、といっていいのか。


うわーん 444。


今更ですが、ptach patch コマンドをはじめて使う。

本当に今更。


先日の WebDAV の件があったので、じゃぁ explore に簡単な put/get するだけのインターフェースをくっつけるにはどうすればいいんか、というのをちょびっと調べたら、Shell Namespace Extension でどうのこうのすればいい、ということまではわかったのだけれど、もうドキュメントを読む気力がない・・・。というか、COM のインターフェースについてやっぱり全然わかっていない。で、レジストリがどうのとか言われて、もう混乱。やっぱり、昔ちゃんと何か作っておけばよかった。

しかし、久しぶりに MSDN 見たなぁ。

多分、決まりが多すぎるだけで、やるべきことはほんのちょっとしかないんだと思うんだけど。


インタビュー用のマイクを買った。

定価一万数千円。値札には 6890円。レジで一万円札を出したら、980円といわれた。店員さんも不思議がってた。で、980円で購入。いったいなにが起こったんだろう。まぁ、私は嬉しいのだけれど。


RubyQuizu: p で何が表示される?

1. p((a, b = 1, 2))
2. p((a, b = c, d = 1, 2))
3. c, d = 100, 200; p((a, b = c, d = 1, 2))

2 は意外。

というか、

p((a, b = c, (d = 1), 2))

と評価してるのか。

_ac(Mon Nov 01 05:46:30 JST 2004)

 patchですよね?

Sasada Koichi / sasada@namikilab.tuat.ac.jp
$Date: 2003/04/28 10:27:51 $