debugDDr (1158410), страница 4
Текст из файла (страница 4)
Для описания контекста программы служит структура типа CONTEXT, которая содержит такие данные как уровень вложенности цикла или области задач, номер конструкции, ранг цикла и т.д.:
| typedef struct _tag_CONTEXT | ||||
| { | ||||
| byte | Rank; | |||
| byte | Type; | |||
| int | No; | |||
| byte | ItersInit; | |||
| long | Iters[MAXARRAYDIM]; | |||
| s_REGULARSET | Limits[MAXARRAYDIM]; | |||
| } | CONTEXT; | |||
| Rank | – | ранг цикла; | ||
| Type | – | тип конструкции: область задач, параллельный или обычный цикл; | ||
| No | – | уникальный номер конструкции; | ||
| ItersInit | – | определяет, выполнилась ли хотя бы одна итерация цикла или задача из области задач; | ||
| Iters | – | массив текущих значений итерационных перемененных. Для области задач содержит номер текущей выполняющейся задачи. | ||
| Limits | – | массив начальных и конечных значений и шагов приращения итерационных переменных. | ||
Каждая структура типа CONTEXT описывает свой цикл программы или область задач. Последовательный набор таких структур полностью описывает текущий контекст выполнения и порядок вложенности выполняющихся конструкций.
Для хранения последовательности структур CONTEXT в отладчике используется глобальная таблица gContext. При инициализации отладчика, в данную таблицу помещается корневой контекст с номером 0, который соответствует процедуре main() программы.
Рис. 3. Представление контекстов выполнения программы
Для работы с контекстом выполнения предназначен следующий набор функций:
| void cntx_Init(void) |
Функция инициализацирует глобальную таблицу gContext для работы с контекстами. В gContext помещается корневой контекст с номером 0, соответствующий основной ветви программы.
| void cntx_Done(void) |
Функция разрушает глобальную таблицу gContext и освобождает всю память, занятую для работы с контекстами.
| void cntx_LevelInit(int No, byte Rank, byte Type, long* pInit, long* pLast, long* pStep) | ||
| No | – | уникальный номер конструкции; |
| Rank | – | ранг цикла; |
| Type | – | тип конструкции: область задач, параллельный или последовательный цикл; |
| pInit | – | массив начальных значений итерационных переменных цикла; |
| pLast | – | массив конечных значений итерационных переменных цикла; |
| pStep | – | массив шагов приращения итерационных переменных цикла. |
Функция заносит в gContext описание нового контекста. Вызывается при входе программы в область задач, параллельный или последовательный цикл.
| void cntx_LevelDone(void) |
Функция вызывается при завершении текущей исполняющейся конструкции. Удаляет из gContext текущий контекста.
| void cntx_SetIters( AddrType *index , long IndexTypes[] ) | ||
| index | – | массив, содержащий текущие значения итерационных переменных или номер задачи. Размерность массива должна совпадать с рангом текущей конструкции; |
| IndexTypes | – | массив типов индексных переменных. |
Функция изменяет текущие значений итерационных переменных. Вызывается при начале новой итерации цикла или задачи.
| CONTEXT *cntx_CurrentLevel(void) |
Функция возвращает указатель на структуру, описывающую текущий контекст.
| CONTEXT *cntx_GetLevel( long No ) | ||
| No | – | номер контекста. |
Функция возвращает указатель на структуру, описывающую контекст с указанным порядковым номером.
| long cntx_LevelCount(void) |
Функция возвращает величину вложенности контекстов исполнения программы.
| long cntx_GetParallelDepth(void) |
Функция возвращает глубину вложенности параллельных конструкций (параллельных циклов или областей задач) программы.
| int cntx_IsInitParLoop(void) |
Функция возвращает значение, отличное от 0, если началось выполнения тела текущего параллельного цикла.
| long cntx_GetAbsoluteParIter(void) |
Функция вычисляет и возвращает как результат абсолютный индекс текущего витка цикла. Для области параллельных задач функция возвращает текущий номер задачи.
| int cntx_IsParallelLevel(void) |
Функция возвращает значение, отличное от нуля, если в момент вызова функции исполняется хотя бы одна параллельная конструкция.
| CONTEXT* cntx_GetParallelLevel(void) |
Функция возвращает описание самого вложенного выполняющегося параллельного контекста. Если параллельных контекстов нет, то возвращает NULL.
| char *cntx_FormatLevelString( char* Str ) | ||
| Str | – | указатель на начало буфера. |
Функция формирует в строке по адресу Str описание текущего контекста выполнения программы. Возвращает указатель на конец сформированной строки.
4.4.2Функции выдачи диагностики
При обнаружении тех или иных ошибок, динамический контроль выводит пользователю соответствующую диагностику. Диагностика выводится на экран или в файл, в зависимости от параметров динамического контроля и режимов работы системы. При многократном обнаружении одной и той же ошибки в разных витках цикла, ошибка выдается только в первый раз. По завершении программы, динамический контроль выдает итоговую информацию обо всех найденных ошибках с числом их повторений.
Общая структура сообщения об ошибке:
(<process number>)<context> File: <file>, Line: <line>
(<count> times)<error message>
где
<process number> – номер процессора, на котором произошла ошибка. Номер процессора выводится, только при запуске программы на нескольких процессорах.
<context> – контекст, в котором произошла ошибка. Контекст может иметь одну из следующих форм:
Sequential branch – ошибка произошла в последовательной части программы
Loop( No(N1), Iter(I1,I2,…) ), …, Loop( No(Nm), Iter(I1,I2,…) ) – ошибка произошла при выполнения цикла m-степени вложенности.
<file> – имя файла, где произошла ошибка.
<line> – номер строки.
<count> – число повторений данной ошибки в данном контексте. Выводится при итоговой выдаче всех найденных ошибок.
<error message> – описание произошедшей ошибки.
Структура, используемая для хранения описания ошибки:
| typedef struct _tag_ERROR_RECORD | ||||
| { | ||||
| int | StructNo; | |||
| long | CntxNo; | |||
| char | Context[MAX_ERR_CONTEXT]; | |||
| char | Message[MAX_ERR_MESSAGE]; | |||
| char | File[MAX_ERR_FILENAME]; | |||
| unsigned long | Line; | |||
| int | Count; | |||
| } | ERROR_RECORD; | |||
| StructNo | – | номер текущего цикла. Равен -1, если нет текущего цикла; | ||
| CntxNo | – | номер текущего контекста исполнения. Вычисляется как cntx_LevelCount() – 1; | ||
| Context | – | строка с описанием контекста; | ||
| Message | – | строка с описанием ошибки; | ||
| File | – | имя файла; | ||
| Line | – | номер строки; | ||
| Count | – | число ошибок данного типа в данном контексте. | ||
Структура таблицы для накопления диагностических сообщений:
| typedef struct _tag_ERRORTABLE | ||||
| { | ||||
| TABLE | tErrors; | |||
| int | MaxErrors; | |||
| int | ErrCount; | |||
| } | ERRORTABLE; | |||
| tErrors | – | таблица, содержащая элементы типа ERROR_RECORD; | ||
| MaxErrors | – | максимальное число обрабатываемых ошибок; | ||
| ErrCount | – | текущее число произошедших ошибок. | ||
Прототипы функций для работы с диагностикой:
| void error_Init(ERRORTABLE* errTable, int MaxErrors) | ||
| errTable | – | указатель на инициализируемую таблицу диагностики; |
| MaxErrors | – | максимально число обрабатываемых ошибок. |
Функция инициализирует таблицу диагностики.
| void error_Done(ERRORTABLE* errTable) | ||
| errTable | – | указатель на таблицу диагностики |
Деструктор таблицы диагностики. Освобождает память, занятую под таблицу.
| ERROR_RECORD *error_Put(ERRORTABLE* errTable, char* File, unsigned long Line, char* Context, char* Message, int StructNo, long CntxNo) | ||
| errTable | – | указатель на таблицу диагностики; |
| File | – | имя файла; |
| Line | – | номер строки; |
| Context | – | описание контекста; |
| Message | – | сообщение об ошибке; |
| StructNo | – | номер цикла; |
| CntxNo | – | номер контекста исполнения. |
Функция заносит в таблицу диагностики новое сообщение об ошибке.
| ERROR_RECORD *error_Find(ERRORTABLE* errTable, char* File, unsigned long Line, char* Message, int StructNo, long CntxNo) | ||
| errTable | – | указатель на таблицу диагностики; |
| File | – | имя файла; |
| Line | – | номер строки; |
| Message | – | сообщение об ошибке; |
| StructNo | – | номер цикла; |
| CntxNo | – | номер контекста исполнения. |
Функция осуществляет поиск сообщения с заданными параметрами в таблице диагностики.
| byte error_Message(char* To, ERRORTABLE* errTable, char* File, unsigned long Line, char* Context, char* Message) | ||
| To | – | имя файла, куда выводится диагностика. Если равен NULL, то диагностика выводится в поток stderr; |
| errTable | – | указатель на таблицу диагностики; |
| File | – | имя файла; |
| Line | – | номер строки; |
| Context | – | описание контекста; |
| Message | – | сообщение об ошибке. |
Функция помещает сообщение в таблицу диагностики и выводит его на экран, если данное сообщение отсутствует в таблице диагностики. Иначе, для сообщения только увеличивается счетчик количества сообщений.
| byte error_Print(char* To, ERROR_RECORD* pErr) | ||
| To | – | имя файла, куда выводится диагностика. Если равен NULL, то диагностика выводится в поток stderr; |
| pErr | – | указатель на структуру, описывающую диагностику. |
Функция выдает сообщение в указанный файл.
| void error_PrintAll( char *To, ERRORTABLE *errTable ) | ||
| To | – | имя файла, куда выводится диагностика. Если равен NULL, то диагностика выводится в поток stderr; |
| errTable | – | указатель на таблицу диагностики. |
Функция выдет все диагностические сообщения из таблицы диагностики в указанный файл.
| void error_DynControl( int code, ... ) | ||
| code | – | код ошибки |
Функция выдает диагностику с указанным кодом для модуля динамического контроля.
| void error_DynControlPrintAll(void) |
Функция выдает все диагностические сообщения модуля динамического контроля.
| void error_CmpTrace( char *File, unsigned long Line, int code ) | ||
| File | – | имя файла трассировки |
| Line | – | номер строки трассировки |
| code | – | код ошибки |
Функция выдает диагностику с указанным кодом для модуля сравнения результатов выполнения при обработке файла трассировки.
| void error_CmpTraceExt( long RecordNo, char *File, unsigned long Line, int code, ... ) | ||
| RecordNo | – | номер записи в файле трассировки |
| File | – | имя файла |
| Line | – | номер строки |
| code | – | код ошибки |
Функция выдает диагностику с указанным кодом для модуля сравнения результатов выполнения.
| void error_CmpTracePrintAll(void) |
Функция выдает все диагностические сообщения модуля сравнения результатов выполнения.
5Метод контроля DVM-указаний
Все данные, которые могут использоваться в DVM-программе, разделяются на следующие классы:
-
Приватные переменные. Каждый параллельная ветвь (группа витков параллельного цикла) и каждая параллельная задача имеет свою локальную копию переменной и работает только с ней. При входе и выходе из параллельной конструкции переменная имеет неопределенное значение. Использование таких переменных в каждой задаче и в каждом витке цикла должно начинаться с их инициализации.
-
Неизменяемые переменные. К этому классу относятся переменные, значения которых внутри параллельной конструкции используются только на чтение.
-
Редукционные переменные. Каждая параллельная ветвь обладает своей локальной копией переменной. При выходе из параллельной конструкции над всеми локальными значениями выполняется указанная операция редукции, и полученное значение рассылается всем ветвям.
-
Распределенный массив. Элементы массива распределены по разным процессорам. Каждая параллельная ветвь может читать и модифицировать только те элементы, которые расположены на том же процессоре, на котором эта ветвь выполняется, а также читать элементы теневых граней.
-
Буфер удаленных элементов. Для каждого процессора содержит некоторую секцию элементов распределенного массива, доступную только на чтение.
Исходя из этих классов данных, строятся алгоритмы проверки.
5.1Контроль инициализации переменных и элементов массивов
Данный контроль осуществляется для всех классов переменных. Каждой переменной соответствует флаг ее инициализации (массиву соответствует массив флагов). Данный флаг устанавливается при записи нового значения в переменную или элемент массива. При чтении переменной или элемента массива проверяется состояние данного флага, и если он не установлен, то диагностируется ошибка использования неинициализированных данных.
5.2Контроль доступа к элементам распределенного массива
Проверка зависимости цикла по данным осуществляется только при обращении к элементам распределенного массива. Витки параллельного цикла могут зависеть друг от друга из-за использования в них редукционных переменных, однако, в этом случае зависимость по данным не препятствует параллельному выполнению цикла и должна быть объявлена программистом при спецификации параллельного цикла. При отсутствии такого объявления, переменная будет рассматриваться как приватная, и будет зафиксирована ошибка использования приватной переменной (см. ниже).















