憂鬱な午後のひととき


3月31日_
恥ずかしいいくつかのミスを修正して256usec@Core2Duo 1.8GHz. 2.6GHzだと200usecを切って188usec. 数日で1割速くなるってことはやっぱりまだ余裕があるんだろうなあ. ただレジスタ足りん!と思ったことが何度もあり, ええ加減重い腰をあげて64bit版に挑んでみるか. まずはOSのインストールから.
3月30日_
うーん, 思ったより速くならず272usec. 今週は頭痛が激しくてしんどい. 頭が緊張しっぱなしなのか夜1時頃寝ても朝6時頃目が覚めてしまう. まだ耳鳴り直らんしなあ. 困った.
3月29日_
なんか乗算内部でちょっと変更すれば数割ぐらいは速くできそうな気がした. それ以前にペアリングの関数名を間違えていた. 恥ずかしー.
3月28日_
下記のソースでなんとなくmovdqaを全てmovapsに置換したら2%ほど速くなった. この二つの命令は動作は同じ(はず)だが0x66プレフィクスが無い分, 前者は後者よりも1byte命令長が長い. なら何故使っていたのかというとマニュアルにmovapsはfloat用とあったから. 0x66プレフィクスはLCPストールを起こすので減らすべきというのは知っていたが, 以前movdqaとmovapsの違いを試したときは差は出なかった(のでマニュアルに従っていた). こんなある程度の規模のプログラムで差が出るのは面白い. ただ同様にpandをandpsに, porをorpsに変更したら速度は変わらなかったり遅くなったりした. デリケートだなあ. 考えられる原因としてはバイト長が変わったことでクリティカルパスで16byte命令境界をまたぐようになったのかもしれない. そのうち調べる(かもしれない).
プリデコードユニットは最大6命令の先頭位置を見つけることが出来るのですが,フェッチされた16バイトの中に6個を越える命令がある場合は,最初の6命令を1サイクルで処理し,残りは次のサイクルで処理されると書かれています。つまり,7命令を含む場合は,プリデコードに2サイクルを必要とし,平均速度は3.5命令/サイクルに低下してしまいます。
なお, xorに関してはpxor xm0, xm0とxorps xm0, xm0は影響が異なるので注意する. 処理は同じだが, 前者はxm0のレジスタの一部を変更した後に実行したときのpartial register stallが発生しないが後者は発生する. ---と覚えていたが, 今マニュアルを見直すとそれはPentium4までの話でCore2系ではどちらも同じらしい. ならorpsの方がよさそうだ.
3月27日_
288usec@Core2Duo 1.8GHz. 目標値に達したので公開した. 参照していた論文の実装が同クロックのCore2Duoで400usec程度だったそうなのでとりあえず現時点では世界最速と言ってよいよね?
本音をいうと209usec@Core2Duo 2.6GHzだったのでこちらで200usecを切りたかったのだがちと疲れたし, Xbyak存分に利用したつもりなのでよしとする.
あ, なんかしゃべってって頼まれたのでそこで多少解説するかもしれない.
まだまだ甘い部分はいっぱいあるので近いうちに抜かれるだろうなあ.
3月26日_
『Googleを支える技術』(西田圭介)
MapやReduceの話よりも, とにかく桁違いな, というか単位違いのスケールの大きい話に圧倒される. ちまちまやってるのが馬鹿らしくなるというかなんというか.
3月23日_
ストレスのせいかか疲れのせいか, 金曜日の夜から耳鳴りがする. 作業に集中できずあまり進まない.
3月21日_
赤外線は赤かった.
メールで
ちなみに暗順応した目でも赤外線リモコンの光は見えます。真っ暗闇に1時間くらい 居れば目の感度が最大になりますので、そこでリモコンを直視すると赤黒く光る LEDが見えます。
と教えていただいたので試してみる. 凄い. 本当に赤く光ってるのが見える. 蛍光灯のリモコンでも, パソコンやエアコンのでも見えた. エアコンのはボタンがいっぱいあるだけあって, 押す場所によって光る場所も変わった. やってる最中にうっかり蛍光灯を点灯してしまうとさっぱり見えなくなった.
3月20日_
赤外線はデジカメで見える
本当だ, 知らんかった.
3月19日_
C++ コンパイラにおける値渡しの最適化
gcc 4.1.0 -O2 -fomit-frame-pointerなら
   movl    36(%esp), %eax
   movl    $.LC1, (%esp)
   movl    %eax, 4(%esp)
   call    printf
   movl    36(%esp), %eax
   movl    $.LC1, (%esp)
   movl    %eax, 4(%esp)
   call    printf
   movl    36(%esp), %eax
   movl    $.LC1, (%esp)
   movl    %eax, 4(%esp)
   call    printf
   movl    36(%esp), %eax
   movl    $.LC1, (%esp)
   movl    %eax, 4(%esp)
   call    printf
