Как работает внутренняя реализация memcpy?
Как работает стандартная функция C memcpy? Он должен скопировать (большую) часть ОЗУ в другую область в ОЗУ. Поскольку я знаю, что вы не можете двигаться прямо из ОЗУ в ОЗУ в сборке (с инструкцией mov), поэтому я предполагаю, что при копировании он использует регистр CPU в качестве промежуточной памяти?
Но как он копируется? Блоками (как бы они копируются блоками?), Отдельными байтами (char) или самым большим типом данных, который у них есть (копия в длинном длинном двойном - что составляет 12 байтов в моей системе).
EDIT: Хорошо, видимо, вы можете напрямую перемещать данные из ОЗУ в ОЗУ.. Я не эксперт по сборке, и все, что я узнал о сборке, из этого документа (Руководство по сборке X86), в котором упоминается раздел о команде mov, которую вы не можете перенести из ОЗУ в ОЗУ. По-видимому, это не так.
Ответы
Ответ 1
Зависит. В общем, вы не могли бы физически копировать что-либо большее, чем самый большой полезный регистр за один цикл, но это не так, как работают машины в эти дни. На практике вы действительно заботитесь о том, что делает процессор, и о характеристиках DRAM. Иерархия памяти машины будет играть решающую роль при выполнении этой копии самым быстрым способом (например, загружаете ли вы целые строки кэша? Каков размер строки DRAM в отношении операции копирования?). Вместо реализации вместо этого можно использовать какие-либо векторные инструкции для реализации memcpy
. Без ссылки на конкретную реализацию он эффективно представляет собой байтовую копию с одноместным буфером.
Вот интересная статья, в которой описывается приключение одного человека в оптимизацию memcpy
. Основная точка приема - это то, что она всегда будет нацелена на определенную архитектуру и среду на основе инструкций, которые вы можете выполнить недорого.
Ответ 2
Реализация memcpy
очень специфична для системы, в которой она реализована. Реализации часто оказываются аппаратными.
Команды mov-to-memory mov не так уж необычны - они были вокруг с по крайней мере PDP-11
раза, когда вы могли написать что-то вроде этого:
MOV FROM, R2
MOV TO, R3
MOV R2, R4
ADD LEN, R4
CP: MOV (R2+), (R3+) ; "(Rx+)" means "*Rx++" in C
CMP R2, R4
BNE CP
Прокомментированная строка примерно эквивалентна C
*to++ = *from++;
Современные процессоры имеют инструкции, которые непосредственно реализуют memcpy
: вы загружаете специальные регистры с исходными и целевыми адресами, вызываете команду копирования памяти и позволяете процессору делать все остальное.
Ответ 3
Тривиальная реализация memcpy
:
while (n--) *s2++ = *s1++;
Но glibc
обычно использует некоторые умные реализации в коде сборки. memcpy
вызовы обычно встраиваются.
На x86 код проверяет, является ли параметр размера литералом, кратным 2
или кратным 4
(используя gcc
встроенные функции), и использует цикл с инструкцией movl
(copy 4
байты), иначе он вызывает общий случай.
В общем случае используется блок быстрого копирования блоков с помощью инструкций rep
и movsl
.