VDK API для получения информации инструментальной сборки Печать
Добавил(а) microsin   

Отладочная информация, которую собирает инструментальная сборка приложения VDK (эта информация отображается выбором пунктов меню View -> VDK Windows во время работы сессии отладки, см. [3, 4]), может быть доступна в коде приложения с помощью вызовов соответствующего API.

Функция Краткое описание Thread Kernel ISR Startup
GetClockFrequency Получение тактовой частоты ядра в МГц. + - - +
SetClockFrequency Установка тактовой частоты ядра в МГц. + - - +
GetContextRecordSize Показывает размер памяти для потока, необходимой для сохранения контекста при переключениях между потоками. + + + +
GetHeapIndex Получение индекса кучи по его идентификатору VDK. + - - -
GetThreadHandle Получение указателя на контекст потока. + - - -
GetThreadID Получение идентификатора текущего активного потока. + - - -
GetThreadStackUsage Получение информации по максимальному использованию стека потока. + - - -
GetThreadStack2Usage То же самое, что и GetThreadStackUsage, только для потоков систем, где применяются процессоры с двумя стеками. + - - -
InstrumentStack Запуск сбора статистики по стеку потока. + - - -
GetThreadStatus Получение состояния потока (активен, заблокирован, готов к запуску). + - - -
GetTickPeriod Получение длительности тика в миллисекундах. + + + +
SetTickPeriod Установка длительности тика в миллисекундах. + - - +
GetUptime Сколько система проработала времени, в тиках. + + + +
GetVersion Получение информации о библиотеках VDK. + + + +
LogHistoryEvent Запись в лог информации. + + - -
ReplaceHistorySubroutine Замена встроенной процедуры записи в лог на пользовательскую функцию. + + - -

В столбцах Thread, Kernel, ISR и Startup показана доступность функции соответственно в коде потока, коде ядра, коде обработчика прерывания и коде начального запуска ("+" функцию можно использовать, "-" функция не доступна).

//Прототип C:
unsigned int VDK_GetClockFrequency (void);
 
//Прототип C++:
unsigned int VDK::GetClockFrequency (void);

Возвращает тактовую частоту (в мегагерцах). Значение частоты указывается как часть конфигурации проекта VDK, и это значение можно поменять runtime вызовом функции SetClockFrequency(). В зоне ответственности разработчика гарантировать соответствие этой частоты используемому аппаратному обеспечению. Функция GetClockFrequency не вовлекает планировщик, и время выполнения этой функции фиксированное.

Примечание: реальное значение тактовой частоты процессора может не соответствовать значению, которое вернет функция GetClockFrequency. Например, если использовался библиотечный модуль управления питанием системных служб (services.h), и частота процессора была установлена вызовом функции adi_pwr_Init, то реальную частоту CPU и системной шины можно получить вызовом функции adi_pwr_GetFreq.

//Прототип C:
void VDK_SetClockFrequency(unsigned int inFrequency);
 
//Прототип C++:
void VDK::SetClockFrequency(unsigned int inFrequency);

Установит тактовую частоту в мегагерцах, равной значению параметра inFrequency. Тактирование останавливается, параметры тактирования пересчитываются с использованием новой частоты тактирования, после чего тактирование возобновляется. В зоне ответственности разработчика гарантировать соответствие этой частоты используемому аппаратному обеспечению. Функция GetClockFrequency не вовлекает планировщик, и время выполнения этой функции не определенное.

//Прототип C:
unsigned int VDK_GetContextRecordSize(void);
 
//Прототип C++:
unsigned int VDK::GetContextRecordSize(void);

Это API применимо только для процессоров Blackfin и SHARC. Функция вернет размер области памяти, требуемой для сохранения информации потоков во время переключения контекста.

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

Функция GetContextRecordSize не вызывает запуск планировщика, и её время выполнения фиксировано.

//Прототип C:
unsigned int VDK_GetHeapIndex(VDK_HeapID inHeapID);
 
//Прототип C++:
unsigned int VDK::GetHeapIndex(VDK::HeapID inHeapID);

Транслирует идентификатор кучи HeapID (как он был сконфигурирован на закладке Kernel окна свойств проекта VDK) в индекс кучи, который можно передать функциям heap_malloc(), heap_calloc(), heap_realloc() и heap_free() [2].

