namespace cpp

C++ lernen, kennen, anwenden

Benutzer-Werkzeuge

Webseiten-Werkzeuge


parallel:openmp

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.

parallel/openmp.txt · Zuletzt geändert: 2014-07-14 12:09 (Externe Bearbeitung)