Опубликован: 06.12.2004 | Доступ: свободный | Студентов: 1180 / 143 | Оценка: 4.76 / 4.29 | Длительность: 20:58:00
ISBN: 978-5-9556-0021-5
Лекция 8:

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

Стандартом 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\n", trbuf);

    if ((errno = posix_trace_attr_getname 
            (&attr, trbuf)) != 0) {
        perror ("POSIX_TRACE_ATTR_GETNAME");
        return (errno);
    }
    printf ("Имя потока трассировки: %s\n", 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\n", dtbuf);

    if ((errno = posix_trace_attr_getclockres 
            (&attr, &tms)) != 0) {
        perror ("POSIX_TRACE_ATTR_GETCLOCKRES");
        return (errno);
    }
    printf ("Разрешающая способность часов потока "
                "трассировки: %ld нсек\n", 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\n");
            break;
        case POSIX_TRACE_UNTIL_FULL:
            printf ("POSIX_TRACE_UNTIL_FULL\n");
            break;
        case POSIX_TRACE_FLUSH:
            printf ("POSIX_TRACE_FLUSH\n");
            break;
        default:
            printf ("неизвестно\n");
    }

    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\n");
            break;
        case POSIX_TRACE_UNTIL_FULL:
            printf ("POSIX_TRACE_UNTIL_FULL\n");
            break;
        case POSIX_TRACE_APPEND:
            printf ("POSIX_TRACE_APPEND\n");
            break;
        default:
            printf ("неизвестно\n");
    }

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

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

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

    if ((errno = posix_trace_attr_getstreamsize 
            (&attr, &mdatsz)) != 0) {
        perror ("POSIX_TRACE_ATTR_GETSTREAMSIZE");
        return (errno);
    }
    printf ("Размер потока трассировки: %d\n", 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.

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