我试图在C(OpenMP)中通过向量乘法来编写矩阵 但是当我添加处理器时,我的程序会变慢...
1 proc - 1,3 s
2 proc - 2,6 s
4 proc - 5,47 s
我在我的PC(核心i5)和我们学校的群集上进行了测试,结果相同(程序变慢)
这是我的代码(矩阵是10000 x 10000),矢量是10000:
double start_time = clock();
#pragma omp parallel private(i) num_threads(4)
{
tid = omp_get_thread_num();
world_size = omp_get_num_threads();
printf("Threads: %d\n",world_size);
for(y = 0; y < matrix_size ; y++){
#pragma omp parallel for private(i) shared(results, vector, matrix)
for(i = 0; i < matrix_size; i++){
results[y] = results[y] + vector[i]*matrix[i][y];
}
}
}
double end_time = clock();
double result_time = (end_time - start_time) / CLOCKS_PER_SEC;
printf("Time: %f\n", result_time);
我的问题是:有什么错误吗?对我来说,它似乎很简单,应该加快
答案 0 :(得分:4)
我基本上已经回答了这个问题parallelizing-matrix-times-a-vector-by-columns-and-by-rows-with-openmp。
当您写信至results[y]
时,您有竞争条件。要解决此问题,并且仍然并行化内部循环,您必须创建results[y]
的私有版本,并行填充它们,然后将它们合并到一个关键部分。
在下面的代码中,我假设您正在使用double
,将其替换为float
或int
或您正在使用的任何数据类型(请注意您的内部循环遍历matrix[i][y]
的第一个索引,它是缓存不友好的。)
#pragma omp parallel num_threads(4)
{
int y,i;
double* results_private = (double*)calloc(matrix_size, sizeof(double));
for(y = 0; y < matrix_size ; y++) {
#pragma omp for
for(i = 0; i < matrix_size; i++) {
results_private[y] += vector[i]*matrix[i][y];
}
}
#pragma omp critical
{
for(y=0; y<matrix_size; y++) results[y] += results_private[y];
}
free(results_private);
}
如果这是家庭作业,你想真正给你的教练留下深刻的印象,那么在没有关键部分的情况下进行合并是可能的。请参阅此链接以了解该做什么fill-histograms-array-reduction-in-parallel-with-openmp-without-using-a-critic,但我无法保证会更快。
答案 1 :(得分:0)
我暂时没有进行任何并行编程,也没有任何数学,但是你不想并行分割矩阵的行而不是列吗?
如果您尝试这样做会发生什么:
double start_time = clock();
#pragma omp parallel private(i) num_threads(4)
{
tid = omp_get_thread_num();
world_size = omp_get_num_threads();
printf("Threads: %d\n",world_size);
#pragma omp parallel for private(y) shared(results, vector, matrix)
for(y = 0; y < matrix_size ; y++){
for(i = 0; i < matrix_size; i++){
results[y] = results[y] + vector[i]*matrix[i][y];
}
}
}
double end_time = clock();
double result_time = (end_time - start_time) / CLOCKS_PER_SEC;
printf("Time: %f\n", result_time);
另外,你确定一切都可以编译并链接到openMP
吗?
答案 2 :(得分:0)
您遇到缓存冲突的典型案例。
考虑到CPU上的缓存行可能长达64个字节。让一个处理器/核心写入前4个字节(float
)会导致该高速缓存行在每个其他L1 / L2和L3上无效。这是一个很大的开销。
更好地对数据进行分区!
#pragma omp parallel for private(i) shared(results, vector, matrix) schedule(static,16)
应该做的伎俩。如果这没有帮助,请增加chunksize。
另一个优化是在将结果刷新到内存之前将结果存储在本地。
此外,这是一个OpenMP的东西,但你不需要为循环开始一个新的并行区域(每次提到parallel
都会启动一个新团队):
#pragma omp parallel default(none) \
shared(vector, matrix) \
firstprivate(matrix_size) \
num_threads(4)
{
int i, y;
#pragma omp for schedule(static,16)
for(y = 0; y < matrix_size ; y++){
double result = 0;
for(i = 0; i < matrix_size; i++){
results += vector[i]*matrix[i][y];
}
result[y] = result;
}
}