English 中文(简体)
在连续运行时对程序优化程序使用开开放MP 后没有业绩增益
原标题:No performance gain after using openMP on a program optimize for sequential running

I have optimized as much as I could my function for sequential running. When I use openMP I see no gain in performance. I tried my program on a machine with 1 cores and on a machine with 8 cores, and the performance is the same.
With year set to 20, I have
1 core: 1 sec.
8 core: 1 sec.

With year set to 25 I have
1 core: 40 sec.
8 core: 40 sec.

1 core machine: my laptop s intel core 2 duo 1.8 GHz, ubuntu linux
8 core machine: 3.25 GHz, ubuntu linux

我的程序罗列了二进制树的所有可能路径, 并在每个路径上做一些工作 。 因此我的环形尺寸会成倍增长, 我期望打开MP 线条的足迹为零 。 在我的环状中, 我只能减少一个变量。 所有其他变量都是只读的 。 我只使用我写的函数, 我认为它们是安全的线条 。

我也在我的程序上管理着Valgrind 暗礁。 我并不完全理解输出, 但似乎没有缓存误差或虚假共享 。

我编集与

gcc -O3 -g3 -Wall -c -fmessage-length=0 -lm -fopenmp -ffast-math

我的完整程序如下。 抱歉张贴了很多代码。 我对 OpenMP 和 C 都不熟悉, 我无法恢复我的代码而不忽略主要任务 。

How can I improve performance when I use openMP?
Are they some compiler flags or C tricks that will make the program run faster?

测试测试。 c

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>
#include "测试 h"

