» Главная
eXcode.ru » Статьи » Другие » Мобильное программирование приложений реального времени в стандарте POSIX
» Новости
» Опросы
» Файлы
» Журнал



Пользователей: 0
Гостей: 4





Трассировка пользовательских приложений




Основные идеи, понятия и объекты

Под трассировкой в стандарте POSIX-2001 понимается порождение, накопление и анализ данных о событиях, имевших место при выполнении пользовательского приложения.

Применительно к приложениям реального времени трассировка помогает достичь по крайней мере трех целей:

  • оптимизировать структуру приложения на основе анализа трассировочных данных (например, попытаться сгладить пики активности, распределить нагрузку равномерно по времени);
  • отладить приложение (традиционные интерактивные отладчики могут быть неприменимы к приложениям реального времени);
  • выявить причину аварийного завершения работы приложения (обнаружить место и первые признаки ненормального поведения).

С логической точки зрения в трассировке (в том виде, как она рассматривается в стандарте POSIX-2001) участвуют три процесса (физически они могут совпадать между собой):

  • трассируемый (целевой);
  • трассирующий (управляющий трассировкой);
  • анализирующий данные трассировки.

Сведения о действиях, производимых при выполнении приложения, фиксируются в виде объектов данных, называемых событиями трассировки (или, для краткости, просто событиями). События записываются в потоки трассировки, которые содержат также служебные данные, необходимые для интерпретации событий.

Трассируемый процесс должен быть специальным образом оборудован: его программа должна содержать точки трассировки – действия, способные генерировать события трассировки. Для каждого трассируемого процесса должен быть открыт по крайней мере один поток трассировки.

Процесс, создавший поток трассировки, называется трассирующим (управляющим трассировкой).

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

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

События трассировки подразделяются на две категории:

  • пользовательские;
  • системные.

Пользовательские события генерируются при вызове функции posix_trace_event().

Системные события генерируются реализацией в ответ на действия ОС или приложения. Отметим, что в первом случае событие не ассоциировано с каким-либо процессом.

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

В стандарте POSIX-2001 специфицированы следующие типы системных событий, анализ которых помогает интерпретировать поток трассировки.

POSIX_TRACE_START

Начало трассировки.

POSIX_TRACE_STOP

Приостановка трассировки.

POSIX_TRACE_OVERFLOW

Возникновение ситуации переполнения потока трассировки.

POSIX_TRACE_RESUME

Устранение ситуации переполнения потока трассировки.

POSIX_TRACE_FLUSH_START

Начало сброса потока трассировки в журнал.

POSIX_TRACE_FLUSH_STOP

Завершение сброса потока трассировки в журнал.

POSIX_TRACE_ERROR

Ошибка трассировки, зависящая от реализации.

Стандартизован также один тип пользовательских событийPOSIX_TRACE_UNNAMED_USEREVENT. Это значение возвращается, когда приложение пытается зарегистрировать больше имен событий, чем допускается в соответствии со значением конфигурационной константы TRACE_USER_EVENT_MAX.

Стандартом POSIX-2001 предусмотрен механизм фильтрации, позволяющий отключить генерацию событий определенных типов и, тем самым, уменьшать объем трассировочных данных. Это полезно, например, в ситуациях, когда у приложения есть заведомо «неинтересные» фрагменты, трассировать которые нет смысла, или многочисленные системные события (такие, например, как переключение контекстов), «неинтересные» с точки зрения приложения.

Фильтр устанавливает трассирующий процесс. По умолчанию события не фильтруются.

При смене фильтра генерируется системное событие POSIX_TRACE_FILTER.

Ключевыми элементами реализации средств трассировки являются описанные в заголовочном файле <trace.h> структуры posix_trace_event_info и posix_trace_status_info. Первая специфицирует формат событий, вторая – данные, хранящиеся в потоке трассировки.

Согласно стандарту POSIX-2001, структура типа posix_trace_event_info должна содержать по крайней мере следующие поля.

trace_event_id_t     posix_event_id;     
    /* Идентификатор типа события     */ 
pid_t     posix_pid;     
    /* Идентификатор трассируемого процесса */ 
void     *posix_prog_address;     
    /* Адрес точки трассировки */ 
int     posix_truncation_status; 
    /* Признак усечения данных */
struct timespec     posix_timestamp;     
    /* Временной штамп события */
pthread_t     posix_thread_id;     
    /* Идентификатор трассируемого потока управления */

Смысл некоторых полей, вероятно, нуждается в пояснении.

Если, в соответствии с типом (поле posix_event_id) событие является системным и не ассоциировано с каким-либо процессом, значение posix_pid должно быть нулевым.

Для пользовательских событий в поле posix_prog_address помещается адрес вызова posix_trace_event(); для системных, сгенерированных в результате явного обращения приложения к системному сервису (такому, например, как fork()), в этом поле находится адрес вызова системного сервиса.

В поле posix_truncation_status хранится признак того, были ли данные усечены при генерации или чтении события. Возможных значения три:

POSIX_TRACE_NOT_TRUNCATED

Доступны все данные, ничего не усечено.

POSIX_TRACE_TRUNCATED_RECORD

Данные усечены при генерации.

POSIX_TRACE_TRUNCATED_READ

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

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

Поле posix_thread_id по смыслу и трактовке близко к posix_pid, только в нем хранится идентификатор потока, а не процесса (если, конечно, реализация поддерживает потоки).

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

Структура типа posix_trace_status_info содержит информацию о состоянии активного потока трассировки. Согласно стандарту POSIX-2001, она должна содержать по крайней мере следующие поля.

