ククログ

株式会社クリアコード > ククログ > Gandivaが使っているLLVMのJIT機能をMCJITからORCv2にしたらシンボルが見つからないエラーになっていたけどLLVM 18.1で直った

Gandivaが使っているLLVMのJIT機能をMCJITからORCv2にしたらシンボルが見つからないエラーになっていたけどLLVM 18.1で直った

Apache Arrowの開発に参加している須藤です。LLVMは詳しくないし、LLVMのどのコミットで直ったとかも調べていないし、私はレビューとか調査をしていただけで実装していないとかなんですが、最近、数年越しのGandivaの問題が直ったので雰囲気で紹介します。

Gandiva

GandivaはAapche Arrow C++に含まれている実行時式コンパイラーです。ようは実行時に与えられた式(1 + 1とか)をJITコンパイルして、さもビルド時にコンパイルしたような速度で実行できるようにするやつです。

もともと、Dremioで使いたくて作ったものをApache Arrowに寄贈したものです。DremioはJavaで実装されているので、Apache Arrow Javaからも使えるようになっています。

GandivaとLLVM

GandivaはLLVMを使って式をJITコンパイルしています。LLVMには複数のJIT機能があるらしく、当初はMCJITというJITエンジンを使っていました。その後、ORCv2というJIT APIがMCJITを非推奨にしたということで、ORCv2に移行しました

ところで、ORCがなんの略かわかっていません。何度かざっと調べたのですが見つけられませんでした。あと、JITエンジンとJIT APIをどう使い分けているのかもわかっていません。MCJITのドキュメントではJITエンジンで、ORCv2のドキュメントではJIT APIなんです。

(「ORC JIT」とかで検索するとORCは「On-Request-Compilation」の略だとわかると@hsbtに教えてもらいました!たしかにLLVMのチュートリアルにそう書いてありました!)

ORCv2とLLVM 17

しばらくはORCv2で元気に動いていましたが、LLVM 17から特定のケースで動かなくなりました。どういうケースかというと、メインのプロセスがLLVMとリンクしていないケースです。

たとえば、JavaからGandivaを使う場合はGandivaを外部ライブラリーとして用意しておいて、実行時に組み込みます。つまり、Java本体(メインのプロセス)はLLVMとはリンクされていなくて、GandivaだけがLLVMとリンクされています。この状態でORCv2を使うとllvm_orc_registerEHFrameSectionWrapperというシンボルが見つからないというエラーが発生します。関連issueはここらへんです。

私が調べた感じでは、これはLLVMがプロセスグローバルにあるllvm_orc_registerEHFrameSectionWrapperを探そうとしていることが悪いです。

先の例でいうと、JavaはGandivaを組み込むときにGandivaのシンボルをプロセスグローバルに見えるようにはしないで読み込みます。(dlopen()を知っている人にはRTLD_LOCALと言えばわかる話です。)そのため、llvm_orc_registerEHFrameSectionWrapperはプロセスグローバルには存在しません。回避策として、RTLD_GLOBALしちゃうとかLD_PRELOADしちゃうとかは考えられますが、まぁ、現実的ではありません。他にもいろいろ試しましたが、うまくいきませんでした。

そのため、古いLLVMを使ってしのいでいましたが、いつまでもそんなことをしているわけにもいきません。(非推奨になっている)MCJITに戻しちゃおうよ、という話まででてきたりしました。

LLVM 18.1

そんな中、LLVM 18.1では直っているっぽいという話があって、実際に試してみたらたしかに直っていました。

ここでLLVM 17から18.1の間のどのコミットで直ったのかを調べればいいんですけど、めんどうでやっていません。。。

ということで、詳細はわかりませんが、LLVM 18.1を使うことにしたらまた元気に動くようになりました。

まとめ

Gandivaで遭遇したLLVMのORCv2のシンボルが見つからない問題を雰囲気で説明しました。私は、実装はしていないけど、現象を調査したり、レビューしたりには結構時間を使ってがんばったやつだったので、直ってよかったなぁという気持ちでいます。

サポートサービスを契約してもらえればもっとちゃんと調べることもできるので、そんなサービスが必要な場合はクリアコードのApache Arrowサービスをどうぞ。