<<< BACK NEXT >>>

ОТЛАДКА ПРОГРАММ, ОТЛАДЧИКИ

   Проблема отладки параллельных программ является одной из самых трудноразрешимых в области параллельных вычислений. Ключевой причиной этого является жесткая зависимость проблем сбора и отслеживания информации о параллельных вычислениях от тех моделей параллелизма, которые выбраны в качестве основы. Так, при разработке средств отладки необходимо учитывать (и учитывается, см. [] ):
   - принципы распределения/интеграции событий в параллельной системе;
   - принципы распределения/интеграции памяти (оперативной и внешней);
   - принципы исполнения параллельных процессов, и в первую очередь, систему
     распределения процессов, принципы синхронизации.
   Виртуальная машина Caper имеет возможность выполнения программы в отладочном режиме. Одновременно, в Caper заложен принцип выборочной (управляемой) отладки: используя команды препроцессирования компилятора

#debug
. . .
#nodebug

мы можем отметить фрагмент исходного кода, который будет откомпилирован для выполнения в режиме отладки. Отсутствие #nodebug приведет к компиляции для режима отладки всего кода, начинающегося непосредственно за #debug до конца модуля (компилятор сам порождает инструкцию #nodebug в конце модуля).
   Принцип выполнения программы в режиме отладки заключается в вызове блока, определенного в качестве отладчика, каждый раз после выполнения команды, расположенной в отлаживаемом фрагменте программы. То есть в Caper процедура отладки назначается:

   SetDebugger( <указание блока>, <идентификатор процесса>, <директория
                отладчика>, y0, x0, y1, x1 )

<указание блока> - блок, вызываемый в качестве отладчика;
<идентификатор процесса> - числовой идентификатор параллельного процесса, из которого (будет использован стек вызова данного процесса) будет вызываться бок-отладчик. Данный параметр может быть опущен (или NULL), и тогда отладчик будет вызываться в текущем (активном на данный момент) процессе.
<директория отладчика> - директория, в которой находятся файлы отладчика.
y0, x0, y1, x1 – координаты “горячей области” окна программы. Клик мышки в данной области приведет к вызову блока – отладчика.
   Процесс отладки может быть управляем:

   SetDebugStatus( <режим> )

где <режим> - число, определяющее включение (режим = 1) режима отладки или его отключение (режим = 0).
   Блок-отладчик должны иметь определенные параметры, значения которых ему будут переданы виртуальной машиной:

   Параметр 1: число – вариант вызова; 2 – перерисовка окна отладчика; иное  
               значение – генерация окна отладчика.
   Параметр 2: указание блока, из которого вызывается отладчик;
   Параметр 3: номер команды псевдоассемблера в данном блоке;
   Параметр 4: символическое имя блока;
   Параметр 5: адрес массива параметров текущего блока;
   Параметр 6: адрес пула локальных параметров;
   Параметр 7: числовой идентификатор блока;
   Параметр 8: адрес стека вызовов текущего процесса;
   Параметр 9: значение текущей позиции в стеке вызовов;
   Параметр 10: указание строки исходного текста модуля, в котором расположен
               данный блок;
   Параметр 11: смещение от начала исходного кода модуля (количество символов)
               к текущей исполняемой команде;
   Параметр 12: длина записи команды;
   Параметр 13: номер текущего параллельного процесса;
   Параметр 14: имя файла – модуля исходного кода;
   Параметр 15: номер предыдущей откомпилированной для отладки команды (в
               порядковом расположении, а не контексте выполнения);
   Параметр 16: порядковый номер данной команды исходного текста в нумерации
               компилятора;
   Параметр 17: код ошибки выполнения (если таковая случилась);
   Параметр 18: уточненный код ошибки;
   Параметр 19: код команды псевдоассемблера;
   Параметр 20: тип первого операнда команды псевдоассемблера;
   Параметр 21: базовая составляющая адреса первого операнда команды
               псевдоассемблера;
   Параметр 22: индексная составляющая адреса первого операнда команды
               псевдоассемблера;
   Параметр 23: тип второго операнда команды псевдоассемблера;
   Параметр 24: базовая составляющая адреса второго операнда команды
               псевдоассемблера;
   Параметр 25: индексная составляющая адреса второго операнда команды
               псевдоассемблера;
   Параметр 26: указание переменной результата трехадресной команды
               псевдоассемблера.

   Таким образом, отладка в Caper может быть организована следующим образом:

Пример:
   Пусть задан фрагмент кода программы

#macro   DEBUGGER_ACTIVE   1
#macro   DEBUGGER_PASSIVE  0

#debug  

* мы определили два варианта отладчиков, выбор которых регулируется параметром

  InitiateDebugger( 1 ) ;* включаем первый вариант отладчика

  private <int> sum1 := 0’F, <int> ind := 0

  while ( ind += 1 ) < 10
    sum += i
  endw

InitiateDebugger( 2 ) ;* включаем второй вариант отладчика

  Sum /= Something()
  . . .
  InitiateDebugger( 3 ) ;* выключаем режим отладки (см. текст процедуры)
  . . .
