在程序上使用openMP后性能没有提高,可以优化顺序运行

我尽可能地优化了顺序运行的function。 当我使用openMP时,我看不到性能上的好处。 我在1核心机器和8核心机器上试过我的程序,性能是一样的。
随着年份设置为20,我有
1个核心:1秒
8核心:1秒

随着年份设置为25我有
1核心:40秒
8核心:40秒

1核心机器:我的笔记本电脑的英特尔酷睿2双核1.8 GHz,Ubuntu的Linux
8核心机器:3.25 GHz,Ubuntu的Linux

我的程序列举了二叉树的所有可能path,并在每个path上做了一些工作。 所以我的循环大小呈指数增长,我预计openMP线程的占用空间为零。 在我的循环中,我只做了一个variables的减less。 其他所有variables都是只读的。 我只使用我写的函数,而且我认为它们是线程安全的。

我也在我的程序上运行Valgrind cachegrind。 我不完全理解输出,但似乎没有caching缺失或错误的共享。

我编译

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

我的完整程序如下。 对不起,张贴了很多代码。 我不熟悉openMP和C,在不失去主要任务的情况下,我不能恢复我的代码。

当我使用openMP时,如何提高性能?
他们是一些编译器标志或C技巧,将使程序运行速度更快?

test.c的

 #include <stdio.h> #include <stdlib.h> #include <math.h> #include <omp.h> #include "test.h" int main(){ printf("starting\n"); 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\n"); 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); } 

test.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(); 

编辑我把所有的全局variables简化为常量。 20年来,程序运行速度提高了两倍(太棒了!)。 例如,我试图设置OMP_NUM_THREADS=4 ./test的线程数。 但是这并没有给我带来任何性能上的好处。
我的gcc可以有一些问题吗?

test.c的

 #include <stdio.h> #include <stdlib.h> #include <time.h> #include <math.h> #include <omp.h> #include "test.h" int main(){ starttimer(); printf("starting\n"); int i; float v=0; #pragma omp parallel for reduction(+:v) for(i=0;i<numberofpath;i++) v+=pathvalue(i); printf("v:%f\nfinished\n",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("\nelapsed: %f\n",elapsed); } 

test.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,您也不会看到它,因为您正在测量错误的时间。

clock()返回在所有线程中花费的总CPU时间 。 如果使用四个线程运行并且每个运行四分之一的时间,则clock()将从4 *(1/4)= 1返回相同的值。您应该测量挂钟时间

使用omp_get_wtime()gettimeofday()将呼叫replace为clock() gettimeofday() 。 他们都提供高精度的挂钟时间。

PS为什么周围有那么多人使用clock()进行计时?

它似乎应该工作。 可能你需要指定要使用的线程数。 你可以通过设置OMP_NUM_THREADSvariables来实现。 例如,使用4个线程:

 OMP_NUM_THREADS=4 ./test 

编辑:我刚编译的代码,我观察到改变线程数时显着加速。

我没有看到您指定OpenMP将使用的内核数量的任何部分。 默认情况下,它应该使用它所看到的CPU数量,但是为了达到我的目的,我一直强迫它使用尽可能多的CPU。

在parallel for构造之前添加这一行:

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

…其中num_threads是1到您的机器上核心数的整数。

编辑:这是用于构build代码的生成文件。 把它放在一个名为Makefile的文本文件中。

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