Найти тему
Блокнот математика

Рубрика "Секреты Вим". Скриптовый язык: хронометрия

Привет, коллеги! Поговорим о профилировке (profiling), что лучше переводить как "хронометрия" или "хронометраж". Или, если вы славянофил, "замер быстродействия".

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

Проверьте: echo has('profile') должно выдать 1, если профилировка поддерживается, а echo has('reltime') даст 1, если имеется таймер.
У меня на Ubuntu всё есть в поставке.

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

Начнем с таймера. У нас есть функции reltime и reltimestr, с которыми и познакомимся. Первая может вызываться без параметров, с одним или двумя. Возвращает нечто, имеющее смысл времени; формат зависит от системы, но может быть преобразован в строку, о чем далее. Без параметров возвращает текущее время ("засекает время"). С одним параметром возвращает время, прошедшее с указанного (там должно быть что-то, возвращенное той же функцией). С двумя аргументами возвращает время от первого до второго, и оба должны быть ранее возвращены этой же функцией.

Вторая функция принимает результат первой и преобразует его в текст: число секунд, точка, число микросекунд. Например, 5.189144.

Вот как это работает:

let start = reltime()
call MyFunction()
echo reltimestr(reltime(start))

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

Профилировщик может выполнить часть работы за нас.

Начинаем с команды

:profile start ФАЙЛ

В указанном файле будет отчет по быстродействию. Если файл существует, он будет перезаписан без предупреждения. Запись произойдет после закрытия Вим. Системная переменная v:profiling будет равна 1.

profile pause приостановит хронометрию. Позволяет выполнить что-то, что "не считается".

profile continue возобновляет хронометрию.

profile func ИМЯ замерит функцию, имя которой подпадает под шаблон. Про шаблоны см. заметку про отладку.

profile file ИМЯ замерит скрипт, имя которого подпадает под шаблон. Отчет будет по файлу, но не по функциям в нем. Если использовать восклицательный знак, отчет будет также по всем функциям в файле.

Хронометрия начнется после загрузки скрипта после этой команды, поэтому включать ее саму в файл смысла нет.

profdel отменяет хронометрию для указанных объектов. Полностью аналогично удалению контрольных точек (см. материал про отладку).

Типичная хронометрия выглядит так:

:profile start my_script_profile.txt
:profile! file my_script.vim
:source one_script.vim
:exit

Вот, например, я написал небольшой скрипт, просто на пробу:

function! Exp(x)
let s=0
let i=0
let f=1
let pf=1
while i < 200
let s+=pf
let i+=1
let pf=pf*(a:x+0.0)/(i+0.0)
endwhile
return s
endfunc
let b:x=1.1
echo Exp(b:x) '=' exp(b:x)

Сохранил его и провел хронометрию. Получил отчет, который на скриншотах.

Обратите внимание, что если идет взаимодействие с пользователем, например, запрос символа - то время на ожидание в счет не идет.

Ещё немного нюансов из Справки:

  • Скрипт может узнать, что он в режиме хронометрии: по переменной v:profiling.
  • Системные часы не дают такой точности, как можно ожидать от выдачи: до микросекунды. Точность намного ниже.
  • Кроме того, в мультизадачных многопроцессорных системах могут быть задержки.
  • Если несколько команд на одной строке через связку |, то они считаются за одну команду
  • Обычно сумма времен для строк функции меньше, чем время на функцию. Вот в моем примере, если я правильно посчитал, сумма строк функции дает 0.001252, а вся функция 0.001340.
  • Если функция отработала и позже удалена, она в счет не пойдет.
  • Собственное время неправильно считается для рекурсивных функций.

Удачи, коллеги! Ссылки на все мои материалы по языку Вим вы найдете в предыдущей заметке.

Научно-популярные каналы на Дзене: путеводитель
Новости популярной науки12 марта 2022