世界を動かす技術を、日本語で。

OpenBSDは非常に高速なので、自己測定するためにプログラムを少し修正する必要がありました

概要

  • LinuxOpenBSD での簡単なスレッド+ソケット作成ベンチマークの比較
  • OpenBSD の方が 圧倒的に高速 な結果
  • ソースコードの要点:2スレッドでそれぞれ256ソケット生成
  • Linux は0.017〜0.026秒、 OpenBSD は0.002〜0.006秒
  • 背景や詳細な理由はリンク先スレッドで解説

LinuxとOpenBSDにおけるスレッド&ソケット生成ベンチマーク比較

  • Jann Horn 提供のベンチマークプログラム紹介
    • 2スレッドで各256個のソケットを生成するCコード
    • ソケット生成失敗時はエラー出力
  • Linux での実行結果
    • 平均 0.017〜0.026秒 の実行時間
    • ソケット生成自体は問題なく完了
  • OpenBSD での実行結果
    • 初回は「 Too many open files」エラー(ulimit設定不足)
    • ulimit調整(例:ulimit -n 1024)後は 0.002〜0.006秒 の高速実行
  • 機械構成 は完全一致しないが、ほぼ同等スペック
  • OpenBSD がLinuxより 約5〜10倍高速 な結果
  • 一般的にはOpenBSDが遅いベンチマークが多いが、本件は逆パターン

ベンチマークのポイントと補足

  • プログラムの主な処理内容
    • 1つの追加スレッドを生成
    • 両スレッドで 256個のソケット を作成
    • 実行時間を gettimeofday で計測
  • timeコマンド の精度が足りないため、プログラム内で自計測
  • ネットワークスタック自体の違いではなく、他の要因が影響
  • 詳細な理由やヒントは スレッド元の議論 参照推奨
  • Linuxで本ベンチマークを上回る環境があれば興味深い

所感とまとめ

  • 通常はOpenBSDが極端に遅いベンチマークが多い
  • 今回のような例は 珍しくコレクション入り
  • 比較的小規模なスレッド・ソケット生成 ではOpenBSDの実装が有利な場合あり
  • 性能評価時は 単純な先入観に頼らず、実測値と考察が重要

Hackerたちの意見

いや、一般的にLinuxはOpenBSDより少なくとも3倍は速いよ。最適化にあんまり気を使ってないからね。

特定のケースについて話してるんだよね: https://infosec.exchange/@jann/115022521451508325

かなり広い主張だね。

でもOpenBSDは特定の分野ではかなり速いよ。例えば、/dev/urandomからの乱数生成とかね。大学にいた頃(2010年くらい)、OpenBSDのノートパソコンで/dev/urandomを読み取って、友達のLinuxノートパソコンにイーサネットでパイプする方が、彼のノートパソコンで直接cat /dev/urandom > /dev/sdaを実行するより速かったんだ。ほんの少しじゃなくて、10MB/sと100MB/sの違いがあったよ。

むしろ、彼らはセキュリティを重視してるんだ。Linuxの同じ対策だと、もっと遅くなる可能性が高いよ。

面白いね。リンク先のスレッドの議論を追おうとしたけど、得られたのは「RCUに関係してる」ってことだけだった。簡単に説明するとどういうこと?

2つのスレッドがソケットを順番に割り当てると、ロックを争うことになるよ。最初にfd 666を作って大きなテーブルを事前に割り当てると、ロックの競合がなくなるんだ。

Linuxでは、プロセスのファイルディスクリプタテーブル(fdtable)は最低256スロットから始まるんだ。2つのスレッドがそれぞれ256ソケットを作ると、合計で512のfdを使うことになるから、標準入力、標準出力、標準エラーの3つに加えて、256から512に容量が倍増する際にfdtableを半分くらい拡張する必要があるんだ。そして、512から1024にリサイズする際にもまた拡張が必要になる。これはカーネル内のexpand_fdtable()によって行われるよ。以下のコードが含まれてる:if (atomic_read(&files->count) > 1) synchronize_rcu(); files->countは参照カウンタなんだ。2つのスレッドがオープンファイルのセットを共有しているから、この値は2になる。つまり、fdtableの拡張中にsynchronize_rcu()が呼ばれるってこと。これによって、現在作成中のソケットのために新しいfdを取得するのが遅れるんだ。もし新しいスレッドを作成する前にfdtableを拡張すると、テストプログラムがコマンドライン引数を与えられた場合にdup(0, 666)を呼び出すことでこれを避けられる。そうすると、files->count == 1になるからsynchronize_rcu()の呼び出しがなくなるんだ。だから、これをやれば、fdtableが十分な容量を持っているから、すべてのソケットを作成する際に遅れがなくなるよ。一方で、OpenBSDのカーネルにはRCUのようなものはなくて、プロセスのファイルディスクリプタテーブルが変更されるときにrwlockを使うだけだから、Linuxで見られるような拡張時の長い遅延を避けられるんだ。

つまり、ファイルディスクリプタの割り当てオーバーヘッドをテストしてるってことだね。

まあ、そうだね。fdテーブルのサイズは、fdsとはちょっと違うし(ulimitに達したら、サイズを大きくする必要はないし)、マルチスレッドプログラムでのみの話。

そうそう、君のウェブサイトを読みやすくするために修正しなきゃいけなかったよ。なんで人はこんなことするんだろう?

モバイルではいい感じに見えるよ。コントラストも高いし、ラインも長すぎないし。何か問題あったの?

より良いタイトル: Linux向けの病的なテストプログラムがOpenBSDでは病的な動作を引き起こさない

きっと、テドゥの投稿は初めてなんだね…

