Иногда необходимо получить представление о том, насколько часто происходит некоторое событие. Иногда требуется сравнить несколько событий и вычислить характеристики для их сравнения. Это очень легко сделать путем введения статистки и механизма для экспортирования соответствующих параметров.
Например, допустим, что необходимо выяснить на сколько часто происходит событие foo и событие bar . В файле исходного кода, в идеале там, где соответствующие события возникают, вводится две глобальные переменные.
unsigned long foo_stat = 0;
unsigned long bar_stat = 0;
Как только наступает интересующее событие, значение соответствующей переменной увеличивается на единицу. Эти переменные могут быть экспортированы как угодно. Например, можно создать интерфейс к ним через файловую систему /proc, или написать свой системный вызов. Наиболее просто прочитать их значение с помощью отладчика.
Следует обратить внимание, что такой подход принципиально не безопасен на SMP машине. В идеале необходимо использовать атомарные переменные. Однако, для временной статистики, которая необходима только для отладки, никакой защиты обычно не требуется.
Ограничение частоты следования событий при отладке
Часто необходимо встроить в код отладочные проверки (с соответствующими функциями вывода информации), чтобы визуально производить мониторинг проблемы. Однако, в ядре некоторые функции вызываются по много раз в секунду. Если в такую функцию будет встроен вызов функции printk()
, то системная консоль будет перегружена выводом отладочных сообщений и ее будет невозможно использовать.
Для предотвращения такой проблемы существует два сравнительно простых приема. Первый — ограничение частоты следования событий — очень полезен, когда необходимо наблюдать, как развивается событие, но частота возникновения события очень большая. Чтобы ограничить поток отладочных сообщений, эти сообщения выводятся только раз в несколько секунд, как это показано в следующем примере.
static unsigned long prev_jiffy = jiffies; /* ограничение частоты */
if (time_after(jiffies, prev_jiffy + 2*HZ)) {
prev_jiffy = jiffies;
printk(KERN_ERR "blah blah blah\n");
}
В этом примере отладочные сообщения выводятся не чаще, чем один раз в две секунды. Это предотвращает перегрузку консоли сообщениями и системой можно нормально пользоваться. Частота вывода может быть большей, или меньшей, в зависимости от требований.
Вторая ситуация имеет место, когда необходимо замечать любые появления события. В отличие от предыдущего примера нет необходимости выполнять мониторинг развития событий. А только получить сообщение о том, что что-то произошло. Вероятно это уведомление необходимо получить один, или два раза. Проблема возникает в том случае, если проверка, которая после того, как сработала один раз, начинает срабатывать постоянно. Решением в данном случае будет не ограничение частоты, а ограничение общего количества повторений.
static unsigned long limit = 0;
if (limit < 5) {
limit++;
printk(KERN_ERR "blah blah blah\n");
}
В этом примере количество отладочных сообщений ограничено числом пять. После пяти сообщений условие всегда будет ложно.
В обоих примерах переменные должны быть статическими ( static
) и локальными по отношению к той функции, где используются. Это позволяет использовать одинаковые имена переменных в разных функциях.
Ни один из этих примеров не рассчитан на SMP, или преемптивность, хотя очень легко перейти к атомарным операциям и сделать их безопасными для использования и в этих случаях. Однако, честно говоря, это всего лишь отладочный код, поэтому зачем нужны лишние проблемы?
Нахождение исполняемых образов с изменениями приводящими к ошибкам
Обычно полезно знать, в какой версии исходных кодов ядра появился дефект. Если известно, что дефект появился в версии 2.4.18, но его не было в версии 2.4.17, то сразу появляется ясная картина изменений, которые привели к появлению ошибки. Исправление ошибки сводится к обратным изменениям, или другим исправлениям измененного кода.
Однако, чаще оказывается неизвестным в какой версии появился дефект. Известно, что проблема проявляется в текущей версии ядра, и кажется, что она всегда была в текущей версии. Хотя это и требует некоторой исследовательской работы, но приложив небольшие усилия можно найти изменения, которые привели к ошибкам. Если известны эти изменения, то до исправления ошибки уже недалеко.
Читать дальше