Функция GetHeapIndex не вызывает запуск планировщика, и её время выполнения фиксировано.

Обработка ошибок с применением инструментальной сборки: значение ошибки kInvalidHeapID покажет, что inHeapID является недопустимым идентификатором кучи.

//Прототип C:
void** VDK_GetThreadHandle(void);
 
//Прототип C++:
void** VDK::GetThreadHandle(void);

Вернет указатель на выделенный указатель данных на поток, определенный пользователем. Этот указатель может быть использован в потоках C или ассемблера для удержания локального состояния потока; например, через него может быть получен доступ к переменным потока (member variables).

Функция GetThreadHandle не вызывает запуск планировщика, и её время выполнения фиксировано.

//Прототип C:
VDK_ThreadID VDK_GetThreadID(void);
 
//Прототип C++:
VDK::ThreadID VDK::GetThreadID(void);

Вернет идентификатор текущего работающего потока, или вернет VDK_KERNEL_LEVEL_, если функция отработала на уровне ядра. Функция не вызывает запуск планировщика, и её время выполнения фиксировано.

//Прототип C:
unsigned int VDK_GetThreadStackUsage(const VDK_ThreadID inThreadID);
 
//Прототип C++:
unsigned int VDK::GetThreadStackUsage(const VDK::ThreadID inThreadID);

Получает информацию по максимальному использованию стека указанного потока в момент вызова функции (размер стека будет возвращен в 32-битных словах). Для приложений, которые были собраны с установкой "Full Instrumentation", будет возвращено максимальное использование стека либо с момента создания потока, либо с момента последнего API-вызова InstrumentStack(). Для приложений, которые были собраны не с установкой "Full Instrumentation", информация о стеке потоков по умолчанию недоступна. Таким образом, эта функция не вернет какую-либо значимую информацию в этих случаях, за исключением случая, когда ранее была вызвана функция InstrumentStack() для сбора инструментальной информации по стеку потоков.

Функция GetThreadStackUsage не вызывает запуск планировщика, и её время выполнения не определено.

Обработка ошибок с применением инструментальной сборки: значение ошибки kUnknownThread покажет, что в параметре был передан недопустимый идентификатор потока.

//Прототип C:
unsigned int VDK_GetThreadStack2Usage(const VDK_ThreadID inThreadID);
 
//Прототип C++:
unsigned int VDK::GetThreadStack2Usage(const VDK::ThreadID inThreadID);

Вернет максимальное используемое пространство стека stack2 для указанного потока в момент вызова функции (размер стека будет возвращен в 32-битных словах). Для приложений, которые были собраны с установкой "Full Instrumentation", будет возвращено максимальное использование стека либо с момента создания потока, либо с момента последнего API-вызова InstrumentStack(). Для приложений, которые были собраны не с установкой "Full Instrumentation", информация о стеке потоков по умолчанию недоступна. Таким образом, эта функция не вернет какую-либо значимую информацию в этих случаях, за исключением случая, когда ранее была вызвана функция InstrumentStack() для сбора инструментальной информации по стеку потоков.

Примечание: это API применимо только к некоторым процессорам, которые используют два стека. В настоящий момент это семейство процессоров ADSP-TSxxx.

Функция GetThreadStack2Usage не вызывает запуск планировщика, и её время выполнения не определено.

Обработка ошибок с применением инструментальной сборки: значение ошибки kUnknownThread покажет, что в параметре был передан недопустимый идентификатор потока.

//Прототип C:
void VDK_InstrumentStack(void);
 
//Прототип C++:
void VDK::InstrumentStack(void);

Запускает сбор информации по стеку вызвавшего потока, чтобы впоследствии можно было определить максимальный объем стека, который использовал поток. API-вызов GetThreadStackUsage() возвратит максимальное использование стека, для которого был запущен сбор инструментальной информации.

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

Функция InstrumentStack не вызывает запуск планировщика, и её время выполнения не определено.

//Прототип C:
VDK_ThreadStatus VDK_GetThreadStatus(const VDK_ThreadID inThreadID);
 
//Прототип C++:
VDK::ThreadStatus VDK::GetThreadStatus(const VDK::ThreadID inThreadID);

