1 ポイント 投稿者 GN⁺ 2025-03-19 | 1件のコメント | WhatsAppで共有
  • Ubuntuで提供されるjqのソースコードパッケージを自分でビルドすると、性能が最大90%向上する可能性がある
  • コンパイラ、最適化フラグ、メモリアロケータを改善することで性能を最大化する

設定

  • jqはJSON形式のGeoJSONファイル処理に使われる
    • 500MBのAlameda County Assessor's parcel mapで、特定の値以上のすべてのparcelの都市名を出力するクエリを実行
  • Ryzen 9 9950Xシステムで、キャッシュ済みファイル基準で約5秒かかるため、これを改善してみることにした

1段階: パッケージの再ビルド

  • Launchpadからjqのソースコードをダウンロードし、フラグなしで再ビルド
  • 結果: 2〜4%性能向上
  • ベンチマーク結果
    • ビルドしたjq: 平均4.517秒
    • Ubuntu標準パッケージ: 平均4.641秒
    • 性能改善: 1.03倍高速化

2段階: Clangと高度な最適化フラグの使用

  • Clang-18でコンパイルし、最適化レベルとLTOを使用
  • 使用した主なフラグ:
    • -O3 → 最適化レベルを向上
    • -flto → Link-Time Optimizationを適用
    • -DNDEBUG → デバッグコードを除外
  • ベンチマーク結果
    • ビルドしたjq: 平均3.853秒
    • Ubuntu標準パッケージ: 平均4.631秒
    • 性能改善: 1.20倍高速化

3段階: TCMallocを追加

  • GNU libcのデフォルトmallocの代わりにTCMallocを使用
  • -L/usr/lib/x86_64-linux-gnu -ltcmalloc_minimalを追加してビルド
  • ベンチマーク結果
    • ビルドしたjq: 平均3.253秒
    • Ubuntu標準パッケージ: 平均4.611秒
    • 性能改善: 1.42倍高速化

4段階: TCMallocの動的プリロードを適用

  • Ubuntu標準パッケージで動的プリロードによりTCMallocを使用
  • ベンチマーク結果
    • 標準jq: 平均4.601秒
    • TCMalloc適用jq: 平均4.082秒
    • 性能改善: 1.13倍高速化

5段階: 別のアロケータの動的プリロードをテスト

  • Ubuntuで提供される別のメモリアロケータであるjemallocmimallocをテスト
  • mimallocが最も優れた性能を提供
  • ベンチマーク結果
    • 標準jq: 平均4.123秒
    • TCMalloc適用jq: 平均4.130秒
    • jemalloc適用jq: 平均3.510秒
    • mimalloc適用jq: 平均3.154秒 → 性能1.31倍向上

6段階: mimallocで直接ビルド

  • mimallocを動的プリロードではなく静的リンク
  • 性能を最大化
  • ベンチマーク結果
    • ビルドしたjq: 平均2.428秒
    • Ubuntu標準パッケージ: 平均4.606秒
    • 性能改善: 1.90倍高速化

🚀 最終結果

  • Ubuntuパッケージより、自分でビルドしたjqのほうが90%高速
  • 2.2GBのJSONファイル13,000件の処理性能:
    • ビルドしたjq: 0.755秒
    • 標準jq: 1.424秒
    • 性能改善: 約2倍

1件のコメント

 
GN⁺ 2025-03-19
Hacker Newsのコメント
  • 「Ubuntuパッケージを再構築し、メモリアロケータを変更して90%高速化する」というタイトルはクリックベイトっぽい

    • たった1つのパッケージについての話であり、一部の性能向上は再コンパイルによって実現されたものではない
    • jemalloc をプリロードして malloc 実装を置き換えた経験があり、メモリ使用量の安定化に良い結果が得られた
    • これはメモリリーク問題を解決し、アプリケーション自体の問題ではなくメモリ断片化の問題だった可能性が高い
  • エンジニアリングは妥協の芸術である

    • 記事では、メモリアロケータを特化させることで性能向上の大部分を得たと説明している
    • マルチスレッドのプロジェクトではアロケータの選択が重要で、あるプロジェクトでの高速化が別のプロジェクトではクラッシュを引き起こす可能性がある
    • 再割り当て戦略も考慮すべきで、長期的な安定性と短期的な速度の間で選択が必要になる
    • 動画編集ソフトの開発中にさまざまなアロケータを試し、glibc のアロケータが長期的な安定性を提供することを発見した
  • Gentoo Linuxは、ユーザーの特定の用途に合わせて最適化できるよう設計されたオペレーティングシステムである

    • 初期設定後は使いやすく、Gentoo Linuxのチャンネルで多くの友人を作った記憶がある
    • 初期のChromeOSは、基本的にカスタムGentoo Linuxのインストールだった
  • jq のようなパッケージを手動でインストールすると、セキュリティアップデートの対象外になる可能性がある

    • たとえば onigurama のセキュリティアップデートがあり、このような状況が再び起これば脆弱になる可能性がある
    • CVE-2017-9224 など、複数のセキュリティ脆弱性が修正された事例がある
  • 非公式な malloc を使うと奇妙なバグが発生することがある

    • 開発者が使っているフラグの範囲を超えると、問題が起こる可能性が高い
  • 単純な変更で大きな高速化が得られると読んで、jq の開発者に知らせたいと思った

    • 記事ではこのオプションを検討していないようで、コメントでも言及されていない
  • パッケージをソースからコンパイルしたり、公式バイナリをダウンロードしたりすることは有益な場合がある

    • 手動インストールやソースコンパイルしたパッケージの更新確認は難しかったが、これを解決するためのツールを開発した
  • Rustの cargo install 機能は、特定プラットフォーム向けの最適化を可能にするため有用である

    • jaqyq は、jq を使う際に性能向上のためによく使う選択肢である
  • メモリアロケータを変更した後にUbuntuパッケージを再構築すると、90%高速化できる可能性がある

    • DebianやRedHatでも動作する可能性がある
    • 最初は、UbuntuをLinux From Scratchに変換する記事かと思った