@re-shell/cli
Version:
Full-stack development platform uniting microservices and microfrontends. Build complete applications with .NET (ASP.NET Core Web API, Minimal API), Java (Spring Boot, Quarkus, Micronaut, Vert.x), Rust (Actix-Web, Warp, Rocket, Axum), Python (FastAPI, Dja
191 lines (190 loc) • 6.66 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.profiler = exports.PerformanceProfiler = void 0;
/**
* Performance profiler for CLI startup and command execution
*/
const perf_hooks_1 = require("perf_hooks");
const fs_1 = require("fs");
const path_1 = require("path");
const os_1 = require("os");
class PerformanceProfiler {
constructor() {
this.marks = new Map();
this.startTime = 0;
this.enabled = false;
const cacheDir = (0, path_1.join)((0, os_1.homedir)(), '.re-shell', 'performance');
if (!(0, fs_1.existsSync)(cacheDir)) {
(0, fs_1.mkdirSync)(cacheDir, { recursive: true });
}
this.reportPath = (0, path_1.join)(cacheDir, 'performance.json');
// Enable profiling based on environment variable
this.enabled = process.env.RESHELL_PROFILE === 'true' || process.env.DEBUG === 'true';
}
static getInstance() {
if (!PerformanceProfiler.instance) {
PerformanceProfiler.instance = new PerformanceProfiler();
}
return PerformanceProfiler.instance;
}
/**
* Start profiling
*/
start(command = 'unknown') {
if (!this.enabled)
return;
this.startTime = perf_hooks_1.performance.now();
this.marks.clear();
this.mark('startup', {
command,
argv: process.argv.slice(2).join(' ')
});
}
/**
* Mark a performance checkpoint
*/
mark(name, metadata) {
if (!this.enabled)
return;
const timestamp = perf_hooks_1.performance.now();
const memory = process.memoryUsage();
this.marks.set(name, {
name,
timestamp,
memory,
...(metadata && { metadata })
});
}
/**
* Measure duration between two marks
*/
measure(name, startMark, endMark) {
if (!this.enabled)
return;
const start = this.marks.get(startMark);
const end = endMark ? this.marks.get(endMark) : { timestamp: perf_hooks_1.performance.now() };
if (start && end) {
const duration = end.timestamp - start.timestamp;
this.marks.set(name, {
name,
timestamp: end.timestamp,
duration
});
}
}
/**
* End profiling and generate report
*/
end() {
if (!this.enabled)
return null;
const endTime = perf_hooks_1.performance.now();
const totalDuration = endTime - this.startTime;
const report = {
startTime: this.startTime,
endTime,
totalDuration,
marks: Array.from(this.marks.values()),
command: process.argv.slice(2).join(' ') || 'none',
version: require('../../package.json').version,
platform: process.platform,
nodeVersion: process.version
};
// Save report
this.saveReport(report);
if (process.env.DEBUG === 'true') {
this.printReport(report);
}
return report;
}
/**
* Save performance report
*/
saveReport(report) {
try {
let reports = [];
if ((0, fs_1.existsSync)(this.reportPath)) {
const existing = (0, fs_1.readFileSync)(this.reportPath, 'utf-8');
reports = JSON.parse(existing);
}
// Keep only last 100 reports
reports.push(report);
if (reports.length > 100) {
reports = reports.slice(-100);
}
(0, fs_1.writeFileSync)(this.reportPath, JSON.stringify(reports, null, 2));
}
catch (error) {
// Ignore save errors
}
}
/**
* Print performance report to console
*/
printReport(report) {
console.log('\n=== Performance Report ===');
console.log(`Total Duration: ${report.totalDuration.toFixed(2)}ms`);
console.log(`Command: ${report.command}`);
console.log(`Platform: ${report.platform} (Node ${report.nodeVersion})`);
console.log('\nTimings:');
const sortedMarks = report.marks.sort((a, b) => a.timestamp - b.timestamp);
let lastTime = 0;
for (const mark of sortedMarks) {
const delta = mark.timestamp - lastTime;
const fromStart = mark.timestamp - report.startTime;
console.log(` ${mark.name.padEnd(30)} +${delta.toFixed(2).padStart(8)}ms (${fromStart.toFixed(2).padStart(8)}ms from start)`);
if (mark.duration) {
console.log(` └─ Duration: ${mark.duration.toFixed(2)}ms`);
}
if (mark.memory) {
const heapMB = (mark.memory.heapUsed / 1024 / 1024).toFixed(2);
console.log(` └─ Memory: ${heapMB}MB`);
}
lastTime = mark.timestamp;
}
console.log('========================\n');
}
/**
* Get average startup time from recent reports
*/
getAverageStartupTime() {
if (!(0, fs_1.existsSync)(this.reportPath)) {
return null;
}
try {
const reports = JSON.parse((0, fs_1.readFileSync)(this.reportPath, 'utf-8'));
if (reports.length === 0)
return null;
const recentReports = reports.slice(-10);
const avgTime = recentReports.reduce((sum, r) => sum + r.totalDuration, 0) / recentReports.length;
return avgTime;
}
catch {
return null;
}
}
/**
* Analyze performance bottlenecks
*/
analyzeBottlenecks() {
const marks = Array.from(this.marks.values()).sort((a, b) => a.timestamp - b.timestamp);
const bottlenecks = [];
for (let i = 0; i < marks.length - 1; i++) {
const current = marks[i];
const next = marks[i + 1];
const duration = next.timestamp - current.timestamp;
const percentage = (duration / (perf_hooks_1.performance.now() - this.startTime)) * 100;
if (duration > 10) { // Only report phases taking more than 10ms
bottlenecks.push({
phase: `${current.name} → ${next.name}`,
duration,
percentage
});
}
}
return bottlenecks.sort((a, b) => b.duration - a.duration);
}
}
exports.PerformanceProfiler = PerformanceProfiler;
// Export singleton instance
exports.profiler = PerformanceProfiler.getInstance();