コールバックでJavaScriptコードの実行時間を測定するにはどうすればよいですか?


319

node.jsインタープリターを使用して実行しているJavaScriptコードがあります。

for(var i = 1; i < LIMIT; i++) {
  var user = {
    id: i,
    name: "MongoUser [" + i + "]"
  };
  db.users.save(user, function(err, saved) {
    if(err || !saved) {
      console.log("Error");
    } else {
      console.log("Saved");
    }
  });
}

これらのデータベース挿入操作にかかる時間をどのように測定できますか?このコードの前後の日付値の差を計算することもできますが、コードの非同期性のため、これは正しくありません。


8
ジャストは..デシベルの呼び出しの前に開始時間を読んで、コールバックINSIDE終了時刻
BFil

DBが挿入を完了する時間とコールバックが実行される時間は同じではない可能性があり、これにより測定でエラーが発生しますか?
ストームシャドー

1
いいえ、心配する必要はありません。dbライブラリコードが適切に設計されていて、コールバックを開始する前に他の操作を処理しない場合は、適切な対策が必要です。あなたはまた、私はそれについて心配しないだろう、もう一度、代わりに自分自身の、挿入が実際に行われているライブラリのコード内のタイムスタンプを置くことによって挿入をプロファイリングすることができますが、
BFil

NodeTimeを試してみることをお勧めします。
ジュリアンナイト

私はtimerlogこれに似てconsole.time()いますが、追加の機能があります。github.com/brillout/timerlog
brillout

回答:


718

Node.js console.time()console.timeEnd()

var i;
console.time("dbsave");

for(i = 1; i < LIMIT; i++){
    db.users.save({id : i, name : "MongoUser [" + i + "]"}, end);
}

end = function(err, saved) {
    console.log(( err || !saved )?"Error":"Saved");
    if(--i === 1){console.timeEnd("dbsave");}
};

31
ノードのクリーンで組み込みのソリューション。
BehlülUCAR

45
>これらのdb挿入操作にかかる時間を測定する方法を知りたい。--- console.timeEnd( "dbsave")は、タイミングをコンソールに出力するだけです。それ以上使用することはできず、柔軟性が低くなります。元の質問のように実際のタイミング値が必要な場合は、console.timeEnd( "dbsave")を使用できません
gogaman

@gogamanこれは、console.timeEnd()からの出力をキャプチャできないため、良い点です。おそらく、出力をファイルにパイプしてそこから利用するのが便利でしょうか?
Doug Molineux 2014

5
それで、以下の答えのconsole.time()とprocess.hrtime()の違いは何ですか?
yellow-saint

3
実行時間が印刷されるというメモを追加する価値があります。これは、新しいユーザーが利用できるようにするためです。
janko-m 2015

208

このために設計された方法があります。process.hrtime();を確認しください

したがって、基本的にはこれをアプリの一番上に配置します。

var start = process.hrtime();

var elapsed_time = function(note){
    var precision = 3; // 3 decimal places
    var elapsed = process.hrtime(start)[1] / 1000000; // divide by a million to get nano to milli
    console.log(process.hrtime(start)[0] + " s, " + elapsed.toFixed(precision) + " ms - " + note); // print message + time
    start = process.hrtime(); // reset the timer
}

次に、それを使用して、関数にかかる時間を確認します。次に、「output.txt」というテキストファイルの内容を出力する基本的な例を示します。

var debug = true;
http.createServer(function(request, response) {

    if(debug) console.log("----------------------------------");
    if(debug) elapsed_time("recieved request");

    var send_html = function(err, contents) {
        if(debug) elapsed_time("start send_html()");
        response.writeHead(200, {'Content-Type': 'text/html' } );
        response.end(contents);
        if(debug) elapsed_time("end send_html()");
    }

    if(debug) elapsed_time("start readFile()");
    fs.readFile('output.txt', send_html);
    if(debug) elapsed_time("end readFile()");

}).listen(8080);

ターミナル(BASHシェル)で実行できる簡単なテストを次に示します。

for i in {1..100}; do echo $i; curl http://localhost:8080/; done

3
それは何らかの方法でconsole.timeソリューションよりも優れていますか?
クレイジー

31
はい、より正確で、結果を変数に保存できます
Dallas Clark

