You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 16:04:57