Почему sscanf в glibc намного медленнее, чем fscanf в Linux?

Я использую GCC 4.8 и glibc 2.19 на Linux x86_64.

Играя с разными методами ввода длядругой вопросЯ сравнилfscanf а такжеsscanf, Конкретно я бы либо использовалfscanf на стандартный ввод напрямую:

char s[128]; int n;

while (fscanf(stdin, "%127s %d", s, &n) == 2) { }

Или я сначала прочитал бы весь ввод в буфер, а затем прошел через буферsscanf, (Чтение всего в буфер занимает немного времени.)

char s[128]; int n;
char const * p = my_data;

for (int b; sscanf(p, "%127s %d%n", s, &n, &b) == 2; p += b) { }

К моему удивлению,fscanf версиязначительно Быстрее. Например, обработка нескольких десятков тысяч строкfscanf занимает много времени:

10000       0.003927487 seconds time elapsed
20000       0.006860206 seconds time elapsed
30000       0.007933329 seconds time elapsed
40000       0.012881912 seconds time elapsed
50000       0.013516816 seconds time elapsed
60000       0.015670432 seconds time elapsed
70000       0.017393129 seconds time elapsed
80000       0.019837480 seconds time elapsed
90000       0.023925753 seconds time elapsed

Теперь то же самое сsscanf:

10000       0.035864643 seconds time elapsed
20000       0.127150772 seconds time elapsed
30000       0.319828373 seconds time elapsed
40000       0.611551668 seconds time elapsed
50000       0.919187459 seconds time elapsed
60000       1.327831544 seconds time elapsed
70000       1.809843039 seconds time elapsed
80000       2.354809588 seconds time elapsed
90000       2.970678416 seconds time elapsed

Я использовал инструменты Google perf, чтобы измерить это. Например, для 50000 строкfscanf код требует около 50 миллионов циклов, аsscanf код около 3300M циклов. Таким образом, я сломал верхние сайты вызовов сperf record/perf report, Сfscanf:

 35.26%  xf  libc-2.19.so         [.] _IO_vfscanf
 23.91%  xf  [kernel.kallsyms]    [k] 0xffffffff8104f45a
  8.93%  xf  libc-2.19.so         [.] _int_malloc

И сsscanf:

 98.22%  xs  libc-2.19.so         [.] rawmemchr
  0.68%  xs  libc-2.19.so         [.] _IO_vfscanf
  0.38%  xs  [kernel.kallsyms]    [k] 0xffffffff8104f45a

Так почти все время сsscanf проводится вrawmemchr! Почему это? Как можноfscanf код избежать этой стоимости?

Я пытался найти это, но лучшее, что я мог придумать, этоэто обсуждение заблокированrealloc звонки, которые я не думаю, применимы здесь. Я также думал, чтоfscanf имеет лучшую локальность памяти (используя один и тот же буфер снова и снова), но это не может иметь такого большого значения.

У кого-нибудь есть понимание этого странного несоответствия?

Ответы на вопрос(2)

Ваш ответ на вопрос