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に関する初期実装がもうすぐ入りそう。
まだまだ未実装な部分が多いので、今後に期待。