Bzip2クレートがCから100% Rustへ切り替え
引用元:https://news.ycombinator.com/item?id=44303361
Trifecta Techのbzip2って、Linuxで使われてる古い公式版を置き換えられそう?Fedoraがzlibをzlib-ngに変えたみたいに、CのABI互換があればイケるかもね?
C ABI互換って話だけど、動的リンクとはどうなるの?Rustって静的リンクしかできないんじゃないの?
下のコメントで話がごっちゃになってるよ。Rustバイナリは動的リンクできるけど、ABIが安定してないからCみたいにバージョンの壁を越えられないんだ。だから、結局みんな静的リンクしてるってこと。
uutilsプロジェクトの目標がこれなんじゃないかな。URLはこれ→https://uutils.github.io/
Rust版になると、ツールも改善されてほしいな。ripgrepとかtokeiは、grepやclocより断然速くてすごいんだ。
静的リンクって、バイナリが小さくなるし、LTOもできていいんだよね。
コア標準の一部で、何十年もちゃんと動いてたツールを”代替”って呼ぶのは本当に嫌だね。ripgrepは最高だけど、grepの代わりじゃないし、そうあるべきじゃないんだ。
静的リンクはバイナリを小さくしないよ。ライブラリのシンボル全部が実行ファイルに入っちゃうからね。複数のバイナリがあるなら、動的リンクの方が合計サイズが小さい場合が多いんだ。
静的リンクと依存関係を”バンドル”するのを混同してるよ。静的リンクがバイナリを小さくするのは、依存関係をバンドルする場合の話。静的リンクか動的リンクか、と、バンドルするか共有するかは違う話なんだ。
ページキャッシュの仕組み、知ってる?静的リンクだとそれが効かないんだ。libcとかがプロセス間で共有されないから、3000個プロセスがあったら3000回ロードしなきゃいけなくなるよ。
コマンドラインツールの進化の歴史について語ってるね。AT&T→BSD→GNUって進化して、毎回「元のままがいい」って文句言う人がいたんだ。grepもegrepとかfgrepが出て、結局統合されたし。もし標準に固執してたら今だにBourne shell使ってるよ。GNUツールはもう標準みたいになってるけど、Rust以外でもackやagみたいな新しいツールが出てきてて、次の革新期が来てて嬉しいな。
自分の書いたコードは全部まとめて静的リンクできるけど、libcとかシステムのライブラリは動的リンクにするってやり方もあるよ。
平気で事実と違うこと言う人ってどういう頭してんだろうね?「僕が正しい、宇宙が間違ってるんだ」とか思ってんのかな?それとも真実の概念をぶっ壊したいの?(君のセリフに混乱してる人のために言うけど、もちろんRustでもそれができるよ)
今手元にあるRustで書かれたバイナリでlddコマンドを試してみてくれる?結果を楽しみに待ってるよ!
>君の言う通りだね。僕も同意するよ。「XだけどZで書き直しました」って宣伝文句、すごく嫌なんだよね。ツールも作者もinstantly嫌いになりそうになる。(Rustは好きだよ。この雰囲気〈vibe〉が嫌いなだけ)。
これは、元々CのラッパーだったRustクレートを、Rustネイティブに置き換えるために作られたRustクレートだよ。Rustプロジェクトで使う時に、もっと速くてリンクしやすいんだ。「Rust」って言わないで、どうやってこのRustクレートがより良いRustクレートだって伝えればいいのさ?
本当に気になったんだけどさ、なんで完全に静的リンクされるってそんなに確信してたの?
Bourne shellのことなんだけど、無知でごめんね、bashの何が悪いの?全部のサーバーやワークステーションで使ってるし、複雑なスクリプトも書いてるよ。古いプロジェクトじゃないし、主流のシェルに見えるんだけど、僕が間違ってる?
Update: ああ、オリジナル版のBourne Shellのことだったんだね、bashじゃなくて。
1)このプロジェクトはクールで成功を祈ってるよ。いつかこれがデフォルトのユーティリティになったら最高だね。2)MITライセンスにしたのは間違いだったと思う。GNUユーティリティをクローンしてるんだから、元のGNUソースをRustに移植するのが一番obviousだろう?でもGPLコードをMITプロジェクトに移植するのはダメなんだ。だから、ユーティリティを全部ゼロから書き直さなきゃいけない。これって時間の無駄に見えるね。僕はGNUソースをRustに移植する作業には興味あるけど、全部ゼロから書き直すのには興味ないから、このプロジェクトには貢献してないんだ。
C++のバイナリも同じようにすべきだね。外部向けにはC ABIで話して、内部的にはRustかC++の標準ライブラリを静的リンクする感じに。
Rustは静的リンクしかサポートしないってよく言われるから、動的リンクできないって推測しちゃったんだろうね。GoもLinuxで完全静的バイナリを作るし、Rustも同じだと勘違いするのも無理はないかも。でも、そんなに自信満々に言っちゃダメだよ!
うん、そうかもね。でもそれが何だって言うの?Rust製のシェルnuを見てごらんよ。
$ ldd ~/.cargo/bin/nu
linux-vdso.so.1 (…)
libssl.so.3 => /lib/x86_64-linux-gnu/libssl.so.3
…(他のライブラリも続く)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6
って感じで動的リンクしてるでしょ?C製のシェルashだってそうだし。
$ ldd /bin/sh
linux-vdso.so.1 (…)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6
(…)
圧縮が10~15%速く、解凍が5~10%速くなるって、めちゃくちゃ良い「機能」じゃない?
「[…] 完了してるってことなんじゃないの?」
って、必ずしもそうとは限らないと思うよ。例えば、2019年からリリースがないプロジェクト全部が完了してるわけじゃないでしょ?ほとんどは単に放棄されてるんじゃない?
もちろん、完了してるっていうのも理由としてはあり得るけどね。
このbzip2の場合は、課題トラッカーに未解決のバグがいくつかあるんだ。だから、プロジェクトが完了してるってわけではなさそうだよ。
参考:https://sourceware.org/bugzilla/buglist.cgi?product=bzip2
静的リンクするとバイナリがすごく大きくなるし、LTOできても使えるメモリの量に制限されるんだよね。あと、静的リンクだとアーカイブ全体を常に再構築する必要があるのも面倒。
C++プロジェクトから別のC++プロジェクトにC APIをエクスポートするのって、本当に大変なんだ。COMみたいになっちゃうし。(COMはC++よりちょっと前にできたと思うけど)
「圧縮が10~15%速く、解凍が5~10%速くなるって、すごく良い「機能」じゃん?」
確かにコードを最適化して10~15%速くできる部分は多いけど、もしそれがコードの読みやすさを犠牲にするなら、最近はそういう「機能」は敬遠されるんだよね。既存コードを、「もっと難しく¹」て(そのせいで)そこで開発したいエンジニアが少ない(そしてこれからも少ないだろう)言語に移すのって、すごく読みやすさを損なう最適化に似てるように見えるんだよね。¹…それだけじゃないけど。ソフトウェア開発ツールとしてのRustの問題点については、他のコメントでも説明したことがあるよ。ここ↓見てね。
https://news.ycombinator.com/item?id=31565024
https://news.ycombinator.com/item?id=33390634
https://news.ycombinator.com/item?id=42241516
RustはRustに動的リンクできないんだ。Cとは動的リンクできるし、Cから動的にリンクされることもできる。この二つを組み合わせれば「ごまかせる」けど、それは結局Cを扱ってるだけで、たとえ両側にRustがあってもRustを扱ってることにはならないんだ。
ねえねえ、“rewritten IN rust”じゃなくて“rewritten FOR rust”って言う方が正しいんじゃない?
俺 Common Crawl のデータ処理でこのクレート使ってるんだよね、何百 TB も!速度アップめっちゃ助かるわー
なんでここで bz2 使ってるの?一回 zstd に変換してから処理する方が速くない?俺の知る限り、zstd って高圧縮レベルだと bzip2 より全部の面で優れてるはずだけどなー。
もっとコメントを表示(1)
だって Common Crawl はデータ bz2 で配布してるんだもん。実際、俺も中間データは ZFS で zstd にして保存してるよ。
それってデータを何回も処理することを前提にしてる話だよね。
そうそう、俺も言いに来たんだけど、圧縮で 14パーセント スピードアップって結構すごいよね!
bzip2 って(特に並列実装とかだと)圧縮に関しては結構イケてるんだよ。遅れるのは解凍時間の方。lz77 ベースのアルゴリズムは解凍がめちゃくちゃ速いから、そこで差がつくんだよね。
マジで爆速じゃん!
これで未解決の CVE 11個はデフォルトで解消されるのかな?ってかさ、皮肉にもこの bzip2 クレートに CVE が1個報告されてるんだってよ[1]
https://app.opencve.io/cve/?product=bzip2&vendor=bzip2_proje…
Rust クレートででかいファイルが実行時エラーになったのと、C で範囲ミスが多発してるのって対照的だよね。C の範囲ミスを突いてコード実行されるか試されたのかな? それは不可能かもしれないし、そうじゃないかもね。
> bzip2 クレート 0.4.4 以前
今日 0.6.0 リリースしてるじゃん :>
でも、これはまさに話題になってる bzip2 クレートの話でしょ。その新しい純粋な Rust 実装は libbz2-rs-sys で、bzip2-rs じゃないんだよ。最後の文は関係ないね。
この記事は bzip2 クレートについてなんだよ、bzip2-rs クレートじゃないんだ。リポジトリ名が後者と同じ名前だけどね。
FTA:
> 今日ほとんど使われない 90 年代のアルゴリズムにわざわざ取り組むのはなぜ?
今は何が使われてるの? zstd とか?
ああ、これ見たよ: https://quixdb.github.io/squash-benchmark/
C と Rust のバージョンで同じ LLVM コード生成(同じ最適化)バックエンドを使ってるか気になるな。もしそうなら、どこで速度アップしてるの?
(つまり、なんか Rust の自動 SIMD なの、それとも他の部分を手で最適化したの、新しい最適化されたライブラリ使ってるの、それとも…他?)
ただ推測だけど、Rust はコード生成器にもっとヒントを与えられるのかもね。例えば、C のポインタみたいにエイリアシングをそんなに心配しなくていいとか。 https://en.wikipedia.org/wiki/Aliasing_(computing)#Conflicts… 見てみて。
なるほど、すごく納得できるよ。公式の回答は知らないから推測だけどね。記事からリンクされてる c2rust での最初の翻訳についての記事 https://trifectatech.org/blog/translating-bzip2-with-c2rust/ を見ると、C コードは変数の範囲保証がないせいでコードが最適じゃない箇所があるって指摘してるんだ。
たくさんの人が数がそんなに大きくならない時でも ’int’ を使ってるってことも。
でも適切な型を使えば Rust コンパイラはパフォーマンスが良くなるなら別のことをするって決められるんだね。
だから、より多くの知識によってより良い最適化を引き出せるっていう君のアイデアは多分正しいと思うよ。
適切なデータ構造やアルゴリズムを使う時の使いやすさも、すごく大事な役割を果たすことがあるんだ。C だと、基本的な配列以外はすごく手間がかかりすぎるからね。
ああ、それってブライアン・カントリルがdtraceの一部をRustで書き直した時の気づきだよな。学習のためにやったのに、オリジナルのコードより素朴な実装の方が速くてビックリしたんだって。結局、理由はRustの標準ライブラリに入ってる”I used a BTreeMap”を使ったことだって話だったよ。
ふむ.. それってclang+linuxとかclang+stl、hotspot+j2eeと比べたらどうなんだろうね。Perlがよくネイティブc/c++より速かった時代を思い出すな、あれも優秀な文字列処理ライブラリが組み込まれてたからだし。空間効率はどう?Rustのバイナリって大きくなりがちだけど、システム全体に影響しない? RedoxOSと普通のlinuxのベンチマークとか見てみたいね。
とにかく、俺が見つけた詳細はここにあるよ。[0]
[0] https://bcantrill.dtrace.org/2018/09/28/the-relative-perform…
かなりクールだね!単体で見ると最高だ!でも、実行ファイルのイメージサイズが大きくなる影響、特にコンプリートシステムでの影響がまだ少し気になるんだ。もしバイナリが全部大きかったら、キャッシュ領域を圧迫し始めない?スタティックリンキングってフルシステムで理にかなってるのかな?
カーネルは実際に実行するバイナリの部分だけをロードするし、しばらく実行されてない部分はディスクキャッシュを解放できるんだよ。だから、バイナリの絶対的なサイズよりも、実際に’active set’にどれだけあるかを気にするべきなんだ。
Cは正直言って、現代のハイパフォーマンスコードを書くのにはかなりイケてない言語だよ。C99からC21まで20年くらい、新しいインストラクションを(インラインasmなしで)使うためのフィーチャーが追加されなかったんだ。clz/popcnt/clmul/pdepみたいなのための良いアブストラクトマシンインストラクションがあるだけで、こういうコードを書くのにすごく役立つんだ。
Popcount, clz, ctzはGCCでノンスタンダードファンクションとして提供されてるよ(clangもGNUモードでサポートしてるかも)。PDEPとPEXTはないみたいだけど、あるべきだと思うな(PEXTはINTERCALにすらあったし)。PDEPとPEXPはx86で-mbmi2付きで使えるけどね。MMIXのMORとMXORもビルトインファンクションで使えるといいな。
どんなXとかYとかZ言語で書き直しても、スピードアップするチャンスは生まれるんだよ。Rustに固有の何かがあるわけじゃない。
彼らかProssimoがBzip2だけじゃなくて、コアインターネットプロトコル、例えばBGP, OSPF, RIP、他のルーティングインプリメンテーション、DNSサーバーなんかも、同じように(Rustで)書き直してくれるといいな。
これ見て!
https://nlnet.nl/project/current.html
https://www.sovereign.tech/programs/fund
ここ数年、Rustみたいなより安全な言語で重要なインターネット&OSツールを書き直すのに結構良い支援があるんだ。例えばRustでBGPとかね。https://www.nlnetlabs.nl/projects/routing/rotonda/
ありがとう!まさに探してたやつ!なぜかこのプロジェクト見落としてたわ。HoloっていうRustのルーティングプロジェクトもね [1] https://github.com/holo-routing/holo
このページhttps://www.memorysafety.org/initiative/にTLSとDNSのことが書いてあって、あんたの提案にちょっと近いかもね。
そのドメインてメモリ安全性のこと?それともRustのこと?どっちなの?
SPARK Adaでもっと強力な証明付きのIronsides DNS作った人がいるよ。
Ada自体は別に良い言語だし、何も反対しないよ。唯一の問題は、その場合コントリビューターが見つかるかどうかだろうね。
もっとコメントを表示(2)
macOSでperfがない件だけど、dtraceでプロファイリングは結構できるよ。オリジナルのPerlのflame graphスクリプトもこれ使うって言ってたし、Rustで再実装されたflame graphもdtraceを使ってる。キャッシュミスとかマイクロインストラクションみたいな一部のメトリクスは取れないけど、それでもすごく使えるよ。
じゃあ未来の読者のために、具体的に説明してあげなよ?
これってlbzip2みたいに並列解凍できるのかな?(それか、ブロックマジックを事前スキャンして並列解凍を上に乗せられるようなイテレータがあるのかな)。
追記:多分できないね。
Rustは置いといて、いろんな実装のベンチマークを見るのってマジ楽しいわ。読んでてすごく満足感ある。
Rust好きだし学びたいんだけど(何回か挫折してる…)。ちょっと大げさだけど、見かけるライブラリがだいたい0.x.yなんだよね。このライブラリも2014年に0.1.0が出てからまだ1.0.0が出てないし、Rustコミュニティって1.0.0にしたがらない傾向あるの?
これ見て→https://0ver.org/#notable-zerover-projects
真面目な答え:しょっちゅう変わるから安定版を宣言する必要ないと感じてる人もいる。別のケースでは、安定してて広く使われてる0.xパッケージなんだけど、1.0にすると大体なんか破壊的変更があるってことになっちゃう。(そうあるべきかは分かんないけど、依存ライブラリが0.xから1.0になったら、時間できるまでアップデート待つくらい慎重になるね)。
まぁ、大抵の人はそんなに気にしてないよ。
あのリスト、Zigが入ってるけど、Zigプロジェクトは1.0リリースの明確な計画[0]があるんだよね。それは0verじゃなくて、ただのsemverのベータ段階だよ。
[0] https://github.com/ziglang/zig/milestone/2
そうそう、Rustではパッケージマネージャーがアップデートのルールを組み込んでるんだ。メジャーバージョン(1.0とか)が変わると、なんか壊れる変更があったってことだから自動でアップデートしないの。自動アップデートしても大丈夫なうちは、メジャーバージョンは変えたくないんだよね。
「uutilsの失敗の後」
どんな失敗?
なんかさ、uutilsのsortってlocaleによっては速くないんでしょ?それにテストケースでモメるのっていつものことじゃん。この批判、細かいところにこだわりすぎだよ。RustのライセンスはMITとApache2が普通だし、陰謀とか見えないな。てか、あなたが批判してるのってUbuntuなの?
>1. The uutils project didn’t also make all locales cases for sort faster even though the majority of people will be using UTF-8, C or POSIX where it is indeed faster
localeとencodingは違うよ!トルコ語(tr_TR.UTF-8)とUS英語(en_US.UTF-8)の電話帳ソートで試してみなよ。
知ってるよ。UTF-8とかCとかPOSIXって、localeの文字列だよね。
その4chanみたいなサイトから何を知ってほしいわけ?今のところGNUほど速くないってこと?嘘はどこにあるの?
自分で結果を確かめるのは大事だけど、正直bzip2のパフォーマンスを気にする人なんて今どきいるの?zstdにはどうやったって勝てないよ。同じ時間ならzstdはめっちゃ小さくなるし、解凍も20~50倍速いんだから。bzip2の実装速度なんてどうでもいいんじゃない?
いや、そういうケースもあるよ。誰かからbzip2ファイルをもらったり、その形式で渡す必要があったり。そうなると他に選択肢ないじゃん。使うしかないなら、14%速くなるのはすごく嬉しいことだよ。
CからRustへの書き換えに、なんかLLM使ったの?
もしトランスパイルツール使うなら、適当なこと言わない正確なやつがいいよ。c2rustってのがかなりいいらしい。ImmunantがQuake3をRust化した時のブログ記事もあるよ。https://immunant.com/blog/2020/01/quake3/ 生成されたRustコードは綺麗じゃないけど、そこから直せばいいんだって。
記事によると、最初c2rustで書き換えたみたいだよ。ここ見て。https://trifectatech.org/blog/translating-bzip2-with-c2rust/