2 ポイント 投稿者 GN⁺ 2025-07-19 | 1件のコメント | WhatsAppで共有
  • lsrは、io_uringベースのIOライブラリ ourio を活用して開発された新しい ls(1) 代替プログラム
  • 既存の ls および代替ツール(eza, lsd, uutils ls)と比べて、コマンド実行速度が非常に高速で、システムコール数も10倍以上少ない
  • ディレクトリのオープン、statlstat など主要なIOをすべて io_uring で非同期・バッチ処理し、性能を最大化。ファイル数が多いほどより高速
  • Zigの StackFallbackAllocator を活用し、メモリ割り当て時の mmap 呼び出しを最小化
  • 動的リンクなしで静的ビルドされており、実行ファイルサイズも既存の ls より小さい

紹介と意義

  • lsrプロジェクトは、一般的な ls コマンドの代替として io_uring を活用する高速なディレクトリ一覧ツール
  • 既存の lsezalsduutils ls と比較して、実行速度システムコール使用量の両面で優れた性能を示す
  • 自作のIOライブラリ(ourio)により、可能な限り多くのIOを直接処理
  • ベンチマークを通じて、lsrが大規模なファイル環境でも高い性能と品質を証明

ベンチマーク結果

  • hyperfine を使い、n個の通常ファイルがあるディレクトリで各コマンドの実行時間を測定
    • lsr -al は10〜10,000個のファイル条件で、既存の ls / 代替ツールに比べて圧倒的に短い実行時間を記録
    • 例:10,000個のファイルでは lsr が 22.1ms、既存の ls(38.0ms)、eza(40.2ms)、lsd(153.4ms)、uutils ls(89.6ms)を上回る最高速度を記録
  • システムコール集計は strace -c で実施
    • lsr -al:最小20回(n=10)から最大 848回(n=10,000)と、非常に少ないコール数を維持
    • ls は最大30,396回(n=10,000)、lsd は100,512回など、他の代替ツールも数千〜十万回規模
    • 同一条件で lsr は最低でも10倍以上少ない syscall 数で、最高の効率を達成

lsrの構造と実装方式

  • プログラムは 引数解析、データ収集、データ出力 の3段階で動作
  • すべてのIOは2番目のデータ収集段階で発生し、可能なあらゆるファイルアクセス / 情報取得を io_uring で処理
    • 対象ディレクトリのオープン、statlstat、時刻 / ユーザー / グループ情報の取得をすべて io_uring ベースで実行
    • stat をバッチ処理することで、システムコール数を大幅に削減
  • Zigの StackFallbackAllocator により1MBのメモリを事前確保し、mmap など追加のシステムコールを最小化

静的ビルドと最適化

  • libc の動的リンクなしの完全静的ビルドのため、実行オーバーヘッドが著しく小さい
  • GNU ls と比べて、lsr の ReleaseSmall ビルドサイズは 138.7KB 対 79.3KB で、より小さい
  • ただし lsr には ロケール(言語 / 地域)サポートがない。一般的な ls は多言語対応のためにオーバーヘッドが発生する

システムコールと性能課題の分析

  • lsd はファイルごとに clock_gettime を5回以上呼び出しており、その理由は不明(内部タイミング計測などと推測)
  • ソート処理が全体処理のかなりの部分(約30%)を占める
    • uutils ls はシステムコール効率は高いが、ソート処理で遅くなる
  • io_uring の導入だけでも、サーバーなど高負荷IO環境で革新的な性能向上の可能性が確認された

結論

  • 開発時間もそれほど長くかからず、syscall 最適化の効果は期待以上
  • lsr は 高速、少ないシステムコール、コンパクトなサイズ を同時に実現する実験的な ls 代替ツール
  • 大量ファイル環境や高性能IOが重要なシステムに非常に適している
  • locale 未対応など一部の機能制約はあるが、実運用でもベンチマークでも革新的な結果を示している

