2011年7月31日日曜日

今年は蝉が少ない?

自分は田園都市線沿線に住んでいますが、例年よりも蝉の鳴き声が少ない気がします。毎年誰かが少ないと言っているような気もしますが、今年は地震の影響も多少あったのかなと思っています。原因として考える要因を、思いつくままにあげてみると

  1. 地震の揺れで圧縮された土に押しつぶされて圧死。
  2. 局部的な液状化で溺死。
  3. 寒いのでもう少し待っている。
  4. 8月から本気出す。
  5. 放射線の影響で巨大化している最中。
  6. 怒りの頂点に達していないので、サナギマンから脱皮できない。

例年だと、後半大量に羽化して五月蠅くなののですが、今年の8月は涼しいらしいので、少ないまま終わってしまうかも。

自分は、ミンミンゼミ・ツクツクボウシ・ひぐらし等のリズム系の鳴き声は好きなのですが、アブラゼミ等のノイズ系は嫌いなので、所々で聞こえる程度の方が返って良かったりします。

2011年7月28日木曜日

スニペットの管理ツールCodeBoxが85円だったので買ってみた。

以前から、スニペットを管理するアプリが欲しかったのですが、フリーなものだと機能が微妙な感じで、有料なものだと今度は価格面が微妙で買いあぐねていました。 今日、何となくApp Storeをのぞいてみると、CodeBoxと言うアプリが85円で売っていました(確か以前は850円だったと思うので90%off!!)。

CodeBox

CodeBoxは候補の一つに挙がっていたのですが、お試しができないのと最近作成されたアプリの様でしたので保留にしていました。でも、今回85円だったので失敗してもいい金額かなと思いポチッとしてしまいました。

まだ使い始めたばかりですが、基本的な機能は備えているようです。しばらくはこれで様子を見てみようと思います。

CodeBoxのサイトでは$9.99になっているようです。入力ミスなのかセール中なのかいまいち不明なので、欲しい人は今のうちに買っておいた方がよいかも。

2011年7月20日水曜日

64bit版emacsのwnn7eggがbackend timeoutになる件を調査してみた

emacsの64bit化を阻むもの

自宅サーバ(NetBSD 64bit)には、32bit Linux emulationでオムロンソフトウェアのWnn7が動作しています。そして、これを自宅サーバ(NetBSD)・開発マシン(Mac mini)・サブマシン(Macbook air)上のemacsから使用しています。この構成だと学習した情報をサーバー側で一元管理できるので、学習データを共有するための同期処理をどうしようかと悩む必要がなくて重宝しているのですが、以前、各マシンのemacsを64bit化しようと目論んだのだけれども、64bit化するとwnn7eggがbackend timeoutというエラーを吐いてしまい断念してしまいました。

デバッグ

まず64bit版 Emacsを"--debug"を付けて立ち上げてbackend timeoutするときのBacktraceを取って、不具合のありそうな関数に当たりをつけて32bit番の動きと違いがないか一個ずつ調べてみました。Elispのデバッグはしたことがかなったので、凄く効率が悪く面倒臭いデバッグ方法になってしまいました。

上記のやり方で調査していくと、 wnn7rpc-get-autolearning-dic関数で違いが出ることがわかりました。

  (defun wnn7rpc-get-autolearning-dic (env type)
  "Get id of auto learning dictionary on the server.
Return dictionary id + 1 on success, 0 on no dictionary, negate-encoded
error code on faiulure."
  (wnn7rpc-call-with-environment env (result)
    (comm-format (u u u) (wnn-const JS_GET_AUTOLEARNING_DIC)
                 env-id type)
    (wnn7rpc-get-result
      (comm-unpack (u) result)
      (print result)
      (1+ result))))

上記のソースのように(print result)を付加してresultの値を表示すると32bitと64bitで違いが発生します

;; 32bit Emacsで正常の場合
Wnn: connecting to jserver at foo.rfc2606.invalid.jp(22273)...done
ホスト foo.rfc2606.invalid.jp の Wnn を起動しました
Loading /Users/bar/.eggrc-wnn7...

-1

32

-1

34

Loading /Users/bar/.eggrc-wnn7...done

;; 64bit Emacsでbackend timeoutの場合
Wnn: connecting to jserver at foo.rfc2606.invalid.jp(22273)...done
ホスト foo.rfc2606.invalid.jp の Wnn を起動しました
Loading /Users/bar/.eggrc-wnn7...

