Question

Je souhaite copier une séquence relativement courte de la mémoire (moins de 1 Ko, typiquement 2-200 octets) dans un temps fonction critique. Le meilleur code de ce côté CPU semble être rep movsd. Cependant, je ne peux pas faire en quelque sorte mon compilateur pour générer ce code. J'espérais (et je me souviens vaguement avoir vu si) à l'aide memcpy ferait ce compilateur à l'aide intégrés intrinsics, mais d'après le démontage et le débogage il semble compilateur utilise appel à memcpy / implémentation de la bibliothèque memmove à la place. J'espérais aussi le compilateur pourrait être assez intelligent pour reconnaître la boucle suivante et utiliser rep movsd lui-même, mais il semble qu'elle ne fonctionne pas.

char *dst;
const char *src;
// ...
for (int r=size; --r>=0; ) *dst++ = *src++;

Y at-il un moyen de faire le compilateur Visual Studio pour générer séquence rep movsd autre que l'utilisation de l'assemblage en ligne?

Était-ce utile?

La solution 3

Utilisation memcpy avec une taille constante

Ce que j'ai trouvé quant à lui:

compilateur utilisera intrinsèque lorsque la taille du bloc copié est temps de compilation connu. Quand il n'est pas, est la demande de mise en œuvre de la bibliothèque. Lorsque la taille est connue, le code généré est très agréable, sélectionné en fonction de la taille. Il peut être un mov unique ou movsd ou movsd suivi par movsb, au besoin.

Il semble que si je veux vraiment utiliser movsb ou movsd toujours, même avec une taille « dynamique » Je vais devoir utiliser l'assembleur en ligne ou intrinsèque spéciale (voir ci-dessous). Je sais que la taille est « assez court », mais le compilateur ne le sait pas et je ne peux pas communiquer à - j'ai même essayé d'utiliser __assume (taille <16), mais il ne suffit pas

.

Code de démonstration, compilation avec « -Ob1 (extension pour ligne uniquement):

  #include <memory.h>

  void MemCpyTest(void *tgt, const void *src, size_t size)
  {
    memcpy(tgt,src,size);
  }

  template <int size>
  void MemCpyTestT(void *tgt, const void *src)
  {
    memcpy(tgt,src,size);
  }

  int main ( int argc, char **argv )
  {
    int src;
    int dst;
    MemCpyTest(&dst,&src,sizeof(dst));
    MemCpyTestT<sizeof(dst)>(&dst,&src);
    return 0;
  }

intrinsics spécialisés

J'ai trouvé récemment il existe de manière très simple comment faire des caractères de copie du compilateur Visual Studio en utilisant movsd - très simples et naturels: l'utilisation intrinsics. A la suite intrinsics peut être pratique:

Autres conseils

Plusieurs questions viennent à l'esprit.

Tout d'abord, comment savez-vous movsd serait plus rapide? Avez-vous regardé son temps de latence / débit? L'architecture x86 est plein d'instructions crufty anciens qui ne devraient pas être utilisés parce qu'ils sont tout simplement pas très efficace sur CPU moderne.

En second lieu, ce qui se passe si vous utilisez std::copy au lieu de memcpy? std::copy est potentiellement plus rapide, car il peut être spécialisé à la compilation pour le type de données spécifiques.

Et troisièmement, avez-vous activé les fonctions intrinsèques dans les propriétés du projet -> C / C ++ -> Optimisation

Bien sûr, je suppose que d'autres optimisations sont activées aussi bien.

Vous exécutez une version optimisée? Il ne sera pas utiliser une intrinsèque à moins optimisation est activée. Il est également intéressant de noter qu'il utilisera probablement une meilleure boucle de copie que représentant movsd. Il faut essayer d'utiliser MMX, au moins, pour effectuer une 64 bits à une copie de temps. En fait revenir 6 ou 7 ans, j'ai écrit une boucle de copie optimisée MMX pour faire ce genre de chose. Malheureusement memcpy intrinsèque du compilateur a surclassé ma copie MMX d'environ 1%. Cela m'a vraiment appris à ne pas faire des hypothèses sur ce que le compilateur fait.

Avez-vous chronométré memcpy? Sur les versions récentes de Visual Studio, la mise en œuvre memcpy utilise SSE2 ... qui devrait être plus rapide que rep movsd. Si le bloc que vous copiez est 1 Ko, alors il est pas vraiment un problème que le compilateur n'utilise un intrinsèque depuis le temps de l'appel de fonction sera négligeable par rapport au temps de la copie.

Notez que pour pouvoir utiliser movsd, src doit pointer vers une mémoire alignée sur la limite de 32 bits et sa longueur doit être un multiple de 4 octets.

Dans ce cas, pourquoi votre utilisez le code char * au lieu de int * ou quelque chose? Si ce n'est pas, votre question est sans objet.

Si vous changez char * à int *, vous peut obtenir un meilleur résultat de std::copy.

Modifier: avez-vous mesuré que la copie est le goulot d'étranglement

Utilisez memcpy. Ce problème a déjà été résolu.

Pour votre information, représentant movsd est pas toujours le meilleur, représentant movsb peut être plus rapide dans certaines circonstances et avec ESS et comme le meilleur est [edi] movntq, xmm0. Vous pouvez même optimiser pour une grande quantité de mémoire à l'aide de la localité de la page en déplaçant les données dans une mémoire tampon, puis le déplacer vers votre destination.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top