1件のコメント

 
GN⁺ 2025-07-19
Hacker Newsのコメント
  • プロジェクトの作者であることを明かしたうえで、io_uring ベースの lsr の紹介記事はこちらで読めるとのこと

    • Sun で I18N プロジェクトに携わっていた経験を共有。複数の環境(ローカライズ、utf8 など)をサポートするにはプログラムにさまざまな処理を追加する必要があり、結果を出すためのコストと速度が反比例することを実感したという。もともとの UNIX の ls(1) は単純な設計で非常に高速だったが、さまざまな機能追加や仮想ファイルシステム(VFS)、多様な文字セット、カラー対応などの小さなコストが積み重なって遅くなった。io_uring が扱う抽象化コストに関する面白い議論だと感じる
    • bfs プロジェクトも io_uring を使っている(ソースコードへのリンク)。lsr と bfs -ls の性能比較が気になる。現状の bfs はマルチスレッド時のみ io_uring を使っているが、single thread(bfs -j1)でも活用するか検討の余地がある
    • tim紹介リンク)で時間計測すると hyperfine より良さそう。Nim 製なのでハードルはあるかもしれないが、名前が似ているのは偶然にしては面白い
    • C++ プロジェクトを Zig に移植することを念頭に置いている。自作の「libevring」もまだ初期段階なので、必要なら ourio へ置き換えることにも前向き。Zig ベースのプロジェクトに C/C++ バインディング対応があれば、C/C++ から Zig へ移行する際に役立つだろうという考え
    • その紹介記事のほうが背景説明が充実しているのでメインリンクにし、リポジトリのスレッドは上に追加しておく予定とのこと
  • NFS サーバー上で(特に良くないネットワーク環境で)lsr の性能がどうなるのか気になる。信頼性の低いネットワークサービスに blocking な POSIX syscall を使うことが NFS 設計の弱点であるのは明らかで、io_uring がこうした問題をどこまで緩和できるかも観察ポイント

    • NFS の設計者は、分散システムをハードドライブのように非常に一貫して動作するよう実装した。既存ツール(ls など)がネットワーク障害を直接処理する必要がなかったのは利点だった。元の NFS プロトコルはステートレスだったため、サーバー再起動時でもクライアントが自動復旧できた。io_uring がこの種のケースでエラーをきちんと返すのか気になる。NFS タイムアウト時にどう処理されるのかも関心がある
    • 自宅で複数台の PC から NFS の $HOME を使っているが、ネットワークが良好で並列書き込みのような難しいケースさえ避ければ、NFS の平均的な使い勝手にはかなり満足している。ただし、ネットワークケーブルが不安定だったときは接続断で苦労したことがある
    • NFS フォルダを読んでいるアプリで ctrl+c が効かない状況はよく知られた不便さ。理論上は intr マウントオプションが、ハングしているリモートサーバー上の処理へシグナルを届けて中断できるようにしていたが、Linux ではかなり前に削除されており(現在は soft オプションのみ可能)、参考1参考2(FreeBSD ではサポート)
    • Samba にも似たような問題がある
  • syscall 呼び出し回数を 35 倍減らしたのに、速度改善が 2 倍程度という点は興味深い

    • 大半の syscall は VDSO 経由で行われるため、コストはそれほど大きくない
    • 以前読んだ io_uring 関連のベンチマークでは、io_uring ベースの syscall が従来の syscall より重いという結果が出ていたこともあった。それでも体感としてはかなり大きな改善だ。正確な出典は思い出せないが、印象に残っている
  • io_uring の活用事例として期待していた長期的な性能向上というより、チュートリアル的な使い方紹介としてのほうが関心を引くプロジェクト。既存の eza のようなツールと比べて、なぜこれが必要なのかという体感的な動機付けがなかった。ファイル 1 万件の一覧表示が 40ms と 20msだとしても、単発実行ではまったく違いを感じない気がする

    • 面白半分で io_uring の使い方を学ぶために作った実験的プロジェクト。実用上の時間短縮効果はごく小さく(人生で 5 秒節約する程度)、そこが本質ではなかった
    • 実際には数百万個の JSON ファイルが入ったディレクトリでは、ls/du の実行に数分かかる。coreutils の基本コマンドは最新 SSD の性能を十分活かせていないことが多い
  • lsr も良いが、カラー表示やアイコン対応は eza のほうが優れている。自分は "eza --icons=always -1" に設定しているので、音楽ファイル(.opus など)は自動でアイコンと色が付くが、lsr ではただの普通のファイルとして表示される。それでも lsr はパッチも当てやすく、非常に速いことは確かに感じる。さらに cat や他のユーティリティもこういう形で作ってほしいという期待や、tangled.sh と atproto を使っている点も面白い。Zig 製なので Rust より初心者にはとっつきやすく感じる

    • “bat” はモダンな “cat” 代替だ(bat はこちら
    • カラー対応は LS_COLORS/dircolors のような標準的方式を実装するのが一番良さそう。GNU ls の色付けはきれい
  • なぜすべての CLI ツールが io_uring を使わないのか気になっていた。自分は nvme を usb 3.2 gen2 に接続したとき、普通のツールでは 740MB/s だが、aio や io_uring ベースのツールでは 1005MB/s まで出る。キュー長戦略やロック削減の効果もあると思う

    • 移植性を重視して、伝統的に #ifdef のようなマクロ分岐なしで書かれてきたため、プラットフォームやバージョン固有の新技術の導入が遅い。今となっては、さまざまな posix 系プラットフォーム間の互換性の利点は昔ほど大きくないと思う
    • io_uring を効率よく使うには非同期イベントベースのモデルが必要。既存の CLI ツールの大半は直感的で逐次的に書かれている。言語レベルで async が自然に使えれば移植も容易だっただろうが、現状では大規模なリファクタリングが必要。io_uring も完全に安定したわけではないので、新しい技術の登場を待ちながら、自動移植ツールや AI などが出てくる可能性もあると思う
    • io_uring には導入初期に大きなセキュリティ問題があった(2年ほど前)。今ではかなり解決されたが、普及には悪影響を与えた
    • io_uring はセキュリティ面で非常に難しい
    • io_uring はかなり新しい技術なので、coreutils(および先行パッケージ)には数十年の歴史があり、io_uring 導入にはさらに時間がかかるだろう。「共有リングバッファ」方式のシステムコールが既存の同期方式に代わる標準になるには時間が必要
  • lsd がファイルごとに clock_gettime を 5 回ほど呼んでいるように strace で観察される。正確な理由は分からず、おそらく各タイムスタンプについて「何分前/何時間前/何日前」を計算しているか、ライブラリのレガシーかもしれない

    • 最近の clock_gettime は本物の syscall ではなく、vDSO 経由で処理される(man 7 vDSO を参照)。もしかすると Zig がこの構造を活用していないのでは、という推測
  • やや脱線気味かもしれないが、Mellanox 4 または 5 のようなハイエンド企業向けサーバーで、10G NIC 環境において io_uring が LD_PRELOAD と比べてソケット遅延オーバーヘッドをマイクロ秒単位でどれだけ減らせるのか、実体験やベンチマーク値が気になる。効果は積み上がらないようにも見えるので、直接の経験があれば数値を聞きたい

  • io_uring は getdents をサポートしていないため、主な利点は bulk stat(例: ls -l)で現れる。getdents 処理を非同期化して並行実行できればよいのに、という惜しさがある

    • POSIX で NFS の “readdirplus”(getdents + stat)操作が標準化されれば、io_uring 特有の利点の一部は相殺されるだろう
  • .mjs や .cjs 拡張子のアイコンはあるのに、.c、.h、.sh のようなファイル拡張子にはないのが面白い