憂鬱な午後のひととき


7月31日_
でかっ
こういうとき便利だ.
7月27日_
しまった, 諸般の都合で1カ月ほど自宅のADSLが使えなくなってしまいそう(今朝から既に使えない). まいったな. ああ, テレビの予約もできなくなるのかぁ.
7月26日_
・↓2詳細を聞いてみた. なんと外部アセンブラ禁止, インラインアセンブラ禁止だそうな. iccの組み込み関数は利用可能らしいが, うーんモチベーションが. char配列にバイトコードつっこんで呼ぶのはありなんだろうか.
・とあるLinux用のPCIドライバがSMPで動作しなくてずっと困っていたのだがやっとこさ原因が分かった. 割り当てられたirqを取得するのに pci_read_config_byte + PCI_INTERRUPT_LINE を使っていたが, APICの場合は値が異なることがあるようでstruct pci_dev *devのirqメンバを直接見た方がよいようだ.
7月25日_
数週間英語の勉強をさぼったら, 折角少し慣れてきたかなと思ってたのに全然聞こえなくなってる. また一からやり直し.
7月24日_
インテル・チューニング・コンテスト2006のご案内」(首藤さん経由)
面白そうだ. 応募してみようかな. あ, でもオーバークロックする人も参戦するのか….
7月23日_
今週末はかなりゆっくりして気力回復. 明日からいろんなこと復活させよう.
7月17日_
疲れが酷くてごろごろの三連休.
7月15日_
・今日煮物にしようと昨日買ったかぼちゃが暑さのためもう傷んでる. 捨ててしまったがああもったいない.
2006年7月度LILO Monthly Seminar
時期的にちょっと無理. 残念.
7月12日_
↓やはり副作用を持つ書き方はアウト. というわけで
void strcpy2C(char *s, const char *t)
{
    int i = 0;
    int j = 0;
    while ((s[i++] = t[j++]) != '\0')
        ;
}
が正しい. これはVC6 -O2にて
    mov    eax, [esp+4] ; s
    mov    edx, [esp+8] ; t
    sub    edx, eax
.lp:
    mov    cl, [edx+eax]
    mov    [eax], cl
    inc    eax
    test   cl, cl
    jne    .lp
    ret
となった. 泥臭い最適化はかかってないが, iとjが同時にインクリメントされるということがきちんと認識されている. 1Aの
    mov    edx, [esp+8] ; t
    mov    ecx, [esp+4] ; s
.lp:
    mov    al, [edx]
    mov    [ecx], al
    inc    ecx
    inc    edx
    test   al, al
    jne    .lp
    ret
と比べても素直で特に問題ないコード. つまり, 議論の発端は1Aと次の1B
void strcpy1B(char *s, const char *t)
{
    while (*s = *t) {
        s++;
        t++;
    }
}
を比較すべき話であった. そして昨日書いたように二つの差はループにおいてはどう書いても殆ど変わらない. ま, もっと複雑な例ではこのような微妙な表現を変えていくと結構速度が変わるあたり, まだまだ甘いなあとは思う. そしてその辺が飯の種になったりするわけやけど(というかなって!).
7月11日_
本当にアセンブリコード読んでからそう言ってます?(ttさんの日記経由)
確かに同じものになれば悩みは減るけど, 難しいな. ただこれをサラッと読んで「配列よりポインタの方がよいコードが生成される」と勘違いしちゃうとまずいと思う.
void strcpy1A(char *s, const char *t)
{
    while (*s++ = *t++)
        ;
}
はループの回数だけ必ずsやtはインクリメントされるけど
void strcpy2A(char *s, const char *t)
{
    int i = 0;
    while ((s[i] = t[i]) != '\0')
        i++;
}
のiはそうじゃない(t[0] == 0ならi = 0). だからこの文が続いたときの挙動は異なる(のが異なる要因となっている). strcpy1Aと比較するなら
void strcpy2B(char *s, const char *t)
{
    int i = 0;
    while ((s[i] = t[i++]) != '\0')
        ;
}
で, これならループ自体は1Aよりも1命令少ないコードが生成された(gcc 4.0.2, VC6, VC8).
またコメントにある「VC8(VC++2005)はスパゲッティ」というのは少々ミスリーディング. 1Aは
    mov    edx, DWORD PTR [esp+8]
    mov    ecx, DWORD PTR [esp+4]
.lp:
    mov    al, BYTE PTR [edx]
    mov    BYTE PTR [ecx], al
    add    ecx, 1
    add    edx, 1
    test   al, al
    jne    SHORT .lp
    ret
で2Aは
    mov    edx, DWORD PTR [esp+8]
    mov    cl, BYTE PTR [edx]
    test   cl, cl
    mov    eax, DWORD PTR [esp+4]
    mov    BYTE PTR [eax], cl
    je    .exit
    sub    edx, eax
.lp:
    mov    cl, BYTE PTR [edx+eax+1]
    add    eax, 1
    test   cl, cl
    mov    BYTE PTR [eax], cl
    jne    SHORT .lp
.exit:
    ret
だから最近のPentiumならあんまし変わんないかもしれないけどクラシックPentiumに関しては2Aの方がループ処理が高速な分優秀だ.
って書いてて思ったけどs[i] = t[i++];って合法なんだっけ. i = i++;は駄目やよね. あとで調べよう.
7月9日_
久しぶりに友達と家で鍋を囲む.
大学近辺にあった食堂の話題を振ろうとしたが名前を忘れたので「ええと, なんだっけ. いろは食堂ってあったよね」 と問いかけると, すかさず「ひらがな館のことか」と合いの手が入った. 自分の記憶力のなさと連想クイズ的ボケに苦笑しつつ, よくまあ瞬時に判ってくれたと感動した(卒業以来一度も行ってないのに).
7月2日_
今年も半年過ぎた. 昨晩は湿度の高さに負けてエアコンのドライを使う. しまった, 去年(7/19)より2週間以上も早い. だって部屋の中にP4D x 2 + P4 + CoreDuoがうなってるから, と言い訳する(最近言い訳ばかり…).

御意見は光成滋生<herumi@nifty.com>までお願いします