Опубликован: 15.04.2008 | Доступ: свободный | Студентов: 1558 / 544 | Оценка: 4.36 / 4.02 | Длительность: 06:55:00
ISBN: 978-5-94774-857-4
Специальности: Программист
Лекция 7:

Средства автоматизированного распараллеливания программ

< Лекция 6 || Лекция 7: 1234

Загрузка данных в общую для всех узлов кластера память в Cluster OpenMP

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

char a[100], b[100]

а затем эти переменные определены как sharable, то следующий параллельный блок в программе выполняться не будет:

#pragma omp parallel for 
for( i=0; i<N; i++ ) 
 { 
   a[i] = b[i]; 
 }

Для динамической загрузки переменных в общую ( sharable ) для всех узлов кластера память в программах, написанных на языке C/C++, можно воспользоваться одной из двух следующих функций:

void * kmp_sharable_malloc ( int size )

или

void * kmp_aligned_sharable_malloc ( int size )

Обе эти функции определяют в динамическом режиме в общей для всех узлов кластера памяти области заданного размера и возвращают адреса этих областей. При этом следует иметь в виду, что вторая из этих функций осуществляет выравнивание выделяемой области памяти по границе страницы и тем самым существенно ускоряет процесс обращения к памяти. Для освобождения выделенной памяти следует использовать функцию

void kmp_sharable_free ( *ptr )

Здесь ptr - указатель на освобождаемую область памяти.

Динамическое выделение памяти в общей ( sharable ) для всех узлов кластера памяти в программах, написанных на языке Fortran, осуществляется следующим образом:

integer, allocatable :: x( : ) 
!dir$ omp sharable (x) 
    allocate( x( 500 ) )

В этом примере в общей для всех узлов кластера памяти динамически размещается целочисленный массив, состоящий из 500 элементов.

В программах, написанных на языке C++, при динамическом размещении переменных и объектов в общей для всех узлов кластера памяти необходимо добавить включение ссылки на файл, в котором описаны переменные sharable. Эта ссылка имеет следующий вид:

#include <kmp_sharable.h>

Теперь рассмотрим вопрос создания динамических объектов в общей для всех узлов кластера памяти. Пусть в исходном тексте программы динамически определяется объект класса zoo, например, следующим образом:

zoo * fp = new zoo (10);

В Cluster OpenMP это определение модифицируется так:

zoo * fp = new kmp_sharable zoo (10);

Теперь рассмотрим вопрос создания класса объектов, динамически размещаемых в общей для всех узлов кластера памяти. Пусть в исходной программе этот класс создавался, например, следующим образом:

class zoo : public zoo_base 
 { 
  // …содержание класса zoo 
 };

В программе, написанной с использованием Cluster OpenMP, создание этого класса осуществляется следующим образом:

class zoo : public zoo_base, public kmp_sharable_base 
 { 
  // …содержание класса zoo 
 };

При динамическом создании STL (Standard Template Library) контейнеров в общей для всех узлов кластера памяти следует иметь в виду, что, во-первых, необходимо описать динамическое размещение контейнера как объекта и, кроме того, необходимо описать динамическое размещение его содержания. Если в исходной программе контейнер создавался, например, следующим образом:

std::vec<int> * vecp = new std :: vec<int>;

то в программе, написанной с использованием ClusterOpenMP, создание такого контейнера должно быть описано, например, так:

std::vec<int,kmp_sharable_allocator<int>>*vecp=new 
kmp_sharable std :: vec<int, kmp_sharable_allocator<int>>;

Настройки отладчиков в Cluster OpenMP

