Fehler, Irrtümer, Fragen - Seite 2505

 

ein seit langem bestehender Fehler im Editor:

- Speichern Sie die Datei unter einem neuen Namen (zum Beispiel: name_v1.2)
- den Cursor auf eine Variable (oder einen Funktionsaufruf) setzen
- alt+g drücken

- wird eine alte Datei geöffnet und die Bearbeitung springt zu ihr (

 
Vict:

Im Allgemeinen habe ich nicht einmal das erwartet:

Der Code ist etwas zu kompliziert - ich habe versucht, das Element zu finden, das nicht in die Cache-Zeile passt, und direkt darauf zu hämmern, aber es ist fehlgeschlagen (ich hätte es wahrscheinlich schaffen können, wenn ich es wirklich gewollt hätte, aber mir wurde langweilig), und ich habe den Code nicht allzu sehr verändert. Aber auf diese Weise ist es noch beeindruckender - nur einer von 16 Zusammenbrüchen wird an einem Element durchgeführt, das nicht in die Cache-Zeile passt, trotzdem hat er ein spürbares Ergebnis.

SZY: In diesem Fall ist es objektiver, RIGHT_ALIGNED durch das Einfügen von zwei kurzen Zeilen und nicht durch das Entfernen einer einzelnen Zeile durchzuführen (so erreichen wir zwei Aktualisierungen der Cache-Zeile für beide Fälle). Der Geschwindigkeitszuwachs ist bescheidener, aber immer noch etwa 1,5-mal so groß.

Entschuldigung, aber wozu dient die Ausrichtung? Darum geht es in diesem Beispiel nicht.

П. С. Wenn Sie Ihren Code unkommentiert und in grober Form veröffentlichen, ist das respektlos gegenüber Ihren Freunden.

 

Richtig bemerkt, wurde eine Anpassung hinzugefügt, um MQL-Strukturobjekte in Bibliotheken von Drittanbietern zu verwenden, insbesondere in Dotnet.

Als die Dotnet-Bibliotheken zur Unterstützung von Dotnet hinzugefügt wurden, wurde den Feldern von Packstrukturen/Klassen die Ausrichtung hinzugefügt.

Um es kurz und einfach zu machen, funktioniert es folgendermaßen:

Für jeden Typ (char, short, int, ...) gibt es eine Standardausrichtung (1, 2 bzw. 4 Byte).
Für das Feld der Struktur wird das Minimum von zwei Ausrichtungen gewählt: die Standardausrichtung und die vom Benutzer definierte (über pack)

Gleichzeitig wird die Größe des gepackten Objekts so eingestellt, dass die Adressierung des Objektfeldes im Array immer "richtig" ist (standardmäßig wird beim Packen ein Byte eingestellt).
Durch letzteres wird der falsche Eindruck erweckt, dass das Pack die Größe der Struktur anpasst; das stimmt nicht, die Feldadressen werden angeglichen, was eine Anpassung der Größe der Struktur zur Folge hat.



Zum Beispiel

struct A pack(8)
  {
   double d;
   char   c;
  };

void OnStart()
  {
   Print(sizeof(A));
   
  }

Ergebnis 16, so dass die Adressierung an das erste Feld d immer um 8 Bytes ausgerichtet ist

 
fxsaber:

Bei meinen eigenen Fahrten habe ich keinen merklichen Unterschied festgestellt.

Ich habe die ursprüngliche Idee verbessert (im ersten Code habe ich die Adressen nicht richtig gezählt). Wenn es Ihnen nichts ausmacht, wäre es interessant, das Ergebnis mit Ihnen zu sehen.

#define  WRONG_ALIGNED
#define  CACHE_LINE_SIZE 64

struct Data {
#ifdef  WRONG_ALIGNED
   ushort pad;
#else
   uint pad;
#endif
   uint ar[CACHE_LINE_SIZE/sizeof(int)+1];
};

#import "msvcrt.dll"
  long memcpy(uint &, uint &, long);
#import
#define  getaddr(x) memcpy(x, x, 0)

void OnStart()
{
   Data data[32768];
   ZeroMemory(data);
   
   srand(GetTickCount());
   
   ulong start_time = GetMicrosecondCount();
   
   for(unsigned i = 0; i < 10000; ++ i) {
      int rndnum = rand();
      while (++rndnum < 32768) {
         int index = int(CACHE_LINE_SIZE - getaddr(data[rndnum].ar[0]) % CACHE_LINE_SIZE) / sizeof(int);
         ++ data[rndnum].ar[index];
         ++ data[rndnum].pad;
      }
   }
      
   Alert(GetMicrosecondCount() - start_time);
   
   Print(data[100].ar[0]);
   Print(data[100].pad);
}
/*
WRONG_ALIGNED:
6206397
6185472

RIGHT_ALIGNED
4089827
4003213
*/
Im Wesentlichen die gleiche Sache passiert mit/ohne WRONG_ALIGNED - auf jeder, während wir in zwei benachbarte Cache-Zeilen schreiben (Schreiben von Pad immer an die richtige Adresse), der einzige Unterschied ist, dass mit WRONG_ALIGNED gibt es Fälle (nicht immer), wenn einer der Einträge in ar in uint, die nicht vollständig in die Cache-Zeile erhalten wird, ich habe einen stabilen Unterschied von etwa 1,5 mal.
 
Vict:

Ich habe die ursprüngliche Idee überarbeitet (der erste Code zählte die Adressen nicht richtig). Wenn Sie nichts dagegen haben, wird es interessant sein, das Ergebnis in Ihrem Fall zu sehen.

Im Grunde passiert das gleiche mit/ohne WRONG_ALIGNED - auf jeder, während wir in zwei benachbarte Cache-Zeilen schreiben (Pad-Eintrag immer auf die richtige Adresse), der einzige Unterschied ist, dass mit WRONG_ALIGNED gibt es Fälle (nicht immer), wenn einer der Einträge in ar in uint auftritt, die nicht die ganze Cache-Zeile treffen, ich habe einen stabilen Unterschied etwa 1,5 mal.

Erklären Sie bitte, was Sie mit diesem Satz bezwecken? Im vorigen Beispiel war es unsinniger Code.

int index = int(CACHE_LINE_SIZE - getaddr(data[rndnum].ar[0]) % CACHE_LINE_SIZE) / sizeof(int);
 
Francuz:

Erklären Sie bitte, was Sie mit diesem Satz bezwecken? Im vorigen Beispiel war es unsinniger Code.

Finde unsere Position in der aktuellen Cache-Zeile (die, in der sich das Pad befindet) und nimm einen solchen Index für ar[], dass das Element mit ihm in der nächsten Cache-Zeile ist (vielleicht ist das Element in zwei Cache-Zeilen mit WRONG_ALIGNED)

 
Vict:

Finden Sie unsere Position in der aktuellen Cache-Zeile (diejenige, in der pad ist) und nehmen Sie einen solchen Index für ar[], dass das Element mit ihm in der nächsten Cache-Zeile ist (vielleicht ist das Element in zwei Cache-Zeilen bei WRONG_ALIGNED)

Jetzt geht es um einen Ausgleich. Aber was Sie zeigen, ist ein rein synthetisches Beispiel, das im wirklichen Leben nie vorkommen wird. In realen Beispielen beträgt der Geschwindigkeitsgewinn bestenfalls 1 %. Sie sollten wegen einer so geringen Beschleunigung keine große Sache daraus machen.

П. С. Außerdem haben Sie die Registergröße falsch berechnet.
 
Francuz:

Jetzt geht es um Verdrängung. Aber was Sie zeigen, ist ein rein synthetisches Beispiel, das im wirklichen Leben nie vorkommen wird. In realen Beispielen liegt der Geschwindigkeitsgewinn bestenfalls bei 1 %. Sie sollten aus einer so geringen Beschleunigung keine große Sache machen.

Nein, das ist ein ganz reales Beispiel. Nur 25 % der Schreibvorgänge erfolgen dort an "problematischen" Stellen an der Schnittstelle von Cache-Zeilen. Wie viel ist das? Wenn Sie zum Beispiel ein langes Double-Array haben, fasst eine Cache-Zeile nur 4 Werte, und wenn Sie sich nicht um die Ausrichtung kümmern (und der Compiler dies nicht für Sie tut), dann haben Sie 25% problematische Double-Stellen - wie in meinem Beispiel. Es gibt noch viele weitere Nuancen, die für eine Angleichung sprechen, aber ich werde nicht auf sie eingehen - ich kenne mich auf diesem Gebiet nicht aus.

Nun, Herr des Hauses.

P.S. Außerdem haben Sie sich bei der Registergröße verrechnet.
Ich habe ihn gar nicht richtig gezählt ))
 
Vict:

Nein, dies ist ein durchaus realistisches Beispiel. Darin kommen nur 25 % der Einträge an "problematischen" Stellen an der Cache-Zeilen-Kreuzung vor. Ist das viel? Wenn Sie zum Beispiel ein langes Double-Array haben, eine Cache-Zeile nur 4 Werte enthält und Sie sich nicht um die Ausrichtung kümmern (und der Compiler es nicht für Sie tut), dann erhalten Sie 25% des problematischen Double - wie in meinem Beispiel. Es gibt noch viele weitere Nuancen, die für eine Angleichung sprechen, aber ich werde nicht auf sie eingehen - ich kenne mich mit dem Thema nicht gut genug aus.

Nun, Sie sind der Chef.

Ich möchte noch einmal darauf hinweisen, dass Sie durch die Registergröße verwirrt sind.

 
Francuz:

Wieder einmal verwechseln Sie die Größe des Registers.

Begründen Sie