簡體   English   中英

需要更正我的OpenMP Mandelbrot集代碼

[英]Need correction to my OpenMP Mandelbrot set code

我在OpenMP中有以下Mandelbrot設置代碼。 我的C代碼可以正常工作,並且它產生的圖片非常完美。 但是使用OpenMP,它可以編譯並正確運行,但是很遺憾,我無法打開輸出.ppm文件,只是Gimp無法讀取它。

// mandopenmp.c
// to compile: gcc -fopenmp mandopenmp.c -o mandopenmp -lm
// usage: ./mandopenmp <no_of_iterations> > output.ppm

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <omp.h>

typedef struct {
    int r, g, b;
} rgb;


void color(rgb **m, int x, int y, int red, int green, int blue)
{
    m[x][y].r = red;
    m[x][y].g = green;
    m[x][y].b = blue;
}

void mandelbrot(int niterations, rgb **m)
{
    int w = 600, h = 400, x, y, i;
    // each iteration, it calculates: newz = oldz*oldz + p, 
    // where p is the current pixel, and oldz stars at the origin
    double pr, pi;                   // real and imaginary part of the pixel p
    double newRe, newIm, oldRe, oldIm;   // real and imaginary parts of new and old z
    double zoom = 1, moveX = -0.5, moveY = 0; // you can change these to zoom and change position

    printf("P6\n# AUTHOR: Erkan Tairi\n");
    printf("%d %d\n255\n",w,h);

    //loop through every pixel
    #pragma omp parallel for private(x,i,pr,pi,newRe,newIm,oldRe,oldIm) schedule(dynamic, 1)
    for(y = 0; y < h; y++) {
        for(x = 0; x < w; x++) {
            // calculate the initial real and imaginary part of z, 
            // based on the pixel location and zoom and position values
            pr = 1.5 * (x - w / 2) / (0.5 * zoom * w) + moveX;
                pi = (y - h / 2) / (0.5 * zoom * h) + moveY;
                newRe = newIm = oldRe = oldIm = 0; //these should start at 0,0
                // start the iteration process
                for(i = 0; i < niterations; i++) {
                        // remember value of previous iteration
                        oldRe = newRe;
                        oldIm = newIm;
                        // the actual iteration, the real and imaginary part are calculated
                        newRe = oldRe * oldRe - oldIm * oldIm + pr;
                        newIm = 2 * oldRe * oldIm + pi;
                        // if the point is outside the circle with radius 2: stop
                        if((newRe * newRe + newIm * newIm) > 4) break;
                }
                if(i == niterations)
                color(m, x, y, 0, 0, 0); // black
            else
            {
                // normalized iteration count method for proper coloring
                double z = sqrt(newRe * newRe + newIm * newIm);
                int brightness = 256. * log2(1.75 + i - log2(log2(z))) / log2((double)niterations);
                color(m, x, y, brightness, brightness, 255);
            }
            }
    }
}

int main(int argc, char *argv[])
{
    int niterations, i, j;

    if(argc != 2)
    {
        printf("Usage: %s <no_of_iterations> > output.ppm\n", argv[0]);
        exit(1);
    }

    niterations = atoi(argv[1]);

    rgb **m;
    m = malloc(600 * sizeof(rgb *));
    for(i = 0; i < 600; i++)
        m[i] = malloc(400 * sizeof(rgb));

    double begin = omp_get_wtime();
    mandelbrot(niterations, m);

    for(i = 0; i < 600; i++) {
        for(j = 0; j < 400; j++) {
            fputc((char)m[i][j].r, stdout);
            fputc((char)m[i][j].g, stdout);
            fputc((char)m[i][j].b, stdout);
        }
    }

    double end = omp_get_wtime();

    double time_spent = end - begin;
    fprintf(stderr, "Elapsed time: %.2lf seconds.\n", time_spent);

    for(i = 0; i < 600; i++)
        free(m[i]);
    free(m);

    return 0;
}

我不了解Mandrelbot集的內部原理,但是我將根據您的程序工作流程進行介紹。

