Отладчик µVision2. Пример использования пользовательских отладочных функций: определение времени выполнения участка программы

Александр Бельченко
20 мая 2003
В этой статье пойдет речь об использовании пользовательских отладочных функций на примере функции, которая вычисляет длительность выполнения участков отлаживаемой программы.
Пример иллюстрирует информацию из следующих документов:
GS51.pdf: глава 6 «Отладочные функции» (перевод), глава 5 — параграф «Системные переменные» (перевод);
Dbg51.chm: команда DEFINE (перевод)

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

Поставленную цель я достиг несколькими способами: выбором уровня оптимизации компилятора, оптимизацией циклов, переписыванием некоторых стандартных арифметических функций. Каждый раз, изменяя что-то в программе, я запускал симулятор и определял насколько быстрее (или медленее) становилось выполнение алгоритма.

Наверное, описание многих тонкостей такой оптимизации программы заслуживает отдельной статьи. В данный момент я перейду к обещанной отладочной функции. Я написал эту пользовательскую отладочную функцию, когда мне надоело каждый раз при прогонке программы в симуляторе вычислять на калькуляторе сколько же времени тратится на ту или иную часть алгоритма, и где еще есть узкие места, которые требуют более тщательной оптимизации. «Как бы эту нудную ручную работу поручить компьютеру?» — подумал я. Решение сформировалось достаточно быстро, поскольку отладчик µVision2 позволяет создавать пользовательские отладочные функции. Если вы еще не знакомы с отладочными функциями, то можете прочитать про них в главе 6 документа GS51.pdf.

Для упрощения я решил ограничиться задачей определения времени в тактах процессора и в миллисекундах, которое прошло с момента последнего вызова этой функции. При каждом вызове функции запоминалось текущее состояние счетчика тактов процессора states, которое затем использовалось при последующих вызовах функции. Для определения прошедшего времени в миллисекундах достаточно использовать виртуальный регистр CLOCK, который показывает сколько инструкций выполняет процессор за одну секунду. Подробнее о системной переменной states и виртуальном регистре CLOCK вы можете прочитать в параграфе «Системные переменные» из главы 5 документа GS51.pdf (стр.113,114).

Вы можете взять пример (7кБ), в котором используется отладочная функция prog_time(), вычисляющая время в тактах процессора и в миллисекундах. Пример содержит один исходный Си-файл main.c, файл с кратким описанием проекта abstract.txt и файл инициализации p_time.ini для симулятора µVision2. В файле инициализации описывается пользовательская функция prog_time(). Рассмотрим его подробнее. Поясняющих комментариев маловато, но надеюсь, что разобраться в логике работы будет легко.

/*
   Вычисление длительности выполнения в отладчике участков программы
   (с) Александр Бельченко, 2003
*/

define long state_point
state_point = 0

func void prog_time()
{
    long  temp, len;
    float timelen;

    temp    = states;
    len     = temp - state_point;
    timelen = (float)len / (float)clock * 1000.0;
    printf("Длина: %u такт  %8.3f мс\n", len, timelen);
    state_point = temp;
}

define button "Длина","prog_time()"

Как это все работает?

В этом файле определяется глобальный символ state_point, определяется пользовательская функция prog_time() и добавляется кнопка Длина на панель окна Toolbox отладчика.

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

Логика работы пользовательской функции prog_time() достаточно проста: берем текущее значение счетчика тактов процессора states и вычитаем из него предыдущее сохраненное значение. Полученная разница будет искомым временем в тактах процессора. Для определения времени в миллисекундах используется виртуальный регистр clock. Вычисленные значения выводятся на странице Command окна отладчика Output Window при помощи встроенной функции форматированного вывода printf(). Текущее значение счетчика тактов states запоминается в глобальном символе state_point.

Для облегчения вызова пользовательской функции prog_time() командой отладчика DEFINE BUTTON определяется кнопка Длина.

Приведенный файл инициализации Вы можете использовать в своих отладочных сессиях. Для использования файла необходимо или указать его в опциях симулятора ( Options for Target - Debug - Initialization File), или включить его в свой файл инициализации либо загрузить во время отладочной сессии, используя команду отладчика

INCLUDE p_time.ini