私はタイマーを複数回呼び出すと思ったので、私にとってこの1つの作品、
tbh__

2
なぜprocess.hrtime(start)二度電話するの?特別な理由はありますか?
Sohail Siの

1
process.hrtime([time])。ここで、timeはオプションのパラメーターであり、現在の時刻との差分をとる前のprocess.hrtime()呼び出しの結果である必要があります。現在の呼び出しと前のhrtime呼び出しの違いを示します。
Nilesh Jain

72

呼び出すconsole.time('label')と現在の時刻がミリ秒単位で記録され、後で呼び出すconsole.timeEnd('label')とその時点からの期間が表示されます。

ミリ秒単位の時間はラベルと一緒に自動的に印刷されるため、ラベルを印刷するためにconsole.logを個別に呼び出す必要はありません。

console.time('test');
//some code
console.timeEnd('test'); //Prints something like that-> test: 11374.004ms

詳細については、Mozillaの開発者向けドキュメントをconsole.time参照してください。



1
受け入れられた回答は、私のコードを使用するように私の回答の後に変更されました
jfcorugedo

24

新しいビルトインライブラリにはまだ誰も言及していませんでした。

Node> = 8.5で利用可能で、Modern Browersにある必要があります

https://developer.mozilla.org/en-US/docs/Web/API/Performance

https://nodejs.org/docs/latest-v8.x/api/perf_hooks.html#

ノード8.5〜9.x(Firefox、Chrome)

// const { performance } = require('perf_hooks'); // enable for node
const delay = time => new Promise(res=>setTimeout(res,time))
async function doSomeLongRunningProcess(){
  await delay(1000);
}
performance.mark('A');
(async ()=>{
  await doSomeLongRunningProcess();
  performance.mark('B');
  performance.measure('A to B', 'A', 'B');
  const measure = performance.getEntriesByName('A to B')[0];
  // firefox appears to only show second precision.
  console.log(measure.duration);
  performance.clearMeasures(); // apparently you should remove entries...
  // Prints the number of milliseconds between Mark 'A' and Mark 'B'
})();

https://repl.it/@CodyGeisler/NodeJsPerformanceHooks

ノード10.x

https://nodejs.org/docs/latest-v10.x/api/perf_hooks.html

const { PerformanceObserver, performance } = require('perf_hooks');
const delay = time => new Promise(res => setTimeout(res, time))
async function doSomeLongRunningProcess() {
    await delay(1000);
}
const obs = new PerformanceObserver((items) => {
    console.log('PerformanceObserver A to B',items.getEntries()[0].duration);
    performance.clearMarks();
});
obs.observe({ entryTypes: ['measure'] });

performance.mark('A');

(async function main(){
    try{
        await performance.timerify(doSomeLongRunningProcess)();
        performance.mark('B');
        performance.measure('A to B', 'A', 'B');
    }catch(e){
        console.log('main() error',e);
    }
})();

TypeError: performance.getEntriesByName is not a functionNode v10.4.1
Jeremy Thilleで

オンラインで実行できるようにサンプルを作成しました。これはノード9.7.1です。それがv10.4.1で機能しない場合は、何が変更されるのでしょうか。
コーディG

1
Stability: 1 - Experimental多分?:) nodejs.org/docs/latest-v8.x/api/...
ジェレミーThille

確かにそれは変わった。v10には新しいオブザーバーがあり、nodejs.org / docs / latest-v10.x / api / documentation.htmlでドキュメントを確認できます。機会があれば更新します!
コーディG

19

コンソール出力の代わりに時間経過値を取得したい人のために:

@ D.Derisoの提案としてprocess.hrtime()を使用します。以下は、より簡単な方法です。

function functionToBeMeasured() {
    var startTime = process.hrtime();
    // do some task...
    // ......
    var elapsedSeconds = parseHrtimeToSeconds(process.hrtime(startTime));
    console.log('It takes ' + elapsedSeconds + 'seconds');
}

function parseHrtimeToSeconds(hrtime) {
    var seconds = (hrtime[0] + (hrtime[1] / 1e9)).toFixed(3);
    return seconds;
}

16
var start = +new Date();
var counter = 0;
for(var i = 1; i < LIMIT; i++){
    ++counter;
    db.users.save({id : i, name : "MongoUser [" + i + "]"}, function(err, saved) {
          if( err || !saved ) console.log("Error");
          else console.log("Saved");
          if (--counter === 0) 
          {
              var end = +new Date();
              console.log("all users saved in " + (end-start) + " milliseconds");
          }
    });
}