#nodebug
  . . .
  return sum

 

/* Initiate debugger */
flick InitiateDebugger static ( variant )

switch variant
  case 1
    SetDebugger( Debugger ) ;* остальные параметры функции могут быть опущены,
                          ;* в этом случае вызов будет осуществляться из
                          ;* текущего процесса, директорией отладчика является
                          ;* текущая директория, зона реакции на интерактивный
                          ;* клик тоже отсутствует.

    break

case 2
* здесь определены директория отладчика и координаты зоны реакции на mouse click
    SetDebugger( Tracer, null, “c:\myDebugFolder\”, 10, 20, 40, 60 )
    break

   case 3
    SetDebugStatus( DEBUGGER_PASSIVE ) ;* дезактивируем отладчик
    return
   ends

   SetDebugStatus( DEBUGGER_ACTIVE ) ;* прямо активируем отладчик
endflick

 

/* block of debugging: debugger */
block Debugger static ( style, cmndArray, curCmnd, bl_name, inputParams,      =>                       
                        locals, blDescr, stack, stackCounter, source,         =>
                        offset, lenght, paralllProcNum, srcFileName, srcTxt,  =>
                        prevCmnd, txtStrNumb, errCode1, errCode2, opc, type1, => 
                        base1, ind1, type2, base1, ind1, resVar )

 

   . . .
endblock

/* the second block of debugging */
block Tracer static ( style, cmndArray, curCmnd, bl_name, inputParams,        =>                       
                        locals, blDescr, stack, stackCounter, source,         =>
                        offset, lenght, paralllProcNum, srcFileName, srcTxt,  =>
                        prevCmnd, txtStrNumb, errCode1, errCode2, opc, type1, => 
                        base1, ind1, type2, base1, ind1, resVar )

 

   . . .
endblock

 

//
func Something
  . . .
endfunc

   Итак, процедурой InitiateDebugger назначаются отладчики (в последнем случае вызова режим отладки будет выключен). После каждой команды, начиная с первого оператора private, будет вызываться процедура Debugger, которая будет получать
полную информацию о состоянии программы и виртуальной машины. Анализ и реакция по результатам анализа текущей команды и состояния программы в целом могут быть выражены в совершенно различных видах: мы можем отобразить результаты анализа в некотором виде, можем принять управляющие действия по функционированию программы, можем вести журнал трассировки и прочая, прочая, прочая.
   После завершения цикла while будет включен отладчик Tracer, который может анализировать работу программы уже в другом (в отличии от Debugger) стиле. Следующие за #nodebug команды уже не будут выполняться в режиме отладки.
   Следующие две функции виртуальной машины обеспечивают получение текущего статуса режима отладки

     GetDebugStatus()

и получение текущих значений переменных программы в массивах:

     GetDebuggedParm(  <тип данных>, <адрес переменной1> , <адрес переменной2> )

GetDebuggedParm возвращает массив имен переменных в <адрес переменной 1> и их значений в
<адрес переменной 2>. Тип переменных – параметры, локальные переменные, private-переменные 
и public-переменные указывается первым параметром.

#macro  DEBUG_PARAMETERS   0
#macro  DEBUG_LOCAL                1
#macro  DEBUG_PRIVATE            2
#macro  DEBUG_PUBLIC              3

  private <var> [] varNames, <var> [] varValues

    GetDebuggedParm(  DEBUG_LOCAL,  @varNames , @varValues )

varNames  будет содержать массив строк - имен локальных переменных, varValues – массив их значений. Если локальные переменные не были определены, то обе переменные будут не определены (равны NULL).

   Заметим, что нынешняя реализация Caper сопровождается набором написанных на нем утилитарных модулей, которые обеспечивают типовые решения по тем или иным функциям, а именно, созданы модули, обеспечивающие работу: с экраном, графические операции, операции с файлами, а также средства анализа и отображения ошибок и типовую отладку. Прагматика использования модуля отладки предполагает два стиля: загрузку модуля с определенного момента и сохранение его в памяти до завершения программы, и загрузку модуля с отладчиком только в нужных точках программы, анализ ее фрагмента и выгрузку после завершения отлаживаемого фрагмента.
   Как уже отмечалось, отладка параллельных вычислений требует множества решений нетривиальных проблем, и в первую очередь, сопряжена с выбором той или иной модели. Так, согласно представленной схеме отладка ведется во вторичном режиме
(отладчик вызывается из активной прикладной программы), в то время как отладчик может доминировать, т.е. регулировать процесс выполнения программы. Одновременно, отладчик последовательно вызывается из текущей исполняемой процедуры. Однако, возможна схема, когда отладчик является еще одним параллельным процессом, “подсматривающим” за другими.
   Обсуждение возможностей реализации схем отладки является самостоятельным и очень объемным предметом и здесь опускается. Заметим только, что они реализуемы в Caper на основе тех средств, которые были представлены выше.

<<< BACK NEXT >>>