Поиск по сайту:

Как использовать strace для мониторинга системных вызовов Linux


Linux-программы просят ядро что-то сделать за них. Команда strace показывает эти системные вызовы. Вы можете использовать их, чтобы понять, как работают программы и почему иногда они не работают.

Ядро и системные вызовы

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

Возможность видеть системные вызовы, сделанные программой, и ответы на них может помочь вам понять внутреннюю работу программ, которые вас интересуют или которые вы написали. Именно это и делает strace. Это может помочь в устранении неполадок и поиске узких мест.

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

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

Установка strace

Если strace еще не установлен на вашем компьютере, вы можете легко установить его.

В Ubuntu используйте эту команду:

sudo apt install strace

В Fedora введите следующую команду:

sudo dnf install strace

На Manjaro команда такая:

sudo pacman -Sy strace

Первые шаги со strace

Мы будем использовать небольшую программу для демонстрации strace. Он мало что делает: открывает файл и записывает в него строку текста, и в нем нет проверки ошибок. Это просто быстрый хак, чтобы нам было что использовать с strace.

#include <stdio.h>

int main(int argc, char argv[]) { 

  // file handle 
  FILE *fileGeek;

  // open a file called "strace_demo.txt", or create it 
  fileGeek = fopen("strace_demo.txt", "w");

  // write some text to the file 
  fprintf(fileGeek, "Write this to the file" );

  // close the file 
  fclose(fileGeek);

  // exit from program 
  return (0); 

} // end of main

Мы сохранили это в файл с именем «file-io.c» и скомпилировали его с помощью gcc в исполняемый файл с именем stex, названный в честь «st раса примердостаточная».

gcc -o stex file-io.c

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

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

strace ./stex

Мы можем ясно видеть системный вызов write, отправляющий текст «Записать это в файл» в наш открытый файл, и системный вызов exit_group. Это завершает все потоки в приложении и отправляет возвращаемое значение обратно в оболочку.

Фильтрация вывода

Даже наша простая демонстрационная программа дает довольно много результатов. Мы можем использовать параметр -e (выражение). Мы передадим имя системного вызова, который мы хотим увидеть.

strace -e write ./stex

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

strace -e close,write ./stex

Отправка вывода в файл

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

Иногда удобнее захватить все, а затем искать и прокручивать весь набор результатов. Таким образом, вы случайно не исключите ничего важного. Параметр -o (вывод) позволяет отправлять выходные данные сеанса strace в текстовый файл.

strace -o trace-output.txt ./stex

Затем вы можете использовать команду less для прокрутки списка и поиска системных вызовов или чего-либо еще по имени.

less trace-output.txt

Теперь вы можете использовать все возможности поиска less для изучения результатов.

Добавление временных меток

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

strace -r ./stex

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

Чтобы увидеть количество времени, потраченное на каждый системный вызов, используйте параметр -T (syscall-time). Это показывает продолжительность времени, проведенного внутри каждого системного вызова.

strace -T ./stex

Продолжительность времени показана в конце каждой строки системного вызова.

Чтобы увидеть время вызова каждого системного вызова, используйте параметр -tt (отметки абсолютного времени). Это показывает время «настенных часов» с микросекундным разрешением.

strace -tt ./stex

Время отображается в начале каждой строки.

Отслеживание запущенного процесса

Если процесс, который вы хотите отслеживать, уже запущен, вы все равно можете прикрепить к нему strace. Для этого вам нужно знать идентификатор процесса. Вы можете использовать ps с grep, чтобы найти это. У нас запущен Firefox. Чтобы узнать идентификатор процесса firefox, мы можем использовать ps и передать его через grep.

ps -e | grep firefox

Мы видим, что идентификатор процесса равен 8483. Мы будем использовать параметр -p (идентификатор процесса), чтобы сообщить strace, к какому процессу следует подключиться. Обратите внимание, что вам нужно будет использовать sudo :

sudo strace -p 8483

Вы увидите уведомление о том, что strace присоединился к процессу, а затем вызовы системной трассировки будут отображаться в окне терминала, как обычно.

Создание отчета

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

strace -c ./stex

Столбцы:

  • % времени: процент времени выполнения, затраченного на каждый системный вызов.
  • секунды: общее время, выраженное в секундах и микросекундах, потраченное на каждый системный вызов.
  • usecs/call: среднее время в микросекундах, потраченное на каждый системный вызов.
  • вызовы: количество выполнений каждого системного вызова.
  • ошибки: количество сбоев для каждого системного вызова.
  • syscall: имя системного вызова.

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

Глубокое понимание, легко

Вывод strace может показать вам, какие системные вызовы выполняются, какие выполняются повторно и сколько времени выполнения тратится на код на стороне ядра. Это отличная информация. Часто, когда вы пытаетесь понять, что происходит внутри вашего кода, легко забыть, что ваш двоичный файл практически безостановочно взаимодействует с ядром для выполнения многих его функций.

Используя strace, вы видите полную картину.

RELATED: Best Linux Laptops for Developers and Enthusiasts