それが関係あるかは分からないけど、1秒未満の時間間隔を測るマイクロベンチマークをやるときは、標準ライブラリの関数の代わりに__rdtsc()コンパイラの内蔵関数を使ってるよ。最新のプロセッサでは、その命令はCPUの基本周波数でカウントアップする壁時計時間を測るんだ。動的周波数スケーリングの影響を受けないからね。高い解像度が得られるだけじゃなくて、この時間測定方法はすごく安価で、OSカーネルの呼び出しよりも数桁速いんだ。

gettimeofdayはカーネルのコンテキストスイッチを避けるためにvDSOで実装されてるんじゃないの?(だから、ほとんどのオーバーヘッドを回避できる)。私の理解では、tscを直接使うのは難しいんだ。レートが一定じゃないかもしれないし、コアごとにレートが違うこともあるし。

これにはノートパソコンの周波数スケーリングや、コンテキストスイッチ、コアの移動、システムコールにかかる時間(カウントしたくないなら無視してもいいけど)とかは考慮されてないよ。Linuxでは、カーネルが本当の(“リファレンス”じゃない)サイクルカウンターを__rdpmc()でアクセスできるようにしてくれるし、補正オフセットをメモリマップされたページに入れることもできる。perf_event_open()のmanページにあるcap_user_rdpmcの例コードを見てみて。そこでのrdpmc(idx-1)の-1に注意ね(これに1時間無駄にしたわけじゃないから)。Windowsでそれをやりたいなら、できるけど、別のスレッドから非同期でやらなきゃいけないし、オフセットも自分で計算しなきゃダメだよ。あと、AMDプロセッサーだけど、Zen 2以降では、__aperf()や__rdpru(__RDPRU_APERF)を使ったり、コンパイラによっては手動のインラインアセンブリで実際のサイクルカウントを取得できるよ。(公式のAMDドキュメントでは、APERF / MPERFの比率以外には意味を持たせないように注意されるけど、他の場所での説明を考えると、MPERFがリファレンスサイクルカウントで、APERFが実際のサイクルカウントだと暗に示されてる。)これは確かに面倒が少ないけど、私の経験ではLinuxのcap_user_rdpmcメソッドの方がずっとノイズが少ないよ。

rdtscは全てのプラットフォームで使えるわけじゃないからね。ユーザースペースでの使用を許可するCPUフラグがあるから、よく無効にされてるし、あまり正確じゃないことも知られてる。

clock_gettime(CLOCK_MONOTONIC)を使えばよかったのに。

__rdtsc()コンパイラ内蔵を使ってるんだけど、ARMではどうしてるの?

__rdtsc()は速いけど、マルチコアのベンチマークには注意が必要だよ。全てのハードウェア、特に古いシステムではコア間のTSC同期が保証されてないからね。最近のIntelやAMDのCPUは「不変TSC」を持ってて助かるけど、まずはCPUフラグを確認する価値があるよ。

コア間で同期されてるとは思わないな。ただ、間違ってるかもしれないけど。

同じCPU上での連続したrdtsc呼び出しは、CPUによって期待通りの順序で実行される保証はないよ - [1]。1 - https://lore.kernel.org/all/da9e8bee-71c2-4a59-a865-3dd6c5c9...

OpenBSDはいろいろな面があるけど、「速い」って言葉は思い浮かばないな。軽量?うん。ミニマリスト?間違いなく。コンパクト?もちろん。でも速い?いや、全然。OpenBSDでデータベースやファイルサーバーをホストする?絶対に無理。ブート時間は20年前と同じくらいかかるし。彼らは速度を犠牲にするあらゆるセキュリティ対策を支持してるけど、それも別にいいと思う。でも、実際のところを隠すのはやめようよ。

あなたは私とは違うOpenBSDのブランチを使ってるんだね。

君のミニマリストな評価には同意できないな。初期状態のOpenBSDは、必要なものが全部揃ってるし、文句はないよ。しっかりした、よく書かれたソフトウェアだと思う。でも、基本的なLinuxディストリビューションでOpenBSDのインストールほど充実してるのは見たことないな。Cコンパイラ、ウェブサーバー、3つのルーティングデーモン(bgpd、ospfd、ripd)、メールサーバー(smtpd、spamd)、サウンドサーバー(sndiod)、リバースプロキシ(relayd)、2つのデスクトップ環境(fvwm、cwm)など、他にもたくさん。OpenBSDはミニマリストで特化したOSじゃないと思うけど、実際に何のためにあるんだろう?含まれている機能を見ると、デスクトップ開発システムでありながら、ルーターやオフィスのウェブ・メールサーバーにもなるのかな?個人的には大好きで、クリーンインストールした後は、目の前にあるものでインターネットをゼロから再構築できる気がするよ。

OpenBSDは20年前よりもずっと速くなったよ。ロックを/dev/nullに送るおかげだね。

OpenBSDはここ4~5回のリリースでかなり速くなったと思うよ。残念ながら、phoronixによる次のベンチマークを待たないといけないね。毎回ベンチマークを実行するたびに問題が出てるみたいだから。どこかで十分速くなって、特定のアプリケーションがいろんな理由で使うようになるかもしれないね。

これはちょっとバカみたいな「ベンチマーク」だけど、もしこの道を進むなら:linux: 経過時間: 0.019895s ナノ(そのLinuxで実行中):経過時間: 0.000886s

「普通はOpenBSDが10倍遅いっていう変なベンチマークがあるから、これはコレクションに加えられるね。」これってhttps://web.archive.org/web/20031020054211if_/http://bulk.fe...のこと?それとも他にある?

それをやるより良い方法(ごめんね)は、テストを修正するんじゃなくて、負荷を増やすことだと思うよ。彼らの方法がより良いベンチマークになる理由を聞けたら嬉しいな。

Linuxで測定されている現象は、プロセスのライフタイムにおける一回限りのイベントだよ。