@Magneto903

Как на javascript замерить время выполнения функции (в наносекундах)?

У меня есть список некоторых функций, выполняющий математические операции. Мне нужно замерить время их выполнения в наносекундах, с учётом того, что аргумент - случайное число. Проблема в том, что когда я несколько раз выполняю измерение, то это время слишком сильно различается.
Рассмотрим на конкретной функции:
var func = function(x) {
   return x*x
}

Она возводит число в квадрат
Теперь кажется очевидным, что скорость нужно измерить таким образом
var func = function(x) {
   return x*x
}

var s_time = performance.now()
func(Math.random())
var dur = performance.now() - s_time
console.log(dur)



Но во-первых, эта функция слишком быстро выполняется, чтобы её можно измерить выполнив один раз (возведение в квадрат это несколько десятков наносекунд, а не микросекунд (я так думал...))
Во-вторых, если несколько раз запускать, то значения сильно разнятся от 0.005 до 0.04 ms

Поэтому выполним сразу достаточно большое число итераций, а время просто разделим на это кол-во итераций.
var func = function(x) {
   return x*x
}

var iterations = 1000000

var s_time = performance.now()
for (var i=0; i < iterations; i++) { func(Math.random()) }
var dur = (performance.now() - s_time)/iterations*1000*1000
document.write(iterations + " итераций: "+ dur.toFixed(4)+' ns/итерация<br>')

Я решил проверить на нескольких итерациях


Чем больше использовать итераций, тем быстрее каждая операция просчитывается. Я думал грубо говоря, что 100 раз возвести в квадрат в 10 раз медленее, чем возвести в квадрат 10 раз. Но судя по результатам этой программы, это не так. Только на последних двух записях примерно равно время выполнения одной операции.

Вопрос в том, какая из полученных скоростей правильная? И можно ли как-то быстрее это измерять? Запускать 1 миллиард и даже 100 миллионов раз операцию может оказаться слишком долго
  • Вопрос задан
  • 3816 просмотров
Решения вопроса 1
Robur
@Robur
Знаю больше чем это необходимо
точное время выполнения одного вызова функции получить довольно сложно.

во первых - performance.now возвращает дробное число, поэтому там в принципе может быть наносекундная точность. однако стандарт определяет что точность должна быть 5 микросекунд. Плюс браузеры могут специально занижать точность чтобы бороться с некоторыми атаками.

поэтому правильно вызывать функцию много раз и считать среднее.
так же в ноде есть process.hrtime которая дает наносекунды.

оба этих метода "в лоб" не дадут нормального результата. Почему? потому что в реальности происходит много всего интересного при выполнении кода.

в движке есть неимоверное количество оптимизаций, и функция вызванная 10 раз будет иметь совершенно другой код чем функция вызванная 100 раз. То же касается и типов параметров - например вы можете передавать целые или дробные числа.
На одну вашу написанную js-функцию движок сгенерирует несколько функций которые это реализуют. У этих функций может быть совершенно разный код с разной произодительностью.

Переключение происходит на лету и в общем виде вы не знаете когда это происходит.

поэтому само по себе замерение скорости "функции" имеет мало смысла, так как там их несколько внутри. Если интересны детали - погуглите JIT, AOT и v8 optimizations.
Сейчас важно то что есть "холодные" функции которые работают медленее но надеждее и как правило используются сразу и есть "горячие" варианты, которые компилятор начинает использовать когда видит что код вызван много раз, и условия не меняются. "Горячие" работают быстрее.

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

зная это, код можно сначала разогреть а потом померять скорость. скорее всего на разогретом коде будет работать один и тот же вариант.

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

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

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

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

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы