Почему у нас есть нижняя и верхняя границы для типов данных в MPI?

Или вопрос можно перефразировать следующим образом:
Зачем нужен тип данных с ненулевой нижней границей?

Рассмотрим следующий пример:

struct S {
  int a;
  int b;
  float c;
  float d;
} array[N];

Если у меня был массив типа S[]и я хотел отправить только значения полей bи
d, Я бы создал datatypeс типом map { (4, MPI_INT), (12, MPI_FLOAT) }.
На первый взгляд кажется, что такой тип можно использовать для корректной отправки массива
struct S:

MPI_Send(array, N, datatype, ...);

Но это не работает, если N > 1.
Такой тип имел бы lb = 4ub = 16и extent = ub - lb = 12. То есть,
MPI будет считать, что второй элемент массива начинается с 12 байт от
первый, который не соответствует действительности.

Ну, это может не иметь большого значения. Ведь, как правило, для таких частично отправленных конструкций
мы должны указать точный размер структуры:

MPI_Type_create_resized(datatype, 0, sizeof(struct S), &resized);

Но мне интересно, почему нам всегда нужно указывать нулевую нижнюю границу. Почему бы
кому-то нужна ненулевая нижняя граница? Типы данных с ненулевыми нижними границами кажутся мне чрезвычайно запутанными, и я не могу понять их смысла.

Если бы я проектировал систему типов для MPI, я бы описал тип с одним
параметр-его размер (экстент), который является шагом между двумя соседними элементами массива. С точки зрения MPI, я бы всегда устанавливал lb = 0и extent = ub. Такая система выглядит для меня гораздо понятнее, и она будет работать правильно в Примере, описанном выше.

Но MPI выбрала другой путь. Вместо этого мы имеем два независимых параметра: Нижний
и верхние границы. Почему это так? Какая польза от этой дополнительной гибкости? Когда следует использовать типы данных с ненулевой нижней границей?

Метки

1 ответ

  1. Вы не представляете, какие странные и сложные структуры можно найти в научных и инженерных кодах. Стандарт разработан, чтобы быть как можно более общим и обеспечить максимальную гибкость. Раздел 4.1.6 маркеры с нижней и верхней границей начинается следующим образом:

    Часто бывает удобно явно определить нижнюю и верхнюю границы карты типов и переопределить определение, данное на стр. 105. Это позволяет определить тип данных, который имеет «отверстия» в его начале или в его конце, или тип данных с записями, которые простираются выше верхней границы или ниже нижней границы. Примеры такого использования приведены в разделе 4.1.14.
    Кроме того, пользователю может потребоваться переопределить [sic] правила выравнивания, используемые для вычисления верхних границ и экстентов. Например, компилятор C может позволить пользователю overide [sic] правила выравнивания по умолчанию для некоторых структур в программе. Пользователь должен явно указать границы типов данных, которые соответствуют этим структурам.

    Простейшим примером типа данных с ненулевой нижней границей является структура с абсолютными адресами, используемыми в качестве смещений, полезных, например, при отправке структур с указателями на данные, разбросанные в памяти. Такой тип данных используется с MPI_BOTTOMуказанным в качестве буфера адресом, который соответствует нижней части пространства памяти (0на большинстве систем). Если нижняя граница будет фиксированной0, то вы должны найти элемент данных с самым низким адресом fist и вычислить все смещения относительно него.

    Другим примером является использование MPI_Type_create_subarrayдля создания типа данных, описывающего поддерево n-мерного массива. С нулевыми нижними границами вы должны будете предоставить указатель на начало поддерева. С ненулевыми нижними границами вы просто даете указатель на начало всего массива. И вы также можете создать смежный тип данных таких типов данных Подрезов, чтобы отправить такие n-мерные «срезы» из N+1-мерного массива.