我正在尝试通过利用尽可能多的计算资源来计算GPU用于sprase矩阵*密集向量乘法的最大吞吐量。
为了实现这个目的,我尝试了两种方法:
在主机上为x和A分配内存。在主机上存储x和A.在设备上为x和A分配内存。将x和A存储在设备上。启动计时器。在循环中通过cusparsecsrmv执行稀疏矩阵*密集向量乘法,并运行cusparsecsrmv NUM_ITERATIONS次。停止计时器。将y从设备复制到主机并检查结果的准确性。
在主机上为x和A分配内存。在主机上存储x和A.为设备上的x和A数组分配内存(即x [NUM_IMPS],A [NUM_IMPS])。将X和A存储在设备上。启动计时器。在循环中通过cusparsecsrmv执行稀疏矩阵*密集向量乘法,并在每个A [i] * x [i]上运行cusparsecsrmv NUM_IMPS次。停止计时器。将[NUM_IMPS-1]从设备复制到主机并检查结果的准确性。
以下是方法1的代码:
// == Start timer for just measuring multiplication ==
QueryPerformanceFrequency(&Frequency1);
QueryPerformanceCounter(&StartingTime1);
// Sparse matrix * dense vector multiplication
/* exercise Level 2 routines (csrmv) */
for (int i = 0; i < NUM_ITERATIONS; i++) {
status = cusparseScsrmv(handle, CUSPARSE_OPERATION_NON_TRANSPOSE, m, n, nnz,
&alpha, descr, cooVal, csrRowPtr, cooColIndex,
&xVal[0], &beta, &y[0]);
}
// == End time for just measuring multiplication ==
QueryPerformanceCounter(&EndingTime1);
ElapsedMicroseconds1.QuadPart = EndingTime1.QuadPart - StartingTime1.QuadPart;
ElapsedMicroseconds1.QuadPart *= 1000000;
ElapsedMicroseconds1.QuadPart /= Frequency1.QuadPart;
以下是方法2的代码:
// == Start timer for just measuring multiplication ==
QueryPerformanceFrequency(&Frequency1);
QueryPerformanceCounter(&StartingTime1);
for (int i = 0; i < NUM_IMPS; i++) {
status = cusparseScsrmv(handle_array[i], CUSPARSE_OPERATION_NON_TRANSPOSE, m, n, nnz,
&alpha, descr_array[i], cooVal_array[i], csrRowPtr_array[i], cooColIndex_array[i],
&xVal_array[i][0], &beta, &y_array[i][0]);
}
// == End time for just measuring multiplication ==
QueryPerformanceCounter(&EndingTime1);
ElapsedMicroseconds1.QuadPart = EndingTime1.QuadPart - StartingTime1.QuadPart;
ElapsedMicroseconds1.QuadPart *= 1000000;
ElapsedMicroseconds1.QuadPart /= Frequency1.QuadPart;
如果NUM_ITERATIONS或NUM_IMPS = 1,则会获得相同的吞吐量。 如果NUM_IMPS = 10,则吞吐量最大化。但是,一旦NUM_IMPS = 100或更多,吞吐量就会开始减少。 与NUM_ITERATIONS类似,它开始增加,但是一旦我将NUM_ITERATIONS设置为超大数字,就说100,000吞吐量将低于NUM_ITERATIONS = 1的吞吐量。
为什么会发生这种情况?我希望在某些时候只能让饱和度达到饱和度,而不能再高,但不会降低。
我的想法是由于多次调用cusparsecsrmv导致GPU陷入困境,或者GPU需要冷却自身以使其速度减慢,因此吞吐量下降,但这些似乎都不是合理的结论。我
答案 0 :(得分:2)
cuSPARSE库函数与异步执行 尊重主机并可能将控制权交还给应用程序 结果准备好之前的主机。开发人员可以使用 cudaDeviceSynchronize()函数确保执行一个 特定的cuSPARSE库例程已经完成。
除了你的计时方式,这里没有任何错误。目前,您只测量将库调用排入队列的时间,而不是测量它们运行的时间。一旦排队了数十或数百个操作,预计排队性能会下降是完全合理的。