int main(){

    printf("starting
");
    int year=20;
    int tradingdate0=1;

    globalinit(year,tradingdate0);

    int i;
    float v=0;
    long n=pow(tradingdate0+1,year);
    #pragma omp parallel for reduction(+:v)
    for(i=0;i<n;i++)
        v+=pathvalue(i);

    globaldel();
    printf("finished
");
    return 0;
}

//***function on which openMP is applied
float pathvalue(long pathindex) {
    float value = -ctx.firstpremium;
    float personalaccount = ctx.personalaccountat0;
    float account = ctx.firstpremium;
    int i;
    for (i = 0; i < ctx.year-1; i++) {
        value *= ctx.accumulationfactor;
        double index = getindex(i,pathindex);
        account = account * index;
        double death = fmaxf(account,ctx.guarantee[i]);
        value += qx(i) * death;
        if (haswithdraw(i)){
            double withdraw = personalaccount*ctx.allowed;
            value += px(i) * withdraw;
            personalaccount = fmaxf(personalaccount-withdraw,0);
            account = fmaxf(account-withdraw,0);
        }
    }

    //last year
    double index = getindex(ctx.year-1,pathindex);
    account = account * index;
    value+=fmaxf(account,ctx.guarantee[ctx.year-1]);

    return value * ctx.discountfactor;
}



int haswithdraw(int period){
    return 1;
}

float getindex(int period, long pathindex){
    int ndx = (pathindex/ctx.chunksize[period])%ctx.tradingdate;
    return ctx.stock[ndx];
}

float qx(int period){
    return 0;
}

float px(int period){
    return 1;
}

//****global
struct context ctx;

void globalinit(int year, int tradingdate0){
    ctx.year = year;
    ctx.tradingdate0 = tradingdate0;
    ctx.firstpremium = 1;
    ctx.riskfreerate = 0.06;
    ctx.volatility=0.25;
    ctx.personalaccountat0 = 1;
    ctx.allowed = 0.07;
    ctx.guaranteerate = 0.03;
    ctx.alpha=1;
    ctx.beta = 1;
    ctx.tradingdate=tradingdate0+1;
    ctx.discountfactor = exp(-ctx.riskfreerate * ctx.year);
    ctx.accumulationfactor = exp(ctx.riskfreerate);
    ctx.guaranteefactor = 1+ctx.guaranteerate;
    ctx.upmove=exp(ctx.volatility/sqrt(ctx.tradingdate0));
    ctx.downmove=1/ctx.upmove;

    ctx.stock=(float*)malloc(sizeof(float)*ctx.tradingdate);
    int i;
    for(i=0;i<ctx.tradingdate;i++)
        ctx.stock[i]=pow(ctx.upmove,ctx.tradingdate0-i)*pow(ctx.downmove,i);

    ctx.chunksize=(long*)malloc(sizeof(long)*ctx.year);
    for(i=0;i<year;i++)
        ctx.chunksize[i]=pow(ctx.tradingdate,ctx.year-i-1);

    ctx.guarantee=(float*)malloc(sizeof(float)*ctx.year);
    for(i=0;i<ctx.year;i++)
        ctx.guarantee[i]=ctx.beta*pow(ctx.guaranteefactor,i+1);
}

void globaldel(){
    free(ctx.stock);
    free(ctx.chunksize);
    free(ctx.guarantee);
}

测试 h

float pathvalue(long pathindex);
int haswithdraw(int period);
float getindex(int period, long pathindex);
float qx(int period);
float px(int period);
//***global
struct context{
    int year;
    int tradingdate0;
    float firstpremium;
    float riskfreerate;
    float volatility;
    float personalaccountat0;
    float allowed;
    float guaranteerate;
    float alpha;
    float beta;
    int tradingdate;
    float discountfactor;
    float accumulationfactor;
    float guaranteefactor;
    float upmove;
    float downmove;
    float* stock;
    long* chunksize;
    float* guarantee;
};
struct context ctx;
void globalinit();
void globaldel();

EDIT I simplify all global variables as constant. For 20 year, the program run two time faster (great!). I tried to set the number of thread with OMP_NUM_THREADS=4 ./test for example. But it didn t give me any performance gain.
Can my gcc have some problem?

测试测试。 c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <omp.h>
#include "测试 h"


int main(){

    starttimer();
    printf("starting
");
    int i;
    float v=0;

    #pragma omp parallel for reduction(+:v)
    for(i=0;i<numberofpath;i++)
        v+=pathvalue(i);

    printf("v:%f
finished
",v);
    endtimer();
    return 0;
}

//function on which openMP is applied
float pathvalue(long pathindex) {
    float value = -firstpremium;
    float personalaccount = personalaccountat0;
    float account = firstpremium;
    int i;
    for (i = 0; i < year-1; i++) {
        value *= accumulationfactor;
        double index = getindex(i,pathindex);
        account = account * index;
        double death = fmaxf(account,guarantee[i]);
        value += death;
        double withdraw = personalaccount*allowed;
        value += withdraw;
        personalaccount = fmaxf(personalaccount-withdraw,0);
        account = fmaxf(account-withdraw,0);
    }

    //last year
    double index = getindex(year-1,pathindex);
    account = account * index;
    value+=fmaxf(account,guarantee[year-1]);

    return value * discountfactor;
}



float getindex(int period, long pathindex){
    int ndx = (pathindex/chunksize[period])%tradingdate;
    return stock[ndx];
}

//timing
clock_t begin;

void starttimer(){
    begin = clock();
}

void endtimer(){
    clock_t end = clock();
    double elapsed = (double)(end - begin) / CLOCKS_PER_SEC;
    printf("
elapsed: %f
",elapsed);
}

测试 h

float pathvalue(long pathindex);
int haswithdraw(int period);
float getindex(int period, long pathindex);
float qx(int period);
float px(int period);
//timing
void starttimer();
void endtimer();
//***constant
const int year= 20 ;
const int tradingdate0= 1 ;
const float firstpremium= 1 ;
const float riskfreerate= 0.06 ;
const float volatility= 0.25 ;
const float personalaccountat0= 1 ;
const float allowed= 0.07 ;
const float guaranteerate= 0.03 ;
const float alpha= 1 ;
const float beta= 1 ;
const int tradingdate= 2 ;
const int numberofpath= 1048576 ;
const float discountfactor= 0.301194211912 ;
const float accumulationfactor= 1.06183654655 ;
const float guaranteefactor= 1.03 ;
const float upmove= 1.28402541669 ;
const float downmove= 0.778800783071 ;
const float stock[2]={1.2840254166877414, 0.7788007830714049};
const long chunksize[20]={524288, 262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1};
const float guarantee[20]={1.03, 1.0609, 1.092727, 1.1255088100000001, 1.1592740743, 1.1940522965290001, 1.2298738654248702, 1.2667700813876164, 1.304773183829245, 1.3439163793441222, 1.384233870724446, 1.4257608868461793, 1.4685337134515648, 1.512589724855112, 1.557967416600765, 1.6047064390987882, 1.6528476322717518, 1.7024330612399046, 1.7535060530771016, 1.8061112346694148};
最佳回答

即使您的程序受益于使用 OpenMP, 您也不会看到它, 因为您测量错误的时间 。

klock () 返回在 < enger> all less 中度过的 < number > commendate CPU time 。 如果您用四根线运行, 且每根线运行四分之一的时间, block () 将返回自 4* (1/4) = 1 以来的相同值 。 您应该测量 < nuger> wall-knight time 。

将调用 klock () 的调用替换为 homp_get_wtime () gettime ofday () 。 它们都提供高精密墙时钟时间 。

P.S.。 为什么在SO周围有这么多人使用 klock () 来计时?

问题回答

它似乎应该起作用。 您可能需要指定要使用的线条数量。 您可以设置 OMP_ NUM_ THREADS 变量来做到这一点。 例如, 使用 4 线条 :

OMP_NUM_THREADS=4 ./test

EDIT: 我刚编译了代码,我观察到在改变线条数量时出现重大超速。

我看不到您在其中重新指定 OpenMP 将使用的核心数的任何部分。 默认情况下, 它应该使用它看到的 CPU 数, 但为了我的目的, 我总是强迫它使用我指定的数量。

在您的平行线之前添加此直线以构建 :

#pragma omp parallel num_threads(num_threads)
{
   // Your parallel for follows here
}

... 在那里 num_threads 是一个在 1 和您机器核心数之间的整数。

EDIT: 这里是用于构建代码的 makefile。 将其放置在同一目录中名为 < code> makefile 的文本文件 。

test: test.c test.h
    cc -o $@ $< -O3 -g3 -fmessage-length=0 -lm -fopenmp -ffast-math




相关问题
Fastest method for running a binary search on a file in C?

For example, let s say I want to find a particular word or number in a file. The contents are in sorted order (obviously). Since I want to run a binary search on the file, it seems like a real waste ...

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

Tips for debugging a made-for-linux application on windows?

I m trying to find the source of a bug I have found in an open-source application. I have managed to get a build up and running on my Windows machine, but I m having trouble finding the spot in the ...

Trying to split by two delimiters and it doesn t work - C

I wrote below code to readin line by line from stdin ex. city=Boston;city=New York;city=Chicago and then split each line by ; delimiter and print each record. Then in yet another loop I try to ...

Good, free, easy-to-use C graphics libraries? [closed]

I was wondering if there were any good free graphics libraries for C that are easy to use? It s for plotting 2d and 3d graphs and then saving to a file. It s on a Linux system and there s no gnuplot ...

Encoding, decoding an integer to a char array

Please note that this is not homework and i did search before starting this new thread. I got Store an int in a char array? I was looking for an answer but didn t get any satisfactory answer in the ...

热门标签