Inhaltsverzeichnis
Apfelmännchen in OpenMP
Ein Apfelmännchen wird berechnet und in eine Datei geschrieben. Die dazu benutzte "Grafik-Bibliothek" finden Sie hier.
//: mandelbrot.cpp : Fraktalbild - R.Richter 2011-01-18 /////////////////////////////////////////////////////// #include <ctime> #include <iostream> #include <complex> #include "image.h" typedef std::complex<double> complex; int compute(complex c, int maxIterations) { int count = 0; complex z; while (abs(z) <= 2.0 && count < maxIterations) { z = z * z + c; ++ count; } return count; } inline Color color(int height, int max) { // color scheme from: // http://shreyassiravara.wordpress.com/2010/08/14/the-mandelbrot-set/ if (height >= max) return Color::BLACK; double h = 255 * log(double(height)) / log(double(max)); return Color(0.9 * h, 0.8 * h, 0.6 * h); } inline double scale(int pos, int length, double low, double high) { return low + pos * (high-low) / (length-1); } Image mandelbrot(int width, int height, int maxIterations, complex left_bottom, complex right_top) { Image image(width, height); #pragma omp parallel for schedule(dynamic) for (int y = 0; y < height; ++y) { std::vector<Color> v(width); for (int x = 0; x < width; ++x) { complex c(scale(x, width, real(left_bottom), real(right_top)), scale(y, height, imag(left_bottom), imag(right_top))); v[x] = color(compute(c, maxIterations), maxIterations); } // reduce shared caches lines by two for loops? for (int x = 0; x < width; ++x) { image.pixel(x, y) = v[x]; } } return image; } int main() { int width = 1000; int height = 1000; int maxIterations = 10000; complex left_bottom(-2.0, -2.0); complex right_top ( 2.0, 2.0); saveBMP("mandel.bmp", mandelbrot(width, height, maxIterations, left_bottom, right_top)); std::cout << clock() / double(CLOCKS_PER_SEC) << " seconds CPU time\n"; return 0; }
Übersetzung, Ausführung
Das Programm wurde mit GCC 4.6 (64bit) unter Windows 7 mit dem Befehl
g++ -O3 -fopenmp mandelbrot.cpp -o mandelpar.exe
übersetzt. Die Compiler-Anweisung
#pragma omp parallel for
in der Funktion mandelbrot() sorgt in Visual C++ (ab Version 2005) standardmäßig, beim GCC nur bei Übersetzung mit der Option -fopenmp für die Aufteilung der Schleife zu Parallelverarbeitung. Da das Programm keine Funktionen der OpenMP-Bibliothek benötigt, sind der Header <omp.h> und die Link-Option -lgomp nicht notwendig.
Bei nicht vorhersagbarem Zeitbedarf der Teilberechnungen empfiehlt sich dynamische Lastverteilung:
#pragma omp parallel for schedule(dynamic)
Zeitmessung
Das Programm benötigte auf der verwendeten Zweikernmaschine (AMD Turion 64, 2.1 GHz) 32 Sekunden bei 100% Prozessorauslastung statt 68 Sekunden bei ca. 50%iger Last ohne Parallelisierung. Der nicht parallelisierbare Aufwand zum Schreiben des Bildes beträgt weniger als 1 Sekunde. Bei etwa gleichem Rechenaufwand in den Teilbereichen der aufgespalteten Schleife mit etwa halber Laufzeit zu rechnen. Werden in diesem Beispiel jedoch innere und äußere Schleife vertauscht, so ist der Teilprozess für die linke Bildhälfte, in dem der größere Bereich des Apfelmännchens liegt, länger beschäftigt.
Weiterführende Links
- http://msdn.microsoft.com/en-us/magazine/cc163717.aspx#S1 : Benefits of multithreading without all the work
- http://www.viva64.com/en/a/0054/ : 32 OpenMP traps for C++ developers
- http://shreyassiravara.wordpress.com/2010/08/14/the-mandelbrot-set/ : Rendering Mandelbrot set