可能是因為您在並行部分中正在將顏色寫入輸出文件。 這意味着您的像素將在計算過程完成時被寫入,但這並不意味着像素X的計算過程將在像素X+1的處理之前結束。

這樣,在寫入文件時,您將首先寫入(例如)像素X+1 ,然后寫入像素X ,從而混合顏色。

嘗試將輸出結果寫入矩陣。 您將不得不更改color功能,將兩個參數ij與要寫入像素的坐標相加。

整個處理完成並計算完每個像素后,應將矩陣的像素寫入輸出文件。

編碼:

typedef struct {
    int r, g, b;
} rgb;

void color(rgb **m, int x, int y, int red, int green, int blue) {
    m[x][y].r = red;
    m[x][y].g = green;
    m[x][y].b = blue;
}

void mandelbrot(rgb **m, int niterations) { // note the new argument, m.
    // and your code goes on and on... until:
            if ( i == niterations )
                color(m, x, y, 0, 0, 0);
            else {
                // normalized iteration count method for proper coloring
                double z = sqrt(newRe * newRe + newIm * newIm);
                int brightness = 256. * log2(1.75 + i - log2(log2(z))) / log2((double)niterations);
                color(m, x, y, brightness, brightness, 255);
            }
        }
    }
}

int main(int argc, char *argv[]) {
    // everything ok until...

    double begin = omp_get_wtime();

    rgb **m;
    m = malloc(sizeof(rgb*) * 600);
    for ( i = 0; i < 600; i++ ) {
        m[i] = malloc(400 * sizeof(rgb));

    // finally call mandelbrot!
    mandelbrot(m, niterations);
    double end = omp_get_wtime();

    // now that you have computed your set, you just walk the array writing the output to the file.

    for ( i = 0; i < 600; i++ ) {
        free(m[i]);
    }
    free(m);

    double time_spent = end - begin;
    fprintf(stderr, "Elapsed time: %.2lf seconds.\n", time_spent);

    return 0;
}

您的實現存在缺陷。 您已經聲明了許多必須private變量才能shared 這包括prpinewRenewIm 默認情況下, oldReoldIm也是共享的,因為它們是在並行區域外部的作用域中聲明的。 這些都應該是私有的:

#pragma omp parallel for private(x,i,pr,pi,newRe,newIm,oldRe,oldIm)

同樣, parallel for循環的默認調度通常是(但不一定總是) static 對於像分形之類的東西而言,這並不是最佳選擇,因為它需要花費不同的時間來計算圖像中的每一行或每一列。 因此,您應該應用schedule(dynamic,1)子句並使用塊大小(在這種情況下為1 ),直到獲得最佳的加速。

#pragma omp parallel for private(x,i,pr,pi,newRe,newIm,oldRe,oldIm) \
            schedule(dynamic,1)

如果要順序寫入文件(在編輯之前是在原始代碼中進行的操作),則可以在寫入文件之前使用ordered編譯指示。 使用原始代碼可以使圖像正確。 請參閱以下鏈接http://bisqwit.iki.fi/story/howto/openmp/#ExampleCalculatingTheMandelbrotFractalInParallel

但是,這不是最佳解決方案。 最佳解決方案是先寫入內存緩沖區,然后在mandelbrot代碼完成填充緩沖區后再寫入文件(就像在新代碼中一樣)。

我有一些建議可以加快您的代碼速度。 融合x和y循環(如鏈接中所示)並使用時間表動態(如該鏈接中所示),因為每個像素花費不同的時間。 最后,使用SSE / AVX一次操作兩個(SSE)或四個(AVX)像素。 總體而言,使用OpenMP和SSE / AVX可以使速度提高20倍以上。

#pragma omp ordered {
    if(i == niterations)
        color(m, x, y, 0, 0, 0); // black - use original color function which writes to file
    else
    {
        // normalized iteration count method for proper coloring
        double z = sqrt(newRe * newRe + newIm * newIm);
        int brightness = 256. * log2(1.75 + i - log2(log2(z))) / log2((double)niterations);
        color(m, x, y, brightness, brightness, 255); //use original color function which writes to file
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM