当迭代次数增加时,cuSparse 吞吐量下降
cuSparse Throughput goes down when number of iterations increases
我正在尝试通过利用尽可能多的计算资源来计算我的 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 次。停止定时器。将 y[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 可能需要自我冷却以减慢速度,因此吞吐量下降,但这些似乎都不合理给我的结论。
The cuSPARSE library functions are executed asynchronously with
respect to the host and may return control to the application on the
host before the result is ready. Developers can use the
cudaDeviceSynchronize() function to ensure that the execution of a
particular cuSPARSE library routine has completed.
这里没有任何问题,除了你计时的方式。目前,您只测量将库调用排队的时间,而不是 运行 它们的时间。一旦有数十或数百个操作排队,预计排队性能会下降是完全合理的。
我正在尝试通过利用尽可能多的计算资源来计算我的 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 次。停止定时器。将 y[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 可能需要自我冷却以减慢速度,因此吞吐量下降,但这些似乎都不合理给我的结论。
The cuSPARSE library functions are executed asynchronously with respect to the host and may return control to the application on the host before the result is ready. Developers can use the cudaDeviceSynchronize() function to ensure that the execution of a particular cuSPARSE library routine has completed.
这里没有任何问题,除了你计时的方式。目前,您只测量将库调用排队的时间,而不是 运行 它们的时间。一旦有数十或数百个操作排队,预计排队性能会下降是完全合理的。