Aparapi

keram

Aktives Mitglied
Hey Leute :)
Ich habe mich die letzten Tage ein bisschen mit Aparapi auseinander gesetzt und bemerkt das durch den Aufbau eine GPU Daten viel schneller berechnet werden können als mit einer CPU.

Ich benutze Aparapi da ich eine AMD GPU habe :)

Der Link zur Aparapi ist: http://developer.amd.com/tools-and-sdks/opencl-zone/aparapi/

Da ich selber noch keine Erfahrung mit Opencl und Aparapi habe, wollte ich euch einmal um einen Rat fragen.

Nehmen wir mal an ich habe folgende Methode:

Java:
void Test() {
   int i = Integer.MAX_VALUE;
   int i2 = 0;
  
   while( i != i2 ) {
     i2++;
   }
}

Diese möchte ich nur über Aparapi auf meine GPU bringen um mehr Leistung zu erzielen, die Methode ist nur symbolisch und hat keinen tieferen Sinn.

Soweit ich es gelesen habe ist die Ausführung ähnlich wie ein Runnable, würde also in etwa so aussehen:

Java:
    Kernel kernel = new Kernel(){
        @Override public void run(){
            //Do something
        }
    };

Ist es möglich eine Klasse zu erzeugen die Kernel implementiert und somit einen Kunstruktor ermöglicht?

In wie weit muss ich meinen Code anpassen um ihn in meine GPU zum laufen zu bringen?

Was muss ich beachten um möglichst hohe Leistung zu erzielen?

Ich bedanke mich schonmal für euren support :)
 

InfectedBytes

Top Contributor
Ist es möglich eine Klasse zu erzeugen die Kernel implementiert und somit einen Kunstruktor ermöglicht?

In wie weit muss ich meinen Code anpassen um ihn in meine GPU zum laufen zu bringen?

Was muss ich beachten um möglichst hohe Leistung zu erzielen?

Ich bedanke mich schonmal für euren support :)

Natürlich geht das. Der folgende Code macht nichts anderes als eine anonyme innere klasse zu erzeugen, welche von Kernel erbt:
Java:
Kernel kernel = new Kernel() {
...
};
Das ganze ist quasi äquivalent zu dem hier:
Java:
class MyKernel extends Kernel {
...
}
und irgendwoanders dann:
Java:
Kernel kernel = new MyKernel();

Wie weit du deinen Code anpassen musst, kommt halt auf deinen Code an. Das einfache Beispiel von oben könnte bereits ohne Änderung laufen.
 

keram

Aktives Mitglied
Erstmal danke für deine Antwort :)
Nun ist natürlich die Frage wie ich meinen Code optimieren kann. Mein Ziel ist es einen Hash immer wieder neu zu hashen und mit einem anderen Hash zu vergleichen...

Nun ist die Frage wie ich das ganze sinnvoll aufbauen kann, mein Code sieht bisher so aus:

Java:
    private void test() {
        String sTest = "41de6ab494c3ddfdc175b107bc205ab63377f5e706adfabee33640bc551d68ee";
        String sKey = "26ee73a1070a25b61cafee5756b0e085780dc9133f08aa9459e04d1a772b015c";
        MessageDigest md;
        StringBuilder sb = new StringBuilder();

        try {
            md = MessageDigest.getInstance("SHA-256");

            while( !sTest.equals(sKey) ) {
                md.update(sTest.getBytes());

                byte byteData[] = md.digest();

                sb.setLength( 0 );
                for (int i = 0; i < byteData.length; i++) {
                 sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
                }
            }
        }
        catch( NoSuchAlgorithmException ex ) {
            Logger.getLogger( Testingg.class.getName() ).log( Level.SEVERE, null, ex );
        }
    }

Wenn ich den Code normal ausführe laste ich die CPU mit gerade mal 15% aus.

Wie genau kann ich Aparapi nutzen um meine GPU 100% auszulasten? Theoretisch müsste ich doch für jeden Thread eine Aufgabe geben oder nicht?

Sollte ich eventuell eine Liste erzeugen und jedem Thread eine Teilliste zuweisen?
Oder gibt es andere Vorschläge wie ich den Code optimieren kann, bzw in am besten in Aparapi umsetzen kann?
 

InfectedBytes

Top Contributor
Ich habe aparapi noch nie verwendet, aber ich fürchte dass das nicht gehen wird. aparapi versucht im Grunde den Bytecode zu opencl zu übersetzen, das Problem ist nun, dass du alle möglichen "komplexeren" Objekte benutzt. Ich weiß es zwar nicht, aber ich vermute mal das aparapi mit deinem MessageDigest Objekt nichts anfangen kann. Außerdem wird das Logging ebenfalls nicht funktionieren

aparapi ist eher dazu gedacht eigene Berechnungen zu parallelisieren
 

keram

Aktives Mitglied
Dann könnte ich doch diesen Part:

Java:
                byte byteData[] = md.digest();

                sb.setLength( 0 );
                for (int i = 0; i < byteData.length; i++) {
                 sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
                }

an Aparapi weiter geben oder nicht?
 

InfectedBytes

Top Contributor
nein, da der StringBuilder (und allgemein Strings) keine primitiven Typen sind.
Und selbst wenn es gehen würde, würde es dir nicht helfen, da dass im Grunde der einfache Part ist. Der Part mit dem heftigen Rechenaufwand ist eben die Berechnung innerhalb von MessageDigest
 

keram

Aktives Mitglied
hmmm okay dann liegt die Vermutung doch nahe das mein Programm nur so langsam läuft und so wenig CPU nutzt da MD so viele CPU-Loops braucht, oder?
 

