J'ai besoin d'une fonction de comparaison pour les blocs de mémoire pour effectuer des recherches binaires sur des tableaux d'octets dans la langue de programmation D. Il n'a pas besoin d'avoir une sémantique utile. Il suffit d'être rapide et d'une fonction de comparaison valide (une qui produit une commande totale). Les blocs de la mémoire à comparer sont déjà connus pour être la même longueur.
C édition: j'ai lu sur SSE et je ne sais pas Voulez-vous l'utiliser pour 3 raisons: p> MEMCMP CODE> est vraiment lent car il essaie de préserver la sémantique de comparaison de chaînes utiles, dont je n'ai pas besoin. Ci-dessous est le meilleur que j'ai monté jusqu'à présent. Est-ce que quelqu'un sait de quelque chose de mieux, de préférence sans plonger dans des instructions non portables spécifiques à la CPU? P>
6 Réponses :
Vous pouvez essayer:
edit strong>: si la première boucle est le goulot d'étranglement, le déroulement pourrait être la réponse. Combiné à réduire de moitié le nombre de conditions en cas de valeurs égales, pour dérouler 4 fois, je reçois quelque chose comme: p> bien sûr que laisse (n / uint.sizeof )% 4 code> Les itérations laissées à faire, que vous pouvez mélanger dans cette boucle en entrelant un commutateur, je l'ai laissé comme exercice pour le lecteur grotte maléfique em>. P> p>
1. J'ai essayé d'utiliser Ulongs, c'était plus lent. 2. J'ai essayé de sortir la deuxième déréence. Ce n'était pas plus rapide, de manière proplablement B / C, le compilateur optimise de toute façon la même chose, donc je mets le 2e Deref en arrière car il rend le code plus lisible. 3. Je pense que la majeure partie du goulot d'étranglement est la première boucle.
La personne qui a voté -1 sur toutes les réponses peut-elle ajouter une note de pourquoi?
RSP je suppose que c'est juste un troll. Je ne pense pas que ces réponses méritent un bowvote.
Je pense que MEMCMP est spécifié pour effectuer une comparaison d'octets par octet, quel que soit le type de données. Êtes-vous sûr que la mise en œuvre de votre compilateur conserve la sémantique de la chaîne? Ça ne devrait pas. P>
Je ne sais pas grand chose à ce sujet, mais il y a des instructions vectorielles qui peuvent appliquer des instructions à de nombreux octets à la fois. Vous pouvez utiliser ces résultats pour faire un memcmp rapide de flamboyant. Je ne sais pas quelles instructions dont vous auriez besoin, mais si vous recherchez des nouvelles instructions de Larrabee ou consultez cet article, vous pouvez trouver ce que vous recherchez http://www.dj.com/architect/216402188
Remarque: cette cpu n'est pas hors guibas ATM AFAIK P>
-edit- à l'heure actuelle, je suis positif il y a Une instruction ensembles (essayez d'examiner SSE ou SSE2) qui peut comparer 16 octets à la fois si elles sont alignées. p>
Vous pouvez essayer ce code pur c ++. P>
template<class T> int memoryCompare(const T* lhs, const T * rhs, size_t n) { const T* endLHS = lhs + n/sizeof(T); while(lhs<endLHS) { int i = *lhs - *rhs; if(i != 0) return i > 0 ? 1 : -1; lhs++; rhs++; } //more code for the remaining bytes or call memoryCompare<char>(lhs, rhs, n%sizeof(T)); return 0; }
Cela pourrait vous aider si votre Drérerence LHS et RHS :-)
Eh bien, beaucoup dépend de votre système et de votre donnée. Il n'y a que tant d'hypothèses que nous pouvons faire. Quel processeur utilisez-vous? Doit-il être le code C droit? Quelle est la largeur des registres de la CPU? Quelle est la structure de cache de la CPU? etc etc
Cela dépend également de la différence de vos données. S'il est très peu probable que le premier octet de chaque tampon soit identique, la vitesse de la fonction est assez significative que, logiquement, elle n'atteindra pas le reste de la fonction. S'il est probable que les premiers octets N-1 sont généralement les PME, il devient alors plus important. P>
Tout ce que vous êtes peu susceptible de voir beaucoup de changement, peu importe la façon dont vous faites le test. P> < P> Quoi qu'il en soit, il s'agit d'une petite mise en œuvre de la mienne, elle peut, ou n'est peut-être pas plus rapide que la vôtre (ou, étant donné que je viens de le faire comme je me suis allé, elle peut, ou ne peut pas, travailler;)): p>
La réponse à Cette question vous aidez-vous du tout? p>
Si le compilateur prend en charge la mise en œuvre de MEMCMP () en tant que fonction intrinsèque / intégrée, il semble que vous auriez du mal à le dépasser. P>
Je dois admettre que je connaisse peu à rien sur D, alors je ne sais pas si le compilateur D a le soutien de l'intrinsique. P>
L'OP a déjà déterminé que son alternative est plus rapide que MEMCMP et a demandé d'autres améliorations. Si son compilateur utiliserait un intrinsèque, cela ne serait probablement pas le cas.
Si vous faites confiance à l'optimisation de votre compilateur, vous pouvez essayer quelques modifications à la suggestion Acidzombie24S:
Loop: incl %eax ; %eax is lhs incl %edx ; %edx is rhs cmpl %eax, %ebx ; %ebx is endLHS jbe ReturnEq movb (%edx), %cl cmpb %cl, (%eax) jg ReturnGT jge Loop ReturnLT: ...
Peut-être: Faydoc.tripod.com/cpu/scasb.htm (x86)
Si vous voulez aller vraiment de bas niveau, vous pouvez essayer l'assemblage en ligne avec REP CMPSB, REP CMPSD ou même les comparaisons SSE.
RE "CMCMP de C est réellement assez lent car il essaie de préserver la sémantique de comparaison de chaînes utile". Vous avez bien sûr discuté d'une implémentation particulière, mais en général sur les processeurs modernes
MEMCMP code> est lié par la vitesse par laquelle vous pouvez accéder à la mémoire. Aucun algorithme ne peut faire mieux que cela, Protables i>.
Que voulez-vous dire, "CMCMP de C est réellement assez lent car il essaie de préserver une sémantique de comparaison de chaînes utiles"? Cela ressemble plus à
strncmp () code> que
memcmp () code>. Veuillez afficher des points de repère montrant que votre version (qui ne compilera pas car ce n'est même pas c) est plus rapide qu'un MEMCMP (CODE> MEMCMP () de la bibliothèque de la norme C moderne C () code>.
Je l'ai chargé de "D". Le code est tout d, donc je ne sais pas pourquoi il est marqué "C". N'hésitez pas à le changer si ce n'était pas une faute de frappe, bien sûr, mais cela garderait probablement des lecteurs déroutants et penserait que votre code est en erreur.
Wow, quelqu'un est parti sur un bowvote-tout le monde.
OP Je me demande ce que vous pensez de ma réponse / de ma réponse.
Il utilise D pour l'exemple, mais la question concerne une fonction de bibliothèque C et sur la manière de l'améliorer.
D semble assez translittéral à C. Le code présenté n'est pas portable; Il présume un ordre d'octet et aucune exigence d'alignement ni préférence, qui crie à peu près x86 / x86-64. Quel est le LSB-d'abord pour INTS, la comparaison (uint i>) renvoie la mauvaise valeur du panneau. Par conséquent, peut-être le commentaire "sémantique" :-)
Tous mes points de repère (allant à travers Xeon, Core2 et Divers Amd64) donnent à chaque variante de République CMPS A ThumbsDown. Pitié, parce que GCC 4.4 -O3 génère un représentant en ligne CMPSB pour MEMCMP par défaut (même sans filtrine-tout-stringops. Il est en quelque sorte déprimant qu'ils ont ajouté SSE4.2 PCMpetri au lieu de consacrer un peu d'espace de copeaux pour améliorer la CMPS / MOVS / SCAS. J'ai essayé divers ASM de la vieille école pour faire une meilleure memcmp; rien qui fonctionne bien dans tous les cas. SSE2 est en fait le meilleur, et si vous travaillez x86 de toute façon, SSE2 est sur chaque puce compatible Intel depuis 2005.
En outre, vous n'avez pas besoin d'utiliser ASM pour programmer SSE. Découvrez
Pour des exemples, traiter avec des octets (et des bits), vous pouvez consulter MISCHASAN.WordPress.com/2011/06/22/... et autres articles. Je reproduisais le code source ici, sauf, comme vous pouvez le constater, je passe un peu une lutte avec le formatage de texte ici (damyouenterkey).