2024.10.01
自社の社内情報を未来の“ゴミ”にしないための備え 「情報量が多すぎる」時代がもたらす課題とは?
リンクをコピー
記事をブックマーク
植山類氏:では始めます。本日、機会をいただいて講演をすることになった植山と申します。この講演の内容は「大きな問題のほうが小さな問題より解くのは簡単だ」というタイトルです。
どういう趣旨かというと、常に簡単だというわけではないのですが、いろいろな場面で、1個の本質的な問題をドッカンと解いてしまうほうが、いろいろな細かいことを考えるよりも簡単なことが多いという話です。
そういうソリューションが往々にして見逃されがちということがけっこうあって、そういうことにどうやって挑戦していくのかという気持ちの話を、僕がそういう大きな問題を解決した経験を踏まえて話をしていきたいと思います。
僕が何を作ったかというと、リンカと言われるプログラムです。「LLVM lld」というリンカと、「mold」という2つのリンカを作りました。
リンカが何なのかを説明したほうがいいと思うのですが、リンカというのは、CやC++やRustみたいな、コンパイルする言語のプログラムで必要なプログラムで、プログラムをビルドする時に使われるものです。
CやC++やRustといった種類の言語では、まずソースコードがコンパイラによってオブジェクトファイルといわれるファイルに変換されます。オブジェクトファイルは拡張子が.oのファイルで、ビルドしたあと、makeなどを走らせた後のディレクトリにたくさん.oというファイルができているのを見たことがある人も多いと思います。
オブジェクトファイルには、ソースコードをコンパイルした結果が入っているわけです。そこにはマシンコードや、例えば文字列みたいなデータがそのまま入っているわけです。ただ、オブジェクトファイルは単体では実行可能なプログラムではありません。
というのも、コンパイラは一つひとつこのソースファイルをコンパイルしているわけで、1個のソースファイルにすべてのプログラムのコードが書かれているわけではありません。なので必然的にコンパイラの出力であるオブジェクトファイルは、ソース一つひとつに対応したプログラムの断片しか入っていないわけです。だから、それ単体では実行可能じゃないんですよね。
なので、誰かがオブジェクトファイルを全部1個のファイルにがっちゃんこして、それで実行できるような形式にしてやらないといけないわけですよね。それをするのがリンカといわれるプログラムです。
なので、コンパイルするタイプの言語でプログラムを書いている限りは、意識しているかしていないかに関わらず、リンカは必ずビルドの最終ステップに走っていて、リンカによって実行ファイルなりシェアードオブジェクトファイルなりが作られることになります。
僕がmoldやlldのリンカを書いてどういう問題を解決したかというと、そのプログラムのビルド、リンクが遅い問題を解決しました。これは長らく問題になっていたのですが、解決しちゃったんですよね。
エンジニアリングというものはトレードオフであって、いろいろな要素を鑑みた上でベストな方法を選んで、いろいろな日常のエンジニアリングをしていくわけなんです。だけど往々にして小さな問題を解くことにフォーカスをしてしまって、大きな本質的な問題を解くんじゃなくて、それを回避するとか、ワークアラウンドを実装するとか、そういうことに走りがちな傾向にあります。
ど真ん中で正面から突破するみたいなことは往々にして避けられがちです。必要以上に避けられがちだと思うんですよね。なので、大きな問題を解決していこうよというのが、この講演の趣旨です。
lldやmoldが解決した問題というのは、リンクによるビルドの遅さでした。どういうことかというと、リンカはそもそもプログラムのビルドのボトルネックになりがちなんですよね。コンパイラだったら、ソースファイルの数だけプロセスを同時に立ち上げられます。そうすればCPUのコアの個数分だけは並列性があって、同時にコンパイルを進めることができるわけなんです。
ただ、リンクの最後のステップで複数のファイルを全部1個に合わせるところは、複数のプロセスで分けて分割できるような仕事ではありません。なのでその部分はシリアルにやるしかなくて、そうするとリンクそのものが遅いと、そのままの時間がかかっちゃうんですよね。
これは、ソースツリーがフレッシュな状態、クリーンな状態でビルドをするんだったらそんなには目立たちません。というのは、その時にはそもそもコンパイルが遅いので、最後のリンクが時間かかってもそれほど気にはなりません。
ただ現実的には、ソースファイルをちょこっと変更をして、ビルドして、動作を見てみて、デバッグして、またソースをちょっと変更して、ビルドしてとやっています。
いわゆる普通の開発をしていると、ソースのビルドの遅さはすごく気になってきます。コンパイラが1回だけ走って、1プロセスだけ走ってリンクが走ることになるので、リンクの遅さがすごく目立つんですね。そして、リンクの遅さは作業効率の遅さに直結するわけです。
どれぐらい直結するかというと、現代のプログラムはかなり大きいので、例えばプログラムをビルドした結果、デバッグ情報を含めると、実行ファイルが1GBを超えるものも珍しくはないんですね。そういうプログラムは、かつてはリンクするのに何十秒とか、何分とか、あるいは何十分もかかることが普通にあったんですよ。猛烈に遅いわけですよね。
30秒かかる場合でも、30秒黙って端末の前で待っていられないので、タスクをスイッチしちゃいますよね。そうすると、そこで集中力が切れてしまうわけなんですよ。場合によっては「X」を見始めるとか、Webサーフィンを始めるとかで何をやっているか忘れちゃう。30秒遅いというのは、単に30秒失うわけじゃなくてフローを失うことになるので、すごく悪い状態なんですよね。
これは問題なので、リンクを速くするためのアイデアをみんながいろいろ考えてきました。僕が自作リンカを作る前、いろいろと話を聞いていました。
僕が聞いた1つのアイデアでは、こんなものがありました。コンパイラとリンカの両方に手を入れて、コンパイラがオブジェクトファイルというかたちでマシンコードをファイルに出力するのではなくて、関数単位とかでコードをコンパイルして、データベースにしまって、データベースからリンカがコードを呼んできて出力するというアイデアを聞いたこともあります。
あるいは、2回目以降のリンクでは前回に作成した実行ファイルに、ある意味バイナリパッチを充てるようにして、前回の入力から変更された部分だけを前回の出力にアプライして、リンクの時間を短縮するようなアイデアもありました。
実際にそのアイデアが実装されたことがあって、「インクリメンタルリンク」と呼ばれています。インクリメンタルリンクを実装しているリンカは、実際にいくつもあります。
インクリメンタルリンクは良いアイデアに聞こえますが、実際には実装がすごく複雑になるし、その複雑さによってその機能そのものに実行時間のコストがかかるので、よりリンクの時間が延びたりして、良さそうに思えるけど、実際にはリンク時間を短縮することはあまりできなかったんですよね。
それ以外にもいろいろなリンクの最適化の高速化のアイデアはあったのですが、僕が見る限り、どのアイデアも根本的な理解としては「リンクは時間のかかる処理だ」ということが前提になっていたと思うんですよ。その前提は果たして本当に正しかったんでしょうか。リンクというのはそもそもそんなに重いんですか。本当にそうなんですか?
僕が書いたリンカは既存のものに比べてすごく速くて、インクリメンタルリンクもしていません。僕が考えていたのは、「インクリメンタルリンク自体が複雑だから、インクリメンタルリンクをしたいと思うこともなくなるぐらい速いものを単に作ってしまえばいいんじゃないのか」ということだったんですね。僕の書いたリンカはすごく速くて、1GBの実行ファイルでも手元のマシンだと1秒ぐらいで作れます。
僕の手元のマシンで1GBのファイルをcpコマンドでコピーすると0.5秒ぐらいかかるんですよね。ファイルをコピーするのと比べて、単純に2倍ぐらいの時間しかかからないので、ものすごく速いんですよね。
プログラミングの歴史の中で「リンクが遅い」というのは何十年も存在していた問題だったわけですが、これによってほとんど実質的に解決済みの問題になってしまったわけなんですよ。
不思議な話ですが、実際にイチから作り直してみれば、「リンクが重い処理だということ自体が、なんとなくその業界で共有はされていたけれど間違いだった」と。間違った思い込みだったというわけなんです。
なぜこういうことが可能だったか。僕がスーパープログラマーだったから効率的な物が作れたのかというと、僕としては「そうだ」と言いたいところですが、実際には別にそういうわけではないと思います。
ある程度以上の技術力はいるのですが、僕より前にそういうことをやろうとした人がどのぐらいいたのかというと、ほとんどいなかったんですよね。なので何が足りなかったかというと、単に「イチから書き直してみよう」というクレイジーな人が足りなかっただけで、やってみればかなり多くの人ができることだったということは、たぶん間違いないと思うんですよ。
ずっと業界全体として悩まされていて、ただ、リンクというのはそもそも時間がかかるからと、なんとなく見過ごされていたわけです。本当のところは、20年ぐらい前に誰かが解決するべきだったのではないかというと、そうだったんだと思います。単に挑戦者がいなかっただけの話だと思うんですよ。
今ではlldやmoldも広く使われています。lldはGoogleで僕が仕事としてやっていたプロジェクトです。僕はアメリカのGoogleのC++コンパイラチームにいて、そこで仕事をしていました。Googleで仕事の一環としてlldを作っていました。Googleを辞めて、そのあとmoldを作りました。さらに速いリンカを目指した時、mold(を作った時)なんかは、単なる個人プロジェクトに過ぎないわけです。
ですが、moldも世の中に広く認知されています。例えばGCCコンパイラでも、-fuse-ld=moldを渡すとmoldが使えるみたいな、moldを使うための専用のオプションがあったりします。
なので、僕の自作リンカのためのオプションがGCCに特別に追加されているという、考えてみればなかなかすごい状態ですが、やったらできちゃったりするわけなんですよね。
他の人がやっているのを見ると自分もできるような気がしてくるというのは、大きな会社においても同じで、むしろ大きな会社のほうがやりやすいと思うんですよね。
というのも、マネージャーを説得して新しいプロジェクトをぶち上げようという時に、「他の人がすでにできているんだから、うちの会社も当然できるはず」と言うと、プロジェクトが立ち上げやすいわけです。何の実績もなくうまくいくかわからないものを立ち上げるよりは、はるかに簡単なわけです。
なので、僕がlldとmoldを書いたことによって、スピード競争が始まって、ある意味AppleやMicrosoftは恥ずかしい状態になってしまったわけなんです。MicrosoftやAppleの開発環境のリンクのステップが妙に遅いというのは、本当はそんなにかかるべきじゃないのにかかっているという状態になってしまったわけなんですよね。
なので、Appleはそれに対して実際にプロジェクトを立ち上げて、2023年のWWDCではAppleがイチから書き直したリンカが発表されて、この間出たXcodeにはそれが含まれています。なので、僕が始めたスピード競争が、Appleまで到達しているわけなんです。このプロジェクトをAppleサイドでやっていたのはDavide Italianoという人で、僕の友だちです。
ただ、さすがにAppleでやっている未発表のプロジェクトについて教えてくれるわけはないので、彼がやっているのは知らなかったのですが、まぁ狭い世界なわけです。
なので、このセッションを聞いている人の中に、Appleプラットフォームに向けてソフトウェアを書いている人はけっこうたくさんいると思うんですよね。macOSやiOS向けのアプリケーションを書いている人は、Xcodeのリンカを使っているわけです。
Xcodeの新しいバージョンからリンクが速くなっているので、プログラムによってはビルドが気づくぐらい速くなると思うんですよ。それは僕の始めた競争の結果なので、ある意味「業界全体が改善されて良かったね」という話になると思います。
(次回に続く)
関連タグ:
2024.10.29
5〜10万円の低単価案件の受注をやめたら労働生産性が劇的に向上 相見積もり案件には提案書を出さないことで見えた“意外な効果”
2024.10.24
パワポ資料の「手戻り」が多すぎる問題の解消法 資料作成のプロが語る、修正の無限ループから抜け出す4つのコツ
2024.10.28
スキル重視の採用を続けた結果、早期離職が増え社員が1人に… 下半期の退職者ゼロを達成した「関係の質」向上の取り組み
2024.10.22
気づかぬうちに評価を下げる「ダメな口癖」3選 デキる人はやっている、上司の指摘に対する上手な返し方
2024.10.24
リスクを取らない人が多い日本は、むしろ稼ぐチャンス? 日本のGDP4位転落の今、個人に必要なマインドとは
2024.10.23
「初任給40万円時代」が、比較的早いうちにやってくる? これから淘汰される会社・生き残る会社の分かれ目
2024.10.23
「どうしてもあなたから買いたい」と言われる営業になるには 『無敗営業』著者が教える、納得感を高める商談の進め方
2024.10.28
“力を抜くこと”がリーダーにとって重要な理由 「人間の達人」タモリさんから学んだ自然体の大切さ
2024.10.29
「テスラの何がすごいのか」がわからない学生たち 起業率2年連続日本一の大学で「Appleのフレームワーク」を教えるわけ
2024.10.30
職場にいる「困った部下」への対処法 上司・部下間で生まれる“常識のズレ”を解消するには