2010-11-14 3 views
1

J'utilise memcpy pour copier à la fois des tailles de données variables et des données de taille fixe. Dans certains cas, je copie de petites quantités de mémoire (seulement une poignée d'octets). Dans GCC, je me souviens que memcpy était un intrinsèque/intégré. Profilage de mon code cependant (avec valgrind) Je vois des milliers d'appels à la fonction "memcpy" réelle dans la glibc.un memcpy optimisé pour des données de petite taille ou de taille fixe dans gcc

Quelles sont les conditions à remplir pour utiliser la fonction intégrée? Je peux lancer mon propre memcpy rapidement, mais je suis sûr que le builtin est plus efficace que ce que je peux faire. REMARQUE: Dans la plupart des cas, la quantité de données à copier est disponible en tant que constante de compilation.

CXXFLAGS: -O3 -DNDEBUG

Le code J'utilise maintenant, ce qui oblige builtins, si vous enlevez le _ préfixe builtin la fonction interne n'est pas utilisé. Ceci est appelé à partir de divers autres modèles/fonctions en utilisant T = sizeof (type). Les tailles qui sont utilisées sont 1, 2, multiples de 4, quelques tailles de 50-100 octets, et certaines structures plus grandes.

template<int T> 
inline void load_binary_fixm(void *address) 
{ 
    if((at + T) > len) 
     stream_error(); 

    __builtin_memcpy(address, data + at, T); 
    at += T; 
} 
+0

Fonctionne bien pour moi avec gcc 4.4.1 dès que j'active l'optimisation (-O1). C'est, memcpy est en ligne. Pouvez-vous fournir un petit code simple, et dire quels commutateurs de compilateur vous utilisez? – davmac

+1

Ne pas profiler votre code (pour cela, je veux dire). Regardez le démontage pour un petit mémcpy spécifique, voyez ce qu'il fait. Même avec l'intrinsèque, la memcpy de la bibliothèque pourrait bien être appelée pour des tailles grandes ou variables. –

+0

@Steve, je ne vois aucune raison pour laquelle valgrind signalerait "memcpy" étant appelé si elle n'était pas appelée. Je sais que le memcpy peut toujours être appelé, mais pour ma situation, il ne devrait pas l'être. –

Répondre

2

Pour les cas où T est petit, je me spécialiserais et utiliserais une affectation native.

Par exemple, où T vaut 1, il suffit d'affecter un seul caractère.

Si vous savez que les adresses sont alignées, utilisez un type int de taille appropriée pour votre plate-forme.

Si les adresses ne sont pas alignées, il est peut-être préférable d'effectuer le nombre d'affectations de char approprié.

Le but de ceci est d'éviter une branche et de garder un compteur.

Où T est grand, je serais surpris si vous faites mieux que la bibliothèque memcpy(), et le préfixe d'appel de fonction va probablement être perdu dans le bruit. Si vous voulez optimiser, regardez autour des implémentations de memcpy(). Il existe des variantes qui utilisent des instructions étendues, etc.

Mise à jour:

regarder votre question réelle sur inline memcpy, des questions telles que les versions du compilateur et la plate-forme deviennent pertinentes (!). Par curiosité, avez-vous essayé d'utiliser std :: copy, quelque chose comme ceci:

template<int T> 
inline void load_binary_fixm(void *address) 
{ 
    if((at + T) > len) 
     stream_error(); 

    std::copy(at, at + T, static_cast<char*>(address)); 
    at += T; 
} 
+0

La dernière fois que j'ai regardé, la bibliothèque GNU libstdC++ utilise memmove dans tous les cas et jamais mémcpy. Donc, std :: copy appellera toujours memmove. –

+1

Je suppose que je vais juste devoir l'implémenter comme vous le suggérez (pour un grand T, je vais toujours utiliser le memcpy std). J'espérais juste que GCC alignerait et déploierait correctement des memcpy avec de petites tailles sans que je fasse n'importe quel travail. –

Questions connexes