NodeにPerformance Timing APIが追加される
NodeへPerformance Timing APIの初期実装が入ります。
資料
W3C
NodeへのPR
まだ、masterやリリースラインに入っていないのでドキュメントはPRから見てください。
今回は、PerformanceFrame と PerformanceNodeTiming の説明は書かないので詳しくはドキュメントへ。
Nodeのイベントループの時間測定を測定するのも実装されている。
Performance Timing API
マイクロ秒で経過時間を取得するAPI である。
Dateを使い計測を行うことがあると思うが、以下のような場合がある。
const markStart = Date.now(); (() => {})(); const duration = Date.now() - markStart; console.log(duration); // 0
実際は、正の値, 負の値, 0の値になり得てしまう。
実装
Nodeで使ってみる
processにperformanceというメソッドが追加された。
> process.performance
{ timeOrigin: 14194760.508743,
nodeTiming:
PerformanceNodeTiming {
duration: 2735.97479,
startTime: 14194760.508743,
type: 'node',
name: 'node',
arguments: 14194763.6652,
initialize: 14194764.104207,
inspectorStart: 14194769.714933,
loopStart: 14194854.360176,
loopExit: 0,
loopFrame: 14196891.511942,
bootstrapComplete: 14194854.356646,
third_party_main_start: 0,
third_party_main_end: 0,
cluster_setup_start: 0,
cluster_setup_end: 0,
module_load_start: 14194813.331148,
module_load_end: 14194813.33181,
preload_modules_load_start: 14194813.332309,
preload_modules_load_end: 14194813.356287 },
nodeFrame:
PerformanceFrame {
prior: 0.012497,
type: 'frame',
name: 'frame',
duration: 605.560913,
startTime: 14196891.511942 } }
>
手順
基本的には、
- 開始区間のマーキング(
mark) - 終了区間のマーキング(
mark) - その区間の名前を定義して保存されます。(
measure) - すべて保存されたリストから3で定義した区間の名前を指定し取得(
getEntriesByName)
また、同じ区間の名前をつけたときはスタックしていきます。
なのでgetEntriesByNameで取得した時に配列になっています。
これは新しいのから順にpushされます。(つまりタイムライン順)
区間を逆(未来 to 過去)にした場合、数値がすごいことになるのは仕様なのかな・・・?
少し長いですが、以下のコードを読めばわかると思います。
コード
const fs = require('fs'); const perf = process.performance; perf.mark('A'); (() => {})(); perf.mark('B'); perf.measure('A to B', 'A', 'B'); // tagname, startMark, endMark const measure1 = perf.getEntriesByName('A to B')[0]; // measure1's length is 1 console.log(measure1.duration); // 0.009461 /* ----------------------------------------------------- */ perf.mark('C'); fs.readFileSync('./node'); perf.mark('D'); perf.measure('C to D', 'C', 'D'); const measure2 = perf.getEntriesByName('C to D')[0]; // measure2's length is 1 console.log(measure2.duration); // 28.502531 /* ----------------------------------------------------- */ perf.measure('A to B', 'C', 'D'); // push to `A to B` const measure3 = perf.getEntriesByName('A to B'); // measure3's length is 2 console.log(measure3); // display the performance timeline of `A to B` /* [ PerformanceMeasure { duration: 0.009461, startTime: 15995656.619165, type: 'measure', name: 'A to B' }, PerformanceMeasure { duration: 28.502531, startTime: 15995675.467252, type: 'measure', name: 'A to B' } ] */ console.log(perf.getEntries()); // display the performance timeline(combined `mark` and `measure` into the timeline) /* [ PerformanceNodeTiming { duration: 107.495859, startTime: 15995598.683741, type: 'node', name: 'node', arguments: 15995602.156617, initialize: 15995602.750924, inspectorStart: 15995609.924404, loopStart: 0, loopExit: 0, loopFrame: 0, bootstrapComplete: 0, third_party_main_start: 0, third_party_main_end: 0, cluster_setup_start: 0, cluster_setup_end: 0, module_load_start: 15995653.258513, module_load_end: 15995653.313254, preload_modules_load_start: 15995653.313785, preload_modules_load_end: 15995653.341459 }, PerformanceFrame { prior: 0, type: 'frame', name: 'frame', duration: 15995706.323224, startTime: 0 }, PerformanceMark { duration: 0, startTime: 15995656.619165, type: 'mark', name: 'A' }, PerformanceMark { duration: 0, startTime: 15995656.628626, type: 'mark', name: 'B' }, PerformanceMeasure { duration: 0.009461, startTime: 15995656.619165, type: 'measure', name: 'A to B' }, PerformanceMark { duration: 0, startTime: 15995675.467252, type: 'mark', name: 'C' }, PerformanceMark { duration: 0, startTime: 15995703.969783, type: 'mark', name: 'D' }, PerformanceMeasure { duration: 28.502531, startTime: 15995675.467252, type: 'measure', name: 'C to D' }, PerformanceMeasure { duration: 28.502531, startTime: 15995675.467252, type: 'measure', name: 'A to B' } ] */
API
common
now()
現在の高分解能時刻タイムスタンプを返します。
mark(name: string)
パフォーマンスタイムラインへ新しいPerformanceMarkを追加します。
performanceEntry.typeは常にmarkです。
measure(name: string, startMark: string, endMark: string)
パフォーマンスタイムラインへ新しいPerformanceMeasureを追加します。
performanceEntry.typeは常にmeasureです。
nameは区間の名前です。
startMarkは開始地点の名前を設定します。もし名前が存在しない場合、timeOriginが基準となります。
endMarkは終了地点の名前を設定します。もし指定しない場合は、エラーが投げられます。
get
getEntries()
startTimeを基準にすべてのPerformanceEntry Objectのリストを時間順に返します。
mark 及び measure のタイムラインとなります。
getEntriesByType(type: string)
performanceEntry.typeと同じtypeを持つすべてのPerformanceEntry ObjectのリストをstartTimeを基準に時間順に返します。
古い物から先頭となります。
getEntriesByName(name: string, type?: string)
performanceEntry.typeと同じnameを持つすべてのPerformanceEntry ObjectのリストをstartTimeを基準に時間順に返します。
古い物から先頭となります。
clear
clearMarks(name?: string)
名前を指定すれば、そのマークを消し、
指定しなければ、すべてのマークをパフォーマンスタイムラインから消します。
clearMeasures(name?: string)
名前を指定すれば、そのメジャーを消し、
指定しなければ、すべてのメジャーをパフォーマンスタイムラインから消します。
仕様分類
High Resolution Time Level 2
toJson()
High Resolution Time
now()
Navigation Timing
timing, navigation
Performance Timeline Time Level 2
getEntries()
Performance Timeline
getEntries(), getEntriesByType(), getEntriesByName()
Resource Timing Level 1
clearResourceTimings(), setResourceTimingBufferSize(), onresourcetimingbufferfull
User Timing
mark(), clearMark(), measure(), clearMeasure()
まとめ
Performance Timing APIに関する初期実装がもうすぐ入りそう。
まだまだ未実装な部分が多いので、今後に期待。