int posix_stream_status;     
    /* Состояние потока трассировки */ 
int posix_stream_full_status;     
    /* Признак заполненности потока    */
int posix_stream_overrun_status;    
    /* Признак потери информации    */
int posix_stream_flush_status;     
    /* Идет ли в данный момент сброс в журнал */
int posix_stream_flush_error;     
    /* Были ли ошибки при последнем сбросе     */
int posix_log_overrun_status;     
    /* Признак потери информации в журнале     */
int posix_log_full_status;     
    /* Признак заполненности журнала    */

Значение поля posix_stream_status отражает режим, в котором находится поток трассировки:

POSIX_TRACE_RUNNING

Трассировка выполняется, поток принимает события.

POSIX_TRACE_SUSPENDED

Трассировка приостановлена (или не начиналась), поток не принимает события.

Поле posix_stream_full_status отражает состояние заполненности потока. Оно может содержать следующие значения.

POSIX_TRACE_FULL

Пространство в потоке исчерпано.

POSIX_TRACE_NOT_FULL

В потоке есть свободное пространство для событий.

Отметим, что на практике возможны все четыре комбинации значений полей posix_stream_status и posix_stream_full_status. В частности, сочетание POSIX_TRACE_RUNNING и POSIX_TRACE_FULL свидетельствует о том, что трассировка идет, но с потерей информации (новые события записываются на место старых).

Поле posix_stream_overrun_status содержит признак потери информации. Возможные значения:

POSIX_TRACE_OVERRUN

По крайней мере одно событие было потеряно (и, следовательно, не содержится в потоке трассировки).

POSIX_TRACE_NO_OVERRUN

Ни одно событие не потеряно.

События могут теряться, если они генерируются при заполненном потоке или во время сброса потока трассировки в журнал.

Поле posix_stream_flush_status содержит признак того, что в данный момент происходит сброс потока трассировки в журнал. Возможных значений, разумеется, два.

POSIX_TRACE_FLUSHING

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

POSIX_TRACE_NOT_FLUSHING

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

В поле posix_stream_flush_error находится нуль, если последний сброс прошел нормально; в противном случае там хранится код первой случившейся при сбросе ошибки (информация о последующих ошибках теряется).

Поле posix_log_overrun_status содержит признак потери информации в журнале с двумя возможными значениями: POSIX_TRACE_OVERRUN и POSIX_TRACE_NO_OVERRUN.

Поле posix_log_full_status служит признаком заполненности журнала. Возможных значений, естественно, два: POSIX_TRACE_FULL и POSIX_TRACE_NOT_FULL.

При создании потока трассировки его атрибуты стандартным для POSIX-2001 образом извлекаются из атрибутного объекта. Стандартом предусмотрены следующие атрибуты:

  • имя версии системы трассировки;
  • имя потока трассировки;
  • время создания потока трассировки;
  • разрешающая способность часов, с помощью которых проставляются временные штампы;
  • минимальное число байт, резервируемое для записи событий;
  • правила обработки ситуации заполнения потока трассировки;
  • максимальный размер (в байтах) записываемых в поток событий трассировки;
  • признак наследования трассировки порожденными процессами;
  • максимальный размер (в байтах) журнала трассировки, ассоциированного с потоком;
  • правила обработки ситуации заполнения журнала трассировки.

И для потоков, и для журналов трассировки правила обработки ситуации заполнения могут сводиться к записи новых событий поверх самых старых (политика POSIX_TRACE_LOOP) или к приостановке трассировки (POSIX_TRACE_UNTIL_FULL). Кроме того, для потоков может быть предусмотрен сброс в журнал с последующей очисткой (политика POSIX_TRACE_FLUSH), а для для журналов – потенциально неограниченное расширение (POSIX_TRACE_APPEND).

Трассировка с записью в создаваемый поток может как наследоваться, так и не наследоваться порожденными процессами. Соответствующие значения признака наследования именуются POSIX_TRACE_INHERITED и POSIX_TRACE_CLOSE_FOR_CHILD.

В заключение раздела еще раз подчеркнем важные достоинства, которыми обладает механизм трассировки.

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

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

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

Функции для работы с атрибутными объектами потоков трассировки

Согласно стандарту POSIX-2001, система трассировки строится в объектно-ориентированном стиле. Структура большинства используемых объектов скрыта от приложения, поэтому требуется довольно много относительно мелких функций – конструкторов, селекторов, итераторов.

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

Чтобы получить общее представление о функциях трассировки, рассмотрим сначала два верхних уровня описанной иерархии.

Трассирующий процесс управляет ресурсами, ассоциированными с потоками трассировки, а именно:

  • атрибутными объектами потоков трассировки;
  • собственно потоками трассировки;
  • журналами трассировки;
  • идентификаторами типов событий;
  • фильтрами.

Трассируемый процесс имеет дело со следующими объектами:

  • события;
  • идентификаторы типов событий;
  • точки трассировки.

Анализирующий процесс читает:

  • потоки трассировки;
  • журналы;
  • события;
  • идентификаторы типов событий.

Перейдем к детальному рассмотрению функций трассировки.

Для создания и уничтожения атрибутных объектов потоков трассировки служат функции posix_trace_attr_init() и posix_trace_attr_destroy() (см. листинг 8.1).

#include <trace.h>
int posix_trace_attr_init (
    trace_attr_t *attr);
int posix_trace_attr_destroy (
    trace_attr_t *attr);
    
Листинг 8.1. Описание функций создания и уничтожения атрибутных объектов потоков трассировки.