Для отладки многопоточных параллельных программ в Cluster OpenMP можно использовать как бесплатный отладчик GNU gdb, так и лицензионные отладчики idb компании Intel и TotalView компании Etnus. Однако для того, чтобы корректно пользоваться этими отладчиками, необходимо сделать специальные настройки в системных файлах. Далее рассмотрим подробно эти настройки применительно ко всем вышеперечисленным отладчикам. Предварительно отметим, что для корректной работы всех этих отладчиков необходимо отключить прерывание по сигналу ошибки адресации SIGSEGV (Signal Segmentation Violation). Причина в том, что этот сигнал используется для внутренних нужд Cluster OpenMP, поэтому он не является аварийным и не несет информации об ошибках доступа к памяти (в Cluster OpenMP имеется свой собственный обработчик этого сигнала). Отключение этого сигнала производится по-разному для рассматриваемых отладчиков и будет рассмотрено далее. Для всех отладчиков в kmp_cluster.ini-файле необходимо использовать настройку --no-heartbeat, отключающую режим аварийного завершения параллельных потоков при отсутствии в течение определенного промежутка времени ответных сигналов от параллельных потоков. Такими сигналами в Cluster OpenMP постоянно обмениваются все параллельные потоки. Если в течение определенного промежутка времени ответный сигнал от какого-либо потока отсутствует, то это считается свидетельством его аварийного завершения. В этом случае происходит аварийное завершение всех потоков рассматриваемой задачи.

В бесплатном отладчике GNU gdb для отключения сигнала аварийного доступа к памяти, во-первых, необходимо в системном файле .gdbinit, находящемся в домашнем разделе пользователя, добавить строку

handle SIGSEGV nostop noprint

Во-вторых, необходимо определить отладчик с помощью переменной окружения KMP_CLUSTER_DEBUGGER, например следующим образом:

export KMP_CLUSTER_DEBUGGER=gdb

В-третьих, необходимо определить переменную окружения DISPLAY, указывающую на IP-адрес компьютера, с которого стартует X Windows. Эту переменную можно определить либо в kmp_cluster.ini -файле, например так:

DISPLAY= 10.0.6.191:0

либо с помощью команды

export DISPLAY= 10.0.6.191:0

которую следует поместить в системный файл, откуда считываются переменные окружения при старте программы xterm. После запуска отладчика gdb следует набрать команду

break __itmk_segv_break

для перехвата ошибок адресации памяти.

В отладчике idb компании Intel для отключения сигнала аварийного доступа к памяти необходимо в системном файле .dbxinit, находящемся в домашнем разделе пользователя, добавить строку

ignore segv

Во-вторых, необходимо определить отладчик с помощью переменной окружения KMP_CLUSTER_DEBUGGER следующим образом:

export KMP_CLUSTER_DEBUGGER=idb

Переменная окружения DISPLAY для этого отладчика задается так же, как и для отладчика gdb. После запуска отладчика idb следует набрать команду

stop in __itmk_segv_break

для перехвата ошибок адресации памяти.

В отладчике TotalView компании Etnus для отключения сигнала аварийного доступа к памяти необходимо в системном файле .tvdrc, находящемся в домашнем разделе пользователя, добавить строку

dset TV::signal_handling_mode { Resend=SIGSEGV }

После запуска отладчика TotalView следует набрать команду

breakpoint in __itmk_segv_break

для перехвата ошибок адресации памяти.

Настройка динамической памяти при отладке в Cluster OpenMP

При использовании динамической памяти в программах с использованием Cluster OpenMP возможна следующая ошибочная ситуация: некоторые данные одного типа в параллельных потоках размещены в локальной памяти с одними и теми же адресами (т. е. некоторые данные из параллельных потоков симметрично размещены в локальной памяти). При этом указатель на эти данные в одном из параллельных потоков ошибочно передается в другой поток, и из этого последнего потока осуществляется доступ к данным по переданному адресу. В таком случае ошибки доступа к данным может и не возникнуть, т. е. сигнал SIGSEGV не будет инициирован. Однако данные, которые будут извлечены из другого потока, будут неверными для исходного потока. Для

того чтобы выявить такие ошибочные ситуации, в Cluster OpenMP реализован

механизм несимметричного выделения динамической памяти (Disjoint Heap).

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

export KMP_DISJOINT_HEAPSIZE 128M

