rr

Недавно наткнулся на rr (Record and Replay Framework) от Mozilla и я вам скажу, что это просто незаменимый инструмент для ловли неуловимых багов в отладчике. Это не первый и не единственный инструмент подобного плана. Соответствующая страница проекта описывает десятка три альтернатив. Из этого списка мне раньше доводилось работать только с iDNA, который впоследствии стал Time Travel Tracing (TTT). TTT мог записать процесс выполнения программы с точностью до инструкции и воспроизвести его в точности в прямом и обратном направлении. TTT был просто незаменим для ловли сложных багов и его главным недостатком было то, что TTT был внутренним инструментом, который Microsoft так и не выпустила как отдельный продукт.

rr тоже может записать выполнение процесса с точностью до инструкции и проиграть его назад и вперед. rr требует современного процессора, причем обязательно Intel, так как использует performance counters которые не реализованы в других процессорах. ARM и другие архитектуры тоже не поддерживаются. В обмен на это, rr практически не замедляет записываемый процесс. Скорость выполнения падает в 1.2 раза - сущие пустяки. Размер генерируемой записи тоже крайне скромен - в районе гигабайта за 10-15 минут выполнения “вычислительного” кода. Практически бесплатно. В пересчете на количество выполненных инструкций получается что-то вроде 0.1 бита на выполненную инструкцию.

Что интересно, rr базируется на очень простой идее: большая часть кода выполняется всегда одинаково. Если записать все случайные события (ввод/вывод, RDTSC, системный вызовы) и начальные условия (содержимое памяти), то процесс выполнения становится полностью детерминированным. Более детально можно почитать здесь: http://rr-project.org/rr.html.

Процесс отладки с помощью rr выглядит так:

  1. Записываем процесс: rr record <program>
  2. Запускаем запись в отладчике: rr replay
  3. Проматываем до конца и смотрим чем вызван segfault.
  4. Ставим watchpoint на память из которой читается плохой указатель.
  5. Выполняем программу назад пока не сработает watchpoint.
  6. Смотрим почему в память пишется плохой указатель и повторяем шаги 4-6 до победного конца.

Дополнительный бонус заключается в том, что все адреса при повторном воспроизведении сохраняются. Если нужная переменная находится по адресу 0x123fooba, то она там будет всегда. Отпадает необходимость выяснять где в памяти находится интересный кусок каждый раз при запуске отладчика. rr также может помечать вывод в stdout метками для быстрой перемотки в нужное место. Это помогает сопоставить код с интересными местами в лог файлах.

Само собой, у rr есть куча других ограничений. К примеру, он не работает под Windows, не поддерживаются все системные вызовы, не поддерживается циклическая запись (последние несколько минут выполнения процесса), поддерживается только одно процессорное ядро, и т.д. Тем не менее, если вы столкнулись с “невозможным” багом в Linux, rr - один из наиболее вероятных способов докопаться до источника проблемы.

comments powered by Disqus