Ho un'immagine in formato YUV. Consideriamo solo il componente Y, un
byte per pixel. Il formato originario ha i dati organizzati in blocchi
di 8x8 pixels. Devo convertire il tutto in formato "planare" o "raster".
unsigned char* destination;
unsigned char* source;
int xsize, ysize, x, y, i;
[...]
for(y=0; y<ysize; y+=16)
for(x=0; x<xsize; x+=16)
for(i=0; i<8; i++)
{
memcpy(destination+(y+i)*xsize+x, yuvcurr, sizeof(unsigned char)*8);
yuvcurr+=8;
}
Questo codice e' MOLTO piu' lento del seguente (ARM9, gcc 4.0.0, uClibc):
unsigned int* destination;
unsigned int* source;
int xsize, ysize, x, y, i;
[...]
for(y=0; y<ysize; y+=16)
for(x=0; x<xsize; x+=16)
for(i=0; i<8; i++)
{
dest = (unsigned int*)(final+(y+i)*xsize+x);
*(dest++) = *(source++);
*(dest++) = *(source++);
}
In pratica so che devo copiare 8 byte quindi lo faccio con due letture a
32bit ed ottengo 230fps invece che 70fps. Puo' memcpy essere 3 volte
piu' lento???
ciao!
as
memcpy è una funzione generica che deve garantire buone prestazioni
soprattutto quando copi grandi blocchi di memoria. Usarla per copiare
blocchi da 8 bytes non mi pare opportuno.
Se vuoi ottimizzare ancora il codice ti consiglio di non fare la
moltiplicazione (y+i)*xsize ma di sommare, ad ogni ciclio xsize a dest.
Anche i cicli su x e y potrebbero essere sostituiti con un incremento
opportuno di dest, mentre il controllo lo potresti fare sul valore di
source. Il loop più interno andrebbe "svolto", ma questo quasi
sicuramente lo fa il tuo compilatore.
E.
E.
Alessio Sangalli ha scritto:
> Ciao, ho notato dei problemi nelle performance di memcpy che supponevo
> essere il modo migliore per copiare memoria da un posto all'altro; in
> pratica:
>
>
> unsigned char* destination;
> unsigned char* source;
> int xsize, ysize, x, y, i;
>
> [...]
>
> for(y=0; y<ysize; y+=16)
> for(x=0; x<xsize; x+=16)
> for(i=0; i<8; i++)
> {
> memcpy(destination+(y+i)*xsize+x, yuvcurr, sizeof(unsigned char)*8);
> yuvcurr+=8;
> }
>
>
> Questo codice e' MOLTO piu' lento del seguente (ARM9, gcc 4.0.0, uClibc):
>
>
>
> unsigned int* destination;
> unsigned int* source;
> int xsize, ysize, x, y, i;
>
> [...]
>
> for(y=0; y<ysize; y+=16)
> for(x=0; x<xsize; x+=16)
> for(i=0; i<8; i++)
> {
> dest = (unsigned int*)(final+(y+i)*xsize+x);
> *(dest++) = *(source++);
> *(dest++) = *(source++);
> }
>
>
> In pratica so che devo copiare 8 byte quindi lo faccio con due letture a
> 32bit ed ottengo 230fps invece che 70fps. Puo' memcpy essere 3 volte
> piu' lento???
>
Dipende anche da come e' implementata la memcpy per la CPU target.
Pero' tieni conto che la memcpy e' tanto piu' efficiente tanto maggiore č
il numero di dati da copiare.
Nel tuo caso usi una memcpy per copiare 8bytes, quindi paghi il costo
delle istruzioni per mettere gli operandi sullo stack, il costo della
chiamata,
il costo del ritorno ed il costo per ripristino dello stack:
poi di per se' la copia assembly degli 8 byte e' (magari) velocissima!
Per assurdo tutta la preparazione per l' invocazione della funzione costa
in termini di tempo molto di piu' che la copia stessa ed e' questo il tempo
che vedi.
Per move di pochi byte quindi, č molto piu' efficiente utilizzare i
puntatori
come hai fatto nel secondo esempio.
bye
brix
void *memcpyMia(void *dest, const void *src, size_t count)
{
char *dst8 = (char *)dest;
char *src8 = (char *)src;
if (count & 1)
{
dst8[0] = src8[0];
dst8 += 1;
src8 += 1;
}
count /= 2;
while (count--)
{
dst8[0] = src8[0];
dst8[1] = src8[1];
dst8 += 2;
src8 += 2;
}
return dest;
}
ciao
davide
Alessio Sangalli ha scritto: