Rustのドキュメント生成ツール「Rustdoc」が、ある開発者の一週間の作業で平均25%の処理時間短縮、つまり33%の高速化を達成しました。きっかけは、ベータ版で見つかった一件のエラー報告です。今回は、そのバグ調査から高速化に至るまでの過程を掘り下げます。処理速度の数字だけでなく、何が原因で、どこまでが確認できた事実なのかを順に見ていきます。
Rustdocチームの開発者が語る、25%短縮の中身
この改善を報告しているのは、Rustdocチームのメンバーであるノア・レブ・バーテル=マンゲル氏です。同氏は自身のブログで、Rustdocに対して一連のプルリクエストを送り、その結果「平均で処理時間が25%短縮された」と述べています。かみ砕いて言えば、100秒かかっていた処理が75秒で終わるようになった計算です。これは25%の時間短縮ですが、速度そのもので見ると33%のスピードアップになります(1÷0.75=約1.33)。この換算は、ニコラス・ネザーコート氏の指摘を受けて記事タイトルにも反映されたと、同氏は補足しています。
さらに個別のケースでは幅があります。実際に使われているクレートである「hyper」や「bitmaps」では最大40%の短縮、helloworldのようなマイクロベンチマークでは最大60%の短縮が確認されたとのことです。ここで注意すべき点は、「平均25%」と「最大40%・60%」は別の数字だという点です。平均値は複数のベンチマークをならした結果であり、最大値は特定のクレートやテストで観測された、いわば最も条件が良かったケースの数字です。読者が「Rustdocは常に40%速くなる」と受け取ると、平均との差で誤解が生まれます。
きっかけとなったのは、Rust release teamのメンバーである@theemathas氏が、Rustdocのコミュニティチャット(Zulip)に投稿した一件の報告でした。GitHub上のプロフィールによれば、theemathas氏はTim (Theemathas) Chirananthavat氏で、Rustで書かれたチェスエンジンなどのリポジトリを公開している人物です。GitHub
報告されたのは、Rustの最新ベータ版における「奇妙な回帰(リグレッション)」でした。Rustdocはcargo docの裏側で動くツールで、標準ライブラリのドキュメントやdocs.rs上のクレートのドキュメントは、すべてRustdocの出力です。Rustの安定版がリリースされる前、リリースチームは「Crater」というツールを使い、新しいバージョンを公開のRustエコシステム全体でテストします。GitHub上のCrater公式リポジトリの説明によれば、Craterは「Rustコンパイラの回帰を検出すること」を主な目的とし、多数のクレートをビルドしてテストスイートを実行し、2つのバージョン間で結果を比較する仕組みです。Linux環境でのみ動作し、Dockerさえあればローカルでも実行できるとされています。GitHub
このCraterが、「indented-blocks」という名前のクレートに対してRustdocが新たにエラーを出すことを検出しました。エラーの内容は「設定されたスタックフレームの最大数に達した」というもので、core::fmtにある内部向けのトレイトを解析している最中に発生していました。同じコードに対して、Rustコンパイラ本体(Rustc)はコンパイルを問題なく完了できていました。つまりRustcは通れるのに、Rustdocだけがそこで詰まっていたことになります。
バーテル=マンゲル氏はこの点を「気になる兆候」だったと述べています。Rustdocの多くの機能は、Rustcが提供するAPIを呼び出し、その結果を整理してユーザーに見せる仕組みで成り立っています。たとえば、あるクレートが再エクスポートした項目(自分では定義していないが外部から使えるようにした要素)のドキュメントを、まるで自分のものであるかのように埋め込んで表示する機能があります。std::vec::Vecが実際にはalloc::vec::Vecだけれど、ドキュメント上はシームレスに見えるのがその一例です。ただし、ほぼ空に近いクレートのコードから、core::fmtにある無関係なトレイトのドキュメントを埋め込もうとする理由は、通常は考えにくいはずでした。ログを確認したところ、Rustdocはまさにこのトレイトのドキュメントを埋め込もうとしていたことが確認されたといいます。
なお、Rustコンパイラが使うスタックフレームの数はRustの安定性保証の対象外であるため、このエラー自体は「問題」と断定されるものではなかった、という留保も記事内で述べられています。深く再帰するマクロや複雑なトレイトのロジックを使う場合、ユーザーがrecursion_limitという設定でRustcの再帰の許容量を引き上げる必要が生じることもある、とされています。
出典記事では、この後の具体的な修正手順として、Rustdocの内部アルゴリズムがどのように「ドキュメントページの埋め込み先」を決定しているか(修飾パスの自己型だけを見て判断し、正規化された値までは見ていない、という既存の仕様)についての説明が続きます。ただし、その修正の技術的な詳細をどこまで一般化できるかは、出典の記述の範囲を超えるため、ここでは踏み込みません。出典が説明しているのは「今回はこの既存の挙動を再現する方向で対応した」という方針までです。Lobsters経由の元記事
Rustプロジェクト全体のコンテキスト
Rustコミュニティの週刊ニュースレター「This Week in Rust」の第662号では、その直近週に「570件のプルリクエストがマージされた」ことや、コンパイラのパフォーマンス改善についての定期的な確認(トリアージ)で「複数の大きな改善が着地した」ことが報告されています。ここで言う「複数の大きな改善」がRustdocの今回の変更を直接指しているかどうかまでは、この号の記述だけからは特定できません。あくまで、同号が複数の大きな性能改善を報告していたという事実の範囲で捉えるのが妥当です。This Week in Rust
用語補足:クレートとRustdoc
出典記事では、hyperやbitmapsが実際に使われているクレートの例として、今回の性能測定の対象に挙げられています。「Rustdoc」はそのクレートのソースコードからドキュメントページを自動生成するツールで、cargo docコマンドで動きます。標準ライブラリのリファレンスサイトも、docs.rs上の各種ライブラリの説明ページも、Rustdocが生成したものです。今回の「33%速くなった」という数字は、Rustコンパイラ自体の実行速度ではなく、このドキュメント生成処理にかかる時間についての数字です。
読者にとっての意味としては、Rustでライブラリを開発・公開している人であれば、cargo docの実行時間が短縮される可能性がある、という点に尽きます。ただし、出典記事が示す短縮幅はベンチマークごとに異なり、平均25%からマイクロベンチマークでの最大60%まで幅があるため、示された測定値だけでは自分のプロジェクトでどの程度の短縮につながるかを判断することはできません。
注目ニュース
EPAが酸性雨プログラム(ARP)を「アイランド型」発電施設に適用しないと明確化
米環境保護庁(EPA)は、公共の電力網に接続されていない、いわゆる「アイランド型」の発電施設について、大気浄化法(Clean Air Act)の酸性雨プログラム(ARP)が適用されないとするガイダンスを発表しました。EPAの説明によれば、ARPは電力を販売する施設、またはエネルギー省(DOE)への発電ユニットとしての報告が義務づけられている施設に適用されるものであり、アイランド型施設はどちらにも該当しないため、対象外と結論づけたとしています。このガイダンスは、データセンター向けの発電施設を開発する企業に、立地や建設のスピードについてより多くの選択肢を与えるものだとEPAは説明しています。将来的にこの施設が電力網に接続された場合は、ARPの対象になり得るとも述べられています。EPA担当者は、このガイダンスがAI分野での米国の優位性維持と、地域社会の電気料金上昇からの保護の両立を目指すものだとコメントしています。EPA
編集後記:平均と最大値の間にある温度差
今回の記事を書いていて印象に残ったのは、「平均25%短縮」という控えめな数字と、「最大60%短縮」という数字の間にある幅の大きさです。バーテル=マンゲル氏自身、記事の冒頭で「詳細を飛ばして最後のグラフだけ見てもいい」と書いており、細部の調査プロセスに時間をかけたことを隠していません。地道な原因調査の積み重ねが平均値を押し上げ、条件が噛み合ったケースでは60%という数字にまで届く。この振れ幅こそが、パフォーマンス改善という作業の実態に近いのだろうと感じました。
