более быстрая альтернатива memcpy? - PullRequest
37 голосов
/ 03 июня 2010

У меня есть функция, которая выполняет memcpy, но она занимает огромное количество циклов. Есть ли более быстрый альтернативный подход / подход, чем использование memcpy для перемещения фрагмента памяти?

Ответы [ 17 ]

1 голос
/ 20 октября 2018

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

1 голос
/ 03 июня 2010

Возможно, вы захотите взглянуть на это:

http://www.danielvik.com/2010/02/fast-memcpy-in-c.html

Другая идея, которую я бы попробовал, - это использовать методы COW для дублирования блока памяти и позволить ОС обрабатывать копирование по требованию, как только страница будет записана. Здесь есть некоторые подсказки, использующие mmap(): Могу ли я сделать memcpy копирования при записи в Linux?

1 голос
/ 24 декабря 2015

Вы должны проверить код сборки, сгенерированный для вашего кода. То, что вы не хотите, - это чтобы вызов memcpy генерировал вызов функции memcpy в стандартной библиотеке - то, что вам нужно, - это повторный вызов наилучшей инструкции ASM для копирования наибольшего объема данных - что-то вроде rep movsq.

Как этого добиться? Что ж, компилятор оптимизирует вызовы к memcpy, заменяя его простыми mov s, пока он знает, сколько данных он должен скопировать. Вы можете увидеть это, если напишите memcpy с точно определенным (constexpr) значением. Если компилятор не знает значение, ему придется вернуться к реализации уровня байтов memcpy - проблема заключается в том, что memcpy должен учитывать гранулярность в один байт. Он по-прежнему будет перемещаться по 128 бит за раз, но после каждого 128b он должен будет проверить, достаточно ли у него данных для копирования как 128b или он должен вернуться к 64 битам, затем к 32 и 8 (я думаю, что 16 может быть неоптимальным во всяком случае, но я не знаю точно).

Так что вы можете либо memcpy сообщить, какой размер ваших данных с помощью константных выражений, которые компилятор может оптимизировать. Таким образом, вызов memcpy не выполняется. Чего вы не хотите, так это передавать memcpy переменную, которая будет известна только во время выполнения. Это приводит к вызову функции и множеству тестов для проверки лучшей инструкции копирования. Иногда простой цикл for лучше, чем memcpy по этой причине (исключая один вызов функции). И что вы действительно не хотите - это передача memcpy нечетного числа байтов для копирования.

0 голосов
/ 27 августа 2018

Вот альтернативная версия memcpy для C, которая является встроенной, и я считаю, что она превосходит memcpy для GCC для Arm64 примерно на 50% в приложении, для которого я ее использовал. Это 64-битная платформа, независимая. Хвостовая обработка может быть удалена, если экземпляр использования не нуждается в нем для большей скорости. Копирует массивы uint32_t, меньшие типы данных не проверены, но могут работать. Может быть в состоянии адаптироваться к другим типам данных. 64-битное копирование (два индекса копируются одновременно). 32-разрядный также должен работать, но медленнее. Кредиты проекту Neoscrypt.

    static inline void newmemcpy(void *__restrict__ dstp, 
                  void *__restrict__ srcp, uint len)
        {
            ulong *dst = (ulong *) dstp;
            ulong *src = (ulong *) srcp;
            uint i, tail;

            for(i = 0; i < (len / sizeof(ulong)); i++)
                *dst++ = *src++;
            /*
              Remove below if your application does not need it.
              If console application, you can uncomment the printf to test
              whether tail processing is being used.
            */
            tail = len & (sizeof(ulong) - 1);
            if(tail) {
                //printf("tailused\n");
                uchar *dstb = (uchar *) dstp;
                uchar *srcb = (uchar *) srcp;

                for(i = len - tail; i < len; i++)
                    dstb[i] = srcb[i];
            }
        }
0 голосов
/ 03 июня 2010

Полагаю, у вас должны быть огромные области памяти, которые вы хотите скопировать, если производительность memcpy стала для вас проблемой?

В этом случае я бы согласился с предложением nos найти какой-то способ НЕ копировать вещи ..

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

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

0 голосов
/ 03 июня 2010

Нос прав, ты слишком много это называешь.

Чтобы увидеть, откуда вы звоните и почему, просто приостановите его несколько раз под отладчиком и посмотрите на стек.

0 голосов
/ 24 августа 2010

память в память обычно поддерживается в наборе команд ЦП, и memcpy обычно использует это. И это обычно самый быстрый способ.

Вы должны проверить, что именно делает ваш процессор. В Linux следите за входом и выходом swapi и эффективностью виртуальной памяти с помощью sar -B 1 или vmstat 1 или заглядывая в / proc / memstat. Вы можете увидеть, что ваша копия должна вытолкнуть много страниц на свободное место или прочитать их и т. Д.

Это означает, что ваша проблема не в том, что вы используете для копирования, а в том, как ваша система использует память. Вам может понадобиться уменьшить кэш файлов или начать запись раньше, или заблокировать страницы в памяти и т. Д.

...