Как 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, как правило, сводятся к довольно небольшому количеству машинного кода. Вы вряд ли сможете воспроизвести такую скорость без вставка аналогичного кода сборки. Одним из основных вопросов для рассмотрения в реализации является выравнивание данных.

один общая техника, которую вы можете использовать вставить страж в конце строки поиска, которая гарантирует, что вы найдете его. Он позволяет перемещать тест для конца строки изнутри цикла, чтобы после цикла.