Функция posix_trace_attr_init() инициализирует атрибутный объект подразумеваемыми значениями для всех атрибутов, используемых реализацией. Отметим, что два атрибута – имя версии системы трассировки и разрешающая способность часов, с помощью которых проставляются временные штампы, – доступны только на чтение.

Нормальным является нулевой результат; при наличии ошибки возвращается ее номер.

Для манипулирования атрибутами, идентифицирующими поток трассировки, служат функции posix_trace_attr_getgenversion(), posix_trace_attr_getname(), posix_trace_attr_setname(), posix_trace_attr_getcreatetime() (см. листинг 8.2).

#include <trace.h>
int posix_trace_attr_getgenversion (
    const trace_attr_t *attr, 
    char *genversion);
int posix_trace_attr_getname (
    const trace_attr_t *attr, 
    char *tracename);
int posix_trace_attr_setname (
    trace_attr_t *attr, const 
    char *tracename);
#include <time.h>
#include <trace.h>
int posix_trace_attr_getcreatetime (
    const trace_attr_t *attr, 
    struct timespec *createtime);
    
Листинг 8.2. Описание функций манипулирования атрибутами, идентифицирующими поток трассировки.

Функции опроса копируют значения соответствующих атрибутов (имя версии системы трассировки, имя и время создания потока трассировки) из атрибутного объекта, заданного аргументом attr, в символьный массив (длина которого должна быть не меньше TRACE_NAME_MAX) или в структуру. Функция posix_trace_attr_setname() копирует имя (длина которого не должна превышать TRACE_NAME_MAX) в противоположном направлении.

Функция posix_trace_attr_getclockres() (см. листинг 8.3) позволяет опросить разрешающую способность часов, с помощью которых проставляются временные штампы.

#include <time.h>
#include <trace.h>
int posix_trace_attr_getclockres (
    const trace_attr_t *attr, 
    struct timespec *resolution);
    
Листинг 8.3. Описание функции опроса разрешающей способности часов, с помощью которых проставляются временные штампы.

Поведенческие атрибуты потоков и журналов обслуживаются функциями: posix_trace_attr_getinherited(), posix_trace_attr_setinherited(), posix_trace_attr_getstreamfullpolicy(), posix_trace_attr_setstreamfullpolicy(), posix_trace_attr_getlogfullpolicy(), posix_trace_attr_setlogfullpolicy() (см. листинг 8.4).

#include <trace.h>
int posix_trace_attr_getinherited (
    const trace_attr_t *restrict attr, 
    int *restrict inheritancepolicy);
int posix_trace_attr_setinherited (
    trace_attr_t *attr, 
    int inheritancepolicy);
int posix_trace_attr_getstreamfullpolicy (
    const trace_attr_t *restrict attr, 
    int *restrict streampolicy);
int posix_trace_attr_setstreamfullpolicy (
    trace_attr_t *attr, int streampolicy);
int posix_trace_attr_getlogfullpolicy (
    const trace_attr_t *restrict attr, 
    int *restrict logpolicy);
int posix_trace_attr_setlogfullpolicy (
    trace_attr_t *attr, int logpolicy);
    
Листинг 8.4. Описание функций манипулирования значениями поведенческих атрибутов потоков и журналов в атрибутных объектах.

Функции posix_trace_attr_getinherited() и posix_trace_attr_setinherited() позволяют, соответственно, опросить и установить значение атрибута наследования трассировки порожденными процессами. Если значение этого атрибута равно POSIX_TRACE_INHERITED, то после вызовов fork() и/или spawn() родительский и порожденный процессы будут трассироваться параллельно с использованием общего потока трассировки. Подразумеваемое значение атрибута суть POSIX_TRACE_CLOSE_FOR_CHILD (не трассировать порожденные процессы).

Атрибут, специфицирующий правила обработки ситуации заполнения, и для потоков (функции posix_trace_attr_getstreamfullpolicy() и posix_trace_attr_setstreamfullpolicy()), и для журналов трассировки (функции posix_trace_attr_getlogfullpolicy() и posix_trace_attr_setlogfullpolicy()) может принимать следующие значения.

POSIX_TRACE_LOOP

Для потоков – продолжение трассировки с записью новых событий поверх самых старых; для журналов – сброс всех событий из потока также с записью поверх самых старых.

POSIX_TRACE_UNTIL_FULL

Для потоков – приостановка трассировки с генерацией события POSIX_TRACE_STOP. Реализация обязана возобновить трассировку (с генерацией события POSIX_TRACE_START) после очистки потока, но может сделать это и раньше, за счет повторного использования пространства, которое занимали прочитанные события. Для журналов – прекращение сброса (последним в журнал помещается событие POSIX_TRACE_STOP). События, которые не поместились в журнал, пропадают.

Для потоков трассировки еще одним возможным значением служит

POSIX_TRACE_FLUSH

Регулярно сбрасывать поток в журнал трассировки; в остальном действовать по правилам POSIX_TRACE_UNTIL_FULL.

Если с потоком ассоциирован журнал, то подразумеваемым значением данного атрибута является POSIX_TRACE_FLUSH; в противном случае – POSIX_TRACE_LOOP.

Для журналов трассировки описываемый атрибут может принимать значение

POSIX_TRACE_APPEND

Потенциально неограниченное расширение журнала.

Подразумеваемым для журналов является значение POSIX_TRACE_LOOP.

Опросить и/или установить хранящиеся в атрибутном объекте размеры событий, потоков и журналов можно с помощью функций: posix_trace_attr_getmaxdatasize(), posix_trace_attr_setmaxdatasize(), posix_trace_attr_getmaxsystemeventsize(), posix_trace_attr_getmaxusereventsize(), posix_trace_attr_getstreamsize(), posix_trace_attr_setstreamsize(), posix_trace_attr_getlogsize(), posix_trace_attr_setlogsize() (см. листинг 8.5).