4294967295

4294967295

もしかして変数のbit幅の問題?

32bit Emacsでは-1を取り、64bit Emacsでは4294967295を取る。これを16進数に直すと興味深い値が出てきます。

;; 32bit Emacs場合
(format "%x" -1)
1fffffff

(format "%x" 4294967295)
1fffffff

;; 64bit Emacs場合
(format "%x" -1)
3fffffffffffffff

(format "%x" 4294967295)
ffffffff

え〜っ!? 32bit Emacsの変数のbit幅って、29bitだったんですか! 長年Emacsを使用していたけれどしらなかった。しかも64bit Emacsは62bit? なんでこんなに中途半端なbit数なんでしょうね

上記の結果より処理結果が536870911(#x1fffffff)以上の値をとると32bit Emacsと64bit Emacsで評価内容が変わってしまう事がわかりました。

comm-unpack関数って何しているの?

次に、32bitと64bitで異なった値を返してくるcomm-unpack関数を調べてみました。comm-unpack自体は引数の値によって適切な関数を呼び出すディスパッチ処理を行い、呼び出した関数の値を返すだけの簡単な仕事しかしていませんでした。

(comm-unpack (u) result)のように引数に"u"をつけるとcomm-unpack-u32関数が呼ばれます。

comm-unpack-u32関数って何しているの?

EmacsはJServerと直接通信をしてコマンド/レスポンスのやりとりをしている訳ですが、受信したデータは*Wnn7*バッファに入ってきます。

Wnn7 バッファ

これを適切なbit長で読み出してコマンドを再構築するのが、comm-unpack関数で受信したレスポンスを32bitにアンパックしてする場合にcomm-unpack-u32関数が呼ばれます。

(defun comm-unpack-u32 ()
  (progn
    (comm-require-process-output 4)
    (+ (lsh (comm-following+forward-char) 24)
       (lsh (comm-following+forward-char) 16)
       (lsh (comm-following+forward-char) 8)
       (comm-following+forward-char))))

この時に、0xffffffffというデータを受信していると32bit Emacsと64bit Emacsで結果が変わってしまいます。

では、どんな値が*Wnn7*バッファ入ってきているのでしょう?ダンプしてみました

Wnn7 バッファ

はい、見事に0xffffffffを受信しています。ありがとうございました。

原因

  1. 32bit Emacsの整数bit幅は29bit
  2. 62bit Emacsの整数bit幅は62bit
  3. jserverから0xffffffffを受信すると
  4. 32bit Emacsは-1と評価する。
  5. 62bit Emacsは4294967295と評価する。
  6. 62bit Emacsの場合、不明なレスポンスしかこないので、backend timeoutで落ちる。

対策

原因が判明したので、comm-unpack-u32関数を修正して整数が29bit幅の以外の時は、変数の値を62bit幅に拡張する処理を入れてあげればよいと思われる。整数のbit幅が他の値をとることはあるのかな?考えないことにしておく。

wnn7egg-edep.el

Emacsの依存性があるコードはここに書かれるようなので、下記のコードを追加

(defconst interger_width_29bit (logxor (lsh (lsh 1 29) -29) 1))

interger_width_29bitは整数が29bit幅ならば1、29bit幅以上ならば0を取ります。

wnn7egg-com.el

comm-unpack-u32関数を下記のように修正。

(defun comm-unpack-u32 ()
  (progn
    (comm-require-process-output 4)
    (if (= interger_width_29bit 1)
        (+ (lsh (comm-following+forward-char) 24)
           (lsh (comm-following+forward-char) 16)
           (lsh (comm-following+forward-char) 8)
           (comm-following+forward-char))
      ;; for 62bit width
      (ash (lsh (+ (lsh (comm-following+forward-char) 24)
                   (lsh (comm-following+forward-char) 16)
                   (lsh (comm-following+forward-char) 8)
                   (comm-following+forward-char)) 30) -30))))

変数の値が62bit幅の場合は、31bit目のデータを符号ビットの場所までシフトしてから、算出シフトで元の位置まで戻してあげます。(ソースでは30bitシフトしていますが、33bitシフトの方がよいかもしれません。)

ソースとパッチ

ソースとパッチをおいておきます。ご自由にお使いください。

  1. wnn7egg-edep.el
  2. wnn7egg-com.el
  3. wnn7-egg-backend-timeout.patch