技術部の笹田です。遠藤さんと同じく Ruby のフルタイムコミッタとして、Ruby インタプリタの開発だけをしています。
先日、アメリカのフェニックスで開催された ISMM 2019 という会議で発表してきたのと、同時開催の PLDI 2019 という会議についでに参加してきたので、簡単にご報告します。
ISMM 2019
ISMM は、International Symposium on Memory Management の略で、メモリ管理を専門にした、世界最高の学術会議です。というと凄いカッコイイんですが、メモリ管理専門って凄くニッチすぎて、他にないってだけですね。多分。ACM(アメリカのコンピュータ関係の学会。すごい大きい)SIGPLAN(プログラミングに関する分科会。Special Interest Group)のシンポジウムになります。
発表するためには、他の多くの学術会議と同じく、論文投稿をして、査読をうけ、発表に値すると判断される必要があります。基本的に、ガーベージコレクション(GC)のテクニックの提案や、新しい malloc ライブラリの提案とか、NVMどう使うかとか、そういう話を共有する場です。
ISMM 2019 は、6/23 (日) にアメリカのアリゾナ州フェニックスで1日で開催されました。外はムッチャ暑い(40度近い)ですが、室内は空調でムッチャ寒い、というつらい環境でした。外は暑すぎて歩けなかった。
会議は、キーノート2件に通常発表が11件でした。投稿数が24件だったそうで、採択率は50%弱だったようです。日本国内の会議より難しい(私の知っている範囲では、50%はあまり切らない)けど、トップカンファレンスに比べると通りやすい、というレベルだと思います。
今回、ISMM 2019 に投稿した論文が採択されたので、はじめて行ってきました。GC に関する仕事をしているので、ISMM は一度行ってみたい会議だったので、今回参加できてとても嬉しい。Ruby の GC に関する論文の発表だったので、出張としていってきました。感謝。おかげで、最新研究の雰囲気を感じることができました。
正直、内容と英語が難しくて、あんまり聞き取れなかったんですが、分かる範囲でいくつか発表などをご紹介します。
基調講演
2件の発表がありました。
Relaxed memory ordering needs a better specification
1件目はGoogleのHans-J. Boehmさんよる「Relaxed memory ordering needs a better specification」という発表でした。Boehmさんといえば、私にとってはBoehm GCというよく知られた実装の開発者の方ということで、お会いできて大変光栄でした。最近はC++言語仕様の策定などでお名前をよく聞きますが、今回はその話でした。なお、ここ最近は GC の実装にはほとんど関わってないと伺いました。
マルチスレッドプログラミングにおいて、メモリを読み書きする順序(メモリオーダリングといいます)が問題になることがあります。書いたと思った変数の値を読み込んでみたら、書き込む前の値だった、ってことがあったら驚きますよね。実は、マルチスレッドだとそういうことが起こってしまうんです。性能を良くするために、いくつかのCPUでは、共有メモリに対する他のスレッドからの書き込みが、逐次実行で見える書き込みの順序と違う可能性があるのです。
何を言っているかよくわからないと思うんですが、正直私もよくわかりません。例えば、0初期化された共有メモリ上にある変数 a, b
があったとき、a = 1; b = 2;
というプログラムがあったら、(a, b) の組は (0, 0)、(1, 0)、(1, 2) の3通りしかないように思うんですが(逐次(シングルスレッド)プログラムだと、実際そうです)、他のスレッドから観測すると、(0, 2) という組が見えたりします(他の最適化が絡むと、もっと変なことが起る可能性があるらしいです)。わけわからないですよね? わからないんですよ。人間にはこんなの管理するのは無理だと思う。共有メモリなんて使うもんじゃない(個人の感想です)。
さて、どんなふうにメモリーオーダリングをするか、という指定をするための言語機能が C++ などにあります(std::memory_order - cppreference.com)。例えば memory_order_seq_cst
というのが一番厳しい指定で、他のスレッドからも同じように見える(つまり、上記例だと (0, 2) という組は見えない)ようになり、プログラミングするにはこれが多分一番便利です。ただ、性能のために都合の良いように CPU が順序を変えている(可能性がある)のに、その順序を厳しく制御する、ということになるので、オーバヘッドがかかります。で、どの程度厳しくするか、みたいなので、いくつか種類があるわけです。CPU によって、どの程度デフォルトが厳しいか決まるんですが、幸い、x86(x86_64)は比較的強いメモリオーダリングを行うので、あんまり難しくない、らしいのです。ARM とかだと弱いらしいとか、さっきググったらありました。やばいっすね。
今回の基調講演では memory_order_relaxed
という、多分一番ゆるい(何が起こるかわからない)メモリオーダリング指定を、どうやって仕様化すればいいか難しい、という話を、実際にすごく不思議な挙動があるんだよねぇ、という豊富な実例をあげて紹介されていました。従来の仕様では、例ベースでしか仕様に書けなかったんだけど、なんとか書きたいなぁ、でも難しいなあ、というお話でした。結論がよくわかってなかったんだけど、結局うまいこと書けたんだろうか。
なんでメモリ管理の会議 ISMM でメモリオーダリングの話が問題になるかというと、並行GCっていう研究分野があって、GC するスレッドとプログラムを実行するスレッドを並行・並列に実行していくってのがあるんですね。で、それを実現するためにはメモリオーダリングをすごく気にしないといけないわけです。これもきっと人間には無理だと思うんですが、実際にいくつかの処理系でやってるのが凄いですよねえ。いやぁ凄い。
Why do big data and cloud systems stop (slow down)?
2件目のキーノートは、シカゴ大学のShan Lu氏による「Why do big data and cloud systems stop (slow down)?」という発表でした。
実際のウェブアプリケーションや分散処理基盤(Azure。共同研究されてるんでしょうなあ)でどんな問題があるか、主に性能の観点から分析してみたよ、という話でした。ウェブサイト(Shan Lu, CS@U-Chicago)を拝見すると、輝かんばかりの業績ですね(研究者は良い学会に論文を通すことが良い業績と言われています。で、見てみると本当に凄い学会に沢山論文が採択されていて凄い)。
面白かったのが、ウェブアプリケーションの性能分析で Rails が題材になっていたことです。「あ、見たことあるコードだ」みたいな。
ウェブアプリケーションに関する分析の話は、View-Centric Performance Optimization for Database-Backed Web Applications (ICSE'19) のものだったように思います。主に ORM でのアンチパターンをいろいろ分析して(講演では、そのパターンを色々紹介されていました)、それを静的解析してアプリからそのアンチパターンを見つけて良い方法を提案するツールを作ったよ、と。Panoramaというツールを作っていて公開されています。なんと IDE (Rubymine)との統合までやっているようです。凄い。論文中に、いくつかリファクタリング例があるので、気になる方は参考にしてみてください。しかし、Rails アプリの静的解析って、えらく難しそうだけど、どれくらい決め打ちでやってるんですかねぇ。
Azure のほうは、設定間違いがほらこんなに、とか、そんなご紹介をされてたような気がします。具体的には What bugs cause production cloud incidents? (HotOS'19) の話かなぁ。論文中 Table 1 がわかりやすいので引用します。
What are the causes of incidents? ↓ Few hardware problems ↓ Few memory bugs ↓ Few generic semantic bugs ↑ Many fault-detection/handling bugs ↑ Many data-format bugs ↑ More persistent-data races How are incidents resolved? ↑ More than half through mitigation w/o patches Table 1: How are cloud incidents different from failures in single-machine systems? (↑ and ↓ indicate cloud incidents follow certain pattern more or less than single-machine systems.)
いやぁ、こういう網羅的な調査を行うって凄いですよね。
一般発表
一般発表は、次の4つのセッションに分かれていました(Program - ISMM 2019)。
- Scaling Up
- Exotica
- Mechanics
- Mechanics / Message Passing
かなり大ざっぱな区切りですよね。Exotica とか凄い名前。
そういえば、"Scaling Up"セッションは、東工大とIBM東京基礎研の方々による3件の発表となっており「東京セッション」と座長に紹介されてました。また、私が発表しているので、東京の組織の発表が11件中4件あったことになるんですね。日本人はメモリ管理好きなんでしょうか。まぁ、私は好きですけど。
いくつか紹介します。
malloc の改良
- Timescale functions for parallel memory allocation by Pengcheng Li (Google) et.al.
- A Lock-Free Coalescing-Capable Mechanism for Memory Management by Ricardo Leite (University of Porto) et.al.
- snmalloc: A Message Passing Allocator by Paul Lietar (Drexel University) et.al.
これら3件の発表は、malloc の実装を改良、もしくは新規に作りました、という話でした。なんというか、malloc()
は、まだまだ進化するんだなぁ、やることあるんだなぁ、という感想。どれも、並列計算機(マルチスレッド環境)での弱点をどう克服するか、という研究でした。
とくに最後の snmalloc は面白くて、確保 malloc()
、解放 free()
のペアって、たいていは同じスレッドで行われると仮定してライブラリを作るので、別スレッドで free()
しちゃうと余計なオーバヘッドがかかっちゃう、ことが多いようです(実際、私も作るならそう作りそう)。ただ、いくつかの種類のプログラム、例えば複数スレッドで仕事をパイプライン的に流していくとき、確保と解放は必然的に別スレッドになって、そこがボトルネックになるので、メッセージパッシング機構をうまいこと作ることで、free()
の時にしか同期が不用で速いアロケータを作ったよ、というものでした。
Google の中川さんが論文の説記事を書いていたので、ご参照ください(論文「snmalloc: A Message Passing Allocator」(ISMM 2019))。
GC の改良
- Scaling Up Parallel GC Work-Stealing in Many-Core Environments by Michihiro Horie (IBM Research, Japan) et.al.
- Learning When to Garbage Collect with Random Forests by Nicholas Jacek (UMass Amherst) et.al.
- Concurrent Marking of Shape-Changing Objects by Ulan Degenbaev (Google) et.al.
- Design and Analysis of Field-Logging Write Barriers by Steve Blackburn (Australian National University)
GCの改善の話も結構ありました。
最初の話は、IBM東京基礎研の堀江さんらによる、並列GCの work-stealing を効率化した、という話でした。GCスレッドを複数立てて、GC処理を速く終わらせるには、仕事を分散させるためのテクニックである work-stealing が必要になります。それに関するテクニックの話でした。対象が POWER なのが IBM っぽくて凄いですね。
二つ目は、GCのいろいろなチューニングをランダムフォレストでやってみよう、という話でした。GC の制御も AI 導入、みたいな文脈なんでしょうか?
三つ目は、Google V8 での並行マーキングにおいて、メモリの形(というのは、メモリレイアウトとかサイズとか)を変更しちゃう最適が、並行GCと食い合わせが悪いので、それをうまいこと性能ペナルティなくやるって話で、実際に Chrome に成果が入っているそうです。みんなが使うソフトウェアに、こういうアグレッシブな最適化を入れるの、ほんと凄いですね。話は正直よくわからんかった。
最後は、Field-Logging Write Barriersというのは、フィールド単位(Ruby でいうとインスタンス変数)ごとにライトバリアを効率良く入れる提案でした。Ruby 2.6(MRI)だと、オブジェクト単位でライトバリアを作っているんですが、さらに細かく、バリア、というか、バリアによって覚えておくものを効率良く記録する方法、みたいな話をされていました。むっちゃ既存研究ある中(発表中でも、既存研究こんなにあるよ、と紹介していた)で、さらに提案するのは凄い。
Gradual Write-Barrier Insertion into a Ruby Interpreter
私(笹田)の発表は、Ruby にライトバリア入れて世代別GCとか作ったよ、という Ruby 2.1 から開発を続けている話を紹介しました(Gradual write-barrier insertion into a Ruby interpreter、スライド資料)。2013年に思いついたアイディアなので、こういう学会で発表するのはどうかと思ったんですが、ちゃんとこういう場で発表しておいたほうが、他の人が同じような悩みをしなくても済むかも、と思って発表しました。RubyKaigi などでしゃべっていた内容をまとめたものですね。
簡単にご紹介すると、Ruby 2.1 には世代別GC(マーキング)、2.2 にはインクリメンタルGC(マーキング)が導入されました。これを実現するために、"Write-barrier unprotectred object"という概念を導入して、ライトバリアが不完全でもちゃんと動く仕組みを作った、という話です(次回の Web+DB の連載「Ruby のウラガワ」でも解説しますよ。宣伝でした)。GC は遅い、という Ruby の欠点は、この工夫でかなり払拭できたんじゃないかと思います。まだ GC が遅い、というアプリケーションをお持ちの方は、ぜひベンチマークを添えて笹田までご連絡ください。
「Gradual WB insertion」というタイトルは、ライトバリアをちょっとずつ入れて良い、って話で、実際 Ruby 2.1 から Ruby 2.6 までに、徐々にライトバリアを入れていったという記録を添えて、ちゃんと「Gradual に開発できたよ」ということを実証しました、という話になります。
結構面白い話だと思うんだけど、アイディア自体が簡単だったからか、質問とかほとんどなくて残念でした。まぁ、あまり研究の本流ではないので、しょうがないのかなぁ(本流は、ライトバリアなど当然のようにある環境でのGCを考えます)。
PLDI 2019
PLDI は、Programming Language Design and Implementation の略で、プログラミング言語の設計と実装について議論する、世界で最高の学術会議の一つです。以前は、実装の話が多かったんですが、PLDI 2019から引用しますが、
PLDI is the premier forum in the field of programming languages and programming systems research, covering the areas of design, implementation, theory, applications, and performance.
とあって、設計と実装だけじゃなく、理論やアプリケーション、性能の分析など、プログラミング言語に関する多岐にわたる話題について議論する場です。言語処理系に関する仕事をしているので、一度は行ってみたかった会議です。ISMM出張のついでに出席させて貰いました。参加費だけでも6万円くらいするんですよね。
PLDI 2019 は、6/24-26 の3日間で行われました。ISMM 2019 は、この PLDI 2019 に併設されています。PLDI は言語処理系によるメモリ管理もスコープに入っているので、実は ISMM で発表するよりも PLDI で発表するほうが、他の人から「凄い」と言われます。どの程度凄いことかというと、283論文が投稿され、その中で76本が採択されたそうです(27%の採択率)。これでも、例年より高かったそうです。死ぬまでに一度は通してみたい気もしますね。まぁ、難しいかなぁ(例えば、日本人で PLDI に論文を通した人は、あんまり居ません)。
発表
三日間で最大3セッションパラレルに発表がされるため、あまりちゃんと追えていないのですが、印象に残った発表についてちょっとご紹介します。
ちなみに、以前は結構、がっつり実装の話が多かったんですが、今回の発表は、
- 理論的な分析の話
- 特定分野(例えば機械学習)の DSL の話
が多いなぁという印象であり、あんまり(私が)楽しい実装の話は少なかったように思います。
セッションは次の通り(これだけ見てもムッチャ多い)
- Concurrency 1, 2
- Language Design 1, 2
- Probabilistic Programming
- Synthesis
- Memory Management
- Parsing
- Bug Finding & Testing 1, 2
- Parallelism and Super Computing 1, 2
- Type Systems 1, 2, 3
- Learning Specifications
- Reasoning and Optimizing ML Models
- Static Analysis
- Dynamics: Analysis and Compilation
- Performance
- Systems 1, 2
- Verification 1, 2
いくつかご紹介します。
Renaissance: Benchmarking Suite for Parallel Applications on the JVM
発表は聞いてないんですが、JVM の並列実行ベンチマークについての発表だったそうです。よく DaCapo とかが使われていましたが、また新しく加わるのかな。
DSL
繰り返しになりますが、ある分野に対する DSL の話が沢山ありました。ちょっと例を挙げてみます。
- LoCal: A Language for Programs Operating on Serialized Data は、シリアライズされた状態のままデータを操作する DSL
- Compiling KB-Sized Machine Learning Models to Tiny IoT Devices は、IoT 環境みたいなリソースセンシティブな閑居杖、良い感じに整数で浮動小数点っぽい計算をする DSL
- CHET: An Optimizing Compiler for Fully-Homomorphic Neural-Network Inferencing は、暗号化したまま計算する仕組みのための DSL/Compiler(多分。自信ない)。
- FaCT: A DSL for Timing-Sensitive Computation は、タイミングアタック(計算時間によって秘密情報を取ろうというサイドチャンネルアタック)を防ぐために、計算時間を結果にかかわらず一定にするコードを生成するための DSL(多分)。
なんかがありました。もっとあると思います。適用領域が変われば言語も変わる。正しいプログラミング言語の用い方だと思いました。
メモリ管理
メモリ管理はわかりやすい話が多くて楽しかったです。
- AutoPersist: An Easy-To-Use Java NVM Framework Based on Reachability は、Java (JVM) に、良い感じに NVM (Non-volatile-memory) を導入する仕組みを提案。
- Mesh: Compacting Memory Management for C/C++ Applications C/C++ で無理矢理コンパクションを実現しちゃう共学のメモリアロケータの実装。
- Panthera: Holistic Memory Management for Big Data Processing over Hybrid Memories は、NVM をでかいメモリが必要な計算でうまいこと使うためのシステムの紹介。
Mesh については、これまた Google 中川さんの論文紹介が参考になります(論文「MESH: Compacting Memory Management for C/C++ Applications」(PLDI 2019))。むっちゃ面白い。Stripe にも務めている(多分、論文自体は大学の研究)ためか、評価プログラムに Ruby があって面白かった。ちょっと聞いたら(発表後の質疑応答行列に30分待ちました。凄い人気だった)、Ruby のこの辺がうまくマッチしなくて云々、みたいな話をされてました。
Reusable Inline Caching for JavaScript Performance
V8のインラインキャッシュを、再利用可能にして、次のブート時間を短縮しよう、という研究でした。私でも概要がわかる内容で良かった。インラインキャッシュの情報って、基本的には毎回変わっちゃうんで、難しいのではないかと思って聞いてたんですが、巧妙に変わらない内容と変わる内容をわけて、変わらないものだけうまいことキャッシュして、うまくボトルネック(ハッシュ表の検索など)を避ける、という話でした。V8って膨大なソースコードがありそうなので、Google の人に聞いたのですか、と聞いてみたら、全部独学だそうで、すごい苦労して読んだと言ってました。凄い。
Type-Level Computations for Ruby Libraries
RDL なんかを作っている Foster 先生のグループの発表で、Ruby では動的な定義によって、実行時に型が作られるので、じゃあ実行時に型を作ってしまおうという提案です。Ruby でも PLDI に通るんだなあ、と心強く感じます。Ruby 3 の型はどうなるんでしょうね。
A Complete Formal Semantics of x86-64 User-Level Instruction Set Architecture
x86-64 の全命令(3000命令弱といってた)に形式定義を K というツールのフォーマットで記述した、という発表で、ただただ物量が凄い。おかげで、マニュアルなどにバグを見つけたとのことです。成果は Github で公開されてます(kframework/X86-64-semantics: Semantics of x86-64 in K)。
おわりに
ISMMはPLDIに併設されたシンポジウムですが、PLDIもFCRC という、学会が集まった大きな会議の一部として開催されました。懇親会はボーリング場などが併設された会場で行われ、いろいろ規模が凄かったです。
こういう学会に出席すると、最新の研究成果に触れることができます。正直、しっかりと理解できないものが多いのですが、雰囲気というか、今、どういうことが問題とされ、どういうところまで解けているんだ、ということがわかります(まだ、malloc ライブラリの研究ってこんなにやることあるんだ...とか)。このあたりの知見は、回り回って Ruby の開発にも役に立つと信じています。立つと良いなぁ。
今回の論文執筆と参加をサポートしてくれたクックパッドに感謝します。