Когда memcpy работает быстрее, чем простое повторное присваивание?

Предположим, что кто-то хочет сделать копию массива, объявленного как

DATA_TYPE src[N];

Всегда ли memcpy так же быстро или быстрее, чем следующий фрагмент кода, независимо от того, что такое DATA_TYPE и количество элементов массива?

DATA_TYPE dest[N];

for (int i=0; i<N; i++)
    dest[i] = src[i];

Для маленького типа, такого как char, и большого N мы можем быть уверены, что memcpy быстрее (если только компилятор не заменит цикл вызовом memcpy). Но что, если тип больше, например double, и/или количество элементов массива мало?

Этот вопрос возник у меня при копировании множества массивов double, каждый из которых состоит из 3 элементов.

Я не нашел ответа на свой вопрос в ответе на другой вопрос, упомянутый Вольстадом в комментариях. Принятый ответ на этот вопрос, по сути, говорит: «Оставьте это на усмотрение компилятора». Это не тот ответ, который я ищу. Тот факт, что компилятор может оптимизировать копирование памяти, выбрав одну альтернативу, не является ответом. Почему и когда один из вариантов быстрее? Возможно, компиляторы знают ответ, но разработчики, включая разработчиков компиляторов, не знают!

Отвечает ли это на ваш вопрос? memcpy против присваивания в C

wohlstad 23.04.2022 09:36

@wohlstad, спасибо. Я читаю это.

apadana 23.04.2022 09:38

Используйте www.godbolt.org для проверки альтернативных кодов. Скорее всего, оптимизатор создаст почти одинаковую сборку для обоих.

hyde 23.04.2022 09:38

@wohlstad, принятый ответ на этот вопрос, по сути, говорит: «Оставьте это на усмотрение компилятора». Это не тот ответ, который я ищу.

apadana 23.04.2022 09:48

@wohlstad, тот факт, что компилятор может оптимизировать копирование памяти, выбрав одну альтернативу, не является ответом. Почему и когда один из вариантов быстрее? Возможно, компиляторы знают ответ, но разработчики, включая разработчиков компиляторов, не знают!

apadana 23.04.2022 09:54

Во многих реализациях memcpy есть оптимизации для копирования элементов размером слова на границах слов. Например, если вы DATA_TYPE были байтом, то ваш ручной цикл, предполагающий отсутствие оптимизации, будет выполнять N итераций. На 64-битной машине memcpy может выполнить всю работу за N/8 итераций — копирование более 64-бит за раз.

selbie 23.04.2022 10:00

Какой ответ находятся вы ищете? Нет серебряной пули, которая «лучше». Задействованные переменные слишком разнообразны и зависят от ситуации. Единственный способ узнать определенный — это создать свой оптимизированный asm, подсчитать тактовые циклы и остановки конвейера, включая потенциальные ошибки прогнозирования ветвлений, локальность кеша и, прежде всего, мера.

WhozCraig 23.04.2022 10:02

@WhozCraig, правильно, но обычно есть общие правила.

apadana 23.04.2022 10:19

"для мелкого типа... мы можем быть уверены, что memcpy быстрее" - Нет, нельзя.

Cheatah 23.04.2022 10:22

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

nielsen 23.04.2022 10:39
3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
0
10
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

Тем не менее, любая предоставленная стандартная библиотека, вероятно, будет сильно оптимизирована и может даже использовать специфические аппаратные функции, такие как передача DMA. Принимая во внимание, что производительность вашего цикла кода будет варьироваться в зависимости от настроек оптимизации, поэтому, вероятно, она будет работать намного хуже в неоптимизированных сборках отладки.

Еще одно соображение заключается в том, что производительность memcpy() не зависит от типа данных и, как правило, детерминированный, тогда как производительность вашего цикла, вероятно, будет зависеть от DATA_TYPE или даже от значения N.

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

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

Вы бы сами использовали memcpy для копирования массива из 3 double?

apadana 23.04.2022 10:30

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

Clifford 23.04.2022 10:37

Хороший ответ. Теперь, когда вы упомянули DMA, забавно, что передача DMA может - в зависимости от платформы - быть медленнее, чем, например. memcpy(), но тем временем это позволит процессору заниматься другими делами. В таком случае «быстрее» зависит от того, может ли приложение использовать эту разгрузку.

nielsen 23.04.2022 10:44

@apadana: в общем, я бы не стал париться по мелочам. Такие микрооптимизации редко бывают продуктивными или необходимыми, и их трудно обобщить. Единственный раз, когда я помню, что мне нужно было беспокоиться о подобных вещах, это код DSP в системе жесткого реального времени на основе микроконтроллера. И там я протестировал и профилировал различные реализации, чтобы определить лучшее решение для этого конкретного приложения на этой конкретной платформе ant toolchain.

Clifford 23.04.2022 10:49

@nielsen: да, на практике я сомневаюсь, что реализация будет использовать DMA, поскольку она менее детерминирована и не переносима. Также для небольших копий время установки будет непомерно высоким. Вместо этого могут быть предоставлены специализированные функции копирования памяти DMA.

Clifford 23.04.2022 10:54

Другие вопросы по теме