背景
ある Library 関数において無駄な処理だなぁと思った際に、感覚ではなく、客観的に見せる為に速度比較をしようとした。
TypeScript 初心者が辿り着いたのが
- performance.now による計測
- performance.mark/measure による計測
どちらも同じ performance なんで、何が変わるんだろうとなんも考えず計測関数を用意して測ってみたところ・・
何故か、想定通りに計測出来なかった。その原因推測と対処法の共有
そう
Solve「本質を追求し問題を解決する」
の実現・・の筈
結論
- performance.mark を使う際は、一個目は cache が効いてなさそうなので、使い捨てしよう。(たぶん
ほんとかどうかは、下層まで追ってない(追い方知らない)ので不明ですので、詳しい人の教えがあると嬉しい
調査内容
コード
計測関数
performance.now を使った計測関数
function measureExeFunc(executeFunction: { (timestamp: Date): number; (arg0: Date): void; }, date: Date) {
var startTime = performance.now();
executeFunction(date);
var endTime = performance.now();
console.log(`${executeFunction.name}: `, endTime - startTime);
}
performance.mark/measure を使った計測関数
function measureExeFunc2(executeFunction: { (timestamp: Date): number; (arg0: Date): void; }, date: Date) {
performance.mark('ini'); // ここがcache 効かせるための捨て mark
performance.mark('start');
executeFunction(date);
performance.mark('end');
performance.measure(executeFunction.name, 'start', 'end');
console.log(performance.getEntriesByType('measure'));
performance.clearMarks();
performance.clearMeasures();
}
被計測関数
単純にループ処理にしてみた
100 count
const functionMeasured100 = (timestamp: Date) => {
let sum = 0;
for (let count = 0; count < 100; count++) {
sum += count;
}
return sum;
};
1000 count
const functionMeasured1000 = (timestamp: Date) => {
let sum = 0;
for (let count = 0; count < 1000; count++) {
sum += count;
}
return sum;
}
実際の計測処理
参照キャッシュが影響しないように2つの Date() を用意して計測
const currentDate2 = new Date();
currentDate2.setMilliseconds(currentDate2.getMilliseconds() - 5);
const currentDate3 = new Date();
currentDate3.setMilliseconds(currentDate3.getMilliseconds() + 5);
measureExeFunc(functionMeasured100, currentDate2);
measureExeFunc(functionMeasured1000, currentDate3);
measureExeFunc2(functionMeasured100, currentDate2);
measureExeFunc2(functionMeasured1000, currentDate3);
計測結果
読み捨て無し
読み捨て追加
所感
mark() の初回に now を記録しつつ、初期化処理で時間がかかってそう
Documents
あとがき
VS Code でのインテリセンスもほんと便利ですね。
便利過ぎて、無いとコードかけそうにない気がします