この資料は Rust 製のコマンドラインツール tac について紹介するものです。
Rustの環境構築やツールのインストール方法については以下を参照してください
tac は Coreutils 由来の GNU tac ユーティリティを高速化し、 クロスプラットフォームに書き直したツールです。 tac はファイルや標準入力読み、行ごとに逆に出力します。
GitHub - neosmart/tac: A high-performance, cross-platform file reverse utility
数ギガバイトのウェブアクセスログファイルを逆時系列でgrepしたいときなどに便利です。
現在、arm64 (aarch64) の NEON アクセラレーションはナイトリーコンパイラーでのみ利用可能です。これを使用する場合は、cargo に --features nightly
フラグを指定して、サポートを有効にしてください。
この tac の実装では、SIMD 命令セット (AVX2, NEON) を使用して、改行検出を高速化します。メモリマップドファイルの使用により、投機実行の緩和が有効な場合、入力から読み込む際のコンテキストスイッチによるスローダウンを回避し、さらに性能を向上させることができます。GNU Coreutilsに同梱されているtacのバージョンよりも大幅に(緩和策を無効にした場合は2.55倍、それ以外はもっと)高速であり、さらに自由なライセンスとなっています。
例えば、cat /usr/share/dict/words | tac
を実行する代わりに、 tac /usr/share/dict/words
を直接実行してください。tac は、定義上、行を逆にした入力を出す前にファイルの終端に到達しなければならないので、 tac の標準入力インターフェース (例えば cat foo | tac
) を使う場合、結果の処理を始める前にすべての標準入力をバッファリングしなければなりません。 tac はメモリでバッファリングしようとしますが、ある高水準 (現在 4 MiB) を超えると、ディスクベースのバッファリングに切り替えます (入力がどの程度のものか、利用できる空きメモリを超えて終わるかどうかを知ることはできないため)。
可能な限り、tacをパイプラインの先頭に配置するようにします。tacへの入力がメモリ内バッファリングの制限を超えないことを保証できるとしても(上記参照)、tacはパイプラインの他のどのコマンドよりもほぼ確実に速く、出力を反転させる場合は、常にコマンドを完了するまで実行するのでなければ、最初から反転させた方が最も利益があります。たとえば、grep foo /var/log/nginx/access.log | tac を実行する代わりに、tac /var/log/nginx/access.log | grep foo を実行します。これにより、最初の n 個のマッチが報告されるまでの時間や作業量が (大幅に) 減少します (最初にファイルをすばやく反転させてから目的の順序で検索するのと、ゆっくり全体を検索してから結果を反転させるのとは異なるためです)。
tacが直接ttyに書き込むのではなく、他のコマンドにパイプする場合、ラインバッファ出力モード を使用します。(tac --line-buffered
)
% tac access.log | grep foo # 遅い
% tac --line-buffered access.log | grep foo # ずっと速い
同じように、n個のユーティリティの出力を連結している場合、遅延を気にせずスループットだけを気にするのでなければ、n - 1までのすべてのコマンドがすべてラインバッファモードを使用していることを確認してください。たとえば、ある grep パターンの最初の 2 つのマッチを表示する場合は、次のように実行します。
tac --line-buffered access.log | grep --line-buffered foo | head -n2
tac のヘルプメッセージ
% tac --help
tac 2.0.0 - Copyright NeoSmart Technologies 2017-2021
Developed by Mahmoud Al-Qudsi <[email protected]>
Report bugs at <https://github.com/neosmart/tac>
Usage: tac [OPTIONS] [FILE1..]
Write each FILE to standard output, last line first.
Reads from stdin if FILE is - or not specified.
Options:
-h --help Print this help text and exit
-v --version Print version and exit.
--line-buffered Always flush output after each line.