C: скорость memcpy для динамически размещаемых массивов
Мне нужна помощь с производительностью следующего кода. Он создает memcpy для двух динамически размещаемых массивов произвольного размера:
int main()
{
double *a, *b;
unsigned n = 10000000, i;
a = malloc(n*sizeof(double));
b = malloc(n*sizeof(double));
for(i=0; i<n; i++) {
a[i] = 1.0;
/* b[i] = 0.0; */
}
tic();
bzero(b, n*sizeof(double));
toc("bzero1");
tic();
bzero(b, n*sizeof(double));
toc("bzero2");
tic();
memcpy(b, a, n*sizeof(double));
toc("memcpy");
}
Tic / Toc измеряет время выполнения.
На моем компьютере memcpy требуется 0,035 с (Linux, gcc версия 4.4.6). Если я теперь раскомментирую строку, которая инициализирует целевой массив b, код будет работать в три раза быстрее (!) - 0,011 с.
Я наблюдал подобное поведение при использовании цикла вместо memcpy. Обычно меня это не волнует, так как достаточно «инициализировать»; память перед его использованием. Однако сейчас мне нужно выполнить простую копию памяти и сделать это как можно быстрее. Инициализация данных требует записи, например 0 в память, которая не нужна и требует времени. И я хотел бы выполнить копирование памяти со всей доступной пропускной способностью памяти.
Есть ли решение этой проблемы? Или это связано с тем, как Linux обрабатывает динамическую память (какое-то ленивое распределение страниц?) И не может быть обойдено? Как это на других системах?
Edit: Такие же результаты получены с gcc 4.6. Я использовал -O3 для компиляции.
Edit: Thank you all for your comments. I do understand that memory mapping takes time. I guess I just have a hard time accepting that it takes so long, much longer than the actual memory access. The code has been modified to include a benchmark of the initialization of array b using two subsequent bzero calls. The timings now show
bzero1 0.273981
bzero2 0.056803
memcpy 0.117934
Ясно, что первый вызов bzero делаетmuch больше, чем просто потоковые нули в память - это отображение памяти и обнуление памяти. Второй вызов bzero, с другой стороны, занимает половину времени, необходимого для создания memcpy, что в точности соответствует ожиданиям - запись только время против чтения и записи. Я понимаю, что накладные расходы на второй вызов bzero должны быть из-за соображений безопасности ОС. А как насчет отдыха? Могу ли я не уменьшить его как-нибудь, например использовать большие страницы памяти? Разные настройки ядра?
Я должен упомянуть, что я запускаю это на Ubuntu хрипит.