hns - 日記自動生成システム - Version 2.19.6

予定 TODO Link
    • 81 uim のお手伝い
    • 80 Namazu のお手伝い
    • 75 Zaursu-ja の作業
    • 72 DixChange
    • 70 KAKASI の hack
    • 16 File-MMagic hack & web 用意 (かなり pending)

    先月 2008年11月
    1
    2 3 4 5 6 7 8
    9 10 11 12 13 14 15
    16 17 18 19 20 21 22
    23 24 25 26 27 28 29
    30
    HNS logo

    2008年11月16日() [n年日記]

    [天気:雨]

    #1 Anthy 9100eで'itioku'が変換できない

    Debian BTS経由でバグレポートをいただいたので、調査してみました。 自分の思考の過程を書くだけなので、あんまり他の人への参考にはならないと思います。

    まずgdbで追いかけられるようコンパイラのフラグを適切に設定して buildします。
    $ apt-get source anthy
    $ cd anthy-9000e
    $ CFLAGS="-g -O0" ./configure
    $ make
    
    次に、問題となる変換テキストを用意します。
    itioku
    (space)
     PRINT_CONTEXT
    
    そして、それを使ってgdb経由で実行します。
    $ libtool  --mode=execute gdb anthy-agent
    GNU gdb 6.8-debian
    Copyright (C) 2008 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "i486-linux-gnu"...
    (gdb) run --conffile /etc/anthy/anthy-conf < foo.txt
    Starting program: /home/knok/draft/debian/build/anthy/anthy-9100e/src-util/.libs/lt-anthy-agent --conffile /etc/anthy/anthy-conf < foo.txt
    (2 ((UL) "
    Program received signal SIGSEGV, Segmentation fault.
    0xb7f40ea6 in anthy_get_nth_dic_ent_str (se=0x80a5250, orig=0x80b01a4, n=-1,
        x=0xbffb6408) at word_dic.c:389
    389       x->len = se->dic_ents[n]->str.len;
    (gdb) p x
    $1 = (xstr *) 0xbffb6408
    (gdb) p x->len
    $2 = 1
    (gdb) p se
    $3 = (seq_ent_t) 0x80a5250
    (gdb) p n
    $4 = -1
    
    nが-1となっているのがおかしいようです。実行している箇所は anthy_get_nth_dic_ent_str()です。バックトレースは以下のとおり。
    #0  0xb7f40ea6 in anthy_get_nth_dic_ent_str (se=0x80a5250, orig=0x80b01a4,
        n=-1, x=0xbffb6408) at word_dic.c:389
    #1  0xb7f89c98 in proc_swap_candidate_indep (se=0x80ac498) at candswap.c:172
    #2  0xb7f89d3e in anthy_proc_swap_candidate (seg=0x80ac498) at candswap.c:203
    #3  0xb7f8a2c0 in apply_learning (sl=0x80a4040, nth=0) at candsort.c:233
    #4  0xb7f8a374 in anthy_sort_candidate (sl=0x80a4040, nth=0) at candsort.c:261
    #5  0xb7f823dd in make_candidates (ac=0x80a4038, from=0, from2=0, is_reverse=0)
        at context.c:349
    #6  0xb7f82477 in anthy_do_context_set_str (ac=0x80a4038, s=0x80a35a8,
        is_reverse=0) at context.c:366
    #7  0xb7f8134d in anthy_set_string (ac=0x80a4038, s=0x8077ad8 "    at main.c:230
    #8  0xb7f9437e in enter_conv_state (ictx=0x8077628) at input.c:241
    #9  0xb7f95fb8 in anthy_input_space (ictx=0x8077628) at input.c:1151
    #10 0x0804b027 in dispatch_command (ictx=0x8077628, cmd=0x8077600)
        at agent.c:1013
    #11 0x0804b104 in main_loop () at agent.c:1063
    #12 0x0804b419 in main (argc=-1, argv=0x0) at agent.c:1150
    
    一つ上の関数を調べてみます。
    (gdb) up
    #1  0xb7f89c98 in proc_swap_candidate_indep (se=0x80ac498) at candswap.c:172
    172           res = anthy_get_nth_dic_ent_str(se->cands[i]->elm[core_elm_idx].se,
    (gdb) l
    167       /* 168       for (i = 1; i < se->nr_cands; i++) {
    169         if (se->cands[i]->nr_words == se->cands[0]->nr_words &&
    170             se->cands[i]->core_elm_index == core_elm_idx) {
    171           xstr cand;
    172           res = anthy_get_nth_dic_ent_str(se->cands[i]->elm[core_elm_idx].se,
    173                                           &se->cands[i]->elm[core_elm_idx].str,
    174                                           se->cands[i]->elm[core_elm_idx].nth,
    175                                           &cand);
    176           if (res == 0 &&
    (gdb) p i
    $5 = 5
    (gdb) p *se->cands[5]->elm
    $9 = {nth = -1, wt = {pos = 0, cos = 0, scos = 0, cc = 0, ct = 0, wf = 0},
      se = 0x0, ratio = 0, str = {str = 0x0, len = 0}, id = -1}
    
    このelm(エレメント)は空っぽとなっているようです。これは妙なので、 他のバージョンで実行してみます。
    $ anthy-agent < foo.txt
    (2 ((UL) "(3 ((UL RV) "|
    
    anthy 9100cでは正しく動作しています。なので、どこかでバグが入り込んだ ようです。同じ条件でgdbをかけてみます。
    (gdb) b anthy_get_nth_dic_ent_str
    Function "anthy_get_nth_dic_ent_str" not defined.
    Make breakpoint pending on future shared library load? (y or [n]) y
    
    Breakpoint 1 (anthy_get_nth_dic_ent_str) pending.
    (gdb) run --conffile /etc/anthy/anthy-conf < ../../foo.txt
    Starting program: /home/knok/draft/debian/build/anthy/anthy-9100-c/src-util/.libs/lt-anthy-agent --conffile /etc/anthy/anthy-conf < ../../foo.txt
    Breakpoint 2 at 0xb7f516ec: file word_dic.c, line 382.
    Pending breakpoint "anthy_get_nth_dic_ent_str" resolved
    (2 ((UL) "
    Breakpoint 2, anthy_get_nth_dic_ent_str (se=0x80a66e8, orig=0xbfac3020, n=0,
        x=0xbfac3028) at word_dic.c:382
    382       if (!se) {
    (以下略)
    
    基本的にnの値は常に0以上です。また、anthy-agentの出力も異なります。
    (2 ((UL) "(3 ((UL RV) "|
    
    バックトレースも見てみましょう。
    #0  anthy_get_nth_dic_ent_str (se=0x80a6a48, orig=0xbfacd240, n=0,
        x=0xbfacd248) at word_dic.c:382
    #1  0xb7fa4912 in enum_candidates (seg=0x80a68a8, ce=0x80a6958, from=0, n=1)
        at compose.c:162
    #2  0xb7fa4abd in enum_candidates (seg=0x80a68a8, ce=0x80adc98, from=0, n=0)
        at compose.c:188
    #3  0xb7fa4f93 in make_candidate_from_simple_metaword (se=0x80a68a8,
        mw=0x80a60f8, top_mw=0x80a60f8, is_reverse=0) at compose.c:336
    #4  0xb7fa5148 in proc_splitter_info (se=0x80a68a8, mw=0x80a60f8,
        top_mw=0x80a60f8, is_reverse=0) at compose.c:393
    #5  0xb7fa5347 in anthy_do_make_candidates (sc=0x80a57f4, se=0x80a68a8,
        is_reverse=0) at compose.c:464
    #6  0xb7f9f10d in make_candidates (ac=0x80a57b0, from=0, from2=0, is_reverse=0)
        at context.c:344
    #7  0xb7f9f1cb in anthy_do_context_set_str (ac=0x80a57b0, s=0x80a4e88,
        is_reverse=0) at context.c:366
    #8  0xb7f9e09c in anthy_set_string (ac=0x80a57b0, s=0x8077b10 "    at main.c:230
    #9  0xb7fb015e in enter_conv_state (ictx=0x8077660) at input.c:241
    #10 0xb7fb1d14 in anthy_input_space (ictx=0x8077660) at input.c:1151
    #11 0x0804af21 in dispatch_command (ictx=0x8077660, cmd=0x8077638)
        at agent.c:1013
    #12 0x0804affe in main_loop () at agent.c:1063
    ---Type <return> to continue, or q <return> to quit---
    
    ずいぶん挙動が異なっているようです。比較をしてみると、make_candidatesから 先が違うようなので、そこを重点的に見てみます。
    anthy_sort_candidateの中でanthy_get_nth_dic_ent_strを呼び出し、 この時にsegfaultしています。 その前にanthy_do_make_candidatesを呼び出しており、ここで候補一覧を 生成しているようです。

    この辺で面倒になってきたのでltraceで比較してみることにします。 すると、一点大きな違いがあることに気づきました。
    9100c:
    anthy_input_get_preedit(0x8077660, 0xb7e874c0, 0x8077600, 0xbf8157a8, 0xb7dbe022) = 0x8077600
    
    9100e:
    anthy_input_get_preedit(0x8077628, 1, 0xbf8ead68, 0xb7e9074c, 0xb7f5f160) = 0x80775c8
    
    2番目の引数が妙です。しかしよくみると、実際にはこの関数は構造体へのポインタ のみを受け取る、引数1種類の関数でした。その時の内容をみるとこんな 違いがありました。
    9100c:
    (gdb) p *ictx
    $2 = {state = 2, rkctx = 0x80776c8, map_no = 2, hbuf = 0x8077b10 "  n_hbuf = 8, s_hbuf = 9, hbuf_follow = 0x0, n_hbuf_follow = 0,
      s_hbuf_follow = 0, actx = 0x0, segment = 0x0, cur_segment = 0x0,
      enum_cand_count = 0, enum_cand_limit = 3, enum_reverse = 0,
      last_gotten_cand = 7185, commit = 0x0, n_commit = 0, s_commit = 0,
      cut = 0x0, n_cut = 0, s_cut = 0, cfg = 0x8054a40, next_cfg_owner = 0x0}
    
    9100e:
    $1 = {state = 2, rkctx = 0x8077690, map_no = 2, hbuf = 0x8077ad8 "  n_hbuf = 8, s_hbuf = 9, hbuf_follow = 0x0, n_hbuf_follow = 0,
      s_hbuf_follow = 0, actx = 0x0, segment = 0x0, cur_segment = 0x0,
      enum_cand_count = 0, enum_cand_limit = 3, enum_reverse = 0,
      last_gotten_cand = 0, commit = 0x0, n_commit = 0, s_commit = 0, cut = 0x0,
      n_cut = 0, s_cut = 0, cfg = 0x8054a18, next_cfg_owner = 0x0}
    (gdb) p *ictx
    
    last_gotten_candが0となっているのがおかしい気がします。 加えて、9100cではanthy_input_get_preeditを二回呼んでいるのに対し、 9100eでは一度しか呼んでいません。
    anthy_input_preeditを呼ぶ前の段階で問題が起きているようです。
    さらに細かく見てみると、anthy-agentの構造はトークンを一つづつ読み込んで それらをコマンドとして解釈するdispatch処理をひたすら繰り返す、という 形になっていることを把握できました。

    (space)が変換コマンドなので、そこで発生している何かを掴めば デバッグできそうです。

    そう思ってcmd_spaceにブレークポイントをおいてみたら、この段階で すでにictx->last_gotten_candの値が異なっていました。
    ではこの値が問題か? と思ったのですが、面倒になってきて emacsのgdb-modeで追いかけてみたら最終的にspaceを押した段階で 0にクリアされるのでどうも関係なさそうな感じです。

    ここで視点を再度segfault発生点に向けてみます。 anthy_get_nth_dic_ent_strの引数int nに問題がある(-1)ことが問題ですが、 その親関数はproc_swap_candidate_indepです。一つ一つ親関数で値が どう設定されているかをみてゆけば、問題が発見できるはずです。

    そして、ようやく鍵となる関数anthy_do_make_candidatesを発見しました。 ここで文節の変換を行い、候補として記録して行くようです。 デバッグ用の処理が含まれていたので、それを有効化してみます。
    環境変数ANTHY_ENABLE_DEBUG_PRINTを定義し、もう一つ環境変数 ANTHY_SPLITTER_PRINTに'c'を設定すればよいようです (src-splitter/splitter.c)。他にもいろいろ出力できるようなので、 とりあえず'wmlic'全部定義しておきます。

    これで大量の出力が出るようになりましたが、少なくとも 途中経過で「一億」という候補を出しているようではあります。

    さらにたどって、ようやくcandswap.c内の関数proc_swap_candidate_indep() で呼ばれているprepare_swap_candidate(&key)の結果が異なることがわかりました。 さらに先を調べると、anthy_select_rowの返す値が異なっています。

    ここは個人辞書の排他制御が入るので、2つのバージョンを見比べながら gdbで追いかけるのは無理のようです。まあとりあえず、原因はある程度 絞り込めてきました。
    permlink
    このエントリーを含むはてなブックマーク

    2008年10月28日(火) [n年日記]

    [天気:晴]

    #2 最近はバックスラッシュと円記号を使い分けられる

    PHP 5.3では バックスラッシュをnamespaceの区切りにする そうですが、それをみて セキュリティ&プログラミングキャンプ2008 でのことを思い出しました。

    少なくとも、Debian etch UTF-8環境ではバックスラッシュと円記号を 使い分けることができます。おそらく、Xorg+UTF-8という組み合わせなら OSを問わず同じ状況になるのではないかと思います。
    自分の手元のPCを例にとると、右シフトキーの左隣にあるキーでバックスラッシュ、 バックスペースキーの左隣にあるキーで円記号が出せます。

    生徒向けのPC環境をリモートで設定したために、当日現場で始めてこの問題に 気づいたという次第です。講師が用意した資料のいくつかはエスケープシーケンス として円記号の方を使っており、(主に講師の方が)混乱しました。
    ja_JP.UTF-8ロケールにおいて、gccはちゃんとこの2つを区別してくれます。

    講師陣がみなoldtypeであったことを露呈した一幕でした。なお、このblogは 出力がEUC-JPなので、バックスラッシュと円記号を区別することはできません。
    permlink
    このエントリーを含むはてなブックマーク

    #1 Lennyではshaperパッケージがなくなる

    kmutoさんからshaperがなくなるという話をを聞いて、自分もshaperの 代替を考えなければならなくなりました。

    shaperは CBQ.init をパッケージ化したもので、Linuxのネットワークスケジューラ実装の 一つであるCBQ(CONFIG_NET_SCH_CBQ)を使ったQoSを設定するための スクリプトです。
    自分の場合、sshの優先度を上げたりBittorrentの帯域を絞ったりといった 用途で使っています。
    #/etc/shaper/cbq-0002.ssh
    DEVICE=ppp0,100Mbit,10Mbit
    RATE=90000Kbit
    WEIGHT=9000Kbit
    PRIO=1
    RULE=:22
    
    #/etc/shaper/cbq-0050.bt
    DEVICE=ppp0,100Mbit,10Mbit
    RATE=50Kbit
    WEIGHT=5Kbit
    PRIO=6
    RULE=:7777
    
    実のところちゃんと効いているのかどうかいまいち実感できていないのですが、 なんにせよ他のものに乗り換える必要があります。

    ざっと調べた感じでは、tcngが良さそうな感じでした。shaperは実際には /sbin/tcというコマンドを使うのですが、tcngはこれをよりhuman readableに した設定ファイルを使えるwrapperです。
    ただ、自分の用途にはちょっと複雑すぎるかもしれません。tcでできることは 全部できるから当然といえば当然です。もっとシンプルなものを探すと、 インターフェース単位でしか設定のできないwondershaperぐらいしかなく、 LinuxのQoSに関しては極端に複雑か簡単かのどちらかしかなさそうです。

    JFには Linux Advanced Routing & Traffic Control HOWTOのサンプルスクリプト (tcコマンドを生で使う)があるので、いっそのことそちらを使うのもありかも しれません。
    permlink
    このエントリーを含むはてなブックマーク

    2008年10月22日(水) [n年日記]

    [天気:曇]

    #1 セキュリティ&プログラミングキャンプ 2008 資料公開

    今年の8月に実施された セキュリティ&プログラミングキャンプ2008 の資料を http://www.daionet.gr.jp/~knok/materials/procamp08-ossr3.odp(オープンソースソフトウェアを理解する) として公開しました。ライセンスはGFDLとしています(ODPのスライドマスター に関してはオリジナルに準じてLGPL)。

    内容は、GPLやBSDスタイルライセンスが作られた背景や、各ライセンスの 特徴、そしてFLOSSプロジェクトの立ち上げ、運用などを解説しています。
    結構なボリュームの資料を作成したのですが、プログラミングキャンプでは 時間の都合上、各ライセンスが作られた背景までしかできませんでした。 ひたすら座学となってしまったので、ちゃんと伝わったのかどうか少し不安です。

    この資料を作成するに当たり、改めてUnixの歴史を調べる必要がありました。 "OpenSource Software"という単語の成立やThe OpenSource Definitionができる 以前の、フリーソフトウェア運動とも異なるある種の「ソースコードによる ソフトウェアの流通」文化を説明するためには、歴史をひもとく必要があった からです。

    この経験を通じて、物事を理解する上での歴史の重要性を強く感じました。
    この分野に関しては、生の記録がほぼそのままInternetに残っているて 幸いです。
    それでも、参照した情報や私の解釈が間違っている可能性も否定できないので、 この資料についてのご意見、ご指摘などがあればぜひご一報ください。
    permlink
    このエントリーを含むはてなブックマーク

    2008年10月21日(火) [n年日記]

    [天気:晴]

    #1 日記に関する変更

    私的なことがいろいろとあり、長らく日記を更新できませんでしたが、 一念発起して、今更ながらblogっぽくしてみました。

    otsuneさんのwiki を参考にして、 mod_rewriteでの1記事単位化 とそれをもちいたpermlinkを用意するようにしました。

    記事単位のlinkにはtitleに記事のサブジェクトもつくようになったため、 ブックマークもしやすくなったかと思います。

    というかotsuneさんのwikiが書き換えられているのですが、こちらで 修正を試みても反映されないのでtwitterでつぶやいてみました。
    permlink
    このエントリーを含むはてなブックマーク

    2008年06月10日(火) [n年日記]

    [天気:晴]

    #1 hdparm results on many devices

    仕事が集中しまくっていて、なかなか新しいことに力を入れられない この頃です。細かなアクティビティは Twitter である程度発してはいるのですが、blogにまでまとめる元気が ありません。

    とりあえず、最近再度いじり回しているZaurusや、ちょっとだけ 安くなっていたEeePC 701などのストレージについてhdparmの出力を 載せてみようと思います。
    SL-C3000 (Angstrom 2007.12)
    
    # hdparm -tT /dev/hda     # microdrive
    
    /dev/hda:
     Timing cached reads:   168 MB in  2.02 seconds =  83.06 MB/sec
     Timing buffered disk reads:    8 MB in  3.86 seconds =   2.07 MB/sec
    
    # hdparm -tT /dev/mmcblk0 # 2GB SD
    
    /dev/mmcblk0:
     Timing cached reads:   160 MB in  2.02 seconds =  79.09 MB/sec
    HDIO_DRIVE_CMD(null) (wait for flush complete) failed: Inappropriate ioctl for device
     Timing buffered disk reads:    6 MB in  3.95 seconds =   1.52 MB/sec
    HDIO_DRIVE_CMD(null) (wait for flush complete) failed: Inappropriate ioctl for device
    
    EeePC 701
    $ sudo hdparm -tT /dev/sda # internal SDD
    
    /dev/sda:
     Timing cached reads:   628 MB in  2.01 seconds = 313.21 MB/sec
     Timing buffered disk reads:   72 MB in  3.06 seconds =  23.56 MB/sec
    
    $ sudo hdparm -tT /dev/sdb # SDHC 8GB Class6
    
    /dev/sdb:
     Timing cached reads:   610 MB in  2.00 seconds = 304.64 MB/sec
     Timing buffered disk reads:   50 MB in  3.11 seconds =  16.10 MB/sec
    
    Zaurusだとなんだか警告が出ます。SDはかなり昔にかったものなので、 あまり早くありません。
    一方でEeePCは内蔵SSDが結構早いです。writeもそこそこ出ているようですが、 測定はしていません。SDHC class6も数字上は結構な速度です。

    しかしながら、実運用の際にはデフォルトの状態だとレイテンシがひどくて かなりストレスが溜まります。
    http://wiki.debian.org/DebianEeePC にある SDもしくはUSBメモリにインストールするための解説 によると、IOスケジューラをデフォルトのcfqからdeadlineにして、 適時fifo_batchの値を修正するのがいいようです。
    IOスケジューラにはいろいろありますが、標準のcfqはHDDの構造を想定した スケジューリングを行うので、フラッシュメモリではかえってよくない ということのようでした。

    SDHCにインストールしてみていい感じだったので、最近は8GB USBメモリに Debianを入れて普通のノートPCでも実質disklessにできないかと試行錯誤 しています。内蔵HDDへの給電を止めることでバッテリもより長時間 持つようにならないかなという期待もこめてます。
    permlink
    このエントリーを含むはてなブックマーク
    以上、5 日分です。
    タイトル一覧
    カテゴリ分類
    Powered by hns-2.19.6, HyperNikkiSystem Project