Une fonction de copie de chaîne curieuse en C

Lorsque j’ai lu le code nginx, j’ai vu cette fonction:

#define ngx_cpymem(dst, src, n) (((u_char *) memcpy(dst, src, n)) + (n)) static ngx_inline u_char * ngx_copy(u_char *dst, u_char *src, size_t len) { if (len < 17) { while (len) { *dst++ = *src++; len--; } return dst; } else { return ngx_cpymem(dst, src, len); } } 

C’est une simple fonction de copie de chaîne. Mais pourquoi tester la longueur de la chaîne et passer à memcpy si la longueur est> = 17?

C’est une optimisation – pour les très petites chaînes, la copie simple est plus rapide que d’appeler une fonction de copie du système (libc).

La copie simple avec la boucle while fonctionne assez vite pour les chaînes courtes, et la fonction de copie du système a (généralement) des optimisations pour les chaînes longues. Mais aussi la copie du système fait beaucoup de vérifications et de configuration.

En fait, il y a un commentaire de l’auteur juste avant ce code: nginx, /src/core/ngx_ssortingng.h (recherche ngx_copy)

 /* * the simple inline cycle copies the variable length ssortingngs up to 16 * bytes faster than icc8 autodetecting _intel_fast_memcpy() */ 

En outre, une ligne de deux lignes est

 #if ( __INTEL_COMPILER >= 800 ) 

Ainsi, l’auteur a fait des mesures et a conclu que la version optimisée d’ICC effectuait une longue vérification du processeur pour sélectionner la variante de memcopy la plus optimisée. Il a constaté que la copie manuelle de 16 octets était plus rapide que le code Memcpy le plus rapide d’ICC.

Pour les autres compilateurs, nginx utilise ngx_cpymem (memcpy) directement

 #define ngx_copy ngx_cpymem 

L’auteur a fait une étude de différents memcpy pour différentes tailles:

 /* * gcc3, msvc, and icc7 comstack memcpy() to the inline "rep movs". * gcc3 comstacks memcpy(d, s, 4) to the inline "mov"es. * icc8 comstack memcpy(d, s, 4) to the inline "mov"es or XMM moves. */