MPI排序4字节整数代码出现内存范围重叠错误的修复求助
MPI并行排序代码内存重叠错误的修复方案
错误信息
Assertion failed in file src/mpi/misc/utils.c at line 55: FALSE
memcpy argument memory ranges overlap, dst_=0x555f7f95b820 src_=0x555f7f9569f0 len_=80000
internal ABORT - process 0
问题代码
#include <stdio.h> #include <stdlib.h> #include <mpi.h> #define MAX 999 #define BUFFER_SIZE 1000 #define BLOCK_SIZE (BUFFER_SIZE / sizeof(int)) int main(int argc, char **argv) { int rank, size; int *buffer, *local_counts, *local_data; int count[MAX + 1] = {0}; char file_name[256]; MPI_Offset file_size, local_size, offset; MPI_File file; MPI_Status status; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); if (rank == 0) { printf("Enter a file name: "); scanf("%s", file_name); MPI_File_open(MPI_COMM_SELF, file_name, MPI_MODE_RDONLY, MPI_INFO_NULL, &file); MPI_File_get_size(file, &file_size); buffer = (int *)malloc(file_size); MPI_File_read(file, buffer, file_size / sizeof(int), MPI_INT, &status); MPI_File_close(&file); local_size = file_size / size; local_counts = (int *)calloc(MAX + 1, sizeof(int)); } MPI_Bcast(&local_size, 1, MPI_INT, 0, MPI_COMM_WORLD); local_data = (int *)malloc(local_size * sizeof(int)); MPI_Scatter(buffer, local_size, MPI_INT, local_data, local_size, MPI_INT, 0, MPI_COMM_WORLD); for (int i = 0; i < local_size; i++) { count[local_data[i]]++; } local_counts = (int *)malloc((MAX + 1) * size * sizeof(int)); MPI_Gather(count, MAX + 1, MPI_INT, local_counts, MAX + 1, MPI_INT, 0, MPI_COMM_WORLD); if (rank == 0) { int total[MAX + 1] = {0}; for (int i = 0; i < size; i++) { for (int j = 0; j <= MAX; j++) { total[j] += local_counts[i * (MAX + 1) + j]; } } for (int i = 1; i < MAX; i++) { total[i] += total[i - 1]; } MPI_File_open(MPI_COMM_SELF, file_name, MPI_MODE_WRONLY, MPI_INFO_NULL, &file); offset = 0; MPI_File_write_at(file, offset, total, MAX + 1, MPI_INT, &status); offset += (MAX + 1) * sizeof(int); MPI_File_write_at_all(file, offset, buffer, file_size / sizeof(int), MPI_INT, &status); MPI_File_close(&file); } MPI_Finalize(); return 0; }
错误根源
触发内存重叠的核心原因是**local_size的计算逻辑混淆了字节数与MPI元素个数**:
- 代码中
local_size = file_size / size计算的是每个进程分配的字节数,但MPI_Scatter的第二个参数要求的是MPI_INT类型的元素个数(每个元素占4字节)。 - 当
MPI_Scatter尝试发送local_size个int元素时,实际操作的字节数是local_size * sizeof(int),远大于buffer的实际大小,导致内存越界,进而触发内存重叠断言。
修复步骤
1. 修正local_size计算逻辑
在rank=0的代码块中,先计算文件中的总int元素个数,再按进程数拆分:
int total_elements = file_size / sizeof(int); local_size = total_elements / size;
这样local_size表示每个进程要处理的int元素个数,符合MPI_Scatter的参数要求。
2. 清理冗余内存分配
rank=0中local_counts被先后用calloc和malloc两次分配,造成内存泄漏,直接移除第一次的calloc调用:
// 移除该行:local_counts = (int *)calloc(MAX + 1, sizeof(int));
3. 初始化非root进程的指针
非rank=0进程中buffer未初始化,虽然MPI标准允许忽略非root进程的MPI_Scatter源参数,但为避免潜在的实现级错误,将指针初始化为NULL:
int *buffer = NULL, *local_counts = NULL, *local_data = NULL;
4. 补全计数排序逻辑(功能修复)
原代码仅计算了前缀和,未完成实际排序,需补充根据前缀和数组重新排列元素的步骤,确保输出排序后的结果。
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <mpi.h> #define MAX 999 #define BUFFER_SIZE 1000 #define BLOCK_SIZE (BUFFER_SIZE / sizeof(int)) int main(int argc, char **argv) { int rank, size; int *buffer = NULL, *local_counts = NULL, *local_data = NULL; int count[MAX + 1] = {0}; char file_name[256]; MPI_Offset file_size, local_size, offset; MPI_File file; MPI_Status status; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); if (rank == 0) { printf("Enter a file name: "); scanf("%s", file_name); MPI_File_open(MPI_COMM_SELF, file_name, MPI_MODE_RDONLY, MPI_INFO_NULL, &file); MPI_File_get_size(file, &file_size); int total_elements = file_size / sizeof(int); buffer = (int *)malloc(file_size); MPI_File_read(file, buffer, total_elements, MPI_INT, &status); MPI_File_close(&file); local_size = total_elements / size; } MPI_Bcast(&local_size, 1, MPI_INT, 0, MPI_COMM_WORLD); local_data = (int *)malloc(local_size * sizeof(int)); MPI_Scatter(buffer, local_size, MPI_INT, local_data, local_size, MPI_INT, 0, MPI_COMM_WORLD); for (int i = 0; i < local_size; i++) { count[local_data[i]]++; } local_counts = (int *)malloc((MAX + 1) * size * sizeof(int)); MPI_Gather(count, MAX + 1, MPI_INT, local_counts, MAX + 1, MPI_INT, 0, MPI_COMM_WORLD); if (rank == 0) { int total[MAX + 1] = {0}; for (int i = 0; i < size; i++) { for (int j = 0; j <= MAX; j++) { total[j] += local_counts[i * (MAX + 1) + j]; } } // 修正前缀和计算(覆盖所有元素) for (int i = 1; i <= MAX; i++) { total[i] += total[i - 1]; } // 生成排序后的数组 int total_elements = file_size / sizeof(int); int *sorted_buffer = (int *)malloc(file_size); for (int i = total_elements - 1; i >= 0; i--) { sorted_buffer[--total[buffer[i]]] = buffer[i]; } // 写入排序结果 MPI_File_open(MPI_COMM_SELF, file_name, MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_INFO_NULL, &file); offset = 0; MPI_File_write_at(file, offset, sorted_buffer, total_elements, MPI_INT, &status); MPI_File_close(&file); free(sorted_buffer); free(buffer); } free(local_data); free(local_counts); MPI_Finalize(); return 0; }
内容的提问来源于stack exchange,提问作者Sebastian Llaurador
相关产品推荐
相关产品推荐

