【#も読】高速リンカー mold(@gorilla0513)のトップ画像

【#も読】高速リンカー mold(@gorilla0513)

投稿日時:
ゴリラのアイコン

株式会社テックリード / 代表取締役

ゴリラ

Xアカウントリンク

「あの人も読んでる」略して「も読」。さまざまな寄稿者が最近気になった情報や話題をシェアする企画です。他のテックな人たちがどんな情報を追っているのか、ちょっと覗いてみませんか?


こんにちは。

前回の記事ではオブジェクトファイルについて紹介しました。

今回は最新の高速リンカーであるmoldについて紹介していきたいと思います。

moldとは

moldはLLVM lldのオリジナル作者の植山類氏によって開発された高速リンカーです。現存のリンカーの中でおそらく一番速いのではないかなと思います。

リポジトリのREADMEにも記載されていますが、Chromeをリンクする際はLLVM lldよりも4倍ほど速いです。

about_mold_speed.png

moldは既存のリンカーを簡単に置き換えれるようになっていて、たとえばRustの場合は.cargo/config.tomlに以下の様に記述するだけです。

[target.'cfg(target_os = "linux")']
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=/path/to/mold"]

また、actionsも用意されているのでCIにmoldを組み込むのも簡単です。

rui314/setup-mold: A GitHub Action to install the mold linker

余談ですが、Rustはビルド時間の長さに課題があって、高速化の手段としてmoldを使うのがよくある手法です。

Rustプロジェクトのビルド高速化に関するベストプラクティス(ローカル環境編)

moldはなぜ速いのか

実は速さを追求するための戦略が書かれたdesign docがリポジトリで公開されています。

mold/docs/design.md at main · rui314/mold

より詳細な説明はこちらの記事で書かれています。

Google製GNU gold以上の速さを実現 超高速リンカ「mold」を支えるテクニック

design docと記事によると、高速化のテクニックとして以下のことをやっているとのことです。

  • ファイル内容の直接利用
    • 中間表現(IR)を生成せず、mmap で読み込んだバイナリデータを直接処理に使用して、コピーやフォーマット変換のオーバーヘッドを排除
  • 全処理パスの並列化
    • アムダールの法則をふまえ、「並列化されていない部分を最小化」することで、コア数に応じたスケーラビリティを確保
    • mold は起動から終了までほぼ全てのパスを並列で実行する
    • データ並列処理
      • リロケーション(数千万件)やシンボル(2千万件)など、同種大量データの処理は Intel TBB の parallel_for を用いて独立イテレーションを同時実行
      • 複雑な同期機構(チャネルなど)を避け、単純な並列ループで高効率を実現
    • 並列コンテナの活用
      • 2スレッドでもほぼ2倍の性能が出るconcurrent_hash_map(Intel TBB)を使って、シンボル解決などをロック競合なしに実現
  • Map–Reduce / Merkle ツリーによるハッシュ高速化
    • 出力ファイル(例:2GB)の SHA 計算を 10MB チャンクで並列実行
    • Merkle ツリー構造により最終ハッシュを高速に構成
  • 並列文字列シリアライズ
    • 一見逐次に見える処理を parallels scan パターンで並列化
    • 計算量は若干増えるけど高速化する

個人的にこれらを読んで、なにか新しい手法を開発したわけではなく、高速化できる部分に対して的確な手法を上手に使っているところがうまいなと感心しました。

特に処理パスを可能な限り並列化するために、並列コンテナの活用は個人的になるほどと思いました。

これを知らず、自分で並列化を考える場合はおそらく普通にhash mapにロックをかけていたと思うので、ロックフリーな並列コンテナの存在を知ったのは良かったです。

また、そもそも分割してハッシュ計算するという発想がなかったので、ハッシュ計算を並列化する手法も勉強になりました。

さいごに

簡単ではありますが、高速なリンカーmoldとそれに使われている高速化のテクニックについて紹介しました。

普段ウェブアプリ開発しているとここまで高速化を突き詰めることは少ないと思うのですが、いざ高速化が必要というときに参考になるテクニックがいくつか使われているので、頭の片隅においておきたいところですね。

リンカー周りの紹介はこの記事で終わりになりますが、リンカーはどうやって実装するのかについて興味ある方はぜひこちらの記事も読んでみてください。

Rustでシンプルなリンカーを実装してみた

ゴリラさんの「も読」過去記事

プロフィール