web-dev-qa-db-fra.com

Très rapide memcpy pour le traitement de l'image?

Je fais le traitement de l'image en C qui nécessite de copier de gros morceaux de données autour de la mémoire - la source et la destination ne se chevauchent jamais.

Quel est le moyen le plus rapide absolu de le faire sur la plate-forme x86 à l'aide de GCC (Où [~ # ~ # ~ # ~ # ~] , sse2 mais pas sse3 est disponible)?

Je m'attends à ce que la solution soit à l'assemblage ou à l'utilisation de la GCC intrinsique?

J'ai trouvé le lien suivant mais je n'ai aucune idée de savoir si c'est la meilleure façon d'y aller (l'auteur dit également qu'il a quelques bugs): http://coding.derkeiler.com/archive/assembler/comp. lang.asm.x86/2006-02/msg00123.html

Edit: Notez qu'une copie est nécessaire, je ne peux pas contourner la copie des données (je pourrais expliquer pourquoi, mais je vous éparpre l'explication :))

31
horseyguy

Gracieuseté de William Chan et Google. 30-70% plus rapide que MEMCY dans Microsoft Visual Studio 2005.

void X_aligned_memcpy_sse2(void* dest, const void* src, const unsigned long size)
{

  __asm
  {
    mov esi, src;    //src pointer
    mov edi, dest;   //dest pointer

    mov ebx, size;   //ebx is our counter 
    shr ebx, 7;      //divide by 128 (8 * 128bit registers)


    loop_copy:
      prefetchnta 128[ESI]; //SSE2 prefetch
      prefetchnta 160[ESI];
      prefetchnta 192[ESI];
      prefetchnta 224[ESI];

      movdqa xmm0, 0[ESI]; //move data from src to registers
      movdqa xmm1, 16[ESI];
      movdqa xmm2, 32[ESI];
      movdqa xmm3, 48[ESI];
      movdqa xmm4, 64[ESI];
      movdqa xmm5, 80[ESI];
      movdqa xmm6, 96[ESI];
      movdqa xmm7, 112[ESI];

      movntdq 0[EDI], xmm0; //move data from registers to dest
      movntdq 16[EDI], xmm1;
      movntdq 32[EDI], xmm2;
      movntdq 48[EDI], xmm3;
      movntdq 64[EDI], xmm4;
      movntdq 80[EDI], xmm5;
      movntdq 96[EDI], xmm6;
      movntdq 112[EDI], xmm7;

      add esi, 128;
      add edi, 128;
      dec ebx;

      jnz loop_copy; //loop please
    loop_copy_end:
  }
}

Vous pourrez peut-être l'optimiser davantage en fonction de votre situation exacte et de toutes les hypothèses que vous pouvez faire.

Vous voudrez peut-être aussi consulter la source MEMCY (MEMCY.ASM) et éliminer sa manipulation spéciale. Il peut être possible d'optimiser davantage!

40
hplbsh

À tout niveau d'optimisation de -O1 ou plus, GCC utilisera des définitions intégrées pour des fonctions telles que memcpy - avec la droite -march Paramètre (-march=pentium4 Pour l'ensemble des fonctionnalités que vous mentionnez) Il devrait générer un code intégré spécifique à une architecture très optimale.

Je l'appuierais et voyez ce qui sort.

6
caf

Le code SSE posté par Hapalibashi est la voie à suivre.

Si vous avez besoin de plus de performances et n'échappez pas à la route longue et sinueuse de l'écriture d'un pilote de périphérique: toutes les plates-formes importantes ont aujourd'hui un contrôleur DMA capable de faire une copie-travail plus rapide et en parallèle au code de la CPU pourrait faire.

Cela implique de rédiger un conducteur cependant. Aucun gros système d'exploitation dont je suis conscient d'expose cette fonctionnalité au côté de l'utilisateur en raison des risques de sécurité.

Cependant, cela en vaut la peine (si vous avez besoin de la performance), aucun code sur Terre ne pourrait surperformer un élément de matériel conçu pour faire un tel travail.

6
Nils Pipenbrinck

Si spécifique aux processeurs Intel, vous pouvez bénéficier de [~ # ~ # ~ # ~ ~] . Si vous savez qu'il fonctionnera avec un GPU NVIDIA, vous pourriez peut-être utiliser [~ # ~] cuda [~ # ~ ~] - Dans les deux cas, il peut être préférable de regarder plus large que l'optimisation MEMCY () - ils Fournir des possibilités d'améliorer votre algorithme à un niveau supérieur. Ils sont tous deux si dépendants sur du matériel spécifique.

3
Clifford