5
構文 '+ new Date()'を調べて、その意味を理解する必要がありました。この回答に関するコメント(stackoverflow.com/a/221565/5114)によると、パフォーマンス上の理由と読みやすさのためにこのフォームを使用することはお勧めできません。私はもう少し冗長なものを好むので、読者にはそれがより明確になります。この回答もご覧ください:stackoverflow.com/a/5036460/5114
Mnebuerquo

3
私はしばしばvar start = process.hrtime(); ... var end = process.hrtime(start);高解像度の時間を取得するために使用します(サブミリ秒の精度を期待する必要がある場合)
Andrey Sidorov '20

9

古い質問ですが、シンプルなAPIと軽量のソリューションが必要です。内部で高解像度のリアルタイム()を使用するperfyを使用できます process.hrtime

var perfy = require('perfy');

function end(label) {
    return function (err, saved) {
        console.log(err ? 'Error' : 'Saved'); 
        console.log( perfy.end(label).time ); // <——— result: seconds.milliseconds
    };
}

for (var i = 1; i < LIMIT; i++) {
    var label = 'db-save-' + i;
    perfy.start(label); // <——— start and mark time
    db.users.save({ id: i, name: 'MongoUser [' + i + ']' }, end(label));
}

perfy.end(label)呼び出されるたびに、そのインスタンスは自動的に破棄されることに注意してください。

開示:D.Derisoの回答に触発されて、このモジュールを作成しました。ドキュメントはこちら


2

あなたは与えることができるBenchmark.jsに試して。それらの間で多くのプラットフォームをサポートし、node.jsもサポートします。


11
このユースケースでbenchmark.jsを使用する方法の例を追加できればよいでしょう。
Petah

2

exectimerを試すこともできます。次のようなフィードバックが得られます。

var t = require("exectimer");

var myFunction() {
   var tick = new t.tick("myFunction");
   tick.start();
   // do some processing and end this tick
   tick.stop();
}

// Display the results
console.log(t.timers.myFunction.duration()); // total duration of all ticks
console.log(t.timers.myFunction.min()); // minimal tick duration
console.log(t.timers.myFunction.max()); // maximal tick duration
console.log(t.timers.myFunction.mean()); // mean tick duration
console.log(t.timers.myFunction.median()); // median tick duration

[編集]測定対象のコードをラップできるようになったため、exectimerを使用するさらに簡単な方法があります。コードは次のようにラップできます。

var t = require('exectimer'),
Tick = t.Tick;

for(var i = 1; i < LIMIT; i++){
    Tick.wrap(function saveUsers(done) {
        db.users.save({id : i, name : "MongoUser [" + i + "]"}, function(err, saved) {
            if( err || !saved ) console.log("Error");
            else console.log("Saved");
            done();
        });
    });
}

// Display the results
console.log(t.timers.myFunction.duration()); // total duration of all ticks
console.log(t.timers.saveUsers.min()); // minimal tick duration
console.log(t.timers.saveUsers.max()); // maximal tick duration
console.log(t.timers.saveUsers.mean()); // mean tick duration
console.log(t.timers.saveUsers.median()); // median tick duration

1

AWSからAzureへの移行中に同じ問題が発生しました

express&awsについては、既存のtime()およびtimeEnd()をすでに使用できます。

Azureの場合、これを使用します:https : //github.com/manoharreddyporeddy/my-nodejs-notes/blob/master/performance_timers_helper_nodejs_azure_aws.js

これらのtime()およびtimeEnd()は、高解像度のリアルタイムを提供する既存のhrtime()関数を使用します。

お役に立てれば。


0

もう1つのオプションは、エクスプレスデバッグツールを使用することです。

express-debugは、expressの開発ツールです。シンプルなミドルウェアであり、有用なデバッグ出力を非妨害的な方法でhtmlに注入します。

それは便利なプロファイリングパネルを提供します:

要求処理時間の合計。ミドルウェア、パラメータ、ルートのタイミング。

また。上記の回答に追加するには、この回答をチェックし、開発環境のみのプロファイリングコードを有効にすることができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.