#include <sys/types.h>
#include <trace.h>
int posix_trace_attr_getmaxdatasize (
    const trace_attr_t *restrict attr, 
    size_t *restrict maxdatasize);
int posix_trace_attr_setmaxdatasize (
    trace_attr_t *attr, size_t maxdatasize);
int posix_trace_attr_getmaxsystemeventsize (
    const trace_attr_t *restrict attr, 
    size_t *restrict eventsize);
int posix_trace_attr_getmaxusereventsize (
    const trace_attr_t *restrict attr,
    size_t data_len, size_t *restrict eventsize);
int posix_trace_attr_getstreamsize (
    const trace_attr_t *restrict attr,
    size_t *restrict streamsize);
int posix_trace_attr_setstreamsize (
    trace_attr_t *attr, size_t streamsize);
int posix_trace_attr_getlogsize (
    const trace_attr_t *restrict attr,
    size_t *restrict logsize);
int posix_trace_attr_setlogsize (
    trace_attr_t *attr, size_t logsize);
    
Листинг 8.5. Описание функций манипулирования размерами событий, потоков и журналов в атрибутных объектах.

Функции posix_trace_attr_getmaxdatasize() и posix_trace_attr_setmaxdatasize() позволяют опросить и установить максимальный размер (в байтах) данных, ассоциируемых с пользовательскими событиями. Подразумеваемое значение этого атрибута зависит от реализации.

Функции posix_trace_attr_getmaxsystemeventsize() и posix_trace_attr_getmaxusereventsize() служат для опроса максимального размера системных и пользовательских событий, соответственно (во втором случае учитывается размер ассоциированных данных, определяемый значением аргумента data_len).

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

Функции posix_trace_attr_getlogsize() и posix_trace_attr_setlogsize() обслуживают атрибут журнала трассировки – максимальный размер, резервируемый для хранения событий. Если правило обработки ситуации заполнения журнала определено как POSIX_TRACE_APPEND, данный атрибут игнорируется.

Функции, обслуживающие жизненный цикл потоков трассировки.

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

Основные элементы жизненного цикла потока трассировки.
Рис. 8.1. Основные элементы жизненного цикла потока трассировки.

Создание потока трассировки осуществляется функциями posix_trace_create() или posix_trace_create_withlog() (см. листинг 8.6).

#include <sys/types.h>
#include <trace.h>
int posix_trace_create (pid_t pid, 
    const trace_attr_t *restrict attr, 
    trace_id_t *restrict trid);
int posix_trace_create_withlog (pid_t pid, 
    const trace_attr_t *restrict attr, int fildes, 
    trace_id_t *restrict trid);
    
Листинг 8.6. Описание функций создания потоков трассировки.

Функция posix_trace_create() создает активный поток, в который будут записываться события трассировки целевого процесса с идентификатором pid (при нулевом pid трассируется вызывающий процесс). Ресурсы в потоке отводятся в соответствии со значениями элементов атрибутного объекта, заданного аргументом attr (если attr равен NULL, используются подразумеваемые значения).

Идентификатор созданного потока записывается по указателю trid. Его может использовать только вызывающий процесс.

Фильтр, ассоциированный с новым потоком, пуст.

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

Разумеется, попытки трассировать другие процессы подвержены контролю прав доступа.

Функция posix_trace_create_withlog() делает то же, что и posix_trace_create(), но дополнительно ассоциирует с потоком журнал трассировки, заданный файловым дескриптором fildes.

Сразу после создания потока трассировка считается приостановленной. Чтобы активизировать ее, следует воспользоваться функцией posix_trace_start(); для последующей приостановки нужно вызвать функцию posix_trace_stop() (см. листинг 8.7).

#include <trace.h>
int posix_trace_start (trace_id_t trid);
int posix_trace_stop (trace_id_t trid);
    
Листинг 8.7. Описание функций активизации и приостановки трассировки.

После вызова posix_trace_start() в поток помещается системное событие POSIX_TRACE_START, а статус потока получает значение POSIX_TRACE_RUNNING (если трассировка уже шла, вызов posix_trace_start() игнорируется).

После вызова posix_trace_stop() в поток помещается системное событие POSIX_TRACE_STOP, а статус потока получает значение POSIX_TRACE_SUSPENDED (если трассировка уже была приостановлена, вызов posix_trace_stop() игнорируется).

Если поток трассировки заполнен, вызовы posix_trace_start() и posix_trace_stop() игнорируются.

Функция posix_trace_shutdown() (см. листинг 8.8) завершает трассировку и освобождает ресурсы, ассоциированные с потоком, независимо от того, прочитал ли анализирующий процесс все записанные события.

#include <sys/types.h>
#include <trace.h>
int posix_trace_shutdown (trace_id_t trid);
    
Листинг 8.8. Описание функции завершения трассировки.

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

После возврата из posix_trace_shutdown() аргумент trid перестает быть корректным идентификатором потока трассировки.

Трассировка может завершаться и неявным образом, когда трассирующий процесс терминируется или вызывает функцию семейства exec().

По ходу трассировки управляющий процесс может инициировать сброс потока в журнал, обратившись к функции posix_trace_flush() (см листинг 8.9).

#include <sys/types.h>
#include <trace.h>
int posix_trace_flush (trace_id_t trid);
    
Листинг 8.9. Описание функции сброса потока трассировки в журнал.

