optimisé memcpy
Sont plus rapidement des solutions de rechange à memcpy() en C++?
- Si il y avait un moyen plus rapide, pourquoi n'auraient-ils pas l'utiliser dans
memcpy
mise en œuvre? - Ce sujet de l'ESS?
- Le
memcpy
fonction peut être appelée avec des pointeurs de l'arbitraire à l'alignement, pour les choses de l'arbitraire des GOUSSES de type, et peut arbitrairement alias toute GOUSSES d'objets dont l'adresse a été exposé à l'extérieur de code. Compte tenu destruct fnord a,b; void * volatile p=&a,*volatile q=&b;
je m'attends à ce*((struct fnord*)p)=*((struct fnord*)q);
à effectuer beaucoup mieux quememcpy(p,q, sizeof (struct fnord));
puisque dans le premier cas, un compilateur pourrait légitimement supposer p et q seront alignés pour unstruct fnord
et de ne pas alias autre chose, mais dans ce dernier cas, il ne peut pas.
Vous devez vous connecter pour publier un commentaire.
Peu probable. Votre compilateur/bibliothèque standard sera probablement très efficace et sur mesure mise en œuvre de memcpy. Et memcpy est fondamentalement le plus bas de l'api, il est pour la copie d'une partie de la mémoire à une autre.
Si vous souhaitez plus de la vitesse, de trouver un moyen pour ne pas avoir besoin de la mémoire de la copie.
D'abord, un mot de conseils. Supposons que les personnes qui ont écrit de votre bibliothèque standard ne sont pas stupides.
Si il y avait un moyen plus rapide à mettre en œuvre un général memcpy, ils l'auraient fait.
Deuxième, oui, il y a de meilleures alternatives.
std::copy
fonction. Il fait la même chose, mais c'est 1) de plus sûr, et 2) potentiellement plus rapide dans certains cas. C'est un modèle, ce qui signifie qu'il peut être spécialisé pour des types spécifiques, rendant potentiellement plus rapide que l'ensemble de la C memcpy.memmove
. Si vous fournissez de l'aliasing conseils avec__restrict
puis il va appelermemcpy
.Optimisation expert Agner Brouillard a publié optimisé fonctions de la mémoire: http://agner.org/optimize/#asmlib. C'est sous GPL si.
Il y a quelques temps Agner dit que ces fonctions devraient remplacer GCC objets internes, car ils sont beaucoup plus rapides.
Je ne sais pas si ça a été fait depuis.
Cette réponse pour un très simiar question (à propos de
memset()
) s'applique ici aussi.Il dit essentiellement que les compilateurs de générer de très un code optimal pour
memcpy()
/memset()
- et code différent selon la nature des objets (taille, alignement, etc).Et rappelez-vous, seulement
memcpy()
Gousses en C++.Afin de trouver ou écrire un mémoire rapide routine de copie, nous devons comprendre comment les transformateurs de travail.
Processeurs depuis Intel Pentium Pro faire “Hors-de-exécution de l'ordre”. Ils peuvent exécuter plusieurs instructions en parallèle, si les instructions n'ont pas de dépendances. Mais c'est uniquement le cas lorsque les instructions fonctionner avec les registres seulement. Si ils fonctionnent avec la mémoire, le CPU supplémentaires sont les unités utilisées, appelées “unités de charge” (pour lire les données à partir de la mémoire) et de “stocker les unités” (pour écrire des données dans la mémoire). La plupart des Processeurs de deux unités de chargement et d'un magasin de l'unité, c'est à dire qu'ils peuvent exécuter en parallèle deux instructions qui lit à partir de la mémoire et d'une instruction qui écrit dans la mémoire (encore une fois, si ils ne touchent pas les uns les autres). La taille de ces unités est généralement le même que le maximum de registre de taille si le CPU a des registres XMM (ESS) – il est de 16 octets, si elle a YMM registres (AVX) – il est de 32 octets, et ainsi de suite. Toutes les instructions de lecture ou d'écriture de mémoire sont convertis en micro-opérations (micro-ops), qui vont à la piscine commune de micro-ops et attendre pour le charger et stocker des unités pour être en mesure de les servir. Une seule charge ou de l'unité de magasin ne peut que servir d'un micro-op à un moment, indépendamment de la taille des données qu'il doit charger ou de stocker, soit 1 octet ou 32 octets.
Donc, la mémoire la plus rapide copie serait déplacer vers et à partir des registres avec une taille maximale. Pour AVX-permis de processeurs, de la façon la plus rapide pour copier la mémoire serait de répéter la séquence suivante, boucle déroulé:
Le Google code posté plus tôt par hplbsh n'est pas très bonne, parce qu'ils utilisent tous les 8 registres xmm pour contenir les données avant de commencer à l'écrire, alors qu'il n'est pas nécessaire – comme nous n'avons que deux unités de chargement et d'un magasin de l'unité. Donc, juste deux registres donnent les meilleurs résultats. L'aide que de nombreux registres, en aucune façon, améliore les performances.
Une copie de la mémoire de routine peut également utiliser certaines techniques "avancées" comme “prefetch” pour charger le processeur à la mémoire de chargement dans le cache à l'avance et “non-temporelles de l'écrit” (si vous copiez des très grands segments de mémoire et n'ont pas besoin des données à partir de la sortie de la mémoire tampon pour être lu immédiatement), alignés vs non alignés écrit, etc.
Les processeurs modernes, publié à partir de 2013, si ils ont l'ERMS peu dans le CPUID, ont appelé des “rep movsb”, donc pour les grandes copie de la mémoire, de la “rep movsb” peut être utilisé, – la copie sera très rapide, même plus rapide qu'avec le ymm registres, et elle travaillera avec cache correctement. Cependant, les coûts de démarrage de cette instruction sont très élevés – environ 35 cycles, de sorte qu'il paie jusqu'seulement sur les gros blocs de mémoire.
J'espère qu'il devrait maintenant être plus facile pour vous de choisir ou d'écriture de la meilleure copie de la mémoire de routine nécessaires pour votre cas.
Vous pouvez même garder le standard memcpy/memmove, mais obtenir votre propre largememcpy() pour vos besoins.
En fonction de ce que vous essayez de faire... si c'est un assez grand memcpy, et vous êtes seulement être écrit à la copie peu, un mmap avec MMAP_PRIVATE pour créer une copie sur écriture de cartographie pourrait être plus rapide.
En fonction de votre plate-forme, il est peut-être pour des cas d'utilisation spécifiques, comme si vous en connaissez la source et la destination sont alignés sur une ligne de cache et la taille est un multiple entier de la taille de ligne de cache. En général, la plupart des compilateurs produira plutôt un code optimal pour memcpy bien.
Je ne suis pas sûr que l'utilisation de la valeur par défaut memcpy est toujours la meilleure option. La plupart des memcpy implémentations j'ai regardé ont tendance à essayer de faire concorder les données au début, et puis ne aligné des copies. Si les données sont déjà alignés, ou est assez petit, alors ce serait une perte de temps.
Parfois, il est utile d'avoir des mot de copier, de demi-mot copie, copie octet memcpy est, tant qu'il n'a pas trop négativement un effet sur les caches.
En outre, vous ne voulez plus de contrôle sur la répartition réelle de l'algorithme. Dans l'industrie des jeux c'est exceptionnellement rare que les gens écrivent leurs propres routines d'allocation de mémoire, indépendamment de la façon dont beaucoup d'efforts ont été dépensés par l'ensemble des outils développeurs en premier lieu de la développer. Les jeux que j'ai vu presque toujours tendance à utiliser Doug Lea Malloc.
De façon générale toutefois, vous seriez perdre de temps à essayer d'optimiser memcpy comme il y en a sans doute beaucoup plus facile de bits de code dans votre application pour accélérer.