憂鬱な午後のひととき


6月26日_

『池上彰の宗教がわかれば世界が見える』(池上彰)

最初に, 最近のトピックや事件にからめて世界の宗教についてサーベイし, その後, キリスト教, イスラム教, 仏教, 神道の専門家との対談をしつつそれぞれの宗教について詳しく見る.

よくできてる. 分かりにくい専門的な言葉が飛び出すと著者がちょっと待ってと平易な言葉で解説してくれる.

日本人の「無宗教」はキリスト教などの一神教に対するアンチではなく意識していないだけで深く根付いている, 他の宗教に寛容なのだ. というあたりの話は以前読んだ『日本人はなぜ無宗教なのか』(阿満利麿)でより詳しく解説されていたのですんなり入る.

個人的には「キリスト教やイスラム教の派閥は同じ神様を信じてるのになんで対立ばっかりしてるのか」という疑問が多少は解消されるかと思っていたけど, まあ無理だなという身も蓋もない感想を持った.
「イスラム共同体は73個の分派にわかれてそのうち一つだけが正しい」というムハンマドの言葉があるらしい.

6月24日_

味覚異常

今月頭にえらい風邪ひいてから体調が悪い. ずっと喉が痛いのでいくつか薬を飲んでるのだけどなかなか直らない. で, 最近やけに牛乳が苦いと思ったら飲んでる薬に味覚異常が出るとあった. へぇ. 眠たくなる薬も飲んでるので, めちゃくちゃ眠たいのだが味が変わるのは初めて.

6月22日_

nasmのvpsllwのバグのパッチ

昨日Xbyakに追加し忘れていた命令群を追加したときに, またnasmのバグを見つけたので報告しておいた. レポートが段々定型文になってきてる. しかしこうもバグの割合が高いとテストとして使うにはコストが高いな. yasmだけにしようかな. ただyasmとmasmとnasmの出力が違っててどれが正しいのか分からんというときもあったし, まだしばらくは現状維持するか(人の振りみて我が振り直せ).

6月21日_

Xbaykにラベルのアドレスを埋め込むputL()命令を追加

PCSX2の高速化やってるGabestさんからのご依頼. これまでもよくバグ報告をしてくださって大変ありがたい. 今回も追加し忘れていたいくつかのAVX2命令を教えてくださった.

putL()はテーブルジャンプしたいときに使う. こんな感じ.

    // ジャンプテーブルでraxの値に応じて分岐
    mov(rcx, ".jmp_table");
    jmp(ptr [rcx + rax * (int)sizeof(size_t)]);

L(".label1");
    mov(rax, 5);
    jmp(".end");

L(".label2");
    mov(rax, 8);
    jmp(".end");

L(".label3");
    mov(rax, 9);
    jmp(".end");

L(".end");
    ret();

    align(8);
L(".jmp_table"); // 多分コードとは離して置いた方がよい
putL(".label1"); // .labe1のアドレスを埋め込む
putL(".label2");
putL(".label3");

putL()で指定するラベルは上のように先に定義されていてもいいし, 後で定義してもいい. Xbyak::AutoGrowの自動メモリ伸長モードでも使える.

先頭2行は

jmp(ptr [rcx + rax * 8 + Label(".jmp_table")]);

のように書けるとよいけど, 結構な修正が必要で当分は諦める. 現状の酷いコードをリファクタリングができたらできるようにしたいな.

6月20日_

『日本語の値段』(井上史雄)

世界中にある言語は, 心情的にはそれらは互いに同等の価値があると思いたい. しかし実はれっきとした格差があるということを指摘する. 格差を学びやすさ, それを獲得したことによる利点などの市場価値の観点を用いて示す.

言語の違いだけでなく, 一つの言語でも地域による違い, たとえば戦後, 国内で方言の価値がどう変動したかに関して様々なデータが提示される. おもしろい.