Сброс осуществляется с учетом правил обработки ситуации заполнения журнала.

После завершения сброса пространство в потоке трассировки, которое занимали записанные в журнал события, может быть использовано повторно.

Узнать о завершении операции сброса можно, опрашивая статус потока трассировки с помощью функции posix_trace_get_status() (см. листинг 8.10).

#include <trace.h>
int posix_trace_get_status (trace_id_t trid,
    struct posix_trace_status_info 
                               *statusinfo);
    
Листинг 8.10. Описание функции опроса статуса потока трассировки.

Функция обеспечивает согласованность данных, которые записываются в структуру типа posix_trace_status_info по указателю statusinfo. Сразу после завершения вызова признаки переполнения и для потока, и для журнала получают значение POSIX_TRACE_NO_OVERRUN, а в поле posix_stream_flush_error помещается нуль.

Стандартом POSIX-2001 предусмотрен опрос атрибутов потока трассировки. Для этого служит функция posix_trace_get_attr() (см. листинг 8.11).

#include <trace.h>
int posix_trace_get_attr (
    trace_id_t trid, trace_attr_t *attr);
    
Листинг 8.11. Описание функции опроса атрибутов потока трассировки.

Для возврата значений атрибутов найдено красивое решение – они помещаются в атрибутный объект по указателю attr, откуда могут быть извлечены рассмотренными выше функциями для работы с атрибутными объектами.

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

#include <sys/types.h>
#include <trace.h>
int posix_trace_clear (trace_id_t trid);
    
Листинг 8.12. Описание функции очистки потока трассировки.

Разумеется, после очистки признак заполненности получает значение POSIX_TRACE_NOT_FULL.

Если для журнала предусмотрено неограниченное расширение (POSIX_TRACE_APPEND), эффект от вызова posix_trace_clear() не специфицирован.

При опросе и установке фильтров событий трассировки (функции posix_trace_get_filter() и posix_trace_set_filter(), см. листинг 8.13) применяется апробированная в других частях стандарта POSIX-2001 схема работы с множествами, основанная на функциях: posix_trace_eventset_empty(), posix_trace_eventset_fill(), posix_trace_eventset_add(), posix_trace_eventset_del(), posix_trace_eventset_ismember() (см. листинг 8.14).

#include <trace.h>
int posix_trace_get_filter (
    trace_id_t trid, trace_event_set_t *set);
int posix_trace_set_filter (trace_id_t trid, 
    const trace_event_set_t *set, int how);
    
Листинг 8.13. Описание функций опроса и установки фильтров событий трассировки.
#include <trace.h>
int posix_trace_eventset_empty (
    trace_event_set_t *set);
int posix_trace_eventset_fill (
    trace_event_set_t *set, int what);
int posix_trace_eventset_add (
    trace_event_id_t event_id, 
    trace_event_set_t *set);
int posix_trace_eventset_del (
    trace_event_id_t event_id, 
    trace_event_set_t *set);
int posix_trace_eventset_ismember (
    trace_event_id_t event_id, 
    const trace_event_set_t *restrict set, 
    int *restrict ismember);
    
Листинг 8.14. Описание функций для работы с множествами событий трассировки.

Когда вызывается функция posix_trace_set_filter(), в поток трассировки помещается событие POSIX_TRACE_FILTER с указанием старого и нового фильтров. Аргумент how, определяющий, как меняется фильтр, может принимать следующие значения.

POSIX_TRACE_SET_EVENTSET

Новое значение фильтра задается аргументом set.

POSIX_TRACE_ADD_EVENTSET

Новое значение фильтра вычисляется как объединение текущего значения и множества, заданного аргументом set.

POSIX_TRACE_SUB_EVENTSET

Новое значение фильтра вычисляется как разность текущего значения и множества, заданного аргументом set.

Вероятно, функции для работы с множествами событий трассировки не нуждаются в пространном описании. Аргумент event_id задает тип события. Функция posix_trace_eventset_empty() создает пустое множество событий. Функция posix_trace_eventset_fill() помещает в создаваемое множество события, определяемые аргументом what, который может принимать следующие значения.

POSIX_TRACE_WOPID_EVENTS

Все зависящие от реализации системные события, не ассоциированные с каким-либо процессом.

POSIX_TRACE_SYSTEM_EVENTS

Все зависящие от реализации системные события.

POSIX_TRACE_ALL_EVENTS

Все события (системные и пользовательские).

Для функций posix_trace_eventset_add() и posix_trace_eventset_del() добавление уже присутствующего или, соответственно, удаление отсутствующего типа не считается ошибкой.

Функция posix_trace_eventset_ismember() помещает по указателю ismember ненулевое значение, если тип event_id принадлежит множеству, заданному аргументом set.

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

Играющие техническую роль функции posix_trace_trid_eventid_open(), posix_trace_eventid_get_name() и posix_trace_eventid_equal() (см. листинг 8.15), обслуживают идентификаторы типов событий, рассматриваемые как абстрактные объекты.

#include <trace.h>
int posix_trace_trid_eventid_open (
    trace_id_t trid, 
    const char *restrict event_name, 
    trace_event_id_t *restrict event);

int posix_trace_eventid_get_name (
    trace_id_t trid, 
    trace_event_id_t event, 
    char *event_name);

int posix_trace_eventid_equal (
    trace_id_t trid, 
    trace_event_id_t event1, 
    trace_event_id_t event2);
    
Листинг 8.15. Описание функций для работы с идентификаторами типов событий трассировки.

