MPI_File_write_at : запись одной и той же структуры дважды приводит к немного отличающимся блокам данных в двоичном файле

У меня есть следующий простой код MPI:

#include <iostream>
#include <mpi.h>

int main() {
    struct test {
        int rank = 1;
        double begin = 0.5;
        double end = 0.5;
    };

    MPI_Init(NULL, NULL);
    
    int world_rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);

    int world_size;
    MPI_Comm_size(MPI_COMM_WORLD, &world_size);

    MPI_File fh;
    MPI_Offset offset;
    MPI_Status status;
    MPI_Datatype TIMEDATA_DATATYPE;

    // Create datatype
    int blocklen[3] = {1,1,1};
    MPI_Datatype type[3] = { MPI_INT, MPI_DOUBLE, MPI_DOUBLE };
    MPI_Aint disp[3] = {0, 4, 12};
    MPI_Type_create_struct(3, blocklen, disp, type, &TIMEDATA_DATATYPE);
    MPI_Type_commit(&TIMEDATA_DATATYPE);

    // Open file
    offset = 20*world_rank;

    MPI_File_open(MPI_COMM_WORLD, "test.bin", MPI_MODE_CREATE | MPI_MODE_WRONLY,
            MPI_INFO_NULL, &fh);

    // Write to file
    test t1, t2;
    MPI_File_write_at(fh, offset, &t1, 1, TIMEDATA_DATATYPE, &status);
    MPI_File_write_at(fh, offset, &t2, 1, TIMEDATA_DATATYPE, &status);

    // Close file
    MPI_File_close(&fh);

    MPI_Finalize();
    
    return 0;
}

Запустить и скомпилировать с

mpic++ Test.cpp
mpirun -n 2 a.out 

Итак, в приведенном выше коде я в основном хочу дважды записать в один и тот же файл. Каждый раз с другого процесса. Данные представляют собой структуру формата int, double, double, поэтому 4+8+8=20 байт данных. У нас есть два объекта этой структуры, но оба они инициализированы одинаковыми значениями. Итак, мы записываем два блока по 20 байт данных в файл test.bin, и я ожидаю увидеть эту «симметрию» в двоичном представлении, но получаю: (Я предоставляю два разных вывода двух разных инструментов cli.)

$ xxd test.bin 
00000000: 0100 0000 fe7f 0000 0000 0000 0000 e03f  ...............?
00000010: 0000 e03f 0100 0000 ff7f 0000 0000 0000  ................
00000020: 0000 e03f 0000 0000                      ...?....

$ hexdump test.bin 
0000000 0001 0000 7ffe 0000 0000 0000 0000 3fe0
0000010 0000 0000 0001 0000 7fff 0000 0000 0000
0000020 0000 3fe0 0000 0000                    
0000028

Теперь, если мы посмотрим на вывод xxd, мы увидим:

Первые 20 байт:

  • Целое число: 0100 0000
  • Двойной: fe7f 0000 0000 0000
  • Двойной: 0000 e03f 0000 e03f

Вторые 20 байт:

  • Целое число: 0100 0000
  • Двойной: ff7f 0000 0000 0000
  • Двойной: 0000 e03f 0000 0000

Теперь в основном, я не совсем уверен, почему двойники здесь отличаются.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
174
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вместо:

MPI_Aint disp[3] = {0, 4, 12};

сделайте следующее:

disp[0] = offsetof(test, rank);
disp[1] = offsetof(test, begin);
disp[2] = offsetof(test, end);

не забудьте включить "#include <stddef.h>" и адаптировать смещение (т.е. offset = sizeof(test) * world_rank;)

Не пытайтесь вручную жестко закодировать смещения, лучше использовать offsetof из <stddef.h>, чтобы понять это за вас. Нет никакой гарантии, что отступы, используемые внутри структур, будут соответствовать значениям, которые вы жестко запрограммировали в своем массиве для смещений (т. е. disp).

Заполнение структуры — это концепция в C, которая добавляет один или несколько пустых байтов между адресами памяти для выравнивания данных в памяти. (источник ). Чтобы лучше понять отступы, загляните в эту тему SO

Другие вопросы по теме