となった. つまりこのレベルならどれも一緒. VC2008なら
proc createT_dtor
    mov    eax, DWORD PTR [esp+4]
    mov    ecx, DWORD PTR [esp+8]
    mov    DWORD PTR [eax], ecx
    ret

main
    mov    eax, DWORD PTR _v$[esp+16]
    push   eax
    push   OFFSET $SG3904
    call   _printf
    mov    ecx, DWORD PTR _v$[esp+24]
    push   ecx
    lea    edx, DWORD PTR _t$3906[esp+24]
    push   edx
    call   createT_dtor
    mov    eax, DWORD PTR _t$3906[esp+28]
    push   eax
    push   OFFSET $SG3907
    call   _printf
    mov    ecx, DWORD PTR _v$[esp+40]
    push   ecx
    push   OFFSET $SG3910
    call   _printf
    mov    edx, DWORD PTR _v$[esp+48]
    push   edx
    push   OFFSET $SG3913
    call   _printf
残念ながらcreateT_dtorの呼び出しは省略されなかったがそれ以外はほぼ同じ. というわけで細かいこと気にせず速度が必要なときに再確認した方がよいのではという至極まっとうな意見で終わる.
3月18日_
cube()の手数をできるだけ減らそうとしたけど難しい. 安直にテーブル引きに走るか. 論文ではできるだけ3乗根の方を減らそうとしてたけど, あれは前提条件が悪いと思う. 減らさないままの方が多分速い.
3月17日_
久しぶりに有給とって自転車でどたばた. ちょっと疲れた.
3月15日_
うるう年
golfとしてはjmpよりはcmovz edx, eax, xor edx, edxよりはcdq, cmpよりはtestの方がよいかな. leapじゃなくisNotLeapでよいならseteもなくせる.
proc isNotLeap
    mov     eax, [esp + 4]
    cdq
    mov     ecx, 100
    idiv    ecx
    test    edx, edx
    cmovnz  eax, edx
    and     eax, byte 3
    ret
3月14日_
第1回 勉強会・読書会
参加したいが大阪かあ. 残念.
3月13日_
今日もcube()以外のところをいじる(面倒な部分は避けたい深層意識が…). で325usec. 既に昨日書いた目標値にせまってるなあ. 文献でもSIMD使ってるので400usec程度が限界かと思っていたが, ちとやみくもに最適化を始めるタイミングが早かったかな. コード整理が大変だ. 明日は用事があるので続きは来週.
3月12日_
タコな実装だったdegree(f)を修正して400usec. cube()は明日しよう. ただSIMD化しにくいんだよなあ. どうすべ.
同一クロックでCore2がOpteronの2倍の性能とする(ありえんとおもうが)と, 文献の最速値からの推測値は479 / 2 * 2.2 / 1.8 = 292clk. だからCore2Duo 1.8GHzで300usecだせば文句無しかな. とりあえず当面の目標値とする.
3月11日_
本社のお手伝い調査が一段落したので暫く高速化に専念する. 乗算でCが残っていた部分のSIMD化完了で448usec@Core2Duo 1.8GHz. うーん400usec前半はいくと思ったのになあ. 荒っぽい部分を詰めて地道に稼ぐのも必要だが, とりあえず次はcube()やcubeRoot()を手がけよう.
3月10日_
gcc 4.3.0インストール. 今回からはgccのコンパイルにmpfrとgmpが必須になってちょっと手間取った. これらが入ったことによって
#include <stdio.h>

