Сохранение данных системной трассы
В этой главе:
Программа сбора данных является посредником между диагностической версией ядра и файловой системой.
Основная задача программы сбора данных — передача буферов, полученных от диагностической версии ядра, в файл или на устройство вывода. Для выполнения этой функции программе также необходимо:
Перед регистрацией данных необходимо настраивать диагностическую версию ядра. Конфигурация диагностической версии ядра включает в себя следующие настройки:
![]() | Диагностическая версия ядра сохраняет настройки в одной конфигурации, которой пользуются различные программы. Изменение настроек в одном процессе приводит к отмене настроек, заданных в другом процессе. |
По умолчанию для сбора данных используется утилита tracelogger. При желании пользователь может создать собственную утилиту, однако в этом, как правило, нет необходимости; тем не менее, при возникновении такой задачи самым быстрым способом ее решения является адаптация кода утилиты tracelogger под потребности пользователя.
Управлять сбором данных можно с помощью демона qconn (используя внешние средства), утилиты tracelogger (из командной строки) или непосредственно из пользовательского приложения. Во всех трех методах управление диагностическим ядром осуществляется с помощью функции TraceEvent():
Сначала рассмотрим утилиту tracelogger, а затем управление трассировкой из пользовательского приложения с помощью функции TraceEvent().
![]() |
|
Параметры запуска утилиты tracelogger определяют, каким образом диагностическая версия ядра регистрирует события и как tracelogger собирает их. В этом разделе рассматриваются следующие темы:
Для управления буферами диагностической версии ядра можно использовать командно-строковые параметры утилиты tracelogger:
Также можно задавать количество буферов, используемых самой утилитой tracelogger.
С помощью командно-строковых аргументов можно запускать утилиту tracelogger в различных режимах, которые определяют, как выполняется трассировка и какие события участвуют в ней:
Все описанные выше режимы, за исключением режима демона, в совокупности называются нормальным режимом. В нормальном режиме настройка, запуск и останов трассировки выполняются в командной строке, а в режиме демона (-d1) — в коде приложения. Параметр -E позволяет использовать возможности обоих режимов: командно-строковую настройку трассировки (как в нормальном режиме) и полный контроль над ней (как в режиме демона).
Ниже перечислены преимущества, недостатки и возможности указанных режимов:
Функция | Нормальный режим | Режим демона | Расширенный режим демона |
---|---|---|---|
Поддержка tracelogger | Полная | Ограниченная | Полная |
Управляемость | Ограниченная | Полная | Полная |
События, регистрируемые по умолчанию | Все | Никакие | Все |
Степень сложности настройки | Легкая | Более сложная | Легкая |
Метод настройки | Только командная строка | Пользовательская программа, в которой вызывается функция TraceEvent() | Командная строка и пользовательская программа |
Начало регистрации событий | Моментально | В пользовательской программе (также с вызовом TraceEvent()) | В пользовательской программе (также с вызовом TraceEvent()) |
Полное описание утилиты tracelogger дано на соответствующей странице.
По умолчанию диагностическая версия ядра и утилита tracelogger собирают данные в кратком режиме; чтобы включить подробный режим, следует указать ключ -w при запуске tracelogger.
Утилита tracelogger обеспечивает основные функции управления фильтрацией с помощью ключа -F. Он позволяет отключать регистрацию целых классов событий; для более точной настройки следует использовать функцию TraceEvent(), которая описана в главе Фильтрация событий.
По умолчанию утилита tracelogger регистрирует события всех классов, однако можно отключать трассировку событий определенного класса следующим образом:
Отключаемый класс | Опция |
---|---|
Вызовы ядра | -F1 |
Прерывания | -F2 |
Процессы | -F3 |
Потоки | -F4 |
Виртуальные потоки | -F5 |
Связь | -F6 |
Система | -F7 |
Можно задавать более одного фильтра, указывая ключ -F несколько раз. Следует иметь в виду, что этот ключ не позволяет отключать классы управления и пользователя. Более подробную информацию о классах см. в главе События ядра в системной трассе.
Поскольку кольцевого связанного списка может оказаться недостаточно для хранения всех событий за длительный промежуток времени, необходимо передавать трассировочный буфер программе сбора данных. Как правило, эта программа отправляет данные на устройство вывода или в файл.
По умолчанию утилита tracelogger сохраняет данные в двоичном файле /dev/shmem/tracebuffer
.kev, однако можно задать другой путь с помощью параметра -f.
Также можно размещать файл в общей памяти с помощью ключа -M, однако в этом случае необходимо указывать его максимальный размер с помощью ключа -S.
Управлять трассировкой можно не только с помощью утилиты tracelogger, но и непосредственно с помощью функции TraceEvent(), которая фактически используется утилитой tracelogger. Управление трассировкой с помощью TraceEvent() более трудоемкое, однако позволяет задавать гораздо больше различных параметров.
Можно вообще не использовать утилиту tracelogger и работать исключительно с функцией TraceEvent(), но в этом случае необходимо управлять буферами, собирать трассировочные данные и сохранять их в подходящем формате. Такой подход требует от разработчика написания значительного количества программного кода, однако исходный код утилиты tracelogger облегчает эту задачу.
На практике целесообразно совместно использовать утилиту tracelogger и функцию TraceEvent(). Например, можно управлять трассировочными данными, выполняя утилиту tracelogger в режиме демона, и вызывать функцию TraceEvent() для указания конкретных событий, участвующих в трассировке.
Вызов ядра TraceEvent() принимает различное количество аргументов. Первым аргументом всегда является команда, от которой зависит набор последующих аргументов.
В этом разделе рассматриваются следующие темы:
Подробнее см. на странице TraceEvent().
Как было сказано ранее, функция TraceEvent() позволяет управлять буферами диагностического ядра, однако удобнее следить за буферами, выполняя утилиту tracelogger в режиме демона. Тем не менее, ниже перечислены команды управления буферами функции TraceEvent():
TraceEvent( _NTO_TRACE_ALLOCBUFFER, uint bufnum, void **linkliststart );
В трассировочных буферах можно хранить 1024 простых трассировочных события.
![]() | Для использования этой команды приложение должно выполняться от имени пользователя root . |
TraceEvent( _NTO_TRACE_DEALLOCBUFFER );
Все события, которые хранятся в трассировочных буферах, теряются.
TraceEvent( _NTO_TRACE_FLUSHBUFFER );
num_events = TraceEvent( _NTO_TRACE_QUERYEVENTS );
Функция TraceEvent() не поддерживает различные режимы работы, предусмотренные в утилите tracelogger; разработчик должен указывать в приложении момент начала трассировки, ее длительность и другие параметры:
TraceEvent( _NTO_TRACE_START );TraceEvent( _NTO_TRACE_STARTNOSTATE );
Эти команды схожи, однако _NTO_TRACE_STARTNOSTATE не регистрирует информацию об исходном состоянии системы (в том числе идентификаторы потоков и имена процессов).
TraceEvent( _NTO_TRACE_STOP );
Можно выполнять трассировку до накопления определенного количества данных, в течение заданного интервала времени, или ограничиваясь конкретной операцией. После останова трассировки следует очистить буфер:
TraceEvent( _NTO_TRACE_FLUSHBUFFER );
TraceEvent( _NTO_TRACE_SETRINGMODE );
Как было сказано ранее, в кольцевом режиме ядро сохраняет все события в циклическом связанном списке буферов, не очищая их.
TraceEvent( _NTO_TRACE_SETLINEARMODE );
В этом режиме сбор и очистка каждого заполненного буфера осуществляются немедленно.
Можно добавлять и удалять события из фильтра — например, создавать пустой фильтр и включать в него конкретные классы и события, или включать в фильтр все события, а затем удалять некоторые из них. Мы рассмотрим фильтрацию событий с помощью функции TraceEvent() в главе Фильтрация событий.
Функция TraceEvent() обеспечивает значительно более гибкое управление кратким и подробным режимами, чем утилита tracelogger, которая только задает режим для всех событий всех классов, участвующих в трассировке. С помощью функции TraceEvent() you can set можно назначать краткий и подробный режимы всем или некоторым классам, а также конкретным событиям определенного класса:
TraceEvent( _NTO_TRACE_SETALLCLASSESWIDE );TraceEvent( _NTO_TRACE_SETALLCLASSESFAST );
TraceEvent( _NTO_TRACE_SETCLASSFAST, int class );TraceEvent( _NTO_TRACE_SETCLASSWIDE, int class );
Пример:
TraceEvent( _NTO_TRACE_SETCLASSWIDE, _NTO_TRACE_KERCALLENTER );
TraceEvent( _NTO_TRACE_SETEVENTFAST, int class, int event );TraceEvent( _NTO_TRACE_SETEVENTWIDE, int class, int event );
Пример:
TraceEvent( _NTO_TRACE_SETEVENTFAST, _NTO_TRACE_KERCALLENTER, __KER_INTERRUPT_ATTACH );
Функция TraceEvent() позволяет вставлять пользовательские события в трассировочные данные. Можно вызывать ее непосредственно, однако гораздо удобнее использовать следующие вспомогательные функции:
Чтобы непосредственно вызвать функцию TraceEvent(), следует воспользоваться одной из следующих команд:
Дополнительную информацию см. в описании функции TraceEvent().
При отладке ситуаций, связанных с падением ядра, бывает очень полезно узнать последние выполнявшиеся действия. Выполнить это можно путем расширения информации, включаемой в дамп ядра. Процедура детально описана в статье Postmortem трассировка ядра.
Предыдущий раздел: перейти