Какое узкое место попадает при использовании printf на строках> 65 КБ?

Эта программа печатает 65 тыс. байт в строке.

Я измеряю пропускную способность с помощью ./a.out | pv >/dev/null и получаю около 3 ГБ/с.

Как только я изменяю длину линии до 70k, пропускная способность падает до ~ 1 ГБ/с.

Какое узкое место (кеш процессора, libc idiosynchrasy и т.д.) Я нахожусь здесь?

#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);
}

Обновление: Я запускаю это на 64-битной версии Ubuntu 12.04, которая имеет EGLIBC 2.15, на Core i5-2520M.

Обновление: puts (s) имеет ту же проблему.

Ответ 1

Вы страдаете от использования буфера ввода-вывода ядра при передаче данных. Если мы предположим, что 64 КБ - это размер буфера ввода-вывода ядра, тогда запись 70000 будет блокироваться после записи 64 КБ. Когда он сливается, оставшееся изменение 4 КБ + записывается в буфер ввода-вывода. pv заканчивает выполнение двух чтений для чтения каждого переданного байта 70000, что приводит к примерно половине вашей нормальной пропускной способности из-за плохого использования буфера. Остается все время оставаться в очереди на ввод/вывод во время записи.

Вы можете указать меньший размер чтения до 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] [    <=>                                            ]

Изменить: Еще три прогона (ядро 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] [          <=>                                      ]