2024.12.19
システムの穴を運用でカバーしようとしてミス多発… バグが大量発生、決算が合わない状態から業務効率化を実現するまで
リンクをコピー
記事をブックマーク
光成滋生氏(以下、光成):本題に戻ってWebAssemblyなのですが、レジスタは32bitと64bitのレジスタをもっています。加算は64bit+64bitで、結果は64bitになります。Carryはもっていません。乗算は32bit×32bitの64bitです。128bitに出力する命令はありません。素直なCでできる範囲しかありません。詳しい資料はここに載っています。
Carry演算をエミュレートしないといけません。どうやってやるかですが、やることはそんなに難しくありません。64bitのxとyを足して、65bitになって、そのCarryがなくなったということは、2つの足した値が足す前よりもcに小さくなっているとCarryが発生するということです。
この命令に対応するWebAssemblyのコードは、lt_uというunsignedのless thanという意味でxとyを比較してxがyより小さかったら1になる、そうでなければ0を使います。他にle (less than or equal)とかequalとか同様にsignedに対する命令や、selectという条件演算子相当の命令もあります。
64bitなので、ここでTをunit64_tとして、入力がx、y、cの時に出力をx+yとadoc相当をエミュレートしようとすると、xにCarryに足してその値が元より小さくなっていたらCarryが発生。yに足し込んで、そのあともう1回Carryを更新します。
1回の計算で、addが3回でlt_uが2回。今までのIntelの命令だと1命令でできていたのがこのぐらいかかるのでけっこうヘビーです。しかもlt_uみたいなのは多分JIT化して内部的にはcmpとかcmovとかになるのでもっと重くなります。
数年間これを使って、64bitベースで実装していたのですが、ふと32bit単位になったらどうなるのかなと思いました。32bitのxとyに対して、ゼロ拡張してから足した値を32bit右シフトします。するとこれはCarryが入ってきます。先ほどの例でいうと、xとyとcに対してxを64bit拡張してからyとcを足します。下位32bitを取り出して、上位32bitをCarryします。
32bitのCPUでCarryがない場合は同じことをしようと思っても、64bit拡張するとC言語的に内部的に同じことをするので無駄ですが、WebAssemblyは32bitのレジスタと64bitのレジスタの2つもっているので、ちょっと様子が違います。
1回の要素辺りaddが2回、シフトが1回でゼロ拡張が2回です。64bit単位でやるところを32bit単位でやると2倍の要素になります。例えば256の場合、64bitだと4つでいけたのが32bitだと8個いるので演算回数は増えます。マイクロベンチを取ってみて、もしかしたら速くなるかなと思ったんですが、微妙に64bit版のほうが速いです。
JITがどうなるかわからないので、ブレが大きいです。昔考えた時は、ここで遅くなったので諦めたのですが、もう少し考えてみました。32bit単位の場合、このCarryのcは先ほどは1bitだったのですが、32bitあるわけですね。ということは、途中のCarryをまとめて足してから操作できます。
ここは非常に複雑な話になるので、ざっくりと結果だけ言います。256bit×256bitで512bitの乗算をやって、64bit単位で実装をしてみました。64×64から128はもっていないので、32×32の64を組み合わせて実装しました。それと今回32bit単位で実装したものを比較すると、1割から2割ぐらい速くなりました。これはちょっと意外だったのですがおもしろい結果だと思っています。
最初に紹介したペアリングは、乗算がプロファイルのかなりの部分を占めるので、これだけ速くなると全体も速くなってかなり効果が大きいです。詳しい人のために紹介しておくと、Karatsuba法という、加算を増やす代わりに乗算の回数を4回から3回に減らすという方法があります。32bit単位でやるとけっこう長い範囲になるので効果があるかなと思ったのですが、WebAssemblyの実装だと加算のほうが重くなってしまうので、このぐらいのものは使わないほうが速かったです。メインは32bitでやったほうがうまくいったということです。
ここからはちょっと違う話をします。clang-11から_Extlntという機能が導入されています。これはuint128_tやuint1024_tが実装できる言語拡張で、typedef unsigned_Extlnt(256)とやるとunit256_tが作れます。しかも今までの整数のようにキャストして読み込んで、512bitにゼロ拡張して掛け算すると、これだけで256bitの乗算ができます。
今までunitしていたのはclangが生成してくれるという非常に夢のような世界が始まっています。こういう機能をC++にも入れようという提案があって、解説しているものを要約したのもあります。将来はもしかしたら入ってくるかもしれないです。
今のところ残念なところがいくつかあって、x64でベンチマークを取ってみました。clang-11-Ofastでやりました。mclは私が実装しているライブラリで、職人的にたぶん世界最速でadox、adcxを使っています。clangはmulxまでしか使わないです。なおかつレジスタスピルをやっているのでけっこう遅いです。square演算だと半分ぐらい変わってしまいます。
でも将来clangが進化したら、これぐらいになってくるのかなという気はします。WebAssemblyですが、コンパイルはできますがリンクはできない状況です。_multi3がないと言われます。これはclangを使っていてよく見ます。clang-8の頃は自分でこの_multi3を実装して、うまいこと動いていたのですが、clang-8の時に動いていたものをclang-11で使うと、function signature mismatchと出て動きませんでした。
時間がなくてこれ以上調べていないです。まあ、割と仕様がよく変わるので仕様はよくわからないです。昔は使おうとするとLLVMが落ちていたので、ここまで生なエラーにはなっていたのでだいぶ改善されています。
実際にC、C++でwasmを生成するには、emcc(Emscriten)かclangでやります。私は主にemccを使っています。理由はいくつかあって、標準ライブラリに対応していてmallocも使えます。使わないようにしているのですが、clangだとまだまだ生なコンパイラです。
関数exportする時のやり方がちょっと違ったり、名前に"_"が付く・付かないだったり。emccで便利なのは、SINGLE_FILEとやるとWebAssemblyのバイトコード、base64コードを指定して埋め込んだjsを1個にして作ってくれるのでWebPackなどで、使いやすいです。clangはLLVM IRを使えて便利ですが、ちょっとおかしいところが多いです。
まとめます。多倍長演算ではCarryの扱いが重要です。x64には便利な命令がいろいろ書かれていて、高速化に関与しています。wasmはCarryを扱う命令がないので、これは素直に記述する範囲でしかできません。あるいはCで記述して、十分高速なコードになります。それ以上速くできない感じです。clangの_Extlntに期待しています。
個人的にはemccがLLVM IRや_Extlntをサポートしたらclangに移行してみようかなと思います。発表は以上です。ありがとうございました。
司会者:ありがとうございました。では質疑に移ります。これはサイド的な質問ですが、「wasmで暗号処理するというのは、side channel攻撃に対する考慮はどれくらいすべき・しているものでしょうか?」いかがでしょうか?
光成:難しい質問ですね。スマートフォンとかでクライアントで使う時はside channelをほとんど気にしなくていいのかなという気もします。何か攻撃するツールが入っていたらやられるというのはありますが、そうなっていたらもうside channelではなくて、どのレイヤーでもヤバいことになっているので、あまりそこは気にしなくていいのかなと思います。
ただ先ほどの紹介のように、サーバーサイドでAssemblyを使う時はや多少は気にしていかないといけないかなと思います。私自身はそんなに気にしていないのですが、最初のコード生成の時に定数時間で計算するモードを追加したりは多少やています。遅くなるけれども、より安全にしたい時はそちらのモードを使って対策をしている人が多いと思います。そこは程度によるんですけどね。やればやるほど遅くなるので。
司会者:ありがとうございます。「modのpはどうしているのかが気になる」というツイートがありました。
光成:すみません。今回は足し算・掛け算の説明だけで、modは2、3倍しゃべらないといけないのでざっくり消してしまっています。別の学会でしゃべっている資料を公開しているので、資料に興味があればそちらをご覧になってください。
司会者:ありがとうございます。もう1つ「32bitごとの演算をSIMD proposalを使ってやる予定はありますか?」という質問があります。
光成:そうですね。wasmにもSIMDが入ってくるとかあるんですが、先ほど言ったようにツールがまだこなれていません。アルゴリズムのところで悩むならいいんですが、使い勝手のほうでリソースを食ってしまうのはあまり好きではないので、まだ様子見という感じです。
司会者:ありがとうございます。
2024.12.12
会議で発言しやすくなる「心理的安全性」を高めるには ファシリテーションがうまい人の3つの条件
2024.12.19
12万通りの「資格の組み合わせ」の中で厳選された60の項目 532の資格を持つ林雄次氏の新刊『資格のかけ算』の見所
2024.12.16
32歳で成績最下位から1年でトップ営業になれた理由 売るテクニックよりも大事な「あり方」
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
2024.12.10
メールのラリー回数でわかる「評価されない人」の特徴 職場での評価を下げる行動5選
2024.12.13
ファシリテーターは「しゃべらないほうがいい」理由 入山章栄氏が語る、心理的安全性の高い場を作るポイント
PR | 2024.12.20
モンスター化したExcelが、ある日突然崩壊 昭和のガス工事会社を生まれ変わらせた、起死回生のノーコード活用術
2024.12.18
「社長以外みんな儲かる給与設計」にした理由 経営者たちが語る、優秀な人材集め・会社を発展させるためのヒント
2024.12.12
今までとこれからで、エンジニアに求められる「スキル」の違い AI時代のエンジニアの未来と生存戦略のカギとは
PR | 2024.11.26
なぜ電話営業はなくならない?その要因は「属人化」 通話内容をデータ化するZoomのクラウドサービス活用術
Climbers Startup JAPAN EXPO 2024 - 秋 -
2024.11.20 - 2024.11.21
『主体的なキャリア形成』を考える~資格のかけ算について〜
2024.12.07 - 2024.12.07
Startup CTO of the year 2024
2024.11.19 - 2024.11.19
社員の力を引き出す経営戦略〜ひとり一人が自ら成長する組織づくり〜
2024.11.20 - 2024.11.20
「確率思考」で未来を見通す 事業を成功に導く意思決定 ~エビデンス・ベースド・マーケティング思考の調査分析で事業に有効な予測手法とは~
2024.11.05 - 2024.11.05