ただ文章の端々に人を小馬鹿にしたようなやや上から目線の表現があるように感じられた(私の僻みな気もするが).

『ケセン語入門』というテキストで, 辞書と文法書と教科書があるらしい. ケセン語は岩手県南部の地元の言葉. リアル『吉里吉里人』(井上ひさし)だろうな. ちょっとみてみたい.

機械学習 はじめよう 第19回 ロジスティック回帰の学習

本当だlogisticって資材の調達, 物流管理って意味なんだ. 論理学に関係がある言葉とばっかり思い込んでいた. 社内勉強会で教えもらってたっけ. 全然覚えていない…. それはともかく機会学習は計算できてなんぼのものということが分かりやすく書かれててよい.

6月15日_

C++Now! 2013の資料を読む会

私自身はまだC++11でコードを書いてないのだが, 最近社内でもC++11の勉強会始まったし, どんなものか参加してみた.

渋谷の乗り換えは相変わらずどこまで歩かされるのか分からず登ったり降りたりでいらいらする. 下北沢って降りるの初めてで, OpenSource Cafeというのは住宅街の中にあった. 1日1ドリンク1000円でネットワークが使える. 食べ物はあまりないのでお腹が減ると駅前まで戻って買物(持ち込み可).

資料は各自勝手に読み進める. 気になったところがあったら質問する. 最初の方は前から順に読んでいたが飽きたので途中で適当に拾い読み. スレッドネタが多かったが重複してる内容も多い.

Richard Saunders: Thread-safe and Thread-neutral Bagsのグラフに対して 「横軸スレッド数で縦軸時間ならスケールしてるかどうかわからんだろ」というshinhさんのつっこみ.

「スレッド数増えたら速くなってるみたいだからえんちゃいますか」とか適当に答えたら「速くなるのは当たり前で」. それはごもっとも.

でもしばらく前にcygwinのマルチスレッド環境でmalloc/free使うと劇遅になって困ったりして, という話から, tcmallocはどう? そんな感じのゆるやかな雑談.

「std::mutexのunlockって規格上は"Throws: Nothing"なのにnoexceptが付いてないのはなんでなんですかね」って質問するとcpp_akiraさんから すかさず「事前条件が守られていないとき実装上例外を投げてもよいため」とのお答え. なるほど. N3279(Conservative use of noexcept in the library)でごっそりnoexceptが標準ライブラリから消えていた.