Вернет состояние (одно из значений перечисления) указанного потока. Если поток не существует, то вернет VDK::kUnknown.

Функция GetThreadStatus не вызывает запуск планировщика, и её время выполнения фиксированное.

//Прототип C:
float VDK_GetTickPeriod(void);
 
//Прототип C++:
float VDK::GetTickPeriod(void);

Вернет значение периода тика приложения в миллисекундах.

Функция GetTickPeriod не вызывает запуск планировщика, и её время выполнения фиксированное.

//Прототип C:
void VDK_SetTickPeriod(float inPeriod);
 
//Прототип C++:
void VDK::SetTickPeriod(float inPeriod);

Устанавливает период типа в inPeriod миллисекунд. Тактирование останавливается, и параметры тактирования вычисляются заново для новой длительности тика, после чего тактирование возобновляется.

Функция SetTickPeriod не вызывает запуск планировщика, и её время выполнения не определено.

//Прототип C:
VDK_Ticks VDK_GetUptime(void);
 
//Прототип C++:
VDK::Ticks VDK::GetUptime(void);

Вернет время работы приложения в тиках начиная от момента последнего сброса системы.

Функция GetUptime не вызывает запуск планировщика, и её время выполнения фиксированное.

//Прототип C:
VDK_VersionStruct VDK_GetVersion(void);
 
//Прототип C++:
VDK::VersionStruct VDK::GetVersion(void);

Вернет текущую версию VDK.

Тип VersionStruct это структура, содержащая 4 целых числа. Числа описывают системные параметры: номер версии VDK API, поддерживаемое семейство процессоров, базовый поддерживаемый процессор и номер сборки.

//Прототип C++:
typedef struct
{
   int mAPIVersion;
   VDK::DSP_Family mFamily;
   VDK::DSP_Product mProduct;
   long mBuildNumber;
} VDK::VersionStruct;

mAPIVersion это целое число в формате 0xMMmmUURR, где MM это главный номер версии (major version number), mm это младший номер версии (minor version number), UU это номер обновления (update number), и RR зарезервировано для будущего использования. Поле mAPIVersion не меняется в любом релизе VisualDSP++, кроме случаев, когда меняется VDK API. Подробнее см. описание типов DSP_Family и DSP_Product.

Примечание: разные процессоры могут использовать общий набор библиотек VDK. По этой причине поле mProduct может не соответствовать процессору в конкретном приложении.

//Прототип C:
void VDK_LogHistoryEvent(VDK_HistoryEnum inEnum, int inValue);
 
//Прототип C++:
void VDK::LogHistoryEvent(VDK::HistoryEnum inEnum, int inValue);

Добавляет запись в буфер истории (history buffer). Эта функция не выполняет никаких действий, если проект не был линкован на этапе сборки с библиотеками, поддерживающими полную инструментальную информацию (fully instrumented libraries).

Функция LogHistoryEvent не вызывает запуск планировщика, и её время выполнения фиксированное.

Параметр inEnum это значение перечисления, показывающее тип события. Параметр inValue, смысл которого зависит от значения перечисления.

//Прототип C:
void VDK_ReplaceHistorySubroutine (HistoryLoggingFunc inFunc);
//Функция inFunc имеет прототип:
void inFunc(VDK_Ticks inTick,
            const VDK_HistoryEnum inEnum,
            const int inValue,
            const VDK_ThreadID inThreaID);
 
//Прототип C++:
void VDK::ReplaceHistorySubroutine (HistoryLoggingFunc inFunc);
//Функция inFunc имеет прототип:
void inFunc(VDK::Ticks inTick,
            const VDK::HistoryEnum inEnum,
            const int inValue,
            const VDK::ThreadID inThreaID);

Позволяет заменить механизм VDK для записи истории в лог (VDK history logging) на подпрограмму inFunc, которую определит пользователь.

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

Аргументы, передаваемые в функцию inFunc, являются полями структуры HistoryEvent. VDK устанавливает аргументы для inFunc в следующих регистрах, см. таблицу.

Таблица 3-1. В каких регистрах размещены аргументы подпрограммы записи в лог истории.

