7
votes

Quel est le moyen le plus efficace de comparer deux blocs de mémoire dans la langue D?

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 MEMCMP 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? xxx

édition: j'ai lu sur SSE et je ne sais pas Voulez-vous l'utiliser pour 3 raisons:

  1. Ce n'est pas portable.
  2. Cela nécessite une programmation dans l'ASM.
  3. Les instructions de comparaison supposent que vos données sont des points flottants, ce qui peut être problématique si certaines données correspondent au modèle pour une NAAN.

12 commentaires

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 est lié par la vitesse par laquelle vous pouvez accéder à la mémoire. Aucun algorithme ne peut faire mieux que cela, Protables .


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 () que memcmp () . 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 () .


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 ) 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).


6 Réponses :


3
votes

Vous pouvez essayer:

  • Vérifiez si UINT est le type le plus important qui convient à votre processeur cible (Ulongs pourrait mieux adapter un registre indigène mieux)
  • Utilisez 2 pointeurs de ce type
  • Utilisez 2 variables locales à l'aide de * p ++ (ne drégérez pas les pointeurs 2 fois pour 1 valeur)
  • dévier le comptoir de la 1ère boucle à l'avant (utilisation tandis que (compteur -))
  • dérouler la 2ème boucle en le remplaçant par un commutateur (si la taille de la taille de (type qui s'inscrit dans un registre) est connu et sera toujours identique.)

    edit : 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: xxx

    bien sûr que laisse (n / uint.sizeof )% 4 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 .


3 commentaires

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.



1
votes

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.


0 commentaires

2
votes

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;
}


1 commentaires

Cela pourrait vous aider si votre Drérerence LHS et RHS :-)



1
votes

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.

Tout ce que vous êtes peu susceptible de voir beaucoup de changement, peu importe la façon dont vous faites le test. < 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;)): xxx


0 commentaires

1
votes

La réponse à Cette question vous aidez-vous du tout?

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.

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.


1 commentaires

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.



1
votes

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:
        ...


0 commentaires