処理系の話ではgccのstd::listのsize()が4.7.0, 4.7.1でO(1)になったのに4.8でO(n)に戻ったっぽい( Bug 49561 [C++0x] std::list::size complexityとか std::stringがまだCoWの実装で規格に準拠していない, それが嫌だったらext/vstring.hを使う必要があるらしいとか.

簡単なtuple_catのサンプルがVC12では怒濤のコンパイルエラーになって悲しかった.

帰りはshinhさんとpepshisoさんと駅前でカレーを食べて帰る. よく考えたら昨日の朝も, 今日の朝も昼もカレーだった.

6月12日_

定期検査のため病院に行ったら, 1時間以上待ってる間に体調が悪くなって風邪をひいてしまった.

行く前は健康だったのに本末転倒だなあ.

6月11日_

A Fast Implementation of the Optimal Ate Pairing over BN curve on Intel Haswell Processor(ePrint)

Haswellのmulx使うとペアリングが13%速くなったよというレポートを書いてみた. 新しいアルゴリズムは何もないので本当に単なる実験結果. でも意外と反響があって驚いた. 出して数時間で海外の人からメールやtwitter. ガンガンつっこむなあ. この業界, 奥ゆかしさは悪なんやな.

属性ベース暗号の実装 (Software implementation of Atribute-Based Encryption)

しばらく前からLuisさんやFranciscoさんや照屋さんたちとやってたのを公開した. 上記ペアリングを使った応用方面のやつ. こちらは私はサブな感じで. 論文は投稿中.

まだまだプロトタイプ実装の域を出ないので「属性ベース暗号」を簡単には扱えない. こちらも余力があれば使い勝手のよいものにしたいね.

6月8日_

Benchmark of Optimal Ate Pairing on Haswell(続き)

4日のベンチマークはてっきりTurboBoost enableの状態かと思っていたらdisableだった. そして私はenableのときのrdtscの値の意味を間違えていた. w_oさんにいろいろ教えていただいた. どうもありがとうございました.

『単純な脳、複雑な「私」』(池谷裕二)

まだ最初しか読んでないけど実におもしろい. 最初に因果関係と相関関係の違いから入ってるのもよい.

サブリミナルって, 「ポップコーンの売り上げの実験で言われたけどそれは嘘だった」程度の話しか聞いたことなかったけどきちんと実験すれば効果があったことが示されているらしい(2003年の論文).

大脳基底核の淡蒼球(たんそうきゅう)という部分の活動が関わってるらしい. そして大脳基底核は直感という能力にも関わってるそうな. へえ.

「直感」と「ひらめき」は脳内メカニズムが全く違うとかいろいろおもしろい(というかそもそも別物とは思わなかった). 「直感」はなんだかわからないけどそう思うもの, ひらめきは後から理由を説明できるものなんだそうな. 本の最後に参考文献がいろいろあげられているので機会があればみてみたい.

6月4日_

Benchmark of Optimal Ate Pairing on Haswell

@tanakmuraさんがベンチマークをとってbbsに張り付けてくださった. ありがとうございます.

254bit同士のMontgomery乗算であるFp:mulがmulxなしで98clkだったのがmulxを使うと89clk. pairingが1.32Mclkから1.17Mclkと10%ちょいの高速化. i7 2600Kが1.36Mclkだったので1命令の追加としてはかなりいい感じ. 今すぐ全マシンにmulxを入れて欲しい. mulを使うのは面倒すぎる. あと, 私としては1割速くなるという予想があたったので満足.

w_oさんのhaswellの他の命令のベンチマークを見るとFPUの乗算もよいようだ. 期待(してない)のgather命令は予定通りinsert命令使った方が速かったそうな. orz.

6月2日_

Optimal Ate Pairingでmulxを使ってみる

昨日は関東GPGPU勉強会#2に参加したのだけど, あまりに体調が悪くて途中で退出. 新宿までの道のりをふらふらと帰る. 渋谷のJR⇔東急の乗り換えも悪夢だった. 何故か行きも帰りも階段だった. 帰ったら熱が40度以上で, 悪寒がとまらない. 腰も痛い. 歯ががちがちなるというのは初めての経験だ.

今日もまだ38度前後あるのだけど, ぼーとしながらate-pairingでmulxを使ってみた. 256bit x 256bit → 512bit整数乗算はもともとmulが16回で最小だったのでmovしか減らない(Karatsubaは遅かった). それでも36個のmovが減ったので多少は速くなってると思うのだがどうだろう.

Fp::mulが120 clkぐらいなので10clk減ると1割かな. movは実行ユニットにあまり関係なさそうだから, そこまでいかない?

どなたかHaswell持ってる方, 試してもらえるとありがたいのですが. test/bnでmulxが使えるなら使う, test/bn -mulx 0でmulxを使わないバージョンが動作します.

6月1日_

Haswellのmulxを使った多倍長乗算

XbyakをHaswell対応させたので早速mulxを使ってみる. mulxは入力が二つのレジスタ(一つはrdx固定)で, 二つのレジスタに出力する.

 mulx H, L, x ; [H:L] <- x * rdx

H, L, xは(64bit)汎用レジスタ. xとrdxの結果が128bitとして[H:L]になる. そして一番大事な点はフラグを一切変更しないこと.

ためしにuint64_t x[n];にuint64_t yを掛ける乗算命令を実装してみよう.

その前に準備をいくつか. 一つはmulxが使えるかどうかの判定. eax = 7, ecx = 0の状態でcpuidをみればよいらしい. eaxだけじゃないので__cpuid()ではなく__cpuidex()を使う. gccなら__cpuid_count().

Xbyak::util::Cpu.has(tGPR2)がtrueなら使える. 新たに拡張されたVEXエンコード一般命令のうちandn, bextr, blsi, blsmk, blsr, tzcntはグループ1, bzhi, mulx, pdep, pext, rorx, sarx, shlx, shrxはグループ2に属してるらしい.

bsfの後継のtzcntはグループ1なのにbsrの後継のlzcntは専用のフラグが割り当てられている. このあたりどういうルールかよく分からん.

もう一つは私はHaswellを持ってない. Intel Software Development Emulatorを使って試す. 残念ながら命令のCPU cycleは分からないようだ. Xbyakのtest_util.cppサンプルで命令チェックをしてみる.

xbyak/sample>sde -- test_util.exe
64bit
vendor intel
 mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp osxsave
 (xgetvb) pclmulqdq avx fma avx2 gpr-group1 gpr-group2 lzcnt
popcnt ok
family=6, model=C, stepping=1, extFamily=0, extModel=3
display:family=6, model=3C

エミュレータ上ではfma, avx2, gpr-group1, group2, lzcntが利用可能になっている.

さて, 多倍長乗算は筆算で行う.

  x3 x2 x1 x0
*           y
-------------
         x0*y
      x1*y
   x2*y
x3*y

今まではmulがフラグを変更してしまうのでx0*y, x1*yの値を求めながらadcを使って加算していくことができなかった. 仕方がないので一端全部の乗算結果をメモリに保持するか, addの回数を2倍にするか, レジスタの許す限り途中経過を保持してやるかぐらいしか手がなかった.

mulxはフラグを変更しないのでそんなことは気にしなくてよい. すばらしい(fp_generator.hpp).

void gen_raw_mulI_with_mulx(const Reg32e& pz, const Reg32e& px, const Reg64& y, const Reg64& t0, const Reg64& t1, int n)
{
    mov(rdx, ptr [px]);
    mulx(rax, t0, y);
    mov(ptr [pz], t0);
    const Reg64 *pt0 = &rax;
    const Reg64 *pt1 = &t1;
    for (int i = 1; i < n; i++) {
        mov(rdx, ptr [px + 8 * i]);
        mulx(*pt1, t0, y);
        if (i == 1) {
            add(*pt0, t0);
        } else {
            adc(*pt0, t0);
        }
        mov(ptr [pz + 8 * i], *pt0);
        std::swap(pt0, pt1);
    }
    if (pt1 == &rax) mov(rax, *pt0);
    adc(rax, 0);
}

このコードはn = 2ならWindowsでは

uint64_t mulI(uint64_t *pz, const uint64_t *px, uint64_t y);
mov   r11,rdx         // r11 = px
mov   rdx,ptr [r11]   // rdx = px[0]
mulx  rax,r9,r8       // [rax:r9] = px[0] * y
mov   ptr [rcx],r9    // pz[0] = r9
mov   rdx,ptr [r11+8] // rdx = px[1]
mulx  r10,r9,r8       // [r10:r9] = px[1] * y
add   rax,r9
mov   ptr [rcx+8],rax
mov   rax,r10
adc   rax,0
ret

n = 3なら

mov   r11,rdx
mov   rdx,ptr [r11]
mulx  rax,r9,r8
mov   ptr [rcx],r9
mov   rdx,ptr [r11+8]
mulx  r10,r9,r8
add   rax,r9
mov   ptr [rcx+8],rax
mov   rdx,ptr [r11+10h]
mulx  rax,r9,r8
adc   r10,r9
mov   ptr [rcx+10h],r10
adc   rax,0
ret

というコードを生成する. テストは通ってるので正しく動作しているようだ. 早く速度比較をしたいなあ.


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