Аргумент Тип Blackfin TigerSHARC SHARC
Время VDK::Ticks R3 J7 R0
Тип события VDK::HistoryEnum R0 J4 R4
Значение int R1 J5 R8
Идентификатор потока VDK::ThreadID R2 J6 R12

Подпрограмма, определенная пользователем, может вызвать VDK_ISRAddHistoryEvent() для добавления событий в кольцевой буфер VDK, чтобы отобразить события в окне VDK History. VDK_ISRAddHistoryEvent() принимает те же самые аргументы, в тех же регистрах, что и inFunc. VDK_ISRAddHistoryEvent() вызывается библиотекой VDK по умолчанию, если не был заменен оригинальный механизм регистрации истории (VDK history mechanism). ReplaceHistorySoubroutine() может быть вызвана в момент старта приложения VDK (из кода startup) или в конструкторе глобальной переменной, и её вызов доступен только при полном наличии инструментальных библиотек в сборке приложения VDK (fully instrumented libraries).

Функция ReplaceHistorySubroutine не вызывает запуск планировщика, и её время выполнения фиксированное.

[Замена механизма записи в лог истории]

Механизм записи в лог истории (VDK history logging) сохраняет событие (history event) в кольцевой буфер с помощью API-вызова VDK_ISRAddHistoryEvent(). Пользователи могут поменять поведение этого механизма, заменив вызов VDK_ISRAddHistoryEvent() с помощью API-функции ReplaceHistorySubroutine() (см. описание этой функции в соответствующей врезке).

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

• Она должна быть написана на ассемблере, и не может рассчитывать на наличие поддержки со стороны кода C при выполнении программы (C run-time environment недоступен).
• Она не должна вызвать какие-либо функции, которые подразумевают наличие C run-time environment.
• Она не должна вызывать никакие функции VDK API.
• Одна должна сохранять на входе и восстанавливать на выходе все регистры, которые использует либо явно, либо косвенно.
• Вызовы этой пользовательской функции для записи в лог не должны выполняться из какой-либо другой части приложения VDK.
• Она должна использоваться только для трассировки/мониторинга активности системы с целью отладки или анализа поведения системы, и она не должна использоваться для построения функционала приложения, и не должна никак на него влиять.

Код, функции, которая пишет в лог, получает при вызове следующие аргументы:

• Время в тиках, когда произошло записываемое в лог событие.
• Значение из перечисления HistoryEnum, которое описывает событие.
• Целое число, используемое для сохранения в логе дополнительной информации о событии.
• Идентификатор потока.

Аргументы, передаваемые в подпрограмму записи в лог, являются составляющими типа данных VDK (полями структуры) HistoryEvent.

//Прототип HistoryEvent на C:
typedef struct
{
   VDK_Ticks time;
   VDK_ThreadID threadID;
   VDK_HistoryEnum type;
   int value;
} VDK_HistoryEvent;
 
//Прототип HistoryEvent на C++:
typedef struct
{
   VDK::Ticks time;
   VDK::ThreadID threadID;
   VDK::HistoryEnum type;
   int value;
} VDK::HistoryEvent;

Перед вызовом пользовательской функции истории аргументы для неё помещаются в соответствующие регистры (см. таблицу 3-1 во врезке с описанием функции ReplaceHistorySubroutine).

Пользователь может вызвать VDK_ISRAddHistoryEvent() из своего кода, который пишет в лог, если он хочет сохранить информацию в буфер VDK history. Процедура VDK_ISRAddHistoryEvent() должна вызываться только из пользовательской функции записи в лог, и она не должна вызваться ни из какой другой части приложения. VDK_ISRAddHistoryEvent() ожидает появления аргументов в тех же регистрах, что перечислены в таблице 3-1 (см. врезку с описанием функции ReplaceHistorySubroutine).

Примечание: может быть, что окно VDK History будет не в состоянии отобразить выполнение потоков, которые работают в приложении, если события kThreadSwitched или kThreadStatusChange были удалены, либо были использованы неправильно.

[Ссылки]

1. VisualDSP++ 5.0 Kernel (VDK) User’s Guide site:analog.com.
2. VisualDSP: работа с динамически выделяемой памятью.
3. Конфигурирование и отладка проектов VDK.
4. EE-307: советы по отладке для Blackfin.
5. VDK API для получения информации состояния приложения.