2016-03-23 8 views
2

Ich baue eine Simulation des Ising-Modells in OpenCL, was bedeutet, dass meine Daten aus einer Reihe von Zuständen bestehen, die entweder oben/1 oder unten sein können/-1.OpenCL - Der effizienteste Weg, um Byte in einen 8-Komponenten-Vektor zu teilen

Um Speicherbandbreite zu sparen, werden 8 dieser Zustände in ein einzelnes Byte codiert (nach oben = 1, nach unten = 0). Nun benötige ich in einer der Berechnungen einen ganzzahligen Vektor mit Werten, die den ursprünglichen Zuständen entsprechen, d. H. 1 oder -1.

Beispiel:
Eingangsbyte (uchar in OpenCL): 01010011
Umrechnen in: (int8)(-1,1,-1,1,-1,-1,1,1);

Ich habe eine funktionierende Lösung für dieses Problem, aber ich frage mich, ob es ein schneller, effizienter übrigens:

uchar c = spins[id]; 
int8 spin; 
spin.s0 = (c >> 0) & 1; 
spin.s1 = (c >> 1) & 1; 
spin.s2 = (c >> 2) & 1; 
spin.s3 = (c >> 3) & 1; 
spin.s4 = (c >> 4) & 1; 
spin.s5 = (c >> 5) & 1; 
spin.s6 = (c >> 6) & 1; 
spin.s7 = (c >> 7) & 1; 
spin = spin * 2 - 1; 

EDIT:

scheinen nicht schneller in meiner Situation zu sein, aber es ist prägnanter bei leas t:

__constant uchar8 bits = (uchar8)(0,1,2,3,4,5,6,7); 

uchar c = spins[id]; 
int8 spin = convert_int8((uchar8)(c) >> bits & 1) * 2 - 1; 
+0

Das scheint schon eine ziemlich saubere Lösung, warum etwas komplizierter gehen? 'int8 spin = ((int8) (c) >> (int8) (0,1,2,3,4,5,6,7) & 1) * 2 - 1;' – DarkZeros

Antwort

1

bool8 ist immer noch ein reservierter Typ scheint es. Ich dachte, es wäre jetzt für Benutzer offen, ich liege falsch.

Option 1)

Nicht sicher noch (% 100 sicher auf alle Hardware) arbeiten, aber Sie können diese Vereinigung

  typedef union hardwareBool8{ 
       char v; 
       bool bit_select[8]; 
      } vecb8; 

dann in einem Kernel definieren:

  vecb8 t={5}; // initialize with any number from your uchar/char 
      t.v=1; // or initialize with this 
      t.bit_select[4]=0; // set or get to some integer 
      int intVariable =t.bit_select[7]; // can be 1 or 0 or -1,you should try. If not -1 then you can negate 
      int intVariable2=-t.bit_select[7]; 

Das kompiliert auf meiner AMD-Maschine, aber ich bin nicht sicher für andere Hardware. Sogar Endianess kann ein Problem sein.

Option 2)

Vielleicht gleichen char bis 8 Fäden Broadcasting (oder derselben Stelle von 8 threads) den Zugriff auf:

char charVar= ... load from same address/index ; 

dann auf unterschiedlichen Bit-Index für jeden Thread arbeitet:

...

spin.s7 = (c >> 7) & 1; (on thread 7) 

sollte es etwas Leistung aber für nur einzelnes Drehbeschleunigungselement geben. Viele aktuelle GPU-Architekturen unterstützen die Übertragung derselben Daten an alle Threads in einer einzigen Anweisung. Wenn Ihr Gerät eine CPU ist, sollten 8 Threads pro Arbeitsgruppe nicht viel langsamer werden, aber wenn es GPU ist, dann ist es schwierig, 1 Char pro 8 aufeinanderfolgende Threads auszuwählen. So etwas wie

charArrayIndex = globalThreadId/8 
    c = charArray[charArrayIndex]; 

    // assuming spin is local memory array and shared by work group threads 
    spin[globalThreadId % 8] = (c >> (globalThreadId % 8)) & 1; 

Wenn Spin private Variable sein muss, können Sie gleichen lokalen Speicher-Array als Kommunikations Array verwenden, um Werte an alle Threads' private Variablen zu kopieren. Dies geht von (Befehlsebene + Thread-Ebene) Parallelität zu nur Thread-Ebene-Parallelität.

Option 3)

Sie Bohrkronenauswahl verteilen können (alle von denen 8) an verschiedene „Einheiten“ eines Kerns, wenn Operationen in verschiedenen Einheiten durchgeführt werden, dann kann dies aus, um die Ausführung profitieren.

spin.s2 = (c/4) & 1; // 1 division and 1 logical 
spin.s0 = (c) & 1;  // 1 logical 
spin.s1 = (c & 2)>0; // 1 logical and 1 comparison 
+0

Vielen Dank! Ich bekomme den 3. allerdings nicht wirklich. – Gigo

+0

Es ist, als ob man ein Spin-Element auf teure, aber unabhängige Weise bekommt und während es die schwere Arbeit berechnet, werden andere Elemente unter Verwendung der Parallelität auf Befehlsebene berechnet. Auch das letzte Element braucht nicht "und" mit 1. Da es nur ein einzelnes Bit auf der rechten Seite gibt. Sie speichern auf diese Weise eine weitere Anweisung. –

+0

Ich glaube nicht, dass in diesem Fall eine Union funktioniert. Es kompiliert auf meinem Rechner (AMD auch), aber ergibt seltsame Ergebnisse. Ich denke nicht, dass die Adressierung der Bits eines Bytes auf diese Weise erfolgen kann, da Bools wahrscheinlich nicht nur ein Bit breit sind. – Gigo

Verwandte Themen