C: velocidade memcpy em matrizes alocadas dinamicamente
Preciso de ajuda com o desempenho do código a seguir. Ele faz um memcpy em duas matrizes alocadas dinamicamente de tamanho arbitrário:
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 mede o tempo de execução.
No meu computador, leva 0.035s para o memcpy (Linux, gcc versão 4.4.6). Se eu agora descomentar a linha que inicializa o array de destino b, o código é três vezes mais rápido (!) - 0.011s.
Eu observei um comportamento semelhante ao usar um loop em vez de memcpy. Normalmente eu não me importo com isso, já que é suficiente para "inicializar" a memória antes de usá-la. No entanto, agora preciso executar uma cópia de memória simples e fazê-lo o mais rápido possível. A inicializao dos dados requer escrita, e. 0 para a memória, o que não é necessário e leva tempo. E gostaria de realizar uma cópia de memória com toda a largura de banda de memória disponível.
Existe uma solução para este problema? Ou está ligado à forma como o Linux lida com a memória dinâmica (algum tipo de alocação de páginas preguiçosas?) E não pode ser contornado? Como é em outros sistemas?
Editar: Os mesmos resultados são obtidos com o gcc 4.6. Eu usei -O3 para compilar.
Editar: Obrigado a todos por seus comentários. Eu entendo que o mapeamento de memória leva tempo. Acho que é difícil aceitar que demora tanto, muito mais do que o acesso real à memória. O código foi modificado para incluir um benchmark da inicialização do array b usando duas chamadas subseqüentes do bzero. Os horários agora mostram
bzero1 0.273981
bzero2 0.056803
memcpy 0.117934
Claramente, a primeira chamada bzero fazMuito de mais do que apenas zeros de fluxo para memória - isto é, mapeamento de memória e zeramento de memória. A segunda chamada bzero, por outro lado, leva metade do tempo requerido para fazer um memcpy, o que é exatamente como esperado - escreva apenas o tempo vs. ler e escrever. Eu entendo que a sobrecarga da segunda chamada bzero deve estar lá devido a razões de segurança do sistema operacional. E o resto? Não posso diminuir de alguma forma, por exemplo? usar páginas de memória maiores? Configurações diferentes do kernel?
Eu devo mencionar que eu corro isso no chiado do Ubuntu.