Здесь была задана область для несимметричного выделения динамической памяти, равная 128 мегабайтам. При выделении размера этой области следует позаботиться о том, чтобы ее размер был не меньше, чем произведение размера области динамической памяти, выделяемой для одного параллельного потока, на число параллельных потоков. В этом случае области динамической памяти в параллельных потоках будут размещены в адресном пространстве без пересечений и наложений. Тогда обращение в каком-либо из параллельных потоков к области динамической памяти по указателю, переданному из другого потока, приведет к ошибке доступа к данным и возникновению сигнала SIGSEGV. Это и будет побудительной причиной более тщательного анализа работы с данными в параллельных потоках для устранения таких некорректных ситуаций.

В заключение отметим, что по умолчанию значение переменной окружения KMP_DISJOINT_HEAPSIZE задается равным 2 мегабайтам. При задании меньшей величины размер KMP_DISJOINT_HEAPSIZE автоматически увеличивается до 2 мегабайт.

Подчеркнем еще раз, что задание переменной окружения KMP_DISJOINT_HEAPSIZE необходимо только на этапе отладки программы для поиска ошибок некорректного обращения к динамической памяти в параллельных потоках. После выявления всех таких ошибок и создания окончательной оптимизированной версии программы эту переменную окружения следует удалить.

Сводка переменных окружения Cluster OpenMP

В предыдущих разделах был уже рассмотрен ряд специфических переменных окружения Cluster OpenMP. Ниже перечислены все переменные окружения, допустимые в Cluster OpenMP, и описаны способы их применения.

  • Переменная окружения KMP_STACKSIZE задает объем стека в параллельных потоках Custer OpenMP. Величина этой переменной задается в килобайтах (К) или мегабайтах (М). По умолчанию значение этой переменной равно .
  • Переменная окружения KMP_SHARABLE_STACKSIZE задает объем стека для размещения sharable (общих для всех узлов кластера) данных для OpenMP потоков. Величина этой переменной задается в килобайтах (К) или мегабайтах (М). По умолчанию значение этой переменной равно .
  • Переменная окружения KMP_STATSFILE задает имя файла статистики при использовании настройки -cluster-openmp-profile. По умолчанию имя этого файла guide.gvs.
  • Задание значения переменной окружения KMP_WARNINGS выключает ( 0 или off ) или включает ( 1 или on ) выдачу сообщений библиотеки выполнения (run-time library) Cluster OpenMP. По умолчанию значение этой переменной равно 1 или on.
  • Задание значения переменной окружения KMP_WARNINGS выключает ( 0 или off ) или включает ( 1 или on ) выдачу предупреждающих сообщений о переменных в параллельных потоках, которые должны быть общими для всех узлов кластера ( sharable ), но не являются таковыми. По умолчанию значение этой переменной равно 0 или off.
  • Переменная окружения KMP_CLUSTER_SETTINGS задает режим вывода переменных окружения и настроек, определенных в kmp_cluster.ini файле. Значения по умолчанию для этой переменной нет.
  • Переменная окружения KMP_CLUSTER_PATH задает путь к kmp_cluster.ini -файлу, если он отсутствует в текущем разделе. По умолчанию в качестве этого пути задается путь к домашнему разделу пользователя.
  • Задание переменной окружения KMP_CLUSTER_HELP позволяет выводить описание настроек, допустимых в kmp_cluster.ini -файле. Значения по умолчанию для этой переменной нет.
  • Переменная окружения KMP_CLUSTER_DEBUGGER задает имя исполняемого файла отладчика (например, idb для отладчика Intel). Значения по умолчанию для этой переменной нет.
  • Переменная окружения KMP_CLUSTER_VERSION задает режим вывода сообщений о версии системы. Значения по умолчанию для этой переменной нет.
  • Переменная окружения KMP_DISJOINT_HEAPSIZE задает значение размера динамической памяти в параллельных потоках и включает механизм Disjoint Heap. Величина этой переменной задается в килобайтах (К) или мегабайтах (М). По умолчанию значение этой переменной равно . Если заданное значение меньше , то оно автоматически увеличивается до .

На этом завершается знакомство c Cluster OpenMP. Отметим, что для изучения дополнительных материалов, оставшихся за рамками данного изложения, следует обратиться к руководству [7.9].

< Лекция 6 || Лекция 7: 1234