Функция posix_trace_trid_eventid_open() ассоциирует с именем event_name, длина которого не должна превышать значения конфигурационной константы TRACE_EVENT_NAME_MAX, уникальный для потока трассировки, заданного аргументом trid, идентификатор типа событий и записывает его по указателю event. При повторном вызове posix_trace_trid_eventid_open() с тем же именем возвращается ранее созданный идентификатор. При попытке превысить максимально допустимое для процесса количество типов пользовательских событий TRACE_USER_EVENT_MAX возвращается предопределенный идентификатор POSIX_TRACE_UNNAMED_USEREVENT.

Функция posix_trace_eventid_get_name() записывает в массив event_name имя события, ассоциированное с типом, заданным аргументом event.

Сравнить два идентификатора типов из одного потока трассировки можно посредством функции posix_trace_eventid_equal(), возвращающей в случае равенства результат, отличный от нуля.

Функции posix_trace_eventtypelist_getnext_id() и posix_trace_eventtypelist_rewind() (см. листинг 8.16) позволяют обрабатывать совокупность идентификаторов типов событий, присутствующих в заданном потоке трассировки.

#include <trace.h>
int posix_trace_eventtypelist_getnext_id (
    trace_id_t trid, 
    trace_event_id_t *restrict event, 
    int *restrict unavailable);
int posix_trace_eventtypelist_rewind (trace_id_t trid);
    
Листинг 8.16. Описание функций для работы с совокупностью идентификаторов типов событий.

Функция posix_trace_eventtypelist_getnext_id() является итератором. При первом обращении она записывает по указателю event первый идентификатор типа. При каждом следующем вызове туда же помещается очередной идентификатор. Пока перебор идентификаторов не закончен, по указателю unavailable записывается нулевое значение.

Функция posix_trace_eventtypelist_rewind() позволяет вернуться к началу перебора.

Приведем пример программы, выясняющей подразумеваемые значения атрибутов потока трассировки (см. листинг 8.17).

/* * * * * * * * * * * * * * * * * * * * * * * */
/* Программа выясняет подразумеваемые значения */
/* атрибутов потока трассировки                */
/* * * * * * * * * * * * * * * * * * * * * * * */

#include <sys/types.h>
#include <stdio.h>
#include <trace.h>
#include <time.h>
#include <limits.h>
#include <errno.h>

