Domanda

Vorrei copiare relativamente breve sequenza di memoria (meno di 1 KB, tipicamente 2-200 byte) in una funzione critica di tempo. Il codice migliore per questo sul lato CPU sembra essere rep movsd. Comunque io in qualche modo non riesco a fare il mio compilatore per generare il codice. Speravo (e mi ricordo vagamente vedere così) usando memcpy farebbe questo usando il compilatore intrinseche built-in, ma sulla base di smontaggio e il debug sembra compilatore sta usando chiamata a memcpy / implementazione biblioteca memmove invece. Ho anche sperato il compilatore potrebbe essere sufficiente per riconoscere seguente ciclo e utilizzare rep movsd da solo intelligente, ma sembra non è così.

char *dst;
const char *src;
// ...
for (int r=size; --r>=0; ) *dst++ = *src++;

C'è qualche modo per rendere il compilatore Visual Studio per generare la sequenza rep movsd altro che usare l'assembly inline?

È stato utile?

Soluzione 3

Utilizzo memcpy con una dimensione costante

Quello che ho trovato nel frattempo:

compilatore utilizzi intrinseca quando la dimensione del blocco copiato è ora conosciuta compilazione. Quando non è, è chiamata l'attuazione biblioteca. Quando la dimensione è noto, il codice generato è molto bello, selezionati in base alle dimensioni. Può essere un singolo mov o movsd o movsd seguita da movsb, come necessario.

Sembra che se voglio davvero usare movsb o movsd sempre, anche con una dimensione "dinamica" dovrò utilizzare assembly inline o speciali intrinseca (vedi sotto). So che la dimensione è "abbastanza breve", ma il compilatore non lo sa e non posso comunicarlo ad esso - Ho anche provato ad usare __assume (dimensioni <16), ma non è sufficiente

.

Codice Demo, compilare con "-Ob1 (espansione per linea solo):

  #include <memory.h>

  void MemCpyTest(void *tgt, const void *src, size_t size)
  {
    memcpy(tgt,src,size);
  }

  template <int size>
  void MemCpyTestT(void *tgt, const void *src)
  {
    memcpy(tgt,src,size);
  }

  int main ( int argc, char **argv )
  {
    int src;
    int dst;
    MemCpyTest(&dst,&src,sizeof(dst));
    MemCpyTestT<sizeof(dst)>(&dst,&src);
    return 0;
  }

intrinseche specializzate

Ho trovato di recente esiste modo molto semplice come fare di Visual Studio personaggi compilatore copia utilizzando movsd - molto semplici e naturali: intrinseche usando. Dopo intrinseche può tornare utile:

Altri suggerimenti

Diverse questioni vengono in mente.

In primo luogo, come fai a sapere movsd sarebbe più veloce? Hai guardato la sua latenza / rendimento? L'architettura x86 è pieno di vecchie istruzioni crufty che non devono essere utilizzati perché sono semplicemente non molto efficiente sulla moderna CPU.

In secondo luogo, che cosa succede se si utilizza std::copy invece di memcpy? std::copy è potenzialmente più veloce, in quanto può essere specializzato a tempo di compilazione per il tipo di dati specifici.

E in terzo luogo, avete abilitato funzioni intrinseche sotto proprietà del progetto -> C / C ++ -> ottimizzazione

Naturalmente suppongo altre ottimizzazioni sono abilitati pure.

Stai usando una build ottimizzata? Non sarà utilizzare un intrinseco a meno che l'ottimizzazione è acceso. La sua anche la pena notare che probabilmente utilizzare un ciclo di copia migliore di rep movsd. Dovrebbe cercare di utilizzare MMX, per lo meno, per eseguire un 64-bit in una copia di tempo. Infatti 6 o 7 anni fa ho scritto un ciclo copia ottimizzato MMX per fare questo genere di cose. Purtroppo memcpy intrinseca del compilatore ha superato la mia copia MMX di circa l'1%. Che davvero mi ha insegnato a non fare ipotesi su ciò che il compilatore sta facendo.

Avete cronometrato memcpy? Sulle recenti versioni di Visual Studio, l'applicazione utilizza memcpy SSE2 ... che dovrebbe essere più veloce di rep movsd. Se il blocco si sta copiando è di 1 KB, allora non è davvero un problema che il compilatore non utilizza un intrinseco in quanto il tempo per la chiamata di funzione sarà trascurabile rispetto al tempo per la copia.

Si noti che per poter utilizzare movsd, src deve puntare ad una memoria allineato a 32-bit di confine e la sua lunghezza deve essere un multiplo di 4 byte.

Se lo è, perché il codice di utilizzo char * invece di int * o qualcosa del genere? Se non è, la sua domanda è discutibile.

Se si cambia char * a int *, potrebbe ottenere risultati migliori dal std::copy.

Modifica:? avete misurato che la copia è il collo di bottiglia

Usa memcpy. Questo problema è già stato risolto.

FYI rep movsd non è sempre la migliore, rappresentante movsb può essere più veloce in alcune circostanze e con SSE e come il migliore è movntq [edi], xmm0. È anche possibile ottimizzare ulteriormente per la grande quantità di memoria utilizzando la pagina località spostando i dati in un buffer e poi si spostano a destinazione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top