Skip to content

Commit f099997

Browse files
Copilothotlong
andcommitted
fix: restore original formatting, redo structured logging migration preserving indentation
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent de45f21 commit f099997

186 files changed

Lines changed: 27181 additions & 27016 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/ai/src/benchmark.ts

Lines changed: 119 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
* of HotCRM's critical paths: hooks, actions, workflows, and AI predictions.
66
*
77
* Usage:
8-
* const bench = new Benchmark('lead_scoring');
9-
* const result = await bench.run(() => scoreLead(lead), { iterations: 100 });
10-
* logger.info(result.summary());
8+
* const bench = new Benchmark('lead_scoring');
9+
* const result = await bench.run(() => scoreLead(lead), { iterations: 100 });
10+
* logger.info(result.summary());
1111
*/
1212

1313
import { createLogger } from '@hotcrm/core';
@@ -18,146 +18,146 @@ const logger = createLogger('ai:benchmark');
1818
// ---------------------------------------------------------------------------
1919

2020
export interface BenchmarkOptions {
21-
/** Number of iterations (default: 100) */
22-
iterations?: number;
23-
/** Warm-up iterations before measurement (default: 5) */
24-
warmup?: number;
25-
/** Timeout per iteration in ms (default: 30000) */
26-
timeout?: number;
21+
/** Number of iterations (default: 100) */
22+
iterations?: number;
23+
/** Warm-up iterations before measurement (default: 5) */
24+
warmup?: number;
25+
/** Timeout per iteration in ms (default: 30000) */
26+
timeout?: number;
2727
}
2828

2929
export interface BenchmarkResult {
30-
/** Benchmark name */
31-
name: string;
32-
/** Total iterations executed */
33-
iterations: number;
34-
/** Total elapsed time in ms */
35-
totalMs: number;
36-
/** Average time per iteration in ms */
37-
meanMs: number;
38-
/** Median time per iteration in ms */
39-
medianMs: number;
40-
/** 95th percentile latency in ms */
41-
p95Ms: number;
42-
/** 99th percentile latency in ms */
43-
p99Ms: number;
44-
/** Minimum iteration time in ms */
45-
minMs: number;
46-
/** Maximum iteration time in ms */
47-
maxMs: number;
48-
/** Operations per second */
49-
opsPerSecond: number;
50-
/** Standard deviation in ms */
51-
stdDevMs: number;
52-
/** Individual iteration timings in ms */
53-
timings: number[];
30+
/** Benchmark name */
31+
name: string;
32+
/** Total iterations executed */
33+
iterations: number;
34+
/** Total elapsed time in ms */
35+
totalMs: number;
36+
/** Average time per iteration in ms */
37+
meanMs: number;
38+
/** Median time per iteration in ms */
39+
medianMs: number;
40+
/** 95th percentile latency in ms */
41+
p95Ms: number;
42+
/** 99th percentile latency in ms */
43+
p99Ms: number;
44+
/** Minimum iteration time in ms */
45+
minMs: number;
46+
/** Maximum iteration time in ms */
47+
maxMs: number;
48+
/** Operations per second */
49+
opsPerSecond: number;
50+
/** Standard deviation in ms */
51+
stdDevMs: number;
52+
/** Individual iteration timings in ms */
53+
timings: number[];
5454
}
5555

5656
// ---------------------------------------------------------------------------
5757
// Helpers
5858
// ---------------------------------------------------------------------------
5959

6060
function percentile(sorted: number[], p: number): number {
61-
if (sorted.length === 0) return 0;
62-
const idx = Math.ceil((p / 100) * sorted.length) - 1;
63-
return sorted[Math.max(0, idx)];
61+
if (sorted.length === 0) return 0;
62+
const idx = Math.ceil((p / 100) * sorted.length) - 1;
63+
return sorted[Math.max(0, idx)];
6464
}
6565

