我正在 OpenMP 中实现稀疏矩阵多向量乘法,我注意到在预处理函数中包含一些 printf 调用,而不是并行化,从后续并行化产品中获得的 GFLOPS 增加了很多。
我尝试将我的测量方法从 clock_gettime() 更改为 omp_get_wtime(),但结果几乎相同。
为了帮助您理解我在说什么:
int main() {
// some stuff
// serial product computation
clock_gettime(CLOCK_MONOTONIC, &t1);
serial_product(a, x, k, y_s);
clock_gettime(CLOCK_MONOTONIC, &t2);
gflops_s = flop / ((t2.tv_sec - t1.tv_sec) * 1.e9 + (t2.tv_nsec - t1.tv_nsec));
pre_processing(...) // in here there's a loop to do some load balancing
clock_gettime(CLOCK_MONOTONIC, &t1);
openmp_spmm(a, rows_idx, num_threads, x, k, y_p);
clock_gettime(CLOCK_MONOTONIC, &t2);
gflops_p = flop / ((t2.tv_sec - t1.tv_sec) * 1.e9 + (t2.tv_nsec - t1.tv_nsec));
// some other stuff
}
正如我所说,如果我不调用 printf,就像我做一些基本调试一样,在 pre_processing() 函数的循环中,gflops_p 约为 2 GFLOPS。同时,如果我使用这些与 OpenMp 无关的 printf 调用,gflops_p 会跳到 10 GFLOPS。
如果有帮助,这是预处理功能:
void pre_processing(int threads, int tot_nz, const int* irp, int tot_rows, int* rows_idx){
int j, nz, nz_prev = 0, nz_curr, start_row = 0, r_prev, r_curr = 0;
for (int i = 0; i < threads; i++) {
rows_idx[i] = start_row;
printf("."); // why this print enormously speeds up omp product???
nz_curr = ((i + 1) * tot_nz) / threads;
nz = nz_curr - nz_prev;
nz_prev = nz_curr;
for (j = start_row; j < tot_rows; j++) {
r_curr += irp[j + 1] - irp[j];
if (r_curr < nz) {
r_prev = r_curr;
} else {
start_row = ((r_curr - nz) < (nz - r_prev)) ? j + 1 : j;
break;
}
}
r_curr = 0;
}
rows_idx[threads] = tot_rows;
printf("\n");
}
我不知道为什么会这样。也许是关于标准输出刷新或时钟周期或 CPU 利用率?
当一个线程正在做一些 I/O 时(例如通过
printf()
),它被认为是 I/O 绑定。这使得它比 CPU 绑定线程更优先。原因是确保尽快管理 I/O 以使系统响应。例如,最好支持与运算符交互的线程,而不是让底层 CPU 绑定线程占用 CPU。