summaryrefslogtreecommitdiff
path: root/node_modules/@11ty/eleventy/src/Benchmark
diff options
context:
space:
mode:
authorShipwreckt <me@shipwreckt.co.uk>2025-10-31 20:02:14 +0000
committerShipwreckt <me@shipwreckt.co.uk>2025-10-31 20:02:14 +0000
commit7a52ddeba2a68388b544f529d2d92104420f77b0 (patch)
tree15ddd47457a2cb4a96060747437d36474e4f6b4e /node_modules/@11ty/eleventy/src/Benchmark
parent53d6ae2b5568437afa5e4995580a3fb679b7b91b (diff)
Changed from static to 11ty!
Diffstat (limited to 'node_modules/@11ty/eleventy/src/Benchmark')
-rw-r--r--node_modules/@11ty/eleventy/src/Benchmark/Benchmark.js55
-rw-r--r--node_modules/@11ty/eleventy/src/Benchmark/BenchmarkGroup.js135
-rw-r--r--node_modules/@11ty/eleventy/src/Benchmark/BenchmarkManager.js73
3 files changed, 263 insertions, 0 deletions
diff --git a/node_modules/@11ty/eleventy/src/Benchmark/Benchmark.js b/node_modules/@11ty/eleventy/src/Benchmark/Benchmark.js
new file mode 100644
index 0000000..df6dea7
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Benchmark/Benchmark.js
@@ -0,0 +1,55 @@
+import { performance } from "node:perf_hooks";
+
+class Benchmark {
+ constructor() {
+ // TypeScript slop
+ this.timeSpent = 0;
+ this.timesCalled = 0;
+ this.beforeTimers = [];
+ }
+
+ reset() {
+ this.timeSpent = 0;
+ this.timesCalled = 0;
+ this.beforeTimers = [];
+ }
+
+ getNewTimestamp() {
+ if (performance) {
+ return performance.now();
+ }
+ return new Date().getTime();
+ }
+
+ incrementCount() {
+ this.timesCalled++;
+ }
+
+ // TODO(slightlyoff):
+ // disable all of these hrtime requests when not benchmarking
+ before() {
+ this.timesCalled++;
+ this.beforeTimers.push(this.getNewTimestamp());
+ }
+
+ after() {
+ if (!this.beforeTimers.length) {
+ throw new Error("You called Benchmark after() without a before().");
+ }
+
+ let before = this.beforeTimers.pop();
+ if (!this.beforeTimers.length) {
+ this.timeSpent += this.getNewTimestamp() - before;
+ }
+ }
+
+ getTimesCalled() {
+ return this.timesCalled;
+ }
+
+ getTotal() {
+ return this.timeSpent;
+ }
+}
+
+export default Benchmark;
diff --git a/node_modules/@11ty/eleventy/src/Benchmark/BenchmarkGroup.js b/node_modules/@11ty/eleventy/src/Benchmark/BenchmarkGroup.js
new file mode 100644
index 0000000..ee82f6b
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Benchmark/BenchmarkGroup.js
@@ -0,0 +1,135 @@
+import debugUtil from "debug";
+
+import ConsoleLogger from "../Util/ConsoleLogger.js";
+import isAsyncFunction from "../Util/IsAsyncFunction.js";
+import Benchmark from "./Benchmark.js";
+
+const debugBenchmark = debugUtil("Eleventy:Benchmark");
+
+class BenchmarkGroup {
+ constructor() {
+ this.benchmarks = {};
+ // Warning: aggregate benchmarks automatically default to false via BenchmarkManager->getBenchmarkGroup
+ this.isVerbose = true;
+ this.logger = new ConsoleLogger();
+ this.minimumThresholdMs = 50;
+ this.minimumThresholdPercent = 8;
+ }
+
+ setIsVerbose(isVerbose) {
+ this.isVerbose = isVerbose;
+ this.logger.isVerbose = isVerbose;
+ }
+
+ reset() {
+ for (var type in this.benchmarks) {
+ this.benchmarks[type].reset();
+ }
+ }
+
+ // TODO use addAsync everywhere instead
+ add(type, callback) {
+ let benchmark = (this.benchmarks[type] = new Benchmark());
+
+ /** @this {any} */
+ let fn = function (...args) {
+ benchmark.before();
+ let ret = callback.call(this, ...args);
+ benchmark.after();
+ return ret;
+ };
+
+ Object.defineProperty(fn, "__eleventyInternal", {
+ value: {
+ type: isAsyncFunction(callback) ? "async" : "sync",
+ callback,
+ },
+ });
+
+ return fn;
+ }
+
+ // callback must return a promise
+ // async addAsync(type, callback) {
+ // let benchmark = (this.benchmarks[type] = new Benchmark());
+
+ // benchmark.before();
+ // // don’t await here.
+ // let promise = callback.call(this);
+ // promise.then(function() {
+ // benchmark.after();
+ // });
+ // return promise;
+ // }
+
+ setMinimumThresholdMs(minimumThresholdMs) {
+ let val = parseInt(minimumThresholdMs, 10);
+ if (isNaN(val)) {
+ throw new Error("`setMinimumThresholdMs` expects a number argument.");
+ }
+ this.minimumThresholdMs = val;
+ }
+
+ setMinimumThresholdPercent(minimumThresholdPercent) {
+ let val = parseInt(minimumThresholdPercent, 10);
+ if (isNaN(val)) {
+ throw new Error("`setMinimumThresholdPercent` expects a number argument.");
+ }
+ this.minimumThresholdPercent = val;
+ }
+
+ has(type) {
+ return !!this.benchmarks[type];
+ }
+
+ get(type) {
+ if (!this.benchmarks[type]) {
+ this.benchmarks[type] = new Benchmark();
+ }
+ return this.benchmarks[type];
+ }
+
+ padNumber(num, length) {
+ if (("" + num).length >= length) {
+ return num;
+ }
+
+ let prefix = new Array(length + 1).join(" ");
+ return (prefix + num).slice(-1 * length);
+ }
+
+ finish(label, totalTimeSpent) {
+ for (var type in this.benchmarks) {
+ let bench = this.benchmarks[type];
+ let isAbsoluteMinimumComparison = this.minimumThresholdMs > 0;
+ let totalForBenchmark = bench.getTotal();
+ let percent = Math.round((totalForBenchmark * 100) / totalTimeSpent);
+ let callCount = bench.getTimesCalled();
+
+ let output = {
+ ms: this.padNumber(totalForBenchmark.toFixed(0), 6),
+ percent: this.padNumber(percent, 3),
+ calls: this.padNumber(callCount, 5),
+ };
+ let str = `Benchmark ${output.ms}ms ${output.percent}% ${output.calls}× (${label}) ${type}`;
+
+ if (
+ isAbsoluteMinimumComparison &&
+ totalForBenchmark >= this.minimumThresholdMs &&
+ percent > this.minimumThresholdPercent
+ ) {
+ this.logger.warn(str);
+ }
+
+ // Opt out of logging if low count (1× or 2×) or 0ms / 1%
+ if (
+ callCount > 1 || // called more than once
+ Math.round(totalForBenchmark) > 0 // more than 0.5ms
+ ) {
+ debugBenchmark(str);
+ }
+ }
+ }
+}
+
+export default BenchmarkGroup;
diff --git a/node_modules/@11ty/eleventy/src/Benchmark/BenchmarkManager.js b/node_modules/@11ty/eleventy/src/Benchmark/BenchmarkManager.js
new file mode 100644
index 0000000..d7a8f61
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Benchmark/BenchmarkManager.js
@@ -0,0 +1,73 @@
+import { performance } from "node:perf_hooks";
+
+import BenchmarkGroup from "./BenchmarkGroup.js";
+
+// TODO this should not be a singleton, it belongs in the config or somewhere on the Eleventy instance.
+
+class BenchmarkManager {
+ constructor() {
+ this.benchmarkGroups = {};
+ this.isVerbose = true;
+ this.start = this.getNewTimestamp();
+ }
+
+ reset() {
+ this.start = this.getNewTimestamp();
+
+ for (var j in this.benchmarkGroups) {
+ this.benchmarkGroups[j].reset();
+ }
+ }
+
+ getNewTimestamp() {
+ if (performance) {
+ return performance.now();
+ }
+ return new Date().getTime();
+ }
+
+ setVerboseOutput(isVerbose) {
+ this.isVerbose = !!isVerbose;
+ }
+
+ hasBenchmarkGroup(name) {
+ return name in this.benchmarkGroups;
+ }
+
+ getBenchmarkGroup(name) {
+ if (!this.benchmarkGroups[name]) {
+ this.benchmarkGroups[name] = new BenchmarkGroup();
+
+ // Special behavior for aggregate benchmarks
+ // so they don’t console.log every time
+ if (name === "Aggregate") {
+ this.benchmarkGroups[name].setIsVerbose(false);
+ } else {
+ this.benchmarkGroups[name].setIsVerbose(this.isVerbose);
+ }
+ }
+
+ return this.benchmarkGroups[name];
+ }
+
+ getAll() {
+ return this.benchmarkGroups;
+ }
+
+ get(name) {
+ if (name) {
+ return this.getBenchmarkGroup(name);
+ }
+
+ return this.getAll();
+ }
+
+ finish() {
+ let totalTimeSpentBenchmarking = this.getNewTimestamp() - this.start;
+ for (var j in this.benchmarkGroups) {
+ this.benchmarkGroups[j].finish(j, totalTimeSpentBenchmarking);
+ }
+ }
+}
+
+export default BenchmarkManager;