API измерения производительности
Исходный код: lib/perf_hooks.js
Этот модуль предоставляет реализацию подмножества API производительности веб-страниц W3C Web Performance APIs, а также дополнительные API для измерений производительности, специфичных для Node.js.
Node.js поддерживает следующие API производительности веб-страниц:
const { PerformanceObserver, performance } = require('perf_hooks');
const obs = new PerformanceObserver((items) => {
console.log(items.getEntries()[0].duration);
performance.clearMarks();
});
obs.observe({ type: 'measure' });
performance.measure('Start to Now');
performance.mark('A');
doSomeLongRunningProcess(() => {
performance.measure('A to Now', 'A');
performance.mark('B');
performance.measure('A to B', 'A', 'B');
});
perf_hooks.performance
Объект, который можно использовать для сбора метрик производительности текущего экземпляра Node.js. Он аналогичен window.performance в браузерах.
performance.clearMarks([name])
-
name<строка>
Если name не предоставлен, удаляет все PerformanceMark объекты из временной шкалы производительности. Если name предоставлен, удаляет только отметку с указанным именем.
performance.eventLoopUtilization([utilization1[, utilization2]])
-
utilization1<Объект> Результат предыдущего вызоваeventLoopUtilization(). -
utilization2<Объект> Результат предыдущего вызоваeventLoopUtilization()доutilization1. - Возвращает <Объект>
Метод eventLoopUtilization() возвращает объект, содержащий кумулятивную длительность времени, в течение которого цикл событий был как простаивал, так и активен, как таймер миллисекунд с высоким разрешением. Значение utilization - вычисленная загрузка цикла событий (ELU).
Если загрузка основной нити еще не завершена, свойства имеют значение 0. ELU немедленно доступна в потоках-рабочих процессах, так как загрузка происходит в цикле событий.
И utilization1, и utilization2 являются необязательными параметрами.
Если utilization1 передается, вычисляется разность между текущим active и idle временами текущего вызова, а также соответствующее значение utilization, которые возвращаются (аналогично process.hrtime()).
Если utilization1 и utilization2 оба переданы, разность вычисляется между этими двумя аргументами. Это удобный вариант, так как, в отличие от process.hrtime(), вычисление ELU сложнее, чем простое вычитание.
ELU похожа на загрузку ЦП, за исключением того, что она измеряет только статистику цикла событий, а не использование ЦП. Она представляет собой процент времени, потраченного циклом событий вне поставщика событий цикла событий (например, epoll_wait). Другое время простоя ЦП не учитывается. Вот пример того, как у процесса, в основном простаивающего, будет высокая ELU.
'use strict';
const { eventLoopUtilization } = require('perf_hooks').performance;
const { spawnSync } = require('child_process');
setImmediate(() => {
const elu = eventLoopUtilization();
spawnSync('sleep', ['5']);
console.log(eventLoopUtilization(elu).utilization);
}); Хотя ЦП в основном простаивает во время выполнения этого скрипта, значение utilization равно 1. Это происходит потому, что вызов child_process.spawnSync() блокирует цикл событий.
Передача пользовательского объекта вместо результата предыдущего вызова eventLoopUtilization() приведет к неопределенному поведению. Значения возврата не гарантируют отражение какого-либо корректного состояния цикла событий.
performance.mark([name[, options]])
Создает новую запись PerformanceMark в временной шкале производительности. PerformanceMark — подкласс PerformanceEntry, у которого performanceEntry.entryType всегда 'mark', а performanceEntry.duration всегда 0. Отметки производительности используются для обозначения конкретных значимых моментов во временной шкале производительности.
performance.measure(name[, startMarkOrOptions[, endMark]])
-
name<строка> -
startMarkOrOptions<строка> | <Объект> Необязательно.-
detail<любой> Дополнительные необязательные детали для включения в измерение. -
duration<число> Продолжительность между начальным и конечным временем. -
end<число> | <строка> Отметка времени, используемая в качестве конечного времени, или строка, идентифицирующая ранее записанную отметку. -
start<число> | <строка> Отметка времени, используемая в качестве начального времени, или строка, идентифицирующая ранее записанную отметку.
-
-
endMark<строка> Необязательно. Должно быть опущено, еслиstartMarkOrOptionsявляется <Объектом>.
Создаёт новую запись PerformanceMeasure во временной шкале производительности. PerformanceMeasure — подкласс PerformanceEntry, у которого performanceEntry.entryType всегда 'measure', а performanceEntry.duration измеряет количество миллисекунд, прошедших с момента startMark и endMark.
Аргумент startMark может идентифицировать любую существующую PerformanceMark во временной шкале производительности или может идентифицировать любое из свойств отметки времени, предоставляемых классом PerformanceNodeTiming. Если названная startMark не существует, возникает ошибка.
Необязательный аргумент endMark должен идентифицировать любую существующую PerformanceMark во временной шкале производительности или любое из свойств отметки времени, предоставляемых классом PerformanceNodeTiming. endMark будет performance.now(), если параметр не указан; в противном случае, если указанная endMark не существует, будет выброшена ошибка.
performance.nodeTiming
Это свойство является расширением Node.js. Оно недоступно в веб-браузерах.
Экземпляр класса PerformanceNodeTiming, предоставляющий метрики производительности для определенных этапов работы Node.js.
performance.now()
- Возвращает: <число>
Возвращает текущую отметку времени миллисекунд с высоким разрешением, где 0 представляет начало текущего node процесса.
performance.timeOrigin
timeOrigin указывает отметку времени миллисекунд с высоким разрешением, в которой начался текущий node процесс, измеряемую в временной метке Unix.
performance.timerify(fn[, options])
-
fn<Функция> -
options<Объект>-
histogram<RecordableHistogram> Объект гистограммы, созданный с помощьюperf_hooks.createHistogram(), который будет записывать длительности выполнения в наносекундах.
-
Это свойство является расширением Node.js. Оно недоступно в веб-браузерах.
Оборачивает функцию в новую функцию, которая измеряет время выполнения обернутой функции. Для доступа к данным о времени необходимо подписаться на тип события 'function'.
const {
performance,
PerformanceObserver
} = require('perf_hooks');
function someFunction() {
console.log('hello world');
}
const wrapped = performance.timerify(someFunction);
const obs = new PerformanceObserver((list) => {
console.log(list.getEntries()[0].duration);
obs.disconnect();
});
obs.observe({ entryTypes: ['function'] });
// A performance timeline entry will be created
wrapped(); Если обернутая функция возвращает промис, к промису будет добавлен обработчик finally, и продолжительность будет сообщена после вызова обработчика finally.
performance.toJSON()
Объект, представляющий собой JSON-представление объекта performance. Он похож на window.performance.toJSON в браузерах.
Класс: PerformanceEntry
performanceEntry.detail
Дополнительные детали, специфичные для entryType.
performanceEntry.duration
Общее количество миллисекунд, затраченное на эту запись. Это значение не будет иметь смысла для всех типов записей Performance Entry.
performanceEntry.entryType
Тип записи производительности. Он может быть одним из:
-
'node'(только Node.js) -
'mark'(доступно в веб-браузерах) -
'measure'(доступно в веб-браузерах) -
'gc'(только Node.js) -
'function'(только Node.js) -
'http2'(только Node.js) -
'http'(только Node.js)
performanceEntry.flags
Это свойство является расширением Node.js. Оно недоступно в веб-браузерах.
Когда performanceEntry.entryType равно 'gc', свойство performance.flags содержит дополнительную информацию об операции сбора мусора. Значение может быть одним из:
perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_NOperf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_CONSTRUCT_RETAINEDperf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_FORCEDperf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_SYNCHRONOUS_PHANTOM_PROCESSINGperf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_ALL_AVAILABLE_GARBAGEperf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_ALL_EXTERNAL_MEMORYperf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_SCHEDULE_IDLE
performanceEntry.name
Имя записи производительности.
performanceEntry.kind
Это свойство является расширением Node.js. Оно недоступно в веб-браузерах.
Когда performanceEntry.entryType равно 'gc', свойство performance.kind определяет тип операции сбора мусора, которая произошла. Значение может быть одним из:
perf_hooks.constants.NODE_PERFORMANCE_GC_MAJORperf_hooks.constants.NODE_PERFORMANCE_GC_MINORperf_hooks.constants.NODE_PERFORMANCE_GC_INCREMENTALperf_hooks.constants.NODE_PERFORMANCE_GC_WEAKCB
performanceEntry.startTime
Отметка времени в миллисекундах с высоким разрешением, обозначающая начальное время записи Performance Entry.
Подробности сбора мусора ('gc')
Когда performanceEntry.type равно 'gc', свойство performanceEntry.detail будет <объектом> с двумя свойствами:
-
kind<число> Одно из:perf_hooks.constants.NODE_PERFORMANCE_GC_MAJORperf_hooks.constants.NODE_PERFORMANCE_GC_MINORperf_hooks.constants.NODE_PERFORMANCE_GC_INCREMENTALperf_hooks.constants.NODE_PERFORMANCE_GC_WEAKCB
-
flags<число> Одно из:perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_NOperf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_CONSTRUCT_RETAINEDperf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_FORCEDperf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_SYNCHRONOUS_PHANTOM_PROCESSINGperf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_ALL_AVAILABLE_GARBAGEperf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_ALL_EXTERNAL_MEMORYperf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_SCHEDULE_IDLE
Подробности HTTP/2 ('http2')
Когда performanceEntry.type равно 'http2', свойство performanceEntry.detail будет <объектом>, содержащим дополнительную информацию о производительности.
Если performanceEntry.name равно Http2Stream, свойство detail будет содержать следующие свойства:
-
bytesRead<число> Количество байтов фреймаDATA, полученных для этогоHttp2Stream. -
bytesWritten<число> Количество байтов фреймаDATA, отправленных для этогоHttp2Stream. -
id<число> Идентификатор связанногоHttp2Stream -
timeToFirstByte<число> Количество миллисекунд, прошедших междуPerformanceEntrystartTimeи получением первого фреймаDATA. -
timeToFirstByteSent<число> Количество миллисекунд, прошедших междуPerformanceEntrystartTimeи отправкой первого фреймаDATA. -
timeToFirstHeader<число> Количество миллисекунд, прошедших междуPerformanceEntrystartTimeи получением первого заголовка.
Если performanceEntry.name равно Http2Session, свойство detail будет содержать следующие свойства:
-
bytesRead<число> Количество полученных байтов для этогоHttp2Session. -
bytesWritten<число> Количество отправленных байтов для этогоHttp2Session. -
framesReceived<число> Количество полученных фреймов HTTP/2Http2Session. -
framesSent<число> Количество отправленных фреймов HTTP/2Http2Session. -
maxConcurrentStreams<число> Максимальное количество одновременно открытых потоков во время жизниHttp2Session. -
pingRTT<число> Количество миллисекунд, прошедших между отправкой фреймаPINGи получением его подтверждения. Присутствует только если фреймPINGбыл отправлен наHttp2Session. -
streamAverageDuration<число> Среднее время (в миллисекундах) для всех экземпляровHttp2Stream. -
streamCount<число> Количество обработанных экземпляровHttp2StreamHttp2Session. -
type<строка> Либо'server', либо'client'для идентификации типаHttp2Session.
Подробности функции Timerify ('function')
Когда performanceEntry.type равно 'function', свойство performanceEntry.detail будет <массивом>, перечисляющим входные аргументы отмеренной функции.
Класс: PerformanceNodeTiming
- Расширяет: <PerformanceEntry>
Это свойство является расширением Node.js. Оно недоступно в веб-браузерах.
Предоставляет подробные данные о времени выполнения самого Node.js. Конструктор этого класса не доступен для пользователей.
performanceNodeTiming.bootstrapComplete
Маркер времени в миллисекундах высокого разрешения, когда процесс Node.js завершил загрузку. Если загрузка еще не завершена, свойство имеет значение -1.
performanceNodeTiming.environment
Маркер времени в миллисекундах высокого разрешения, когда среда Node.js была инициализирована.
performanceNodeTiming.idleTime
Маркер времени в миллисекундах высокого разрешения, обозначающий количество времени, в течение которого цикл событий был неактивен внутри поставщика событий цикла событий (например, epoll_wait). Это не учитывает использование ЦП. Если цикл событий еще не запущен (например, в первом цикле основного скрипта), свойство имеет значение 0.
performanceNodeTiming.loopExit
Маркер времени в миллисекундах высокого разрешения, когда цикл событий Node.js завершился. Если цикл событий еще не завершился, свойство имеет значение -1. Оно может иметь значение, отличное от -1, только в обработчике события 'exit'.
performanceNodeTiming.loopStart
Маркер времени в миллисекундах высокого разрешения, когда цикл событий Node.js был запущен. Если цикл событий еще не запущен (например, в первом цикле основного скрипта), свойство имеет значение -1.
performanceNodeTiming.nodeStart
Маркер времени в миллисекундах высокого разрешения, когда процесс Node.js был инициализирован.
performanceNodeTiming.v8Start
Маркер времени в миллисекундах высокого разрешения, когда платформа V8 была инициализирована.
Класс: perf_hooks.PerformanceObserver
new PerformanceObserver(callback)
-
callback<Функция>-
list<PerformanceObserverEntryList> -
observer<PerformanceObserver>
-
Объекты PerformanceObserver предоставляют уведомления, когда новые экземпляры PerformanceEntry добавлены на временную шкалу производительности.
const {
performance,
PerformanceObserver
} = require('perf_hooks');
const obs = new PerformanceObserver((list, observer) => {
console.log(list.getEntries());
observer.disconnect();
});
obs.observe({ entryTypes: ['mark'], buffered: true });
performance.mark('test'); Поскольку экземпляры PerformanceObserver вносят свой дополнительный накладной расход производительности, экземпляры не должны подписываться на уведомления бесконечно. Пользователи должны отключать наблюдатели, как только они больше не нужны.
Обработчик callback вызывается, когда экземпляр PerformanceObserver получает уведомление о новых экземплярах PerformanceEntry. Обработчик получает экземпляр PerformanceObserverEntryList и ссылку на экземпляр PerformanceObserver.
performanceObserver.disconnect()
Отключает экземпляр PerformanceObserver от всех уведомлений.
performanceObserver.observe(options)
-
options<Объект>-
type<строка> Один тип <PerformanceEntry>. Не должно предоставляться, еслиentryTypesуже указан. -
entryTypes<массив строк> Массив строк, идентифицирующих типы экземпляров <PerformanceEntry>, в которых заинтересован наблюдатель. Если не предоставлен, будет выброшено исключение. -
buffered<логическое значение> Если true, обратный вызов наблюдателя вызывается со списком глобальныхPerformanceEntryбуферизованных записей. Если false, толькоPerformanceEntry, созданные после момента времени, передаются в обратный вызов наблюдателя. По умолчанию:false.
-
Подписывает экземпляр <PerformanceObserver> на уведомления о новых экземплярах <PerformanceEntry>, идентифицируемых либо по options.entryTypes, либо по options.type:
const {
performance,
PerformanceObserver
} = require('perf_hooks');
const obs = new PerformanceObserver((list, observer) => {
// Called three times synchronously. `list` contains one item.
});
obs.observe({ type: 'mark' });
for (let n = 0; n < 3; n++)
performance.mark(`test${n}`); Класс: PerformanceObserverEntryList
Класс PerformanceObserverEntryList используется для предоставления доступа к экземплярам PerformanceEntry, передаваемым наблюдателю PerformanceObserver. Конструктор этого класса не доступен для пользователей.
performanceObserverEntryList.getEntries()
- Возвращает: <PerformanceEntry[]>
Возвращает список объектов PerformanceEntry в хронологическом порядке по отношению к performanceEntry.startTime.
const {
performance,
PerformanceObserver
} = require('perf_hooks');
const obs = new PerformanceObserver((perfObserverList, observer) => {
console.log(perfObserverList.getEntries());
/**
* [
* PerformanceEntry {
* name: 'test',
* entryType: 'mark',
* startTime: 81.465639,
* duration: 0
* },
* PerformanceEntry {
* name: 'meow',
* entryType: 'mark',
* startTime: 81.860064,
* duration: 0
* }
* ]
*/
observer.disconnect();
});
obs.observe({ type: 'mark' });
performance.mark('test');
performance.mark('meow');
performanceObserverEntryList.getEntriesByName(name[, type])
-
name<строка> -
type<строка> - Возвращает: <PerformanceEntry[]>
Возвращает список объектов PerformanceEntry в хронологическом порядке по отношению к performanceEntry.startTime, чье performanceEntry.name равно name, и необязательно, чье performanceEntry.entryType равно type.
const {
performance,
PerformanceObserver
} = require('perf_hooks');
const obs = new PerformanceObserver((perfObserverList, observer) => {
console.log(perfObserverList.getEntriesByName('meow'));
/**
* [
* PerformanceEntry {
* name: 'meow',
* entryType: 'mark',
* startTime: 98.545991,
* duration: 0
* }
* ]
*/
console.log(perfObserverList.getEntriesByName('nope')); // []
console.log(perfObserverList.getEntriesByName('test', 'mark'));
/**
* [
* PerformanceEntry {
* name: 'test',
* entryType: 'mark',
* startTime: 63.518931,
* duration: 0
* }
* ]
*/
console.log(perfObserverList.getEntriesByName('test', 'measure')); // []
observer.disconnect();
});
obs.observe({ entryTypes: ['mark', 'measure'] });
performance.mark('test');
performance.mark('meow');
performanceObserverEntryList.getEntriesByType(type)
-
type<строка> - Возвращает: <PerformanceEntry[]>
Возвращает список объектов PerformanceEntry в хронологическом порядке по отношению к performanceEntry.startTime, чье performanceEntry.entryType равно type.
const {
performance,
PerformanceObserver
} = require('perf_hooks');
const obs = new PerformanceObserver((perfObserverList, observer) => {
console.log(perfObserverList.getEntriesByType('mark'));
/**
* [
* PerformanceEntry {
* name: 'test',
* entryType: 'mark',
* startTime: 55.897834,
* duration: 0
* },
* PerformanceEntry {
* name: 'meow',
* entryType: 'mark',
* startTime: 56.350146,
* duration: 0
* }
* ]
*/
observer.disconnect();
});
obs.observe({ type: 'mark' });
performance.mark('test');
performance.mark('meow');
perf_hooks.createHistogram([options])
-
options<Объект>-
min<число> | <BigInt> Минимальное значение, которое можно записать. Должно быть целым значением, большим 0. По умолчанию:1. -
max<число> | <BigInt> Максимальное значение, которое можно записать. Должно быть целым значением, большимmin. По умолчанию:Number.MAX_SAFE_INTEGER. -
figures<число> Количество цифр точности. Должно быть числом от1до5. По умолчанию:3.
-
- Возвращает <RecordableHistogram>
Возвращает <RecordableHistogram>.
perf_hooks.monitorEventLoopDelay([options])
-
options<Объект>-
resolution<число> Скорость выборки в миллисекундах. Должно быть больше нуля. По умолчанию:10.
-
- Возвращает: <IntervalHistogram>
Эта свойство добавлено Node.js. Оно недоступно в веб-браузерах.
Создаёт объект IntervalHistogram, который отслеживает и сообщает о задержках цикла событий со временем. Задержки будут сообщаться в наносекундах.
Использование таймера для определения приблизительной задержки цикла событий работает, потому что выполнение таймеров напрямую связано с жизненным циклом цикла событий libuv. То есть, задержка в цикле вызовет задержку в выполнении таймера, и именно эти задержки предназначены для обнаружения данным API.
const { monitorEventLoopDelay } = require('perf_hooks');
const h = monitorEventLoopDelay({ resolution: 20 });
h.enable();
// Do something.
h.disable();
console.log(h.min);
console.log(h.max);
console.log(h.mean);
console.log(h.stddev);
console.log(h.percentiles);
console.log(h.percentile(50));
console.log(h.percentile(99)); Класс: Histogram
histogram.exceeds
Количество раз, когда задержка цикла событий превысила максимальное пороговое значение задержки цикла событий в 1 час.
histogram.max
Максимальная зарегистрированная задержка цикла событий.
histogram.mean
Среднее значение зарегистрированных задержек цикла событий.
histogram.min
Минимальная зарегистрированная задержка цикла событий.
histogram.percentile(percentile)
Возвращает значение в заданном процентиле.
histogram.percentiles
Возвращает объект Map, описывающий накопленное распределение процентилей.
histogram.reset()
Сбрасывает собранные данные гистограммы.
histogram.stddev
Стандартное отклонение зарегистрированных задержек цикла событий.
Класс: IntervalHistogram extends Histogram
Histogram, который периодически обновляется через заданный интервал.
histogram.disable()
- Возвращает: <логическое значение>
Отключает таймер интервала обновления. Возвращает true, если таймер был остановлен, false, если он уже был остановлен.
histogram.enable()
- Возвращает: <логическое значение>
Включает таймер интервала обновления. Возвращает true, если таймер был запущен, false, если он уже был запущен.
Клонирование IntervalHistogram
<IntervalHistogram> экземпляры можно клонировать через <MessagePort>. На стороне получателя гистограмма клонируется как обычный объект <Histogram>, который не реализует методы enable() и disable().
Класс: RecordableHistogram extends Histogram
histogram.record(val)
histogram.recordDelta()
Вычисляет количество времени (в наносекундах), прошедшее с момента предыдущего вызова recordDelta(), и записывает это значение в гистограмму.
Примеры
Измерение продолжительности асинхронных операций
В следующем примере используются Async Hooks и API производительности для измерения фактической продолжительности операции Timeout (включая время, затраченное на выполнение обратного вызова).
'use strict';
const async_hooks = require('async_hooks');
const {
performance,
PerformanceObserver
} = require('perf_hooks');
const set = new Set();
const hook = async_hooks.createHook({
init(id, type) {
if (type === 'Timeout') {
performance.mark(`Timeout-${id}-Init`);
set.add(id);
}
},
destroy(id) {
if (set.has(id)) {
set.delete(id);
performance.mark(`Timeout-${id}-Destroy`);
performance.measure(`Timeout-${id}`,
`Timeout-${id}-Init`,
`Timeout-${id}-Destroy`);
}
}
});
hook.enable();
const obs = new PerformanceObserver((list, observer) => {
console.log(list.getEntries()[0]);
performance.clearMarks();
observer.disconnect();
});
obs.observe({ entryTypes: ['measure'], buffered: true });
setTimeout(() => {}, 1000); Измерение времени загрузки зависимостей
В следующем примере измеряется продолжительность операций require() для загрузки зависимостей:
'use strict';
const {
performance,
PerformanceObserver
} = require('perf_hooks');
const mod = require('module');
// Monkey patch the require function
mod.Module.prototype.require =
performance.timerify(mod.Module.prototype.require);
require = performance.timerify(require);
// Activate the observer
const obs = new PerformanceObserver((list) => {
const entries = list.getEntries();
entries.forEach((entry) => {
console.log(`require('${entry[0]}')`, entry.duration);
});
obs.disconnect();
});
obs.observe({ entryTypes: ['function'], buffered: true });
require('some-module');
© Joyent, Inc. and other Node contributors
Licensed under the MIT License.
Node.js is a trademark of Joyent, Inc. and is used with its permission.
We are not endorsed by or affiliated with Joyent.
https://nodejs.org/dist/latest-v16.x/docs/api/perf_hooks.html