[英]What causes my array address to be corrupted (change) when passed to function?
我正在执行压缩稀疏原始矩阵向量乘法(CSR SPMV):这涉及将数组A分成多个块,然后通过引用函数传递这个块,但是只有数组的第一部分( A[0]第一个块开始数组的开头)被修改。 然而,从第二个循环A[0 + chunkIndex] 开始,当函数读取子数组时,它会跳转并读取超出总数组地址范围的不同地址,尽管索引是正确的。
以供参考:
SPMV内核是:
void serial_matvec(size_t TS, double *A, int *JA, int *IA, double *X, double *Y)
{
double sum;
for (int i = 0; i < TS; ++i)
{
sum = 0.0;
for (int j = IA[i]; j < IA[i + 1]; ++j)
{
sum += A[j] * X[JA[j]]; // the error is here , the function reads diffrent
// address of A, and JA, so the access
// will be out-of-bound
}
Y[i] = sum;
}
}
它被称为这样:
int chunkIndex = 0;
for(size_t k = 0; k < rows/TS; ++k)
{
chunkIndex = IA[k * TS];
serial_matvec(TS, &A[chunkIndex], &JA[chunkIndex], &IA[k*TS], &X[0], &Y[k*TS]);
}
假设我处理(8x8) Matrix ,并且每个块处理2 行,因此循环k将是Rows /TS = 4 loops ,传递给函数的chunkIndex和数组将如下所示:
chunkIndex: 0 --> 循环 k = 0, &A[0], &JA[0]
chunkIndex: --> loop k = 1, &A[16], &JA[16] //[此处出错,函数读取不同地址]
chunkIndex: --> loop k = 2, &A[32], &JA[32] //[此处出错,函数读取不同地址]
chunkIndex: --> loop k = 3, &A[48], &JA[48] //[此处出错,函数读取不同地址]
当我运行代码时,只有第一个块正确执行,其他 3 个块内存已损坏,数组指针跳入超出数组大小的边界。
我已经手动检查了所有参数的所有索引,它们都是正确的,但是当我打印地址时,它们不一样。 (现在调试这个 3 天)
我使用了valgrind
,它报告了:
大小 8 的无效读取和使用大小 8的未初始化值总和 += A[j] * X[JA[j]]; 线
我用-g -fsanitize=address
编译它,我得到了
堆缓冲区溢出
我试图在函数之外手动访问这些块,它们是正确的,那么什么会导致堆内存像这样损坏呢?
代码在这里,这是我能做的最低限度。
问题是我在索引传递给函数的数组部分( chunk
)时使用了全局索引(main 内的索引) ,因此出现了越界问题。
解决方案是在每次函数调用时从0
开始索引子数组,但我遇到了另一个问题。 在每次函数调用时,我处理TS
行,每一行都有不同数量的非零。
举个例子,看图片, chunk 1
,抱歉我的笔迹不好,这样更容易。 如您所见,我们将需要3 indices
,一个用于每个块i
处理的TS
行,另一个是因为每行具有不同数量的非零j
,第三个用于索引传递的子数组l
,这是原来的问题。
并且serial_matvec
函数将如下所示:
void serial_matvec(size_t TS, const double *A, const int *JA, const int *IA,
const double *X, double *Y) {
int l = 0;
for (int i = 0; i < TS; ++i) {
for (int j = 0; j < (IA[i + 1] - IA[i]); ++j) {
Y[i] += A[l] * X[JA[l]];
l++;
}
}
}
带有测试的完整代码在这里如果有人有更优雅的解决方案,我们非常欢迎您。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.