6666
function stdDev(values: number[], mean: number): number {
67-
if (values.length <= 1) return 0;
68-
const squaredDiffs = values.map(v => (v - mean) ** 2);
69-
return Math.sqrt(squaredDiffs.reduce((a, b) => a + b, 0) / (values.length - 1));
67+
if (values.length <= 1) return 0;
68+
const squaredDiffs = values.map(v => (v - mean) ** 2);
69+
return Math.sqrt(squaredDiffs.reduce((a, b) => a + b, 0) / (values.length - 1));
7070
}
7171

7272
// ---------------------------------------------------------------------------
7373
// Benchmark Class
7474
// ---------------------------------------------------------------------------
7575

7676
export class Benchmark {
77-
private readonly name: string;
78-
79-
constructor(name: string) {
80-
this.name = name;
81-
}
82-
83-
/**
84-
* Run a synchronous or asynchronous function and collect timing data.
85-
*/
86-
async run(
87-
fn: () => unknown | Promise<unknown>,
88-
options?: BenchmarkOptions,
89-
): Promise<BenchmarkResult> {
90-
const iterations = options?.iterations ?? 100;
91-
const warmup = options?.warmup ?? 5;
92-
const timeout = options?.timeout ?? 30_000;
93-
94-
// Warm-up phase
95-
for (let i = 0; i < warmup; i++) {
96-
await Promise.resolve(fn());
97-
}
98-
99-
// Measurement phase
100-
const timings: number[] = [];
101-
const start = performance.now();
102-
103-
for (let i = 0; i < iterations; i++) {
104-
const iterStart = performance.now();
105-
await Promise.resolve(fn());
106-
const iterEnd = performance.now();
107-
timings.push(iterEnd - iterStart);
108-
109-
if (iterEnd - start > timeout) {
110-
break;
111-
}
112-
}
113-
114-
const totalMs = performance.now() - start;
115-
const sorted = [...timings].sort((a, b) => a - b);
116-
const mean = timings.reduce((a, b) => a + b, 0) / timings.length;
117-
118-
return {
119-
name: this.name,
120-
iterations: timings.length,
121-
totalMs,
122-
meanMs: mean,
123-
medianMs: percentile(sorted, 50),
124-
p95Ms: percentile(sorted, 95),
125-
p99Ms: percentile(sorted, 99),
126-
minMs: sorted[0] ?? 0,
127-
maxMs: sorted[sorted.length - 1] ?? 0,
128-
opsPerSecond: timings.length / (totalMs / 1000),
129-
stdDevMs: stdDev(timings, mean),
130-
timings,
131-
};
132-
}
77+
private readonly name: string;
78+
79+
constructor(name: string) {
80+
this.name = name;
81+
}
82+
83+
/**
84+
* Run a synchronous or asynchronous function and collect timing data.
85+
*/
86+
async run(
87+
fn: () => unknown | Promise<unknown>,
88+
options?: BenchmarkOptions,
89+
): Promise<BenchmarkResult> {
90+
const iterations = options?.iterations ?? 100;
91+
const warmup = options?.warmup ?? 5;
92+
const timeout = options?.timeout ?? 30_000;
93+
94+
// Warm-up phase
95+
for (let i = 0; i < warmup; i++) {
96+
await Promise.resolve(fn());
97+
}
98+
99+
// Measurement phase
100+
const timings: number[] = [];
101+
const start = performance.now();
102+
103+
for (let i = 0; i < iterations; i++) {
104+
const iterStart = performance.now();
105+
await Promise.resolve(fn());
106+
const iterEnd = performance.now();
107+
timings.push(iterEnd - iterStart);
108+
109+
if (iterEnd - start > timeout) {
110+
break;
111+
}
112+
}
113+
114+
const totalMs = performance.now() - start;
115+
const sorted = [...timings].sort((a, b) => a - b);
116+
const mean = timings.reduce((a, b) => a + b, 0) / timings.length;
117+
118+
return {
119+
name: this.name,
120+
iterations: timings.length,
121+
totalMs,
122+
meanMs: mean,
123+
medianMs: percentile(sorted, 50),
124+
p95Ms: percentile(sorted, 95),
125+
p99Ms: percentile(sorted, 99),
126+
minMs: sorted[0] ?? 0,
127+
maxMs: sorted[sorted.length - 1] ?? 0,
128+
opsPerSecond: timings.length / (totalMs / 1000),
129+
stdDevMs: stdDev(timings, mean),
130+
timings,
131+
};
132+
}
133133
}
134134

