Любопытная функция копирования строк в C - PullRequest
9 голосов
/ 13 апреля 2011

Когда я читал код nginx, я видел эту функцию:

#define ngx_cpymem(dst, src, n)   (((u_char *) memcpy(dst, src, n)) + (n))

static ngx_inline u_char *
ngx_copy(u_char *dst, u_char *src, size_t len)
{
    if (len < 17) {

        while (len) {
            *dst++ = *src++;
            len--;
        }

        return dst;

    } else {
        return ngx_cpymem(dst, src, len);
    }
}

Это простая функция копирования строк.Но почему он проверяет длину строки и переключается на memcpy, если длина> = 17?

1 Ответ

12 голосов
/ 13 апреля 2011

Это оптимизация - для очень маленьких строк простое копирование выполняется быстрее, чем вызов системной (libc) функции копирования.

Простое копирование с циклом while работает довольно быстро для коротких строк, а функция системного копирования имеет (как правило) оптимизацию для длинных строк. Но также системное копирование выполняет много проверок и некоторые настройки.

На самом деле перед автором есть комментарий автора: nginx, /src/core/ngx_string.h (search ngx_copy)

/*
 * the simple inline cycle copies the variable length strings up to 16
 * bytes faster than icc8 autodetecting _intel_fast_memcpy()
 */

Кроме того, верхняя строка из двух строк -

#if ( __INTEL_COMPILER >= 800 )

Итак, автор сделал измерения и пришел к выводу, что оптимизированная ICC memcopy выполняет долгую проверку ЦП, чтобы выбрать наиболее оптимизированный вариант memcopy. Он обнаружил, что ручное копирование 16 байт быстрее, чем самый быстрый код memcpy из ICC.

Для других компиляторов nginx использует ngx_cpymem (memcpy) напрямую

#define ngx_copy                  ngx_cpymem

Автор провел исследование различных memcpy s для разных размеров:

/*
 * gcc3, msvc, and icc7 compile memcpy() to the inline "rep movs".
 * gcc3 compiles memcpy(d, s, 4) to the inline "mov"es.
 * icc8 compile memcpy(d, s, 4) to the inline "mov"es or XMM moves.
 */
...