Boost.Compute oder GPU / CPU Parallel Computing. Teil 1

Einführung



Hallo Habr!



Nach meinen Maßstäben habe ich schon ziemlich lange C ++ - Code geschrieben, aber bis zu diesem Zeitpunkt hatte ich noch keine Aufgaben im Zusammenhang mit parallelem Rechnen. Ich habe keinen einzigen Artikel über die Boost.Compute-Bibliothek gesehen, daher wird dieser Artikel darüber handeln.

Alle Teile





Inhalt



  • Was ist boost.compute?
  • Probleme beim Verbinden von boost.compute mit dem Projekt
  • Einführung in boost.compute
  • Grundlegende Rechenklassen
  • Anfangen
  • Fazit


Was ist boost.compute?



Diese C ++ - Bibliothek bietet eine einfache Schnittstelle auf hoher Ebene für die Interaktion mit Multi-Core-CPU- und GPU-Computergeräten. Diese Bibliothek wurde erstmals in Version 1.61.0 hinzugefügt und wird weiterhin unterstützt.



Probleme beim Verbinden von boost.compute mit dem Projekt



Daher bin ich bei der Verwendung dieser Bibliothek auf einige Probleme gestoßen. Eine davon war, dass die Bibliothek ohne OpenCL einfach nicht funktioniert. Der Compiler gibt folgenden Fehler aus:



Bild



Nach dem Verbinden sollte alles korrekt kompiliert werden.



Auf Kosten der Boost-Bibliothek kann sie mit dem NuGet-Paketmanager heruntergeladen und mit einem Visual Studio-Projekt verbunden werden.



Einführung in boost.compute



Nachdem Sie alle erforderlichen Komponenten installiert haben, können Sie sich einfache Codeteile ansehen. Für einen korrekten Betrieb reicht es aus, das Rechenmodul folgendermaßen zu aktivieren:



#include <boost/compute.hpp>
using namespace boost;


Es ist anzumerken, dass reguläre stl-Container nicht für die Verwendung in Compute-Namespace-Algorithmen geeignet sind. Stattdessen gibt es speziell erstellte Container, die nicht mit den Standardcontainern in Konflikt stehen. Beispielcode:



std::vector<float> std_vector(10);
compute::vector<float> compute_vector(std_vector.begin(), std_vector.end(), queue); 
//       ,     .


Die Funktion copy () kann verwendet werden, um zurück in std :: vector zu konvertieren:



compute::copy(compute_vector.begin(), compute_vector.end(), std_vector.begin(), queue);


Grundlegende Rechenklassen



Die Bibliothek enthält drei Hilfsklassen, die ausreichen, um mit Berechnungen auf einer Grafikkarte und / oder einem Prozessor zu beginnen:



  • compute :: device (bestimmt, mit welchem ​​Gerät wir arbeiten)
  • compute :: context (ein Objekt dieser Klasse speichert OpenCL-Ressourcen, einschließlich Speicherpuffer und anderer Objekte)
  • compute :: command_queue (bietet eine Schnittstelle für die Interaktion mit einem Computergerät)


Das Ganze kann so erklärt werden:



auto device = compute::system::default_device(); //     
auto context = compute::context::context(device); //   
auto queue = compute::command_queue(context, device); //   


Selbst wenn Sie nur die erste Codezeile oben verwenden, können Sie sicherstellen, dass alles ordnungsgemäß funktioniert, indem Sie den folgenden Code ausführen:



std::cout << device.name() << std::endl; 


So haben wir den Namen des Geräts erhalten, auf dem wir Berechnungen durchführen werden. Ergebnis (möglicherweise haben Sie etwas anderes):



Bild



Anfangen



Schauen wir uns die Funktionen trasform () und redu () anhand eines Beispiels an:



std::vector<float> host_vec = {1, 4, 9};

compute::vector<float> com_vec(host_vec.begin(), host_vec.end(), queue);
//           
//  copy()

compute::vector<float> buff_result(host_vec.size(), context);
transform(com_vec.begin(), com_vec.end(), buff_result.begin(), compute::sqrt<float>(), queue);

std::vector<float> transform_result(host_vec.size());
compute::copy(buff_result.begin(), buff_result.end(), transform_result.begin(), queue);
	
cout << "Transforming result: ";
for (size_t i = 0; i < transform_result.size(); i++)
{
	cout << transform_result[i] << " ";
}
cout << endl;

float reduce_result;
compute::reduce(com_vec.begin(), com_vec.end(), &reduce_result, compute::plus<float>(),queue);

cout << "Reducing result: " << reduce_result << endl;


Wenn Sie den obigen Code ausführen, sollten Sie das folgende Ergebnis sehen:



Bild



Ich habe mich für diese beiden Methoden entschieden, weil sie die primitive Arbeit mit parallelen Berechnungen ohne alles Überflüssige gut zeigen.



Daher wird die transform () -Funktion verwendet, um ein Datenarray (oder zwei Arrays, wenn wir sie übergeben) zu ändern, indem eine Funktion auf alle Werte angewendet wird.



transform(com_vec.begin(), 
   com_vec.end(), 
   buff_result.begin(), 
   compute::sqrt<float>(), 
   queue);


Fahren wir mit dem Parsen der Argumente fort. Mit den ersten beiden Argumenten übergeben wir einen Vektor mit Eingabedaten. Mit dem dritten Argument übergeben wir einen Zeiger auf den Anfang des Vektors, in den wir das Ergebnis schreiben. Mit dem nächsten Argument geben wir an, was zu tun ist. Im obigen Beispiel verwenden wir eine der Standardfunktionen zur Vektorverarbeitung, nämlich das Extrahieren der Quadratwurzel. Natürlich können Sie eine benutzerdefinierte Funktion schreiben, Boost bietet uns zwei Möglichkeiten, aber dies ist bereits das Material für den nächsten Teil (falls es überhaupt eine gibt). Nun, als letztes Argument übergeben wir ein Objekt der Klasse compute :: command_queue, über das ich oben gesprochen habe.



Die nächste Funktion ist reduzieren (), hier ist alles etwas interessanter. Diese Methode gibt das Ergebnis der Anwendung des vierten Arguments auf alle Elemente des Vektors zurück.



compute::reduce(com_vec.begin(), 
   com_vec.end(), 
   &reduce_result, 
   compute::plus<float>(),
   queue);


Jetzt werde ich anhand eines Beispiels erklären, dass der obige Code mit der folgenden Gleichung verglichen werden kann:

1+4+neun

In unserem Fall erhalten wir die Summe aller Elemente im Array.



Fazit



Nun, das ist alles, ich denke, das ist genug, um einfache Operationen mit Big Data durchzuführen. Jetzt können Sie die primitiven Funktionen der boost.compute-Bibliothek verwenden und bei der Arbeit mit dieser Bibliothek auch einige Fehler vermeiden.



Ich würde mich über positives Feedback freuen. Vielen Dank für Ihre Zeit.



Allen viel Glück!



All Articles