135135
// ---------------------------------------------------------------------------
136136
// Suite (run multiple benchmarks)
137137
// ---------------------------------------------------------------------------
138138

139139
export interface BenchmarkSuiteEntry {
140-
name: string;
141-
fn: () => unknown | Promise<unknown>;
142-
options?: BenchmarkOptions;
140+
name: string;
141+
fn: () => unknown | Promise<unknown>;
142+
options?: BenchmarkOptions;
143143
}
144144

145145
export class BenchmarkSuite {
146-
private readonly entries: BenchmarkSuiteEntry[] = [];
147-
148-
add(name: string, fn: () => unknown | Promise<unknown>, options?: BenchmarkOptions): this {
149-
this.entries.push({ name, fn, options });
150-
return this;
151-
}
152-
153-
async run(): Promise<BenchmarkResult[]> {
154-
const results: BenchmarkResult[] = [];
155-
for (const entry of this.entries) {
156-
const bench = new Benchmark(entry.name);
157-
results.push(await bench.run(entry.fn, entry.options));
158-
}
159-
return results;
160-
}
146+
private readonly entries: BenchmarkSuiteEntry[] = [];
147+
148+
add(name: string, fn: () => unknown | Promise<unknown>, options?: BenchmarkOptions): this {
149+
this.entries.push({ name, fn, options });
150+
return this;
151+
}
152+
153+
async run(): Promise<BenchmarkResult[]> {
154+
const results: BenchmarkResult[] = [];
155+
for (const entry of this.entries) {
156+
const bench = new Benchmark(entry.name);
157+
results.push(await bench.run(entry.fn, entry.options));
158+
}
159+
return results;
160+
}
161161
}
162162

163163
// ---------------------------------------------------------------------------
@@ -168,10 +168,10 @@ export class BenchmarkSuite {
168168
* Format benchmark results as a human-readable table string.
169169
*/
170170
export function formatBenchmarkResults(results: BenchmarkResult[]): string {
171-
const header = '| Benchmark | Ops/s | Mean (ms) | Median (ms) | P95 (ms) | P99 (ms) | Std Dev |';
172-
const sep = '|-----------|-------|-----------|-------------|----------|----------|---------|';
173-
const rows = results.map(r =>
174-
`| ${r.name} | ${r.opsPerSecond.toFixed(0)} | ${r.meanMs.toFixed(2)} | ${r.medianMs.toFixed(2)} | ${r.p95Ms.toFixed(2)} | ${r.p99Ms.toFixed(2)} | ${r.stdDevMs.toFixed(2)} |`
175-
);
176-
return [header, sep, ...rows].join('\n');
171+
const header = '| Benchmark | Ops/s | Mean (ms) | Median (ms) | P95 (ms) | P99 (ms) | Std Dev |';
172+
const sep = '|-----------|-------|-----------|-------------|----------|----------|---------|';
173+
const rows = results.map(r =>
174+
`| ${r.name} | ${r.opsPerSecond.toFixed(0)} | ${r.meanMs.toFixed(2)} | ${r.medianMs.toFixed(2)} | ${r.p95Ms.toFixed(2)} | ${r.p99Ms.toFixed(2)} | ${r.stdDevMs.toFixed(2)} |`
175+
);
176+
return [header, sep, ...rows].join('\n');
177177
}

0 commit comments

Comments
 (0)