Отладка, профилирование и хороший стиль

Как находить ошибки, выяснять, что тормозит, и писать код, который потом можно прочитать.

Профилирование — измерение, сколько времени тратит каждая строка кода, чтобы найти узкое место.

Отладка с точками останова

Когда программа ведёт себя не так, помогает пошаговое выполнение. В редакторе ставят точку останова (breakpoint) щелчком слева от строки. При запуске выполнение замрёт на ней, и в Command Window можно осмотреть значения переменных, выполнить выражения, шагнуть дальше. Программно точку задаёт dbstop, продолжение — dbcont, выход — dbquit.

dbstop if error      % остановиться при любой ошибке
% запустить программу — отладчик поймает место сбоя
x = 5;
whos                 % осмотреть переменные на паузе

Особенно полезен dbstop if error: он автоматически останавливает выполнение в точке, где возникла ошибка, и вы видите состояние программы именно в момент сбоя.

Профилирование скорости

Если код медленный, не гадайте — измеряйте. Профайлер показывает, какие строки и функции съедают время. Его запускают вокруг подозрительного кода.

profile on
my_slow_script        % запустить анализируемый код
profile viewer        % открыть отчёт о времени

Для быстрого замера одного фрагмента есть пара tic/toc: tic запускает секундомер, toc печатает прошедшее время. Это первый инструмент, чтобы проверить, действительно ли векторизация ускорила код.

tic
y = (1:1e6).^2;       % векторизованный расчёт
toc                   % печатает: Elapsed time is ... seconds

Предупреждения редактора

MATLAB-редактор сам подсвечивает проблемные места: неиспользованные переменные, отсутствие точки с запятой в цикле (потенциальный лишний вывод), растущие в цикле массивы без preallocation. Эти подсказки (Code Analyzer, mlint) стоит читать — они часто указывают именно на то, что замедляет код.

Как работает под капотом

Профайлер вставляет в выполнение счётчики, фиксирующие вход и выход каждой функции и время между ними. Поэтому он немного замедляет код, но даёт верную относительную картину: где доля времени велика. Главное правило оптимизации следует прямо из этого: сначала измерь, потом ускоряй. Чаще всего 90% времени уходит на несколько строк — обычно это циклы, которые стоило векторизовать. Оптимизировать что-то ещё до профилирования — почти всегда потеря сил.

Воспроизводимость как страховка

Лучшая отладка — та, которой удалось избежать, и здесь помогает дисциплина воспроизводимости. Скрипт, начинающийся с clear; clc; rng(0);, гарантирует чистый старт и повторяемые случайные числа: запустив его дважды, вы получите тот же результат и сможете уверенно сравнивать «до» и «после» правки. Без этого случайная разница в данных маскируется под баг, и часы уходят на поиск ошибки, которой нет. Разбиение кода на функции с понятными входами и выходами тоже служит отладке: подозрительную функцию можно вызвать изолированно с тестовыми аргументами и проверить её ответ, не запуская всю программу. Эти привычки — чистый старт, фиксированное зерно, изолированные функции — превращают отладку из гадания в методичную проверку, где каждый эксперимент воспроизводим.

Частые ошибки

  • Оптимизировать «на глаз» без профайлера — и ускорять не то место.
  • Игнорировать подсказки Code Analyzer, которые прямо указывают на проблемы.
  • Забыть убрать dbstop или оставить отладочные выводы в итоговом коде.

Векторизация под микроскопом профайлера

Профилирование особенно ценно для проверки главного навыка курса — векторизации. Легко поверить, что переписанный без циклов код стал быстрее; профайлер и пара tic/toc позволяют это измерить и убедиться. Часто результат впечатляет: цикл, перебиравший миллион элементов секунды, после векторизации отрабатывает за миллисекунды. Но бывает и наоборот — преждевременная «оптимизация» усложняет код, не ускоряя его, потому что узкое место было в другом месте. Профайлер расставляет точки над i: он показывает, что код проводит 95% времени вот в этих трёх строках, и именно их стоит улучшать. Без измерения интуиция о «медленных местах» обманывает удивительно часто.

Читаемость как часть качества

Отладка тем легче, чем чище написан код, поэтому стиль — не косметика, а инвестиция. Осмысленные имена переменных (velocity вместо v2), комментарии, объясняющие «зачем», а не «что», разбиение длинных скриптов на функции, единообразное форматирование — всё это сокращает время будущей отладки, в том числе вашей собственной через месяц. MATLAB поощряет хороший стиль встроенными средствами: Code Analyzer подсвечивает сомнительные места, автоформатирование выравнивает отступы, а функция help читает структурированные комментарии в начале файла как документацию. Привычка писать аккуратно с первого раза окупается каждый раз, когда приходится возвращаться к старому коду и разбираться, что он делает.

Итоги

  • Точки останова и dbstop if error ловят момент сбоя для осмотра переменных.
  • profile и tic/toc показывают, где тратится время.
  • Правило: сначала измерь профайлером, потом оптимизируй узкое место (обычно цикл).
Проверьте себя
1. Что делает dbstop if error?
AУдаляет ошибки
BОстанавливает выполнение в точке возникновения ошибки
CИгнорирует ошибки
DПерезапускает программу
2. Зачем нужна пара tic/toc?
AДля отладки синтаксиса
BДля замера времени выполнения фрагмента кода
CДля рисования графика
DДля очистки переменных
3. Какое правило оптимизации следует из работы профайлера?
AОптимизируй всё подряд
BСначала измерь, потом ускоряй узкое место
CНикогда не используй циклы
DПрофилируй только в конце проекта