import os from "os"; import { DynamicBenchmarker } from "../DynamicBenchmarker"; export namespace DynamicBenchmarkReporter { export const markdown = (report: DynamicBenchmarker.IReport): string => { const format = (value: number | null) => value === null ? "N/A" : (Math.floor(value * 100) / 100).toLocaleString(); const head = () => [ "Type", "Count", "Success", "Mean.", "Stdev.", "Minimum", "Maximum", ].join(" | ") + "\n" + new Array(7).fill("----").join("|"); const row = (title: string, s: DynamicBenchmarker.IReport.IStatistics) => [ title, s.count.toLocaleString(), s.success.toLocaleString(), format(s.mean), format(s.stdev), format(s.minimum), format(s.maximum), ].join(" | "); const line = ( title: string, getter: (m: NodeJS.MemoryUsage) => number, ): string => `line "${title}" [${report.memories.map((m) => Math.floor(getter(m.usage) / 1024 ** 2)).join(", ")}]`; return [ `# Benchmark Report`, "> Generated by [`@nestia/benchmark`](https://github.com/samchon/nestia)", ``, ` - Specifications`, ` - CPU: ${os.cpus()[0]!.model}`, ` - RAM: ${Math.floor(os.totalmem() / 1024 / 1024 / 1024).toLocaleString()} GB`, ` - NodeJS Version: ${process.version}`, ` - Backend Server: 1 core / 1 thread`, ` - Arguments`, ` - Count: ${report.count.toLocaleString()}`, ` - Threads: ${report.threads.toLocaleString()}`, ` - Simultaneous: ${report.simultaneous.toLocaleString()}`, ` - Time`, ` - Start: ${report.started_at}`, ` - Complete: ${report.completed_at}`, ` - Elapsed: ${(new Date(report.completed_at).getTime() - new Date(report.started_at).getTime()).toLocaleString()} ms`, ``, head(), row("Total", report.statistics), "", "> Unit: milliseconds", "", "## Memory Consumptions", "```mermaid", "xychart-beta", ` x-axis "Time (second)"`, ` y-axis "Memory (MB)"`, ` ${line("Resident Set Size", (m) => m.rss)}`, ` ${line("Heap Total", (m) => m.heapTotal)}`, ` ${line("Heap Used + External", (m) => m.heapUsed + m.external)}`, ` ${line("Heap Used Only", (m) => m.heapUsed)}`, "```", "", `> - 🟦 Resident Set Size`, `> - 🟢 Heap Total`, `> - 🔴 Heap Used + External`, `> - 🟡 Heap Used Only`, "", "## Endpoints", head(), ...report.endpoints .slice() .sort((a, b) => (b.mean ?? 0) - (a.mean ?? 0)) .map((endpoint) => row(`${endpoint.method} ${endpoint.path}`, endpoint), ), "", "> Unit: milliseconds", "", "## Failures", "Method | Path | Count | Failures", "-------|------|-------|----------", ...report.endpoints .filter((e) => e.success !== e.count) .slice() .sort((a, b) => b.count - a.count) .map((e) => [ e.method, e.path, e.count.toLocaleString(), (e.count - e.success).toLocaleString(), ].join(" | "), ), ].join("\n"); }; }