InfectedBytes

Top Contributor
ja MD ist der Teil des Programmes der den meisten Aufwand hat. Du kannst natürlich dennoch aparapi nutzen, allerdings wird aparapi dein Programm nicht auf der GPU ausführen, sondern mit ThreadPools. Das würde sich natürlich dennoch lohnen, da dein Programm bisher in nur einem Thread läuft und durch aparapi würde es dann in mehreren laufen
 

keram

Aktives Mitglied
Würde ich dann nicht einen anderen Aufbau der Methoden benötigen? Weil ich ja nur eine while Schleife habe die ich abarbeite und somit eine linearen Ablauf habe?
 

InfectedBytes

Top Contributor
das ist richtig, allerdings bin ich mir nicht sicher was du in der Schleife versuchst.
Java:
while( !sTest.equals(sKey) ) {
    md.update(sTest.getBytes());

    byte byteData[] = md.digest();

    sb.setLength( 0 );
    for (int i = 0; i < byteData.length; i++) {
    sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
    }
}
Du lässt die Schleife solange laufen, wie sTest ungleich sKey ist. Aber weder sTest noch sKey wird in der Schleife verändert. Daher ist eigentlich die ganze Schleife unnötig.
 

keram

Aktives Mitglied
So sollte die Methode richtig aussehen:

Java:
while( !sTest.equals(sKey) ) {
    md.update(sTest.getBytes());

    byte byteData[] = md.digest();

    sb.setLength( 0 );
    for (int i = 0; i < byteData.length; i++) {
    sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
    }
    sTest = sb.toString();
}

Wo kann ich den am besten setzen? Das Problem ist das ich in dieser Schleife bleiben muss da ich den Hash immer wieder rehashen muss :/
 

keram

Aktives Mitglied
Sprich wie gehe ich es am besten an?
Hatte bis jetzt nur die Idee eine Liste mit Hashes zu erstellen und diese dann in Threads auf zu teilen um diese auf Richtigkeit zu prüfen, vermute mal dass das nicht der richtige weg ist...
 

InfectedBytes

Top Contributor
Wenn du wirklich den hash immer wieder rehashen musst, dann kannst du es wie gesagt gar nicht Parallel bearbeiten. Denn um durchlauf i berechnen zu können, muss bereits Durchlauf i-1 abgeschlossen sein und da sich das bis zum ersten Durchlauf fortsetzt, muss es zwingend nacheinander durchgeführt werden
 

keram

Aktives Mitglied
Alles klar, gibt es sonst noch Möglichkeiten den Code schneller laufen zu lassen? Siehst du noch ein paar Optimierungen?
 

InfectedBytes

Top Contributor
den stringbuilder wegwerfen und stattdessen direkt mit byte arrays arbeiten. Der MD erwartet sowieso immer byte arrays, warum also immer wieder neue strings und stringbuilder erstellen, wenn du sowieso nur am array interessiert bist.
 

keram

Aktives Mitglied
Danke für deinen Tipp :)
Habe das ganze nun mal umgebaut und nur zum testen mir mal die Hashes ausgegeben, dabei ist mir aufgefallen das nur der erste Hash richtig ist, die restlichen liefern falsche Ergebnisse...

Java:
        barrTest = ("063cdd37df761618406e728498eac5c8359e1ca79bc893306cae92cf3071a8e0").getBytes();
        for( int i = 0; i<100000; i++ ) {
            md.update(barrTest);
            barrTest = md.digest();
            sl.add(barrTest);
          
            sb.setLength( 0 );
            for (int ii = 0; ii < barrTest.length; ii++) {
                sb.append(Integer.toString((barrTest[ii] & 0xff) + 0x100, 16).substring(1));
            }

            System.out.println(sb.toString());
        }
 

InfectedBytes

Top Contributor
wie kommst du denn auf das hier:
Java:
sb.append(Integer.toString((barrTest[ii]& 0xff)+ 0x100, 16).substring(1));

Wenn du den hash einfach direkt rehashen willst, dann nimm doch einfach die bytes die dir md.digest() gegeben hat. Kein Grund da kompliziert drumherum zurechnen
 

keram

Aktives Mitglied
Sollte eventuell noch erwähnen das es sich um Sha256 handelt ^^

@InfectedByte
Dort lasse ich mich den Hash als String ausgeben, bzw berechne den Char aus dem Byte :)
 

InfectedBytes

Top Contributor
dann willst du wohl eher dies machen:
Java:
sb.append(Integer.toString(barrTest[ii]& 0xff, 16));

edit:
wobei, eigentlich sollte der hash von dir bereits passen
kannst ja mal testweise ein paar durchläufe mit http://hashgenerator.de/ vergleichen
 

keram

Aktives Mitglied
Eigentlich schon, habe die selbe Seite getestet, mir seinem StringBuilder bekomme ich ebenfalls falsche Werte, wobei bei dieser Methode dann auch der erste Wert falsch ist.

Das sind die ersten 5 Hashes die ich mit meiner Methode erstelle, komischerweise ist der erste richtig, der rest jedoch nicht o_O

41009448664ff99857a8e5db647ba9a188cfb912d944deb649a927f6ce9dffbc
9e44e6b65abf82fc8b5c0c8d8589dd09edc59a10cef07b8d2c93c5a07ac2ec31
2298ef0b4f9290e0eaa60b53b620aa9fb8ddfbe6b36e0d8291f16707f7a61340
365b6a5c4066c58245f69c8fc5215883fc7d66b4d203976a849aab11df48f713
2b89e72317f2429690e61068b4d487a8ad218bba5b931c446d78cf7f075cebcf
 

Neue Themen


Oben