C++Guns – RoboBlog

27.03.2012

Faster Code - Part 3 - align memory

Filed under: Allgemein — Tags: , , , — Thomas @ 18:03

Variablen deren Adressen ein vielfaches von 4Byte (oder 8Byte auf 64Bit???) sind, können schneller aus dem RAM geladen werden. Man sollte also bei oft benutzen Variablen darauf achten und nicht nur blind der Compiler Optimierung vertrauen. Gerade bei Sachen wie SSE ist es gut, wenn die Array Elemente auf 16Byte ausgerichtet sind, da ein SSE Register 128Bit breit ist.

Der GNU Compiler hat ein spezielles Attribut für Variablen [1].

Hier die Funktion die anzeigt, auf wieviel Byte eine Variable ausgerichtet ist:


void multipleOf(void* p) {
  cout << (size_t)p << " multiple of";
  if((size_t)p % 2 == 0)
    cout << " 2 ";
  if((size_t)p % 4 == 0)
    cout << " 4 ";
  if((size_t)p % 8 == 0)
    cout << " 8 ";
  if((size_t)p % 16 == 0)
    cout << " 16 ";
  if((size_t)p % 32 == 0)
    cout << " 32 ";
  cout << endl;
}

Und hier ein paar Beispiele.


  char unalign;
  char __attribute__ ((aligned (4))) align;
  multipleOf(&unalign);
  multipleOf(&align);

140736773522255 multiple of
140736773522252 multiple of 2  4 

Die erste Zahl ist immer die Adresse der Variable in Dezimal, damit man besser Kopfrechnen kann. Wie man sieht hat die Variable unalign eine ungerade Adresse -> nicht gut. Aber mit dem aligned Attribut kann man das schnell ändern :).

Soweit ich weiß haben int, long, float, double u.s.w. immer mindestens ein align von 4.

Aber wie sieht das mit den Adressen einzelner Arrayelemente aus?


  struct  Point {
  float x, y, z;
  };

  cout << "sizeof Point " << sizeof(Point) << endl;
  Point p[4];
  multipleOf(p);
  multipleOf(p+1);
  multipleOf(p+2);
  multipleOf(p+3);

sizeof Point 12
140733340474464 multiple of 2  4  8  16  32 
140733340474476 multiple of 2  4 
140733340474488 multiple of 2  4  8 
140733340474500 multiple of 2  4 

Das nächste Array Element ist immer 12Byte weiter. So ist die Sache zwar noch auf 4Byte ausgerichtet, aber nicht auf 16Byte wie das für SSE schön wäre. Hier die Lösung:


  struct  __attribute__ ((aligned (32))) Point {
  float x, y, z;
  };

sizeof Point 16
140736307878992 multiple of 2  4  8  16 
140736307879008 multiple of 2  4  8  16  32 
140736307879024 multiple of 2  4  8  16 
140736307879040 multiple of 2  4  8  16  32 

In diesem Fall hätte man auch einfach eine vierte Variable "w" in das Strukt einfügen können. Aber ich denke die Ausrichtung in Bytes manuell angeben ist besser. Es steht nämlich niergends geschrieben, dass ein float auch 4Byte hat. Zum Beispiel hat ein int auf einer 64Bit Maschine unter Linux noch 32Bit aber unter Windows 64Bit. Das gibt böse Fehler.

[1] http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html

No Comments »

No comments yet.

RSS feed for comments on this post.

Leave a comment

You must be logged in to post a comment.

Powered by WordPress