UNPKG

nstdlib-nightly

Version:

Node.js standard library converted to runtime-agnostic ES modules.

255 lines (226 loc) 6.58 kB
// Source: https://github.com/nodejs/node/blob/65eff1eb/lib/internal/perf/usertiming.js import { PerformanceEntry, kSkipThrow, } from "nstdlib/lib/internal/perf/performance_entry"; import { now } from "nstdlib/lib/internal/perf/utils"; import { enqueue, bufferUserTiming } from "nstdlib/lib/internal/perf/observe"; import * as nodeTiming from "nstdlib/lib/internal/perf/nodetiming"; import { validateNumber, validateObject, validateString, validateInternalField, } from "nstdlib/lib/internal/validators"; import { codes as __codes__ } from "nstdlib/lib/internal/errors"; import { structuredClone } from "nstdlib/stub/binding/messaging"; import { lazyDOMException, kEnumerableProperty, } from "nstdlib/lib/internal/util"; const { ERR_ILLEGAL_CONSTRUCTOR, ERR_INVALID_ARG_VALUE, ERR_MISSING_ARGS, ERR_PERFORMANCE_INVALID_TIMESTAMP, ERR_PERFORMANCE_MEASURE_INVALID_OPTIONS, } = __codes__; const kDetail = Symbol("kDetail"); const markTimings = new Map(); const nodeTimingReadOnlyAttributes = new Set( new (Array.prototype[Symbol.iterator]())([ "nodeStart", "v8Start", "environment", "loopStart", "loopExit", "bootstrapComplete", ]), ); function getMark(name) { if (name === undefined) return; if (typeof name === "number") { if (name < 0) throw new ERR_PERFORMANCE_INVALID_TIMESTAMP(name); return name; } name = `${name}`; if (nodeTimingReadOnlyAttributes.has(name)) return nodeTiming[name]; const ts = markTimings.get(name); if (ts === undefined) throw lazyDOMException( `The "${name}" performance mark has not been set`, "SyntaxError", ); return ts; } class PerformanceMark extends PerformanceEntry { constructor(name, options = undefined) { if (arguments.length === 0) { throw new ERR_MISSING_ARGS("name"); } name = `${name}`; if (nodeTimingReadOnlyAttributes.has(name)) throw new ERR_INVALID_ARG_VALUE("name", name); if (options != null) { validateObject(options, "options"); } const startTime = options?.startTime ?? now(); validateNumber(startTime, "startTime"); if (startTime < 0) throw new ERR_PERFORMANCE_INVALID_TIMESTAMP(startTime); markTimings.set(name, startTime); let detail = options?.detail; detail = detail != null ? structuredClone(detail) : null; super(kSkipThrow, name, "mark", startTime, 0); this[kDetail] = detail; } get detail() { validateInternalField(this, kDetail, "PerformanceMark"); return this[kDetail]; } toJSON() { return { name: this.name, entryType: this.entryType, startTime: this.startTime, duration: this.duration, detail: this[kDetail], }; } } Object.defineProperties(PerformanceMark.prototype, { detail: kEnumerableProperty, [Symbol.toStringTag]: { __proto__: null, configurable: true, value: "PerformanceMark", }, }); class PerformanceMeasure extends PerformanceEntry { constructor( skipThrowSymbol = undefined, name = undefined, type = undefined, start = undefined, duration = undefined, ) { if (skipThrowSymbol !== kSkipThrow) { throw new ERR_ILLEGAL_CONSTRUCTOR(); } super(skipThrowSymbol, name, type, start, duration); } get detail() { validateInternalField(this, kDetail, "PerformanceMeasure"); return this[kDetail]; } toJSON() { return { name: this.name, entryType: this.entryType, startTime: this.startTime, duration: this.duration, detail: this[kDetail], }; } } Object.defineProperties(PerformanceMeasure.prototype, { detail: kEnumerableProperty, [Symbol.toStringTag]: { __proto__: null, configurable: true, value: "PerformanceMeasure", }, }); function createPerformanceMeasure(name, start, duration, detail) { const measure = new PerformanceMeasure( kSkipThrow, name, "measure", start, duration, ); measure[kDetail] = detail; return measure; } function mark(name, options) { const mark = new PerformanceMark(name, options); enqueue(mark); bufferUserTiming(mark); return mark; } function calculateStartDuration(startOrMeasureOptions, endMark) { startOrMeasureOptions ??= 0; let start; let end; let duration; let optionsValid = false; if (typeof startOrMeasureOptions === "object") { ({ start, end, duration } = startOrMeasureOptions); optionsValid = start !== undefined || end !== undefined; } if (optionsValid) { if (endMark !== undefined) { throw new ERR_PERFORMANCE_MEASURE_INVALID_OPTIONS( "endMark must not be specified", ); } if (start === undefined && end === undefined) { throw new ERR_PERFORMANCE_MEASURE_INVALID_OPTIONS( "One of options.start or options.end is required", ); } if (start !== undefined && end !== undefined && duration !== undefined) { throw new ERR_PERFORMANCE_MEASURE_INVALID_OPTIONS( "Must not have options.start, options.end, and " + "options.duration specified", ); } } if (endMark !== undefined) { end = getMark(endMark); } else if (optionsValid && end !== undefined) { end = getMark(end); } else if (optionsValid && start !== undefined && duration !== undefined) { end = getMark(start) + getMark(duration); } else { end = now(); } if (typeof startOrMeasureOptions === "string") { start = getMark(startOrMeasureOptions); } else if (optionsValid && start !== undefined) { start = getMark(start); } else if (optionsValid && duration !== undefined && end !== undefined) { start = end - getMark(duration); } else { start = 0; } duration = end - start; return { start, duration }; } function measure(name, startOrMeasureOptions, endMark) { validateString(name, "name"); const { start, duration } = calculateStartDuration( startOrMeasureOptions, endMark, ); let detail = startOrMeasureOptions?.detail; detail = detail != null ? structuredClone(detail) : null; const measure = createPerformanceMeasure(name, start, duration, detail); enqueue(measure); bufferUserTiming(measure); return measure; } function clearMarkTimings(name) { if (name !== undefined) { name = `${name}`; if (nodeTimingReadOnlyAttributes.has(name)) throw new ERR_INVALID_ARG_VALUE("name", name); markTimings.delete(name); return; } markTimings.clear(); } export { PerformanceMark }; export { PerformanceMeasure }; export { clearMarkTimings }; export { mark }; export { measure };