double calcd(int n)
{
    double ret = 0;
    for (int i = 1; i < n; i++) {
        ret += 1 / double(i);
    }
    return ret;
}

float calcf(int n)
{
    float ret = 0;
    for (int i = 1; i < n; i++) {
        ret += 1 / float(i);
    }
    return ret;
}

int main()
{
    printf("calcf=%.15f\n", calcf(10));
    printf("calcd=%.15f\n", calcd(10));
}
というコードを-O3 -Sでコンパイルしたとき
    main
    ...
    fldl    .LC3
    fstpl   4(%esp)
    movl    $.LC4, (%esp)
    call    printf
    movl    $.LC4, (%esp)
    flds    .LC5
    fstpl   4(%esp)
    call    printf
    ...
.LC1:
    .long   1065353216
    .section    .rodata.cst8,"aM",@progbits,8
    .align 8
.LC3:
    .long   463583771
    .long   1074176442
とcalcf(10), calcd(10)の値がそれぞれfloat, doubleの即値となる最適化がされるようになったっぽい. これは凄い. それではfloat型とdouble型にあるVCと同じようにdoubleとfloatを厳密に区別するようになったのかと思ったがクイズの結果は今までのgccと同じくcalcfとcalcdは同一の値を返した. 要はgccが事前計算できるような小さいループの場合はdouble(64bit)とfloat(32bit)と正しく使い分け, そうじゃないときはそのどちらでもない値になってしまう. 中途半端な仕様だなあ. 何かオプションで挙動を変えられるのだろうか(ドキュメントはまだ読んでない).
3月9日_
ただいまF397上のηペアリング475usec@Core2Duo 1.8GHz. 一昨年の最速が479usec@Opteron 275(2.2GHz)らしい. 同一プロセッサだといくらなんやろか. 目指せ300usec代.
3月7日_
ペアリングはintrinsicを使うのを止めてXbyak使って書き直すことにする. もともとこのために開発したようなもんだし. intrinsicはVC/gcc, 32/64bitで動作するからお手軽に高速化できて実践では重宝するんやけどね.
3月6日_
『鉄仮面』読み終わる. 1200ページも引っ張って落ちはそれかあ. まあそんなけ読ませるのもたいしたもんや.
3月5日_
・大学生の頃にその存在だけは聞いていた『たんぽぽ娘』(風見潤編)を貸してもらう. 素朴だがよい感じ. 梶尾真治のそれ系に近い(というかこっちが元祖なのかな).
・Pentium DはやっぱSSEが遅いので見捨てたい. SSSE以降にしちゃうと比較ができなくなってしまうけどまあいいか. あ, VC2008だとデバッガもSSSEに対応してるんだ.
3月4日_
NyaRuRuの日記
Visual C++ 2008 (含む Express Edition) で WINVER を設定しないと 0x0600 (Windows Vista 以降専用) になるのは酷いかも
VC2008を使うときは気をつけよう. VC6以降はバージョンアップする毎にプロジェクトファイルが変わってしまうので可能な限りVC6を使うというのは実践的な観点からすると正しいと思う. VC2008のプロジェクトファイルはVC2005では読めないのだけど何が違うのかと比べたらversion="8.00"が"9.00"になっただけだった. ふざけるなー. ただ最新コンパイラの最適化能力と, テンプレートも魅力なんだよなあ.
3月3日_
上方演芸ホール特別版
おお~, 文枝の「たちぎれ線香」は聞くの初めてや.
3月1日_
Haskell Hackathonを横目に仕事ちょこっと, ペアリングちょこっと. 参加したかったけどこちらを優先ということで. ペアリングはCore2向けにチューンしよう. 既存のやつはPrescott?のしか数値が見当たらない. Core2でどの程度のパフォーマンス出てるんだろう.

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