http://int.main.jpを喪失した
更新を忘れていて契約終了しました…
このドメインはもう誰かに取得されているらしいので復元はできないです。ご愛読ありがとうございました。
僕も元から誰かが使っていた形跡のあるのを知りながら、空いていたので上書きした経緯があるので、これは因果応報ではあります。
悲しいね…データはローカルにはあるはずなのでどこか別のURLのところに置くようにします…
退職した
前回までのあらすじ : http://w0.hatenablog.com/entry/20160921/1474454159
まあ挫折しました。2年11ヶ月です。
特にどうすればよかったかとか全然わからないし無力感がある。所詮雇われ会社員のエンジニアができる事なんてたかが知れてるよねみたいなことを考えがち。
次どうするかはまだ決まっていません。少なくとも9月中は法的にも立派な無職です。15年社会人やってきて、最初の転職の時にミスって2日無職になったのを除いて、はじめて書類上もきちんと無職になります。
いまだかつてないぐらい仕事する気が起きないね…なんかもうみんな好きにすれば的な…
ただ経験的に、こういう場合って休んでても状況が改善する場合はなくて、なんか次やることをはやく見つけたほうがいい。
どうするかな…まあ今の会社では色々好き勝手にやったので、貴重な経験はできた。せっかくだし経験を生かす仕事をしたほうがいいのかなやっぱり。でも(何回も言ってるが)全然違う仕事をしたい気持ちもある。といっても私にできる仕事他にあるのか…?
まあいいや…しばらくふにゃふにゃしよ…
SVEの自動ベクタライズ
ARM SVE というベクタ拡張があるんだけど、それって公開されてるコンパイラでどのぐらい対応されるんや?という話題を見かけたので、ちょっと試してみたら良い感じだったのでついでにもう少し調べてみた。
http://d.hatena.ne.jp/w_o/20150423#1429775436
個人的には自動ベクタライザというのは信用してないんだけど、それはそれとして、ループ変換ツールとしての最適化パスの処理はまあ面白いと思ってるので。
GCCは、ビルドしてもいいけど、
ここからビルド済みバイナリが取得できるので、そちらのほうが簡単だと思う。
このGCCに、-march=armv8-a+sve -O3 を渡すと、SVEを使って自動ベクタライズしてくれるようになる。
自動ベクタライザを信用しない理由として、上のリンク先で上げてる通り、どうしても命令数がかなり膨らんでしまうというのがありますね。これは性能上のデメリットもあるんだけど、出るasmの見た目が汚なくなるから嫌という気持ちの問題も大きい。
ところが、SVE向けに自動ベクトル化で出したコードは、この命令数の膨張が無くて、見ためがスッキリしてたので好きになった。
int f(int *__restrict__ a, int *__restrict__ b, int *__restrict__ c, int n) { for (int i=0; i<n; i++) { a[i] += b[i] * c[i]; } }
これが、
f: .LFB0: .cfi_startproc cmp w3, 0 ble .L2 mov x4, 0 sxtw x3, w3 ptrue p1.s, all whilelo p0.s, xzr, x3 .p2align 3 .L3: ld1w z1.s, p0/z, [x0, x4, lsl 2] ld1w z2.s, p0/z, [x1, x4, lsl 2] ld1w z0.s, p0/z, [x2, x4, lsl 2] mad z0.s, p1/m, z2.s, z1.s st1w z0.s, p0, [x0, x4, lsl 2] incw x4 whilelo p0.s, x4, x3 bne .L3 .L2: ret
vectorizeしない場合は、
f: .LFB0: .cfi_startproc cmp w3, 0 ble .L2 mov x4, 0 .p2align 3 .L3: ldr w6, [x0, x4, lsl 2] ldr w5, [x1, x4, lsl 2] ldr w7, [x2, x4, lsl 2] madd w5, w5, w7, w6 str w5, [x0, x4, lsl 2] add x4, x4, 1 cmp w3, w4 bgt .L3 .L2: ret
ループ前の処理が3命令増えているが、ループ中の命令数は全く同じで、関数レベルで見ても12->15 の 3命令しか増えていない。neonの場合は、これが47命令の+35命令になって、ここに貼るのも嫌なレベルだ。
一番大きいのは、ループ回数がSIMD幅で割り切れない時の端数の処理に必要なマスクをwhilelo 命令一発で作れるところだろう。
http://d.hatena.ne.jp/w_o/20160901#1472719309 に昔説明を書いたけど、実際これだけ自動ベクタライザがスッキリした命令出すのを見てかなり感動しましたね。
自動ベクタライザが出すasmは汚いという時代はもう終わったんだ。
あと
int f(int *__restrict__ a, int *__restrict__ b, int *__restrict__ c, int n) { for (int i=0; i<n; i++) { if (a[i]) { a[i] += b[i] * c[i]; } } }
こういう条件付きストアがある場合でも
f: .LFB0: .cfi_startproc cmp w3, 0 ble .L2 mov x4, 0 sxtw x3, w3 ptrue p2.s, all whilelo p1.s, xzr, x3 .p2align 3 .L3: ld1w z1.s, p1/z, [x0, x4, lsl 2] cmpne p0.s, p2/z, z1.s, #0 and p0.b, p0/z, p0.b, p1.b ld1w z0.s, p0/z, [x1, x4, lsl 2] ld1w z2.s, p0/z, [x2, x4, lsl 2] mad z0.s, p2/m, z2.s, z1.s st1w z0.s, p0, [x0, x4, lsl 2] incw x4 whilelo p1.s, x4, x3 bne .L3 .L2: ret
スッキリしていて美しいですね。(でも条件付きストアはよく考えたらAVX512でも同じことになるのでSVE固有ではない)
で、まあそれはよくて、この whilelo みたいなほぼアーキ固有みたいな命令をGCCがどう扱ってるのか気になったので調べたくなった。
まあこれが富士通コンパイラなら、なんか色々追加したんだろうな、という気持ちになるけど、GCCだとあんまりアーキ固有ベッタリな変換パスがベクタライザに入ってるイメージがないので。
調べた結果としては、以下のとおりだった。
自分で調べる人は、 gcc-8.3で、-fdump-tree-all して、xx.c.161t.vect とかを見れば、色々調べられると思う。あとは -fopt-info-vec-missed の出力も参考になるかもしれない。
WHILE_ULT という whilelo と対応するtree nodeが生まれている。これはまんまwhileloで、ループ最大値とループカウンタを受け取って、それをもとにマスクを作る。
あとMASK_LOAD,MASK_STOREもある。
AVX512 用に自動ベクトル化した場合もMASK_LOAD、MASK_STOREを使うようだ。
direct_internal_fn_supported_p で、バックエンドがWHILE_ULTをサポートしてるかどうか見てる。
direct_internal_fn_supported_p は多分このmdから生成したテーブルとかで見てるんではないかな…(未確認)
それで、LOOP_VINFO_FULLY_MASKED_P が決定されてその場合は端数処理を付けないようにしてると思う。
ベクタライズのアルゴリズム自体は…みんなの宿題だゾ!
PCIe M.2 変換
なんか違和感を感じるよな。変換とは。
NVMeはプロトコルはPCIeなんだから、プロトコルは変換してない。PCIeはスロットの形も定義してるから、PCIeスロット M.2 スロット変換とでも呼ぶべきか?
まあM.2はM.2で、「M.2とは何か」みたいなのが一言で言いづらい感じはあるよな。
あと定期的に書いてる気がするが、これ系で一番好きなのは、「USBシリアル変換」で、U シリアル B シリアル変換であって、お前USBはシリアルとちゃうんか?的な的な。
真面目に考えれば、USBはちゃんとバスとして働いているのに対して、RS232Cは本当にただのシリアルなので、シリアルバス to シリアル変換と考えれば別にそれほどおかしくない気もする。
おぷたん
(書きながら更新中)
[global] ioengine=libaio size=4g direct=1 runtime=30 filename=/dev/nvme0n1 [Seq-Read] iodepth=1 bs=1m rw=read stonewall [rand-4k-q1] iodepth=1 bs=4k rw=randread stonewall [rand-4k-q32] iodepth=32 bs=4k rw=randread stonewall [rand-4k-q256] iodepth=256 bs=4k rw=randread stonewall
http://int.main.jp/files/fio/ST3000DM001.log
ST3000DM001 とかいうヤバいHDD使ってるやつはおらんやろな?
http://int.main.jp/files/fio/sm960evo.log
申しわけないが、この960EVO、NTFSしか入れてないから書き込みは測ってない。/dev/nvme0n1 でとってる。
https://twitter.com/tanakmura/status/902902676236582912
Windows で測ったやつ。CrystalDiskMark はファイルで測るから、公平な比較ではない。けど、スループットはWinのほうがいいね。ランダムは、まあ公平ではないのでなんとも…
CPU Ryzen 7 1700X、960 EVO
- アイドル49Wぐらい。
- シーケンシャル 72W
- rand 4k q32 78-80W
まあ現代のNVMeの速度なら、CPUへの影響はかなりあるので、ワットチェッカではCPUの消費電力とストレージの消費電力うまく切り離せないが…
http://int.main.jp/files/fio/optane16g.log
はい。
https://twitter.com/tanakmura/status/903698660549992448
twitterに書いてしまったのでそっち見て。
まあ一言で言うと、この性能では使うメリット無い。QD=1時の性能は確かに良いが、どこのデスクトップがQD=1時の性能を必要としてるんだ。
つまり、Optane 16G は高いだけで速度も容量もメリットは無く、実質的には、Intel謹製のNVMeキャッシュアプリケーションを買ってるだけと言っていい。
- アイドル49Wぐらい。
- seq read 68W
- seq write 66W
- rand 4k read q32 78-80W
- rand 4k write q32 68
SPDKもやろうと思ったけど、VFIO group is not viable とか出てきて使えぬ…
PCIe 差す場所変えればワンチャンあるっぽいがNVMeは差す場所変えれないが…あとACSがなんとかかんとかって書いてあるが説明読む気力が無い。
PCIe M.2 変換みたいなやつ使ってスロット変えて試すか、i7 で試すか…
http://int.main.jp/files/fio/sm960evo-2.log
960EVO ディスク後ろ空けてwriteも試した。(一瞬間違えてデータ消しかけた)
read もえらい性能上がるな。2.5GB/sと3.5GB/sぐらい違う。まあ後ろ領域使ってないから、そういう違いだろうな。そうすると、何か書いてからテストしたほうが、実際の使い方に近いのでは。
また似たような話書くけど
foobarアーキテクチャが難しいとかいう人は、今のDirectXの初期化コードとか書いて世の中の名も無いゲームプログラマが全員その難しいアーキテクチャの上でプログラム書いてるというのを理解すべきではないか。
まあ大半のプログラマはUnityとか使っててDirectXレイヤなんて使わないというのはそうなんだが、一番下のアーキテクチャが難しいという条件は同じはずで、HPCが他の分野と比べて難しいというなら、最下層アーキテクチャが難しいというところとは別のところに問題があるはずと考えるべき。
例えば、テクスチャの転送が必要でそれ用にリソース管理がいる、シェーダを別に書かないといけない、とかは、HPCでアーキテクチャ難しいと言われるのと本質的には同じ問題で、世の中のゲームは、そういうものの上で動いてるのであって、HPCの人だけが不当に難しいプログラミングをしているわけではない。
この話題しょっちゅう書いてる気がするが、まあ正直言ってHPCの人アーキテクチャに文句言いすぎだと思う。結局本質的にはDRAMと通信が遅いのが問題でどうしようもないのだから、プロセッサアーキテクチャに文句言うのって筋違いじゃない?
■
http://d.hatena.ne.jp/w_o/20170811
いやあとアドレスインターリーブの設定が変わってそう