glibc 2.26 имеет несколько реализаций сборки, оптимизированных вручную: strlen
По состоянию на glibc-2.26
, быстрый:
git ls-files | grep strlen.S
в дереве glibc показывает дюжину реализаций, оптимизированных вручную для всех основных архитектур и вариаций.
В частности, один x86_64 имеет 3 варианта:
sysdeps/x86_64/multiarch/strlen-avx2.S
sysdeps/x86_64/multiarch/strlen-sse2.S
sysdeps/x86_64/strlen.S
Быстрый и грязный способ определить, какой из них используется, - пошаговая отладка тестовой программы:
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main(void) {
size_t size = 0x80000000, i, result;
char *s = malloc(size);
for (i = 0; i < size; ++i)
s[i] = 'a';
s[size - 1] = '\0';
result = strlen(s);
assert(result == size - 1);
return EXIT_SUCCESS;
}
скомпилировано с:
gcc -ggdb3 -std=c99 -O0 a.c
С бита:
disass main
содержит:
callq 0x555555554590 <strlen@plt>
поэтому вызывается версия libc.
После нескольких шагов si
уровня команд GDB достигает:
__strlen_avx2 () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:52
52 ../sysdeps/x86_64/multiarch/strlen-avx2.S: No such file or directory.
, который говорит мне, что strlen-avx2.S
было использовано.
Затем я также подтверждаю:
disass __strlen_avx2
и сравните разборку с источником glibc.
Неудивительно, что использовалась версия AVX2, так как у меня есть i7-7820HQ ЦП с датой запуска Q1 2017 и поддержкой AVX2, а AVX2 является самым передовым реализации сборки, с датой запуска Q2 2013, в то время как SSE2 намного более древний с 2004 года.
Вот откуда взялась большая часть хардкорности glibc: он имеет много оптимизированного для арки рукописного ассемблерного кода.
Протестировано в Ubuntu 17.10, gcc 7.2.0, glibc 2.26.
-O3
TODO: с -O3
, gcc не использует glibc's strlen
, он просто генерирует встроенную сборку, которая упоминается в: https://stackoverflow.com/a/19885891/895245
Это потому, что он может оптимизировать еще лучше? Но его вывод не содержит инструкций AVX2, поэтому я чувствую, что это не так.
https://www.gnu.org/software/gcc/projects/optimize.html упоминает:
Недостатки оптимизатора GCC
glibc имеет встроенные версии ассемблера различных строковых функций; GCC имеет несколько, но не обязательно одинаковых, на тех же архитектурах. Дополнительные записи optab, например, для ffs и strlen, могут быть предоставлены для нескольких дополнительных функций, включая memset, strchr, strcpy и strrchr.
Мои простые тесты показывают, что версия -O3
на самом деле быстрее, поэтому GCC сделала правильный выбор.
На вопрос: https://www.quora.com/unanswered/How-does-GCC-know-that-its-builtin-implementation-of-strlen-is-faster-than-glibcs-when-using-optimization-level-O3