11

このプログラムは、1 行あたり 65k バイトを出力します。

でスループットを測定する./a.out | pv >/dev/nullと、約 3 GB/s が得られます。

回線の長さを 70k に変更するとすぐに、スループットが ~ 1 GB/s に低下します。

ここで発生しているボトルネック(CPU キャッシュ、libc の特異性など)はどれですか?

#include <stdio.h>
#include <string.h>

#define LEN 65000     // high throughput
// #define LEN 70000  // low throughput

int main ()
{
  char s[LEN]; memset(s, 'a', LEN-1); s[LEN-1] = '\0';

  while (1)
    printf ("%s\n", s);
}

更新: Core i5-2520M 上の EGLIBC 2.15 を搭載した Ubuntu 12.04 64 ビットでこれを実行しています。

更新: puts (s)同じ問題があります。

4

1 に答える 1

6

データ転送でカーネル I/O バッファを十分に活用できていません。64KB がカーネル I/O バッファ サイズであると仮定すると、64KB が書き込まれた後に 70000 回の書き込みがブロックされます。排出されると、残りの 4KB + 変更が I/O バッファーに書き込まれます。pv転送された各バイトを読み取るために2回の読み取りを行うこと70000になり、バッファの使用率が悪いため、通常のスループットが約半分になります。書き込み中の I/O のストールが残りを占めている可能性があります。

より小さい読み取りサイズを に指定するpvと、タイム スライスごとに転送される平均バイト数が増えるため、スループットが向上します。書き込みは平均してより効率的になり、読み取りバッファーをいっぱいに保ちます。

$ ./a.out | pv -B 70000 > /dev/null
9.25GB 0:00:09 [1.01GB/s] [        <=>                                        ]

$ ./a.out | pv -B 30k > /dev/null
9.01GB 0:00:05 [1.83GB/s] [    <=>                                            ]

編集:さらに3回実行(2.7GHzコアi7)

$ ./a.out | pv -B 16k > /dev/null
  15GB 0:00:08 [1.95GB/s] [       <=>                                         ]

$ ./a.out | pv -B 16k > /dev/null
 9.3GB 0:00:05 [1.85GB/s] [    <=>                                            ]

$ ./a.out | pv -B 16k > /dev/null
19.2GB 0:00:11 [1.82GB/s] [          <=>                                      ]
于 2012-08-07T19:36:30.453 に答える