int main (void) {
    trace_attr_t attr;                 /* Атрибутный объект потока */
    trace_id_t trid;                 /* Идентификатор потока */
    char trbuf [TRACE_NAME_MAX];    /* Буфер для имен */
    struct timespec tms;             /* Структура для времен */
    char dtbuf [LINE_MAX];             /* Буфер для данных о времени */
    int res;                         /* Целочисленные результаты    */
    size_t mdatsz;                     /* Максимальный размер данных */
if ((errno = posix_trace_create (0, NULL, &trid)) != 0) {
        perror ("POSIX_TRACE_CREATE");
        return (errno);
    }

    if ((errno = posix_trace_get_attr (trid, &attr)) != 0) {
        perror ("POSIX_TRACE_GET_ATTR");
        return (errno);
    }

    if ((errno = posix_trace_attr_getgenversion (&attr, 
            trbuf)) != 0) {
        perror ("POSIX_TRACE_ATTR_GETGENVERSION");
        return (errno);
    }
    printf ("Версия системы трассировки: %s
", trbuf);

    if ((errno = posix_trace_attr_getname 
            (&attr, trbuf)) != 0) {
        perror ("POSIX_TRACE_ATTR_GETNAME");
        return (errno);
    }
    printf ("Имя потока трассировки: %s
", trbuf);

    if ((errno = posix_trace_attr_getcreatetime 
            (&attr, &tms)) != 0) {
        perror ("POSIX_TRACE_ATTR_GETCREATETIME");
        return (errno);
    }
    (void) strftime (dtbuf, sizeof (dtbuf), "%c", 
        localtime (&tms.tv_sec));
    printf ("Время создания потока трассировки: %s
", dtbuf);

    if ((errno = posix_trace_attr_getclockres 
            (&attr, &tms)) != 0) {
        perror ("POSIX_TRACE_ATTR_GETCLOCKRES");
        return (errno);
    }
    printf ("Разрешающая способность часов потока "
                "трассировки: %ld нсек
", tms.tv_nsec);

    if ((errno = posix_trace_attr_getstreamfullpolicy 
            (&attr, &res)) != 0) {
        perror ("POSIX_TRACE_ATTR_GETSTREAMFULLPOLICY");
        return (errno);
    }
    printf ("Правило обработки ситуации заполнения потока: ");
    switch (res) {
        case POSIX_TRACE_LOOP:
            printf ("POSIX_TRACE_LOOP
");
            break;
        case POSIX_TRACE_UNTIL_FULL:
            printf ("POSIX_TRACE_UNTIL_FULL
");
            break;
        case POSIX_TRACE_FLUSH:
            printf ("POSIX_TRACE_FLUSH
");
            break;
        default:
            printf ("неизвестно
");
    }

    if ((errno = posix_trace_attr_getlogfullpolicy 
            (&attr, &res)) != 0) {
        perror ("POSIX_TRACE_ATTR_GETLOGFULLPOLICY");
        return (errno);
    }
    printf ("Правило обработки ситуации заполнения "
                "журнала трассировки: ");
    switch (res) {
        case POSIX_TRACE_LOOP:
            printf ("POSIX_TRACE_LOOP
");
            break;
        case POSIX_TRACE_UNTIL_FULL:
            printf ("POSIX_TRACE_UNTIL_FULL
");
            break;
        case POSIX_TRACE_APPEND:
            printf ("POSIX_TRACE_APPEND
");
            break;
        default:
            printf ("неизвестно
");
    }

    if ((errno = posix_trace_attr_getmaxdatasize 
            (&attr, &mdatsz)) != 0) {
        perror ("POSIX_TRACE_ATTR_GETMAXDATASIZE");
        return (errno);
    }
    printf ("Максимальный размер данных в пользовательском "
                "событии: %d
", mdatsz);

    if ((errno = posix_trace_attr_getmaxusereventsize 
            (&attr, mdatsz, &mdatsz)) != 0) {
        perror ("POSIX_TRACE_ATTR_GETMAXUSEREVENTSIZE");
        return (errno);
    }
    printf ("Максимальный размер пользовательского события: "
                "%d
", mdatsz);

    if ((errno = posix_trace_attr_getmaxsystemeventsize 
            (&attr, &mdatsz)) != 0) {
        perror ("POSIX_TRACE_ATTR_GETMAXSYSTEMEVENTSIZE");
        return (errno);
    }
    printf ("Максимальный размер системного события: "
                "%d
", mdatsz);

    if ((errno = posix_trace_attr_getstreamsize 
            (&attr, &mdatsz)) != 0) {
        perror ("POSIX_TRACE_ATTR_GETSTREAMSIZE");
        return (errno);
    }
    printf ("Размер потока трассировки: %d
", mdatsz);

    return 0;
}
    
Листинг 8.17. Пример программы, выясняющей подразумеваемые значения атрибутов потока трассировки.

Обратим внимание на использование конфигурационной константы TRACE_NAME_MAX для задания размера буфера имен.

При запуске этой программы под управлением операционной системы реального времени oc2000 могут быть получены следующие результаты (см. листинг 8.18).

  Версия системы трассировки: 2.17
  Имя потока трассировки: trace
  Время создания потока трассировки: Пн 19 АПР 2004 11:54:07
  Разрешающая способность часов потока трассировки: 41904 нсек
  Правило обработки ситуации заполнения потока: POSIX_TRACE_UNTIL_FULL
  Правило обработки ситуации заполнения журнала трассировки: POSIX_TRACE_LOOP
  Максимальный размер данных в пользовательском событии: 100
  Максимальный размер пользовательского события: 128
  Максимальный размер системного события: 84
  Размер потока трассировки: 409600
    
Листинг 8.18. Возможные результаты работы программы, выясняющей подразумеваемые значения атрибутов потока трассировки.

Отметим нестандартность конфигурации системы применительно к обработке ситуации заполнения потока: POSIX-2001 предусматривает, что подразумеваемыми (в зависимости от наличия журнала) могут быть лишь значения POSIX_TRACE_LOOP или POSIX_TRACE_FLUSH, но не POSIX_TRACE_UNTIL_FULL.

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

Функции для работы с событиями

От рассмотрения средств, доступных трассирующему процессу, мы переходим к функциям, используемым для оборудования трассируемых пользовательских приложений. Таких функций две: posix_trace_event() и posix_trace_eventid_open() (см. листинг 8.19).

#include <sys/types.h>
#include <trace.h>

void posix_trace_event (
    trace_event_id_t event_id, 
    const void *restrict data_ptr, 
    size_t data_len);

int posix_trace_eventid_open (
    const char *restrict event_name, 
    trace_event_id_t *restrict event_id);
    
Листинг 8.19. Описание функций для оборудования трассируемых пользовательских приложений.

Вызов функции posix_trace_event() создает точку трассировки, при попадании в которую генерируется пользовательское событие с идентификатором типа event_id и ассоциированными данными, специфицированными аргументами data_ptr (адрес буфера) и data_len (размер буфера). Если трассировка идет и события заданного типа не задерживаются фильтром, соответствующая информация будет записана в потоки, созданные ранее для трассировки вызывающего процесса. В противном случае вызов posix_trace_event() игнорируется.

Функция posix_trace_eventid_open(), ассоциирующая имя события с идентификатором типа, по сути аналогична posix_trace_trid_eventid_open(), только поток задается неявно (как поток, куда идет трассировка вызывающего процесса). Очевидно, подобная функция необходима для формирования аргумента event_id перед вызовами posix_trace_event().

Что касается анализирующего процесса, то обычно он в первую очередь открывает ранее записанный журнал трассировки, обращаясь к функции posix_trace_open(), а, обработав, закрывает его с помощью функции posix_trace_close(), быть может, в промежутке позиционируясь на начало журнала посредством функции posix_trace_rewind() (см. листинг 8.20).

#include <trace.h>
int posix_trace_open (
    int fildes, trace_id_t *trid);
int posix_trace_close (trace_id_t trid);
int posix_trace_rewind (trace_id_t trid);
    
Листинг 8.20. Описание функций для работы с журналами трассировки.

Функция posix_trace_open(), отправляясь от файлового дескриптора журнала трассировки fildes, открытого на чтение, создает поток трассировки и записывает его идентификатор по указателю trid. С помощью этого идентификатора анализирующий процесс может опрашивать атрибуты и статус потока и, главное, читать из него события, вызывая функцию posix_trace_getnext_event() (см. листинг 8.21).

#include <sys/types.h>
#include *lt;trace.h>

int posix_trace_getnext_event (
    trace_id_t trid, 
    struct posix_trace_event_info 
                          *restrict event,
    void *restrict data_ptr, 
    size_t num_bytes,
    size_t *restrict data_len, 
    int *restrict unavailable);

int posix_trace_timedgetnext_event (
    trace_id_t trid,
    struct posix_trace_event_info 
                          *restrict event,
    void *restrict data_ptr, 
    size_t num_bytes, 
    size_t *restrict data_len, 
    int *restrict unavailable, 
    const struct timespec *restrict abstime);

int posix_trace_trygetnext_event (
    trace_id_t trid, 
    struct posix_trace_event_info 
                          *restrict event, 
    void *restrict data_ptr, 
    size_t num_bytes, 
    size_t *restrict data_len, 
    int *restrict unavailable);
    
Листинг 8.21. Описание функций чтения событий трассировки.

Функция posix_trace_getnext_event() выдает очередное событие из потока трассировки, который может быть как предварительно записанным в журнале, так и активным (в последнем случае анализирующий процесс должен совпадать с трассирующим). События выдаются в порядке их генерации, то есть от самого старого к самому новому.

Информация о событии помещается в структуру типа posix_trace_event_info, на которую указывает аргумент event. Данные, ассоциированные с событием, записываются в буфер с адресом data_ptr и длиной num_bytes; по указателю data_len размещается число записанных в буфер байт данных. Наконец, в случае успешного чтения по указателю unavailable помещается нулевое значение.

Если аргумент trid идентифицирует активный поток трассировки, вызов posix_trace_getnextК началу статьи





Добавил: MadvEXДата публикации: 2006-02-28 01:29:33
Рейтинг статьи:3.00 [Голосов 5]Кол-во просмотров: 6515

Комментарии читателей

Всего комментариев: 69

2016-06-09 07:56:18
avtoTypE
Аренда толщиномера ЛКП в Киеве http://e95.biz/rent-thickness/

2016-01-17 19:20:40
slavitaSaX
проститутки Нижнего Новгорода <a href=http://dosugnnov.com/>секс знакомства нижний новгород бесплатно</a>

2013-07-20 10:19:55
marketLD
доставка алкоголя ночью Нижний Новгород http://marketnn24.ru/

2013-07-06 20:57:57
MasterLL
Регистрация некоммерческих организаций - НКО http://legal-master.ru/site/38 - Регистрация ООО - Обществ с ограниченной ответственностью

2013-07-03 04:02:18
indivNN
проститутки Нижний Новгород http://individualkinn.com/ - интим

2013-07-03 04:02:03
tusANN
Проститутки Нижнего Новгорода http://tusovkann.com/ - досуг

2013-06-29 16:43:08
WoRkNN
высокооплачиваемая работа девушкам Нижний Новгород http://workdosug.com/

2013-03-30 03:54:20
watchNewS
<p>Брендовые часы могут свидетельствовать о финансовом благополучии их владельца. Ведь это самое настоящее искусство, привлекающее своим неоспоримым достоинством. Только вот купить такой элемент роскоши не все могут себе позволить, потому что цена оригинальной продукции очень часто заоблачная. По этой причине в наше время, очень многие покупатели отдают свое предпочтение, в первую очередь копиям.</p>
http://www.newwatch.com.ua/

2013-03-07 03:13:36
predstar
Представительство в Китае http://www.vostar.ru/services.asp

2013-02-26 21:08:06
MarinaPikap
Проститутки Ростова http://pikaprostov.com/
Ваше имя: *
Текст записи: *
Имя:

Пароль:



Регистрация

Какую БД предпочитаете?
MSSQL
20% (38)
BDE
1% (1)
MySQL
35% (68)
Access
6% (11)
InterBase
11% (21)
Paradox
3% (5)
Oracle
10% (19)
PostgreSQL
0% (0)
Другой
3% (6)
Не использую БД!
12% (23)

Проголосовало: 192
Программист и инженер оказались друг возле друга во время долгого полета из Москвы в Нью-Йорк. Программист обращается к инженеру и спрашивает, не желает ли тот скоротать время игрой в одну занятную игру. Инженеру очень хотелось спать и он, вежливо отказавшись, прильнул к окну, чтобы хоть немного вздремнуть. Программист же, продолжая настаивать, обьясняет, что игра, мол, очень занятная и простая. - Я задаю вам вопрос и если вы не знаете ответа, вы платите мне пять баксов. А потом вы задаете мне вопрос. Если я не знаю ответа, то плачу соответсвенно пять баксов вам. Но инженер снова вежливо отказывается и пытается уснуть. Ну, программист уже самозавелся и говорит:
- Ну ладно, если вы не знаете ответа, то платите мне $5, а если я не знаю, то плачу вам $50!! Это в конце концов заинтересовало инженера, тем более,что он видит, что от программиста отделаться не так легко. Он соглашается. Програмист cпрашивает:
- Каково расстояние между Луной и Солнцем?
Инженер не говоря ни слова лезет в карман, достает бумажник, вытаскивет $5 и протягивает их программисту. Очередь инженера:
- Что идет вверх на трeх ногах, а спускается на четырех? - спрашивает он программиста и отворачивается к окну. Программист ошалело на него посмотрел и достает свой Лаптоп. Прошелся по всем своим поисковым системам. Ничего. Тогда подключается к бортовому телефону, рыщет по Интернету, прочесал всю библиотеку Конгресса. Ничего. Посылает е-мейлы всем своим сотрудникам с запросом. Ничего. Через час он будит инженера и дает ему $50. Инженер аккуратненько свернул деньги, положил их в кармашек и повернулся к окну спать. Охр@невший программист трясет инженера за плечо и спрашивает:
- Так какой же все-таки ответ?!
Не говоря ни слова, инженер достает свой кошелек, дает программисту $5 и поворачивается к окну, чтобы докимарить до Нью-Йорка...
Рейтинг: 8.6/10 (13)
Посмотреть все анекдоты