使用openMP(c代码)并行计算前缀和
在为前缀和问题分配并行算法时遇到一些问题。我正在使用openMP进行并行实现。我有下面的c代码 结果显示:使用openMP(c代码)并行计算前缀和,c,parallel-processing,cygwin,openmp,prefix-sum,C,Parallel Processing,Cygwin,Openmp,Prefix Sum,在为前缀和问题分配并行算法时遇到一些问题。我正在使用openMP进行并行实现。我有下面的c代码 结果显示: seqsum[6] = 28 != parallelsum[6] = 34 请告知。谢谢 #include <stdio.h> #include <stdlib.h> #include <time.h> #include "omp.h" #include <string.h> #define N 10 //33554432 // 2 ^ 2
seqsum[6] = 28 != parallelsum[6] = 34
请告知。谢谢
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "omp.h"
#include <string.h>
#define N 10 //33554432 // 2 ^ 25
#define NUM_THREADS 4
void computeparallelprefix(int *iplist, int *_pprefixsum, unsigned long size)
{
int nthr, *z, *x = _pprefixsum;
int i, j, tid, work, lo, hi;
#pragma omp parallel shared(nthr,x,z) private(i,j,tid,work,lo,hi)
{
int prev_sum;
memcpy((void *)x, (void *)iplist, sizeof(int)*size);
// Assume nthr = 2^k
#pragma omp single
{
nthr = omp_get_num_threads();
z = malloc(sizeof(int)*nthr);
}
tid = omp_get_thread_num();
work = size /nthr + (i = tid < size%nthr ? 1 : 0);
lo = (size/nthr)*tid + (i==1 ? tid : size%nthr);
hi = lo + work;
if (hi > size)
hi = size;
// local prefix sum over x
for(i=lo+1; i<hi; i++)
x[i] += x[i-1];
// local prefix sum for tid
z[tid] = x[hi-1];
#pragma omp barrier
// global prefix sum over z
for(j=1; j<nthr; j=2*j) {
if (tid >= j)
z[tid] = z[tid] + z[tid-j];
#pragma omp barrier
}
// Update local prefix sum x
prev_sum = z[tid] - x[hi-1];
for(i=lo;i<hi;i++)
x[i] += prev_sum;
}
free(z);
}
void initlist(int *iplist, unsigned long size)
{
int i;
for ( i = 0; i < size; i++)
iplist[i] = i+1;
// iplist[i] = rand() % 13;
}
void printlist(int *list, unsigned long size)
{
int i;
for(i = 0; i < size; i++) {
printf("%d ", list[i]);
}
printf("\n");
}
void computeseqprefixsum(int *iplist, int *seqprefixsum, unsigned long size)
{
int i;
seqprefixsum[0] = iplist[0];
for(i = 1; i < size; i++) {
seqprefixsum[i] = seqprefixsum[i-1] + iplist[i];
}
}
void checkresults(int *seqsum, int *parallelsum, unsigned long size)
{
int i;
for(i = 0; i < size; i++)
{
if(seqsum[i] != parallelsum[i]) {
printf("seqsum[%d] = %d != parallelsum[%d] = %d\n", i, seqsum[i], i,
parallelsum[i]);
exit(1);
}
}
}
int main(int argc, char *argv[])
{
// seed the rand generator
srand(time(NULL));
double seqstart, seqend, parstart, parend, seqtime, partime;
// initialize list
int *iplist, *seqprefixsum, *pprefixsum ;
iplist = (int*) malloc(sizeof(int) * N);
seqprefixsum = (int*) malloc(sizeof(int) * N);
pprefixsum = (int*) malloc(sizeof(int) * N);
if(iplist == NULL || seqprefixsum == NULL || pprefixsum == NULL) {
printf("memory cannot be allocated\n");
exit(1);
}
initlist(iplist, N);
seqstart = omp_get_wtime();
computeseqprefixsum(iplist, seqprefixsum, N);
seqend = omp_get_wtime();
seqtime = seqend - seqstart;
omp_set_num_threads(NUM_THREADS);
parstart = omp_get_wtime();
computeparallelprefix(iplist, pprefixsum, N);
parend= omp_get_wtime();
partime = parend - parstart;
checkresults(seqprefixsum, pprefixsum, N);
printf("Seq Time : %f, Par Time : %f, Speedup : %f\n", seqtime, partime,
seqtime/partime);
free(iplist); free(seqprefixsum); free(pprefixsum);
return 0;
}
对于代码中的前缀和,您的想法是正确的 我不确定你为什么没有得到正确的结果,但是我清理了你的代码,我的版本得到了正确的结果。有关更多详细信息,请参见以下问题
由于计算中的数据依赖性,我认为这个问题很难从一开始就并行化。我可以改进它吗?感谢您确实无法并行化computeseqprefixsum,因为每个值都取决于上一个值one@dvhh,在两个过程中并行化并不太困难。第一步是对每个线程进行部分求和,第二步是对每个线程进行偏移校正。问题不在于获得并行算法,而是该操作与许多操作一样受内存带宽限制,因此它不随物理核的数量而扩展。@dvhh,事实上,这正是OP所做的:两次传递,第一次是部分传递,第二次是修正。这里有一个有效的例子。我不知道为什么OPs代码不起作用,但这是正确的想法。谢谢!然而,在我这一方,它仍然不起作用。所有progma命令完全不起作用:错误:预处理指令无效progma@Orangeblue你在说什么?我的代码中没有程序。我只是用-Wall编译,没有收到任何警告。我还搜索了progma,结果什么也没有返回。这个代码很好。我使用gcc-std=gnu99-fopenmp-O3-Wall psum.cIt编译。似乎允许一个线程执行malloc z,但每个线程都可以释放内存z。@Zboson:Orangeblue必须将所有pragma更改为progma。@NisseEngström,他的编辑应该被拒绝。什么是progma?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "omp.h"
#define N 11 //33554432 // 2 ^ 25
void computeparallelprefix(int *iplist, int *_pprefixsum, unsigned long size)
{
int nthr, *z, *x = _pprefixsum;
#pragma omp parallel
{
int i;
#pragma omp single
{
nthr = omp_get_num_threads();
z = malloc(sizeof(int)*nthr+1);
z[0] = 0;
}
int tid = omp_get_thread_num();
int sum = 0;
#pragma omp for schedule(static)
for(i=0; i<size; i++) {
sum += iplist[i];
x[i] = sum;
}
z[tid+1] = sum;
#pragma omp barrier
int offset = 0;
for(i=0; i<(tid+1); i++) {
offset += z[i];
}
#pragma omp for schedule(static)
for(i=0; i<size; i++) {
x[i] += offset;
}
}
free(z);
}
int main(void ) {
int *iplist, *pprefixsum ;
iplist = (int*) malloc(sizeof(int) * N);
pprefixsum = (int*) malloc(sizeof(int) * N);
for(int i=0; i<N; i++) iplist[i] = i+1;
for(int i=0; i<N; i++) printf("%d ", iplist[i]); printf("\n");
computeparallelprefix(iplist, pprefixsum, N);
for(int i=0; i<N; i++) printf("%d ", pprefixsum[i]); printf("\n");
for(int i=0; i<N; i++) printf("%d ", (i+1)*(i+2)/2); printf("\n");
return 0;
}