Frage

Ich möchte eine relativ kurze Speichersequenz (weniger als 1 KB, normalerweise 2-200 Bytes) in einer zeitkritischen Funktion kopieren.Der beste Code dafür scheint auf der CPU-Seite zu sein rep movsd.Allerdings kann ich meinen Compiler irgendwie nicht dazu bringen, diesen Code zu generieren.Ich hatte gehofft (und ich erinnere mich vage daran, es gesehen zu haben), dass die Verwendung von memcpy dies mithilfe der in den Compiler integrierten Funktionen erreichen würde, aber basierend auf der Disassemblierung und dem Debuggen scheint es, dass der Compiler stattdessen den Aufruf der Memcpy/Memmove-Bibliotheksimplementierung verwendet.Ich hoffte auch, dass der Compiler intelligent genug sein würde, um die folgende Schleife zu erkennen und zu verwenden rep movsd von alleine, aber es scheint, dass dies nicht der Fall ist.

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

Gibt es eine Möglichkeit, den Visual Studio-Compiler zum Generieren zu bringen? rep movsd Reihenfolge anders als die Verwendung von Inline-Assembly?

War es hilfreich?

Lösung 3

Verwendung von memcpy mit konstanter Größe

Was ich mittlerweile gefunden habe:

Der Compiler verwendet intrinsisch, wenn die Größe des kopierten Blocks zur Kompilierzeit bekannt ist.Ist dies nicht der Fall, wird die Bibliotheksimplementierung aufgerufen.Wenn die Größe bekannt ist, ist der generierte Code sehr schön und wird basierend auf der Größe ausgewählt.Bei Bedarf kann es sich um eine einzelne mov oder movsd oder movsd gefolgt von movsb handeln.

Es scheint, dass ich, wenn ich movsb oder movsd wirklich immer verwenden möchte, auch bei einer „dynamischen“ Größe Inline-Assembly oder spezielle intrinsische verwenden muss (siehe unten).Ich weiß, dass die Größe „ziemlich kurz“ ist, aber der Compiler weiß es nicht und ich kann ihm das nicht mitteilen – ich habe sogar versucht, __assume(size<16) zu verwenden, aber das reicht nicht aus.

Democode, kompilieren mit „-Ob1 (Erweiterung nur für Inline):

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

Spezialisierte Intrinsiken

Ich habe kürzlich herausgefunden, dass es eine sehr einfache Möglichkeit gibt, den Visual Studio-Compiler dazu zu bringen, Zeichen mithilfe von movsd zu kopieren – sehr natürlich und einfach:Verwendung von Eigenheiten.Folgende Besonderheiten können nützlich sein:

Andere Tipps

Einige Fragen in den Sinn kommen.

Erstens, wie Sie wissen, movsd würde schneller sein? Haben Sie sich seine Latenz / Durchsatz von bis? Die x86-Architektur ist voll von crufty alten Anweisungen, die nicht verwendet werden sollten, weil sie auf modernen CPUs einfach nicht sehr effizient sind.

Zweitens, was passiert, wenn man std::copy statt memcpy verwenden? std::copy ist möglicherweise schneller, da sie zum Zeitpunkt der Kompilierung für den spezifischen Datentyp spezialisiert werden können.

Und drittens haben Sie intrinsische Funktionen unter Projekteigenschaften aktiviert -> C / C ++ -> Optimierung

Natürlich nehme ich andere Optimierungen als auch aktiviert sind.

Sind Sie mit einer optimierten Build? Es wird nicht eine intrinsische verwenden, es sei denn Optimierung eingeschaltet ist. Es ist auch erwähnenswert, dass es wahrscheinlich eine bessere Kopie Schleife als rep movsd verwenden. Es sollte versuchen und verwendet MMX, zumindest, ein 64-Bit zu einem Zeitpunkt Kopie auszuführen. In der Tat 6 oder 7 Jahre schrieb ich eine MMX optimierte Kopie Schleife diese Art der Sache zu tun. Leider übertraf den Compiler intrinsische Memcpy meiner MMX Kopie von etwa 1%. Das ist wirklich hat mich gelehrt, nicht Annahmen zu machen über das, was der Compiler tut.

Haben Sie Memcpy abgelaufen? Auf neuere Versionen von Visual Studio, die Memcpy Implementierung verwendet SSE2 ..., die schneller als rep movsd sein sollte. Wenn der Block sind Kopieren Sie 1 KB ist, dann ist es nicht wirklich ein Problem, dass der Compiler eines intrinsische seit der Zeit für den Funktionsaufruf verwendet wird für die Kopie im Vergleich zu der Zeit vernachlässigbar sein.

Beachten Sie, dass, um movsd zu verwenden, src auf einen Speicher auf 32-Bit-Grenze ausgerichtet zeigen muss und seine Länge muß ein Vielfaches von 4 Byte sein.

Wenn ja, warum hat Ihr Code Verwendung char * statt int * oder so etwas? Wenn es nicht, Ihre Frage ist strittig.

Wenn Sie char * int * ändern Sie Macht erhalten besseres Ergebnis aus std::copy.

Edit: haben Sie gemessen, dass das Kopieren der Engpass

Verwenden Sie memcpy.Dieses Problem wurde bereits gelöst.

Zu Ihrer Information: rep movsd ist nicht immer das Beste, rep movsb kann unter bestimmten Umständen schneller sein und mit SSE und dergleichen ist movntq [edi], xmm0 das Beste.Sie können die Seitenlokalität sogar noch weiter optimieren, um eine große Speichermenge zu erzielen, indem Sie Daten in einen Puffer verschieben und sie dann an Ihr Ziel verschieben.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top