为了练习OpenMP,我决定编写一个算法来减少矩阵行。令人惊讶的是,当我添加和#pragma omp并行到我的内循环时,尽管我的程序花了99%的时间在内循环中,但没有明显的速度增加。我不期望在我的四核i7上看到4倍的性能提升,但我确实希望看到一些东西。
void Matrix::row_reduce(dim_t eff_width)
{
if(eff_width == 0 || eff_width > w)
eff_width = w;
dim_t* leads = new dim_t[h];
double t1 = omp_get_wtime();
for(dim_t r1 = 0; r1 < h; r1++)
{
dim_t lead = 0;
double* ptr1 = (*this)[r1];
while(lead < eff_width && ptr1[lead] == 0)
++lead;
leads[r1] = lead;
if(lead == eff_width)
continue;
//makeing this for parallel has no effect in speed
#pragma omp parallel for
for(dim_t r2 = 0; r2 < h; r2++)
{
if(r2 == r1)
continue;
if((*this)[r2][lead] == 0)
continue;
double scale = -(*this)[r2][lead] / ptr1[lead];
add_scaled_row(r2, r1, scale);
(*this)[r2][lead] = 0;
}
}
t1 = omp_get_wtime() - t1;
double t2 = omp_get_wtime();
for(dim_t r = 0; r < h; r++)
{
if(leads[r] < eff_width)
scale_row(r, 1.0 / (*this)[r][leads[r]]);
}
t2 = omp_get_wtime() - t2;
double t3 = omp_get_wtime();
for(dim_t i = 0; i < h; i++)
{
dim_t min = i;
for(dim_t j = i + 1; j < h; j++)
{
if(leads[min] > leads[j])
min = j;
}
if(min != i)
{
dim_t tmp = leads[i];
leads[i] = leads[min];
leads[min] = tmp;
swap_rows(min, i);
printf("SWAP\n");
}
}
t3 = omp_get_wtime() - t3;
double total = t1 + t2 + t3;
printf("t1 = %lf\t%lf\n", t1, 100 * t1 / total);
printf("t2 = %lf\t%lf\n", t2, 100 * t2 / total);
printf("t3 = %lf\t%lf\n", t3, 100 * t3 / total);
delete[] leads;
}
这里的内环显然是平行的。可以从每行完全独立地消除主导项。我想也许没有性能提升,因为瓶颈是记忆,但我仍然期望稍微提升性能。
此外,如果有人对此感兴趣,那么我的add_scale_row函数。
void Matrix::add_scaled_row(dim_t dest_r, dim_t src_r, double f)
{
if(dest_r == src_r)
{
scale_row(dest_r, 1.0 + f);
return;
}
double* __restrict__ s = (*this)[src_r];
double* __restrict__ d = (*this)[dest_r];
__m256d vf = _mm256_set1_pd(f);
for(dim_t i = 0; i < w; i += 4)
{
__m256d a = _mm256_load_pd(s + i);
__m256d b = _mm256_load_pd(d + i);
b = _mm256_fmadd_pd(a, vf, b);
_mm256_store_pd(d + i, b);
}
}
我还通过调用omp_get_num_threads检查了我的循环,它给出了我的8(4核X 2超线程)。我还检查了我的系统监视器,当我运行它时,它似乎显示所有核心都以100%运行。我在Ubuntu 15.04上使用GCC 4.9。