[英]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.