Как memchr() работает под капотом?
Справочная информация: Я пытаюсь создать чистую реализацию функциональности языка D, которая примерно эквивалентна С memchr но использует массивы и индексы, а не указатели. Причина в том, что ЗППП.string будет работать с оценкой функции времени компиляции. Для тех из вас, кто не знаком с w / D, функции могут быть оценены во время компиляции, если соблюдены определенные ограничения. Одно ограничение заключается в том, что они не могут использовать указатели. Другое, что они не могут вызвать C функции или используйте встроенный язык сборки. Работа библиотеки строк во время компиляции полезна для некоторых взломов кода gen во время компиляции.
вопрос: Как memchr работает под капотом, чтобы работать так быстро, как это делает? На Win32 все, что я смог создать в pure D с помощью простых циклов, по крайней мере, на 2x медленнее даже с очевидными методами оптимизации, такими как отключение проверки границ, развертывание цикла и т. д. Какие виды неочевидных трюков доступны для что-то простое, как найти символ в строке?
4 ответов
Я бы предложил взглянуть на GNU libcС источником. Что касается большинства функций, он будет содержать как общую оптимизированную версию функции C, так и оптимизированные версии ассемблера для как можно большего числа поддерживаемых архитектур, используя преимущества машинных трюков.
на x86-64 SSE2 версия объединяет результаты из pcmpeqb
на всей кэш-строке данных сразу (четыре вектора 16B), чтобы амортизировать накладные расходы из раннего-выход pmovmskb
/test
/jcc
.
gcc и clang в настоящее время неспособны к авто-векторизации циклов с if() break
условия раннего выхода, поэтому они делают наивный ASM байта за раз из очевидной реализации C.
эта реализация memchr из newlib является одним из примеров чьей-то оптимизации memchr: это чтение и тестирование 4 байтов за раз (кроме memchr, другие функции в библиотеке newlib -здесь).
кстати, большая часть исходного кода для библиотеки времени выполнения MSVC доступна, как необязательная часть установки MSVC (так что вы можете посмотреть на это).
вот FreeBSD (BSD-licensed) memchr () от memchr.c. Онлайн-браузер исходного кода FreeBSD является хорошей ссылкой для проверенных временем, лицензированных BSD примеров кода.
void *
memchr(s, c, n)
const void *s;
unsigned char c;
size_t n;
{
if (n != 0) {
const unsigned char *p = s;
do {
if (*p++ == c)
return ((void *)(p - 1));
} while (--n != 0);
}
return (NULL);
}
memchr, как memset и memcpy, как правило, сводятся к довольно небольшому количеству машинного кода. Вы вряд ли сможете воспроизвести такую скорость без вставка аналогичного кода сборки. Одним из основных вопросов для рассмотрения в реализации является выравнивание данных.
один общая техника, которую вы можете использовать вставить страж в конце строки поиска, которая гарантирует, что вы найдете его. Он позволяет перемещать тест для конца строки изнутри цикла, чтобы после цикла.