12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 |
- "use strict";
- const fs = require("fs-extra");
- const npmlog = require("npmlog");
- const upath = require("upath");
- const hrtimeToMicroseconds = (hrtime) => {
- return (hrtime[0] * 1e9 + hrtime[1]) / 1000;
- };
- const range = (len) => {
- return Array(len)
- .fill()
- .map((_, idx) => idx);
- };
- const getTimeBasedFilename = () => {
- const now = new Date(); // 2011-10-05T14:48:00.000Z
- const datetime = now.toISOString().split(".")[0]; // 2011-10-05T14:48:00
- const datetimeNormalized = datetime.replace(/-|:/g, ""); // 20111005T144800
- return `Lerna-Profile-${datetimeNormalized}.json`;
- };
- /**
- * @typedef {object} ProfilerConfig
- * @property {number} concurrency
- * @property {typeof npmlog} [log]
- * @property {string} [outputDirectory]
- */
- /**
- * A profiler to trace execution times across multiple concurrent calls.
- */
- class Profiler {
- /**
- * @param {ProfilerConfig} options
- */
- constructor({ concurrency, log = npmlog, outputDirectory }) {
- this.events = [];
- this.logger = log;
- this.outputPath = upath.join(upath.resolve(outputDirectory || "."), getTimeBasedFilename());
- this.threads = range(concurrency);
- }
- run(fn, name) {
- let startTime;
- let threadId;
- return Promise.resolve()
- .then(() => {
- startTime = process.hrtime();
- threadId = this.threads.shift();
- })
- .then(() => fn())
- .then((value) => {
- const duration = process.hrtime(startTime);
- // Trace Event Format documentation:
- // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
- const event = {
- name,
- ph: "X",
- ts: hrtimeToMicroseconds(startTime),
- pid: 1,
- tid: threadId,
- dur: hrtimeToMicroseconds(duration),
- };
- this.events.push(event);
- this.threads.unshift(threadId);
- this.threads.sort();
- return value;
- });
- }
- output() {
- return fs
- .outputJson(this.outputPath, this.events)
- .then(() => this.logger.info("profiler", `Performance profile saved to ${this.outputPath}`));
- }
- }
- module.exports.Profiler = Profiler;
|