From 3c61dd71c3244f83cba5add71419363a6a8e55f8 Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Tue, 9 Dec 2025 21:41:28 -0500 Subject: [PATCH 01/10] wip --- benchmark/benchmarks.ts | 29 +-- benchmark/compare/compare.ts | 120 ++++----- package-lock.json | 97 ++++--- package.json | 3 +- src/lib/CodeHighlight.svelte | 1 + src/lib/syntax_styler.ts | 14 +- src/routes/benchmark/+page.svelte | 16 +- src/routes/benchmark/BenchmarkResults.svelte | 12 +- src/routes/benchmark/benchmark_results.ts | 76 +++--- src/routes/benchmark/benchmark_runner.ts | 33 +-- src/routes/benchmark/benchmark_stats.ts | 261 ++++--------------- src/routes/benchmark/benchmark_types.ts | 37 ++- src/routes/library.ts | 44 +--- 13 files changed, 278 insertions(+), 465 deletions(-) diff --git a/benchmark/benchmarks.ts b/benchmark/benchmarks.ts index daa95708..ff9b3e85 100644 --- a/benchmark/benchmarks.ts +++ b/benchmark/benchmarks.ts @@ -1,4 +1,4 @@ -import {Bench} from 'tinybench'; +import {Benchmark} from '@fuzdev/fuz_util/benchmark.js'; import {samples as all_samples} from '../src/test/fixtures/samples/all.js'; import {syntax_styler_global} from '../src/lib/syntax_styler_global.js'; @@ -6,7 +6,6 @@ import {syntax_styler_global} from '../src/lib/syntax_styler_global.js'; /* eslint-disable no-console */ const BENCHMARK_TIME = 10000; -const WARMUP_TIME = 1000; const WARMUP_ITERATIONS = 50; const LARGE_CONTENT_MULTIPLIER = 100; @@ -18,10 +17,9 @@ export interface BenchmarkResult { } export const run_benchmark = async (filter?: string): Promise> => { - const bench = new Bench({ - time: BENCHMARK_TIME, - warmupTime: WARMUP_TIME, - warmupIterations: WARMUP_ITERATIONS, + const bench = new Benchmark({ + duration_ms: BENCHMARK_TIME, + warmup_iterations: WARMUP_ITERATIONS, }); const samples = Object.values(all_samples); @@ -59,16 +57,15 @@ export const run_benchmark = async (filter?: string): Promise = []; - - for (const task of bench.tasks) { - if (task.result.state === 'completed' || task.result.state === 'aborted-with-statistics') { - results.push({ - name: task.name, - ops_per_sec: task.result.throughput.mean, - mean_time: task.result.latency.mean, - samples: task.result.latency.samples?.length, - }); - } + const bench_results = bench.results(); + + for (const result of bench_results) { + results.push({ + name: result.name, + ops_per_sec: result.stats.ops_per_second, + mean_time: result.stats.mean_ns / 1_000_000, // Convert ns to ms + samples: result.stats.sample_size, + }); } return results; diff --git a/benchmark/compare/compare.ts b/benchmark/compare/compare.ts index 41cf31b9..029eb355 100644 --- a/benchmark/compare/compare.ts +++ b/benchmark/compare/compare.ts @@ -2,7 +2,7 @@ // This allows CI to pass without running `npm install` for the benchmarks. // @ts-nocheck -import {Bench} from 'tinybench'; +import {Benchmark} from '@fuzdev/fuz_util/benchmark.js'; // Prism imports import Prism from 'prismjs'; @@ -32,7 +32,6 @@ import {tokenize_syntax} from '../../src/lib/syntax_styler.js'; /* eslint-disable no-console */ const BENCHMARK_TIME = 10000; // 10000 -const WARMUP_TIME = 1000; // 1000 const WARMUP_ITERATIONS = 20; // 20 const LARGE_CONTENT_MULTIPLIER = 100; // 100 const MIN_ITERATIONS = 3; // Tiny minimum samples cause of Shiki's pathological cases with TS @@ -112,10 +111,9 @@ const getSampleContent = (lang: SupportedLanguage, large = false) => { export const run_comparison_benchmark = async ( filter?: string, ): Promise> => { - const bench = new Bench({ - time: BENCHMARK_TIME, - warmupTime: WARMUP_TIME, - warmupIterations: WARMUP_ITERATIONS, + const bench = new Benchmark({ + time_ms: BENCHMARK_TIME, + warmup_iterations: WARMUP_ITERATIONS, iterations: MIN_ITERATIONS, }); @@ -190,65 +188,59 @@ export const run_comparison_benchmark = async ( const results: Array = []; for (const task of bench.tasks) { - if ( - task.result.state === 'completed' || - task.result.state === 'aborted' || - task.result.state === 'aborted-with-statistics' - ) { - // Parse benchmark name: implementation_operation_language_size - // Handle multi-word implementations like 'fuz_code' and 'shiki_js' - const parts = task.name.split('_'); - let implementation: string; - let operation: 'tokenize' | 'stylize'; - let language: string; - let content_size: 'small' | 'large'; - - if (task.name.startsWith('fuz_code_tokenize_')) { - implementation = 'fuz_code'; - operation = 'tokenize'; - language = parts[3]; - content_size = parts[4] as 'small' | 'large'; - } else if (task.name.startsWith('fuz_code_stylize_')) { - implementation = 'fuz_code'; - operation = 'stylize'; - language = parts[3]; - content_size = parts[4] as 'small' | 'large'; - } else if (task.name.startsWith('prism_tokenize_')) { - implementation = 'prism'; - operation = 'tokenize'; - language = parts[2]; - content_size = parts[3] as 'small' | 'large'; - } else if (task.name.startsWith('prism_stylize_')) { - implementation = 'prism'; - operation = 'stylize'; - language = parts[2]; - content_size = parts[3] as 'small' | 'large'; - } else if (task.name.startsWith('shiki_js_stylize_')) { - implementation = 'shiki_js'; - operation = 'stylize'; - language = parts[3]; - content_size = parts[4] as 'small' | 'large'; - } else if (task.name.startsWith('shiki_oniguruma_stylize_')) { - implementation = 'shiki_oniguruma'; - operation = 'stylize'; - language = parts[3]; - content_size = parts[4] as 'small' | 'large'; - } else { - console.warn(`Unknown benchmark name format: ${task.name}`); - continue; - } - - results.push({ - implementation, - language, - ops_per_sec: task.result.throughput.mean, - mean_time: task.result.latency.mean, - samples: task.result.latency.samples.length, - content_size, - total_time: task.result.totalTime, - operation, - }); + // Parse benchmark name: implementation_operation_language_size + // Handle multi-word implementations like 'fuz_code' and 'shiki_js' + const parts = task.name.split('_'); + let implementation: string; + let operation: 'tokenize' | 'stylize'; + let language: string; + let content_size: 'small' | 'large'; + + if (task.name.startsWith('fuz_code_tokenize_')) { + implementation = 'fuz_code'; + operation = 'tokenize'; + language = parts[3]; + content_size = parts[4] as 'small' | 'large'; + } else if (task.name.startsWith('fuz_code_stylize_')) { + implementation = 'fuz_code'; + operation = 'stylize'; + language = parts[3]; + content_size = parts[4] as 'small' | 'large'; + } else if (task.name.startsWith('prism_tokenize_')) { + implementation = 'prism'; + operation = 'tokenize'; + language = parts[2]; + content_size = parts[3] as 'small' | 'large'; + } else if (task.name.startsWith('prism_stylize_')) { + implementation = 'prism'; + operation = 'stylize'; + language = parts[2]; + content_size = parts[3] as 'small' | 'large'; + } else if (task.name.startsWith('shiki_js_stylize_')) { + implementation = 'shiki_js'; + operation = 'stylize'; + language = parts[3]; + content_size = parts[4] as 'small' | 'large'; + } else if (task.name.startsWith('shiki_oniguruma_stylize_')) { + implementation = 'shiki_oniguruma'; + operation = 'stylize'; + language = parts[3]; + content_size = parts[4] as 'small' | 'large'; + } else { + console.warn(`Unknown benchmark name format: ${task.name}`); + continue; } + + results.push({ + implementation, + language, + ops_per_sec: task.ops_per_sec, + mean_time: task.mean_time_ms, + samples: task.samples, + content_size, + total_time: task.total_time_ms, + operation, + }); } return results; diff --git a/package-lock.json b/package-lock.json index c88e93db..20a37809 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@changesets/changelog-git": "^0.2.1", "@fuzdev/fuz_css": "^0.42.1", "@fuzdev/fuz_ui": "^0.172.0", - "@fuzdev/fuz_util": "^0.42.0", + "@fuzdev/fuz_util": "file:../fuz_util", "@ryanatkn/eslint-config": "^0.9.0", "@ryanatkn/gro": "^0.181.0", "@sveltejs/adapter-static": "^3.0.10", @@ -27,7 +27,6 @@ "prettier-plugin-svelte": "^3.4.0", "svelte": "^5.45.6", "svelte-check": "^4.3.4", - "tinybench": "^6.0.0", "tslib": "^2.8.1", "typescript": "^5.9.3", "typescript-eslint": "^8.48.1", @@ -52,6 +51,61 @@ } } }, + "../fuz_util": { + "name": "@fuzdev/fuz_util", + "version": "0.42.0", + "dev": true, + "license": "MIT", + "devDependencies": { + "@changesets/changelog-git": "^0.2.1", + "@fuzdev/fuz_code": "^0.38.0", + "@fuzdev/fuz_css": "^0.42.1", + "@fuzdev/fuz_ui": "^0.172.0", + "@ryanatkn/eslint-config": "^0.9.0", + "@ryanatkn/gro": "^0.181.0", + "@sveltejs/adapter-static": "^3.0.10", + "@sveltejs/kit": "^2.49.1", + "@sveltejs/package": "^2.5.7", + "@sveltejs/vite-plugin-svelte": "^6.2.1", + "@types/node": "^24.10.1", + "dequal": "^2.0.3", + "eslint": "^9.39.1", + "eslint-plugin-svelte": "^3.13.1", + "esm-env": "^1.2.2", + "fast-deep-equal": "^3.1.3", + "prettier": "^3.7.4", + "prettier-plugin-svelte": "^3.4.0", + "svelte": "^5.45.6", + "svelte-check": "^4.3.4", + "tslib": "^2.8.1", + "typescript": "^5.9.3", + "typescript-eslint": "^8.48.1", + "vitest": "^4.0.15", + "zod": "^4.1.13" + }, + "engines": { + "node": ">=22.15" + }, + "funding": { + "url": "https://www.ryanatkn.com/funding" + }, + "peerDependencies": { + "@types/node": "^24", + "esm-env": "^1.2.2", + "zod": "^4.0.14" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "esm-env": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, "node_modules/@changesets/changelog-git": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.2.1.tgz", @@ -785,33 +839,8 @@ } }, "node_modules/@fuzdev/fuz_util": { - "version": "0.42.0", - "resolved": "https://registry.npmjs.org/@fuzdev/fuz_util/-/fuz_util-0.42.0.tgz", - "integrity": "sha512-i+/+fySpBYYatkNEzI7WgyPm/KULANQTtj8s/EMGJFkknR0UBJToqTXu8VodCa5yTm6Uo4cowa1CVEQdzSn49g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.15" - }, - "funding": { - "url": "https://www.ryanatkn.com/funding" - }, - "peerDependencies": { - "@types/node": "^24", - "esm-env": "^1.2.2", - "zod": "^4.0.14" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "esm-env": { - "optional": true - }, - "zod": { - "optional": true - } - } + "resolved": "../fuz_util", + "link": true }, "node_modules/@humanfs/core": { "version": "0.19.1", @@ -3816,16 +3845,6 @@ "typescript": "^4.9.4 || ^5.0.0" } }, - "node_modules/tinybench": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-6.0.0.tgz", - "integrity": "sha512-BWlWpVbbZXaYjRV0twGLNQO00Zj4HA/sjLOQP2IvzQqGwRGp+2kh7UU3ijyJ3ywFRogYDRbiHDMrUOfaMnN56g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.0.0" - } - }, "node_modules/tinyexec": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", diff --git a/package.json b/package.json index bdfe5041..a29d6c5a 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "@changesets/changelog-git": "^0.2.1", "@fuzdev/fuz_css": "^0.42.1", "@fuzdev/fuz_ui": "^0.172.0", - "@fuzdev/fuz_util": "^0.42.0", + "@fuzdev/fuz_util": "file:../fuz_util", "@ryanatkn/eslint-config": "^0.9.0", "@ryanatkn/gro": "^0.181.0", "@sveltejs/adapter-static": "^3.0.10", @@ -63,7 +63,6 @@ "prettier-plugin-svelte": "^3.4.0", "svelte": "^5.45.6", "svelte-check": "^4.3.4", - "tinybench": "^6.0.0", "tslib": "^2.8.1", "typescript": "^5.9.3", "typescript-eslint": "^8.48.1", diff --git a/src/lib/CodeHighlight.svelte b/src/lib/CodeHighlight.svelte index da0ab5da..896d3c78 100644 --- a/src/lib/CodeHighlight.svelte +++ b/src/lib/CodeHighlight.svelte @@ -172,6 +172,7 @@ highlight_manager?.destroy(); }); + // TODO use intersect attachment from fuz_ui to optimize ranges // TODO do syntax styling at compile-time in the normal case, and don't import these at runtime // TODO @html making me nervous diff --git a/src/lib/syntax_styler.ts b/src/lib/syntax_styler.ts index 9e9a21ff..48205302 100644 --- a/src/lib/syntax_styler.ts +++ b/src/lib/syntax_styler.ts @@ -35,7 +35,7 @@ export class SyntaxStyler { add_lang(id: string, grammar: SyntaxGrammarRaw, aliases?: Array): void { // Normalize grammar once at registration for optimal runtime performance // Use a visited set to handle circular references - this.normalize_grammar(grammar, new Set()); + this.#normalize_grammar(grammar, new Set()); // After normalization, grammar has the shape of SyntaxGrammar const normalized = grammar as unknown as SyntaxGrammar; this.langs[id] = normalized; @@ -233,7 +233,7 @@ export class SyntaxStyler { } // Normalize the updated grammar to ensure inserted patterns have consistent shape - this.normalize_grammar(updated, new Set()); + this.#normalize_grammar(updated, new Set()); // After normalization, cast to SyntaxGrammar const normalized = updated as unknown as SyntaxGrammar; @@ -334,7 +334,7 @@ export class SyntaxStyler { // Merge normalized base with un-normalized extension const extended = {...structuredClone(this.get_lang(base_id)), ...extension}; // Normalize the extension parts - this.normalize_grammar(extended as SyntaxGrammarRaw, new Set()); + this.#normalize_grammar(extended as SyntaxGrammarRaw, new Set()); // Return as SyntaxGrammar return extended as unknown as SyntaxGrammar; } @@ -343,7 +343,7 @@ export class SyntaxStyler { * Normalize a single pattern to have consistent shape. * This ensures all patterns have the same object shape for V8 optimization. */ - private normalize_pattern( + #normalize_pattern( pattern: RegExp | SyntaxGrammarTokenRaw, visited: Set, ): SyntaxGrammarToken { @@ -366,7 +366,7 @@ export class SyntaxStyler { // Recursively normalize the inside grammar if present let normalized_inside: SyntaxGrammar | null = null; if (p.inside) { - this.normalize_grammar(p.inside, visited); + this.#normalize_grammar(p.inside, visited); // After normalization, cast to SyntaxGrammar normalized_inside = p.inside as unknown as SyntaxGrammar; } @@ -391,7 +391,7 @@ export class SyntaxStyler { * This is called once at registration time to avoid runtime overhead. * @param visited - Set of grammar object IDs already normalized (for circular references) */ - private normalize_grammar(grammar: SyntaxGrammarRaw, visited: Set): void { + #normalize_grammar(grammar: SyntaxGrammarRaw, visited: Set): void { // Check if we've already normalized this grammar (circular reference) const grammar_id = id_of(grammar); if (visited.has(grammar_id)) { @@ -422,7 +422,7 @@ export class SyntaxStyler { // Always store as array of normalized patterns const patterns = Array.isArray(value) ? value : [value]; - grammar[key] = patterns.map((p) => this.normalize_pattern(p, visited)); + grammar[key] = patterns.map((p) => this.#normalize_pattern(p, visited)); } } diff --git a/src/routes/benchmark/+page.svelte b/src/routes/benchmark/+page.svelte index 3597d41c..21fb82d2 100644 --- a/src/routes/benchmark/+page.svelte +++ b/src/routes/benchmark/+page.svelte @@ -13,10 +13,10 @@ // Configuration const config: BenchmarkConfig = $state({ - iterations: 10, - warmup_count: 3, - cooldown_ms: 100, - content_multiplier: 20, // 100 is hanging at CSS in html mode + iterations: 5, + warmup_count: 2, + cooldown_ms: 50, + content_multiplier: 10, }); // UI state @@ -93,22 +93,22 @@ config diff --git a/src/routes/benchmark/BenchmarkResults.svelte b/src/routes/benchmark/BenchmarkResults.svelte index 3af3bff7..3dccc49a 100644 --- a/src/routes/benchmark/BenchmarkResults.svelte +++ b/src/routes/benchmark/BenchmarkResults.svelte @@ -4,6 +4,7 @@ import {fmt} from './benchmark_stats.js'; import {RESULT_COLUMNS, results_to_markdown} from './benchmark_results.js'; import type {BenchmarkResult, SummaryStats} from './benchmark_types.js'; + import type {ImplementationName} from './benchmark_fixtures.js'; const { results = [], @@ -11,7 +12,7 @@ warnings = [], }: { results: Array; - summary: Record | null; + summary: Record | null; warnings: Array; } = $props(); @@ -76,8 +77,8 @@ {#each results as result (result)} {#each RESULT_COLUMNS as column (column)} - - {column.format(result[column.key], result)} + + {column.get_value(result)} {/each} @@ -98,9 +99,10 @@ CV: Coefficient of Variation (std_dev/mean) - lower is better, <15% is good -
  • P95: 95th percentile - 95% of measurements were faster than this
  • +
  • + P75/P90/P95/P99: Percentiles - X% of measurements were faster than this +
  • Ops/sec: Operations per second (throughput)
  • -
  • Per Item: Time per individual component in batch
  • Stability: Percentage of iterations with stable system metrics
  • diff --git a/src/routes/benchmark/benchmark_results.ts b/src/routes/benchmark/benchmark_results.ts index 90c95e1b..b1ff3243 100644 --- a/src/routes/benchmark/benchmark_results.ts +++ b/src/routes/benchmark/benchmark_results.ts @@ -1,80 +1,92 @@ +/** + * Benchmark results display utilities. + * Uses fuz_util's time formatting for consistent display. + */ + +import {TIME_NS_PER_MS} from '@fuzdev/fuz_util/time.js'; + import {fmt} from './benchmark_stats.js'; import type {BenchmarkResult} from './benchmark_types.js'; /** - * Column definitions for benchmark results table + * Helper to convert nanoseconds to milliseconds for display. + */ +const ns_to_ms = (ns: number): number => ns / TIME_NS_PER_MS; + +/** + * Column definitions for benchmark results table. */ export interface ResultColumn { header: string; - key: keyof BenchmarkResult; - format: (value: any, result: BenchmarkResult) => string; - class?: (value: any, result: BenchmarkResult) => string; + get_value: (result: BenchmarkResult) => string; + get_class?: (result: BenchmarkResult) => string; } export const RESULT_COLUMNS: Array = [ { header: 'Language', - key: 'language', - format: (v) => v, + get_value: (r) => r.language, }, { header: 'Implementation', - key: 'implementation', - format: (v) => v, + get_value: (r) => r.implementation, }, { header: 'Mean (ms)', - key: 'mean', - format: (v) => fmt(v), + get_value: (r) => fmt(ns_to_ms(r.stats.core.mean_ns)), }, { header: 'Median (ms)', - key: 'median', - format: (v) => fmt(v), + get_value: (r) => fmt(ns_to_ms(r.stats.core.median_ns)), }, { header: 'Std Dev', - key: 'std_dev', - format: (v) => fmt(v), + get_value: (r) => fmt(ns_to_ms(r.stats.core.std_dev_ns)), }, { header: 'CV', - key: 'cv', - format: (v) => `${fmt(v * 100, 1)}%`, - class: (v) => (v > 0.15 ? 'warning' : ''), + get_value: (r) => `${fmt(r.stats.core.cv * 100, 1)}%`, + get_class: (r) => (r.stats.core.cv > 0.15 ? 'warning' : ''), + }, + { + header: 'P75 (ms)', + get_value: (r) => fmt(ns_to_ms(r.stats.core.p75_ns)), + }, + { + header: 'P90 (ms)', + get_value: (r) => fmt(ns_to_ms(r.stats.core.p90_ns)), }, { header: 'P95 (ms)', - key: 'p95', - format: (v) => fmt(v), + get_value: (r) => fmt(ns_to_ms(r.stats.core.p95_ns)), + }, + { + header: 'P99 (ms)', + get_value: (r) => fmt(ns_to_ms(r.stats.core.p99_ns)), }, { header: 'Ops/sec', - key: 'ops_per_second', - format: (v) => fmt(v, 0), + get_value: (r) => fmt(r.stats.core.ops_per_second, 0), }, { header: 'Outliers', - key: 'outliers', - format: (v, result) => `${v}/${result.raw_sample_size}`, - class: (_v, result) => (result.outlier_ratio > 0.1 ? 'warning' : ''), + get_value: (r) => `${r.stats.core.outliers_ns.length}/${r.stats.core.raw_sample_size}`, + get_class: (r) => (r.stats.core.outlier_ratio > 0.1 ? 'warning' : ''), }, { header: 'Failed', - key: 'failed_iterations', - format: (v) => v.toString(), - class: (v) => (v > 0 ? 'warning' : ''), + get_value: (r) => r.stats.core.failed_iterations.toString(), + get_class: (r) => (r.stats.core.failed_iterations > 0 ? 'warning' : ''), }, { header: 'Stability', - key: 'stability_ratio', - format: (v) => `${fmt(v * 100, 0)}%`, - class: (v) => (v > 0.9 ? 'good' : ''), + get_value: (r) => `${fmt(r.stats.stability_ratio * 100, 0)}%`, + get_class: (r) => (r.stats.stability_ratio > 0.9 ? 'good' : ''), }, ]; /** - * Convert benchmark results to a markdown table + * Convert benchmark results to a markdown table. */ export const results_to_markdown = (results: Array): string => { if (results.length === 0) return ''; @@ -86,7 +98,7 @@ export const results_to_markdown = (results: Array): string => // Add rows for (const result of results) { - const row = RESULT_COLUMNS.map((col) => col.format(result[col.key], result)); + const row = RESULT_COLUMNS.map((col) => col.get_value(result)); markdown += '| ' + row.join(' | ') + ' |\n'; } diff --git a/src/routes/benchmark/benchmark_runner.ts b/src/routes/benchmark/benchmark_runner.ts index 4030be85..1e840b1e 100644 --- a/src/routes/benchmark/benchmark_runner.ts +++ b/src/routes/benchmark/benchmark_runner.ts @@ -1,3 +1,5 @@ +import {TIME_NS_PER_MS} from '@fuzdev/fuz_util/time.js'; + import type { BenchmarkedImplementation, MeasurementData, @@ -59,7 +61,7 @@ export const measurement_phase = async ( on_progress?: () => void, should_stop?: () => boolean, ): Promise => { - const times: Array = []; + const times_ms: Array = []; const stability_checks = []; const timestamps = []; @@ -97,22 +99,22 @@ export const measurement_phase = async ( // Validate the timing if (elapsed <= 0) { console.warn(`[Measurement] Suspicious timing (${elapsed}ms) - marking as failed`); - times.push(NaN); + times_ms.push(NaN); timestamps.push(Date.now()); } else if (elapsed < MIN_VALID_TIMING_MS) { console.warn( `[Measurement] Suspiciously fast timing (${elapsed}ms) - possible no-op render`, ); - times.push(elapsed); + times_ms.push(elapsed); timestamps.push(Date.now()); recent_timings.push(elapsed); } else if (elapsed > MAX_VALID_TIMING_MS) { console.warn(`[Measurement] Extremely slow timing (${elapsed}ms) - possible hang`); - times.push(NaN); + times_ms.push(NaN); timestamps.push(Date.now()); } else { console.log(`[Measurement] Iteration ${i + 1} complete: ${elapsed.toFixed(2)}ms`); - times.push(elapsed); + times_ms.push(elapsed); timestamps.push(Date.now()); recent_timings.push(elapsed); } @@ -120,7 +122,7 @@ export const measurement_phase = async ( console.error(`[Measurement] Iteration ${i + 1} failed:`, error); // Continue with next iteration instead of failing entire test // Record a null/NaN to indicate failure - times.push(NaN); + times_ms.push(NaN); timestamps.push(Date.now()); } @@ -133,7 +135,7 @@ export const measurement_phase = async ( } } - return {times, stability_checks, timestamps}; + return {times_ms, stability_checks, timestamps}; }; // Run complete benchmark suite @@ -211,27 +213,28 @@ export const run_all_benchmarks = async ( // Analysis const stats = analyze_results(measurement_data); + const mean_ms = stats.core.mean_ns / TIME_NS_PER_MS; console.log( - `[Runner] ${test_name} complete - mean: ${stats.mean.toFixed(2)}ms, ops/sec: ${stats.ops_per_second.toFixed(2)}`, + `[Runner] ${test_name} complete - mean: ${mean_ms.toFixed(2)}ms, ops/sec: ${stats.core.ops_per_second.toFixed(2)}`, ); // Check for suspicious results - if (stats.failed_iterations > 0) { - warnings.push(`${test_name}: ${stats.failed_iterations} failed iterations`); + if (stats.core.failed_iterations > 0) { + warnings.push(`${test_name}: ${stats.core.failed_iterations} failed iterations`); } - if (stats.mean < SUSPICIOUS_MEAN_MS) { - warnings.push(`${test_name}: Suspiciously fast mean time (${stats.mean.toFixed(3)}ms)`); + if (mean_ms < SUSPICIOUS_MEAN_MS) { + warnings.push(`${test_name}: Suspiciously fast mean time (${mean_ms.toFixed(3)}ms)`); } - if (stats.outlier_ratio > HIGH_OUTLIER_RATIO) { + if (stats.core.outlier_ratio > HIGH_OUTLIER_RATIO) { warnings.push( - `${test_name}: High outlier ratio (${(stats.outlier_ratio * 100).toFixed(1)}%)`, + `${test_name}: High outlier ratio (${(stats.core.outlier_ratio * 100).toFixed(1)}%)`, ); } results.push({ implementation: impl.name, language: lang, - ...stats, + stats, }); if (callbacks?.on_test_complete) { diff --git a/src/routes/benchmark/benchmark_stats.ts b/src/routes/benchmark/benchmark_stats.ts index b4b8af67..750b5bd8 100644 --- a/src/routes/benchmark/benchmark_stats.ts +++ b/src/routes/benchmark/benchmark_stats.ts @@ -1,221 +1,44 @@ -// Statistical analysis functions for benchmark results +/** + * Statistical analysis functions for browser benchmark results. + * Uses fuz_util's BenchmarkStats for core statistics, adding browser-specific stability tracking. + */ + +import {BenchmarkStats} from '@fuzdev/fuz_util/benchmark_stats.js'; +import {TIME_NS_PER_MS} from '@fuzdev/fuz_util/time.js'; import type { BenchmarkResult, - BenchmarkStats, + BrowserBenchmarkStats, MeasurementData, SummaryStats, } from './benchmark_types.js'; -// Statistical constants -const QUARTILE_Q1 = 0.25; -const QUARTILE_Q3 = 0.75; -const IQR_MULTIPLIER = 1.5; -const MAD_Z_SCORE_THRESHOLD = 3.5; -const MAD_Z_SCORE_EXTREME = 5.0; -const MAD_CONSTANT = 0.6745; // For normal distribution approximation -const OUTLIER_RATIO_HIGH = 0.3; -const OUTLIER_RATIO_EXTREME = 0.4; -const OUTLIER_KEEP_RATIO = 0.8; -const PERCENTILE_95 = 0.95; -const PERCENTILE_99 = 0.99; -const CONFIDENCE_INTERVAL_Z = 1.96; -const MS_PER_SECOND = 1000; -const MIN_SAMPLE_SIZE = 3; - -// Calculate median -const calculate_median = (sorted_array: Array): number => { - const mid = Math.floor(sorted_array.length / 2); - return sorted_array.length % 2 === 0 - ? (sorted_array[mid - 1]! + sorted_array[mid]!) / 2 - : sorted_array[mid]!; -}; - -// Outlier detection using MAD (Median Absolute Deviation) method -export const detect_outliers = ( - times: Array, -): { - cleaned_times: Array; - outliers: Array; -} => { - if (times.length < MIN_SAMPLE_SIZE) { - return {cleaned_times: times, outliers: []}; - } - - const sorted = [...times].sort((a, b) => a - b); - const median = calculate_median(sorted); - - // Calculate MAD (Median Absolute Deviation) - const deviations = times.map((t) => Math.abs(t - median)); - const sorted_deviations = [...deviations].sort((a, b) => a - b); - const mad = calculate_median(sorted_deviations); - - if (mad === 0) { - const q1 = sorted[Math.floor(sorted.length * QUARTILE_Q1)]!; - const q3 = sorted[Math.floor(sorted.length * QUARTILE_Q3)]!; - const iqr = q3 - q1; - - if (iqr === 0) { - return {cleaned_times: times, outliers: []}; - } - - const lower_bound = q1 - IQR_MULTIPLIER * iqr; - const upper_bound = q3 + IQR_MULTIPLIER * iqr; - - const cleaned_times: Array = []; - const outliers: Array = []; - - for (const time of times) { - if (time < lower_bound || time > upper_bound) { - outliers.push(time); - } else { - cleaned_times.push(time); - } - } - - return {cleaned_times, outliers}; - } - - // Use modified Z-score with MAD - const cleaned_times: Array = []; - const outliers: Array = []; - - for (const time of times) { - const modified_z_score = (MAD_CONSTANT * (time - median)) / mad; - if (Math.abs(modified_z_score) > MAD_Z_SCORE_THRESHOLD) { - outliers.push(time); - } else { - cleaned_times.push(time); - } - } - - // If too many outliers, increase threshold and try again - if (outliers.length > times.length * OUTLIER_RATIO_HIGH) { - cleaned_times.length = 0; - outliers.length = 0; - - for (const time of times) { - const modified_z_score = (MAD_CONSTANT * (time - median)) / mad; - if (Math.abs(modified_z_score) > MAD_Z_SCORE_EXTREME) { - outliers.push(time); - } else { - cleaned_times.push(time); - } - } - - if (outliers.length > times.length * OUTLIER_RATIO_EXTREME) { - // Sort by distance from median and keep closest values - const with_distances = times.map((t) => ({ - time: t, - distance: Math.abs(t - median), - })); - with_distances.sort((a, b) => a.distance - b.distance); - - const keep_count = Math.floor(times.length * OUTLIER_KEEP_RATIO); - cleaned_times.length = 0; - outliers.length = 0; - - for (let i = 0; i < with_distances.length; i++) { - if (i < keep_count) { - cleaned_times.push(with_distances[i]!.time); - } else { - outliers.push(with_distances[i]!.time); - } - } - } - } - - return {cleaned_times, outliers}; -}; - -// Statistical analysis -export const analyze_results = (data: MeasurementData): BenchmarkStats => { - // Filter out invalid values (failed iterations) - const valid_times: Array = []; - let failed_count = 0; - - for (const t of data.times) { - if (!isNaN(t) && isFinite(t) && t > 0) { - valid_times.push(t); - } else { - failed_count++; - } - } - - // If no valid times, return empty stats - if (valid_times.length === 0) { - return { - mean: NaN, - median: NaN, - std_dev: NaN, - min: NaN, - max: NaN, - p95: NaN, - p99: NaN, - cv: NaN, - confidence_interval: [NaN, NaN], - outliers: 0, - outlier_ratio: 0, - sample_size: 0, - raw_sample_size: data.times.length, - stability_ratio: 0, - unstable_iterations: data.times.length, - ops_per_second: 0, - failed_iterations: failed_count, - }; - } - - const {cleaned_times, outliers} = detect_outliers(valid_times); - const final_sorted = [...cleaned_times].sort((a, b) => a - b); - - const mean = cleaned_times.reduce((a, b) => a + b, 0) / cleaned_times.length; - const median = calculate_median(final_sorted); +/** + * Analyze measurement data and return browser benchmark stats. + * Converts millisecond timings to nanoseconds for fuz_util's BenchmarkStats. + */ +export const analyze_results = (data: MeasurementData): BrowserBenchmarkStats => { + // Convert milliseconds to nanoseconds for BenchmarkStats + const timings_ns = data.times_ms.map((ms) => ms * TIME_NS_PER_MS); - const variance = - cleaned_times.reduce((sum, val) => sum + (val - mean) ** 2, 0) / cleaned_times.length; - const std_dev = Math.sqrt(variance); + // Create core stats using fuz_util + const core = new BenchmarkStats(timings_ns); - const min = final_sorted[0]!; - const max = final_sorted[final_sorted.length - 1]!; - const p95 = final_sorted[Math.floor(final_sorted.length * PERCENTILE_95)]!; - const p99 = final_sorted[Math.floor(final_sorted.length * PERCENTILE_99)]!; - - const cv = std_dev / mean; - - const se = std_dev / Math.sqrt(cleaned_times.length); - const ci_margin = CONFIDENCE_INTERVAL_Z * se; - const ci_lower = mean - ci_margin; - const ci_upper = mean + ci_margin; - - // Stability analysis + // Calculate browser-specific stability metrics const unstable_count = data.stability_checks.filter((s) => !s.is_stable).length; - const stability_ratio = 1 - unstable_count / data.stability_checks.length; - - // Throughput calculation (operations per second) - const ops_per_second = mean > 0 ? MS_PER_SECOND / mean : 0; + const stability_ratio = + data.stability_checks.length > 0 ? 1 - unstable_count / data.stability_checks.length : 1; return { - mean, - median, - std_dev, - min, - max, - p95, - p99, - cv, - confidence_interval: [ci_lower, ci_upper], - outliers: outliers.length, - outlier_ratio: outliers.length / valid_times.length, - sample_size: cleaned_times.length, - raw_sample_size: data.times.length, + core, stability_ratio, unstable_iterations: unstable_count, - ops_per_second, - failed_iterations: failed_count, }; }; -// Calculate summary across all tests +/** + * Calculate summary statistics across all test results. + */ export const calculate_summary = ( results: Array, ): Record => { @@ -231,13 +54,15 @@ export const calculate_summary = ( const summary: Record = {}; - // Calculate averages for each implementation + // Calculate averages for each implementation (convert ns to ms for display) for (const [impl, impl_results] of Object.entries(by_impl)) { - const mean_times = impl_results.map((r) => r.mean); - const avg_mean = mean_times.reduce((a, b) => a + b, 0) / mean_times.length; + const mean_times_ms = impl_results.map((r) => r.stats.core.mean_ns / TIME_NS_PER_MS); + const avg_mean = mean_times_ms.reduce((a, b) => a + b, 0) / mean_times_ms.length; const avg_ops = - impl_results.map((r) => r.ops_per_second).reduce((a, b) => a + b, 0) / impl_results.length; - const avg_cv = impl_results.map((r) => r.cv).reduce((a, b) => a + b, 0) / impl_results.length; + impl_results.map((r) => r.stats.core.ops_per_second).reduce((a, b) => a + b, 0) / + impl_results.length; + const avg_cv = + impl_results.map((r) => r.stats.core.cv).reduce((a, b) => a + b, 0) / impl_results.length; summary[impl] = { avg_mean, @@ -248,16 +73,21 @@ export const calculate_summary = ( } // Calculate relative performance (only if baseline exists) - const baseline_mean = summary.html!.avg_mean; - for (const impl of Object.keys(summary)) { - summary[impl]!.relative_speed = baseline_mean / summary[impl]!.avg_mean; - summary[impl]!.improvement = (summary[impl]!.relative_speed - 1) * 100; + const baseline_mean = summary.html?.avg_mean; + if (baseline_mean !== undefined) { + for (const impl of Object.keys(summary)) { + const impl_summary = summary[impl]!; + impl_summary.relative_speed = baseline_mean / impl_summary.avg_mean; + impl_summary.improvement = (impl_summary.relative_speed - 1) * 100; + } } return summary; }; -// Check for high variance +/** + * Check for high coefficient of variation in results. + */ export const check_high_variance = ( results: Array, threshold = 0.15, @@ -265,9 +95,9 @@ export const check_high_variance = ( const warnings: Array = []; for (const result of results) { - if (result.cv > threshold) { + if (result.stats.core.cv > threshold) { warnings.push( - `High variance for ${result.implementation}/${result.language}: CV=${(result.cv * 100).toFixed(1)}%`, + `High variance for ${result.implementation}/${result.language}: CV=${(result.stats.core.cv * 100).toFixed(1)}%`, ); } } @@ -275,7 +105,10 @@ export const check_high_variance = ( return warnings; }; -// Format number for display +/** + * Format number for display. + */ export const fmt = (n: number, decimals = 2): string => { + if (!isFinite(n)) return String(n); return n.toFixed(decimals); }; diff --git a/src/routes/benchmark/benchmark_types.ts b/src/routes/benchmark/benchmark_types.ts index 2c5e6a88..fb828991 100644 --- a/src/routes/benchmark/benchmark_types.ts +++ b/src/routes/benchmark/benchmark_types.ts @@ -1,4 +1,6 @@ import type {SvelteHTMLElements} from 'svelte/elements'; +import type {Component} from 'svelte'; +import type {BenchmarkStats as FuzBenchmarkStats} from '@fuzdev/fuz_util/benchmark_stats.js'; import type {ImplementationName} from './benchmark_fixtures.js'; @@ -15,8 +17,6 @@ export interface BenchmarkConfig { content_multiplier: number; } -import type {Component} from 'svelte'; - export interface BenchmarkedImplementation { name: string; component: Component; @@ -31,34 +31,31 @@ export interface StabilityCheck { } export interface MeasurementData { - times: Array; + times_ms: Array; stability_checks: Array; timestamps: Array; } -export interface BenchmarkStats { - mean: number; - median: number; - std_dev: number; - min: number; - max: number; - p95: number; - p99: number; - cv: number; - confidence_interval: [number, number]; - outliers: number; - outlier_ratio: number; - sample_size: number; - raw_sample_size: number; +/** + * Browser benchmark stats extending fuz_util's BenchmarkStats with stability tracking. + * Uses milliseconds for display (mean_ms, median_ms, etc.) while storing nanoseconds internally. + */ +export interface BrowserBenchmarkStats { + /** Core stats from fuz_util (in nanoseconds) */ + core: FuzBenchmarkStats; + /** Browser-specific: ratio of stable iterations (0-1) */ stability_ratio: number; + /** Browser-specific: count of unstable iterations */ unstable_iterations: number; - ops_per_second: number; - failed_iterations: number; } -export interface BenchmarkResult extends BenchmarkStats { +/** + * Benchmark result combining stats with test metadata. + */ +export interface BenchmarkResult { implementation: string; language: string; + stats: BrowserBenchmarkStats; } export interface SummaryStats { diff --git a/src/routes/library.ts b/src/routes/library.ts index 6e04079e..b634eff6 100644 --- a/src/routes/library.ts +++ b/src/routes/library.ts @@ -53,7 +53,7 @@ export const library_json: LibraryJson = { '@changesets/changelog-git': '^0.2.1', '@fuzdev/fuz_css': '^0.42.1', '@fuzdev/fuz_ui': '^0.172.0', - '@fuzdev/fuz_util': '^0.42.0', + '@fuzdev/fuz_util': 'file:../fuz_util', '@ryanatkn/eslint-config': '^0.9.0', '@ryanatkn/gro': '^0.181.0', '@sveltejs/adapter-static': '^3.0.10', @@ -68,7 +68,6 @@ export const library_json: LibraryJson = { 'prettier-plugin-svelte': '^3.4.0', svelte: '^5.45.6', 'svelte-check': '^4.3.4', - tinybench: '^6.0.0', tslib: '^2.8.1', typescript: '^5.9.3', 'typescript-eslint': '^8.48.1', @@ -862,47 +861,6 @@ export const library_json: LibraryJson = { }, ], }, - { - name: 'normalize_pattern', - kind: 'function', - modifiers: ['private'], - doc_comment: - 'Normalize a single pattern to have consistent shape.\nThis ensures all patterns have the same object shape for V8 optimization.', - type_signature: - '(pattern: RegExp | SyntaxGrammarTokenRaw, visited: Set): SyntaxGrammarToken', - return_type: 'SyntaxGrammarToken', - parameters: [ - { - name: 'pattern', - type: 'RegExp | SyntaxGrammarTokenRaw', - }, - { - name: 'visited', - type: 'Set', - }, - ], - }, - { - name: 'normalize_grammar', - kind: 'function', - modifiers: ['private'], - doc_comment: - 'Normalize a grammar to have consistent object shapes.\nThis performs several optimizations:\n1. Merges `rest` property into main grammar\n2. Ensures all pattern values are arrays\n3. Normalizes all pattern objects to have consistent shapes\n4. Adds global flag to greedy patterns\n\nThis is called once at registration time to avoid runtime overhead.', - type_signature: '(grammar: SyntaxGrammarRaw, visited: Set): void', - return_type: 'void', - parameters: [ - { - name: 'grammar', - type: 'SyntaxGrammarRaw', - }, - { - name: 'visited', - type: 'Set', - description: - '- Set of grammar object IDs already normalized (for circular references)', - }, - ], - }, { name: 'plugins', kind: 'variable', From 3735e4634df0290dcfa1e1b581325505857f8b31 Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Tue, 9 Dec 2025 21:54:22 -0500 Subject: [PATCH 02/10] wip --- benchmark/compare/compare.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/benchmark/compare/compare.ts b/benchmark/compare/compare.ts index 029eb355..c5435473 100644 --- a/benchmark/compare/compare.ts +++ b/benchmark/compare/compare.ts @@ -31,9 +31,9 @@ import {tokenize_syntax} from '../../src/lib/syntax_styler.js'; /* eslint-disable no-console */ -const BENCHMARK_TIME = 10000; // 10000 -const WARMUP_ITERATIONS = 20; // 20 -const LARGE_CONTENT_MULTIPLIER = 100; // 100 +const BENCHMARK_TIME = 10000; +const WARMUP_ITERATIONS = 20; +const LARGE_CONTENT_MULTIPLIER = 100; const MIN_ITERATIONS = 3; // Tiny minimum samples cause of Shiki's pathological cases with TS export interface ComparisonResult { From 946cbb5089f041e6e01298f072bfc421d032e3ab Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Wed, 10 Dec 2025 09:40:07 -0500 Subject: [PATCH 03/10] wip --- CLAUDE.md | 4 ++-- benchmark/compare/compare.ts | 35 ++++++++++++++-------------- benchmark/results.md | 44 +++++++++++------------------------- package.json | 4 ++-- src/routes/library.ts | 4 ++-- 5 files changed, 37 insertions(+), 54 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 60cfa5fe..82afa1ba 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,7 +13,7 @@ gro test # run all tests gro test src/test/fixtures/check # verify fixture generation gro src/test/fixtures/update # regenerate fixtures npm run benchmark # run performance benchmarks -npm run benchmark-compare # compare performance with Prism and Shiki +npm run benchmark:compare # compare performance with Prism and Shiki ``` ## Architecture @@ -183,7 +183,7 @@ and is not widely supported across browsers. Use the standard `Code.svelte` comp ```bash npm run benchmark # internal performance benchmark -npm run benchmark-compare # compare with Prism and Shiki +npm run benchmark:compare # compare with Prism and Shiki ``` **Internal benchmark** tests fuz_code performance across all sample files with small and large (100x) content. diff --git a/benchmark/compare/compare.ts b/benchmark/compare/compare.ts index c5435473..0b18f625 100644 --- a/benchmark/compare/compare.ts +++ b/benchmark/compare/compare.ts @@ -27,14 +27,14 @@ import nord from 'shiki/themes/nord.mjs'; // Fuz Code imports import {samples as all_samples} from '../../src/test/fixtures/samples/all.js'; import {syntax_styler_global} from '../../src/lib/syntax_styler_global.js'; -import {tokenize_syntax} from '../../src/lib/syntax_styler.js'; +import {tokenize_syntax} from '../../src/lib/tokenize_syntax.js'; /* eslint-disable no-console */ const BENCHMARK_TIME = 10000; const WARMUP_ITERATIONS = 20; const LARGE_CONTENT_MULTIPLIER = 100; -const MIN_ITERATIONS = 3; // Tiny minimum samples cause of Shiki's pathological cases with TS +const MIN_ITERATIONS = 3; // Tiny minimum samples because of Shiki's pathological cases with TS export interface ComparisonResult { implementation: string; @@ -112,9 +112,9 @@ export const run_comparison_benchmark = async ( filter?: string, ): Promise> => { const bench = new Benchmark({ - time_ms: BENCHMARK_TIME, + duration_ms: BENCHMARK_TIME, warmup_iterations: WARMUP_ITERATIONS, - iterations: MIN_ITERATIONS, + min_iterations: MIN_ITERATIONS, }); // Setup Shiki @@ -186,59 +186,60 @@ export const run_comparison_benchmark = async ( // Process results const results: Array = []; + const bench_results = bench.results(); - for (const task of bench.tasks) { + for (const result of bench_results) { // Parse benchmark name: implementation_operation_language_size // Handle multi-word implementations like 'fuz_code' and 'shiki_js' - const parts = task.name.split('_'); + const parts = result.name.split('_'); let implementation: string; let operation: 'tokenize' | 'stylize'; let language: string; let content_size: 'small' | 'large'; - if (task.name.startsWith('fuz_code_tokenize_')) { + if (result.name.startsWith('fuz_code_tokenize_')) { implementation = 'fuz_code'; operation = 'tokenize'; language = parts[3]; content_size = parts[4] as 'small' | 'large'; - } else if (task.name.startsWith('fuz_code_stylize_')) { + } else if (result.name.startsWith('fuz_code_stylize_')) { implementation = 'fuz_code'; operation = 'stylize'; language = parts[3]; content_size = parts[4] as 'small' | 'large'; - } else if (task.name.startsWith('prism_tokenize_')) { + } else if (result.name.startsWith('prism_tokenize_')) { implementation = 'prism'; operation = 'tokenize'; language = parts[2]; content_size = parts[3] as 'small' | 'large'; - } else if (task.name.startsWith('prism_stylize_')) { + } else if (result.name.startsWith('prism_stylize_')) { implementation = 'prism'; operation = 'stylize'; language = parts[2]; content_size = parts[3] as 'small' | 'large'; - } else if (task.name.startsWith('shiki_js_stylize_')) { + } else if (result.name.startsWith('shiki_js_stylize_')) { implementation = 'shiki_js'; operation = 'stylize'; language = parts[3]; content_size = parts[4] as 'small' | 'large'; - } else if (task.name.startsWith('shiki_oniguruma_stylize_')) { + } else if (result.name.startsWith('shiki_oniguruma_stylize_')) { implementation = 'shiki_oniguruma'; operation = 'stylize'; language = parts[3]; content_size = parts[4] as 'small' | 'large'; } else { - console.warn(`Unknown benchmark name format: ${task.name}`); + console.warn(`Unknown benchmark name format: ${result.name}`); continue; } results.push({ implementation, language, - ops_per_sec: task.ops_per_sec, - mean_time: task.mean_time_ms, - samples: task.samples, + ops_per_sec: result.stats.ops_per_second, + mean_time: result.stats.mean_ns / 1_000_000, // Convert ns to ms + samples: result.stats.sample_size, content_size, - total_time: task.total_time_ms, + total_time: result.total_time_ms, operation, }); } diff --git a/benchmark/results.md b/benchmark/results.md index 741676fd..4569f2b4 100644 --- a/benchmark/results.md +++ b/benchmark/results.md @@ -4,39 +4,21 @@ | Sample | Ops/sec | Mean Time (ms) | Samples | |--------|---------|----------------|---------| -| json_complex | 28746.87 | 0.0373 | 268006 | -| css_complex | 27154.80 | 0.0389 | 257068 | -| ts_complex | 1811.93 | 0.5629 | 17765 | -| html_complex | 7624.85 | 0.1344 | 74425 | -| svelte_complex | 2191.20 | 0.4660 | 21462 | -| md_complex | 1919.49 | 0.5377 | 18599 | -| large:json_complex | 251.14 | 4.0689 | 2458 | -| large:css_complex | 233.08 | 4.3726 | 2287 | -| large:ts_complex | 7.27 | 140.2721 | 72 | -| large:html_complex | 48.17 | 21.6499 | 463 | -| large:svelte_complex | 11.89 | 87.4511 | 115 | -| large:md_complex | 6.47 | 156.3995 | 64 | +| json_complex | 29102.94 | 0.0344 | 97284 | +| css_complex | 27087.28 | 0.0369 | 93104 | +| ts_complex | 1857.77 | 0.5383 | 13182 | +| html_complex | 7668.00 | 0.1304 | 72407 | +| svelte_complex | 2122.21 | 0.4712 | 18851 | +| md_complex | 1922.18 | 0.5202 | 18668 | +| large:json_complex | 255.52 | 3.9135 | 2098 | +| large:css_complex | 251.29 | 3.9794 | 2183 | +| large:ts_complex | 7.39 | 135.2742 | 75 | +| large:html_complex | 56.35 | 17.7476 | 501 | +| large:svelte_complex | 11.04 | 90.6188 | 111 | +| large:md_complex | 7.23 | 138.3028 | 73 | **Total samples benchmarked:** 12 -**Average ops/sec:** 5833.93 - -| Sample | Ops/sec | Mean Time (ms) | Samples | -|--------|---------|----------------|---------| -| json_complex | 28865.33 | 0.0359 | 278880 | -| css_complex | 27777.36 | 0.0368 | 272048 | -| ts_complex | 1900.84 | 0.5299 | 18873 | -| html_complex | 8204.91 | 0.1253 | 79783 | -| svelte_complex | 2202.40 | 0.4673 | 21398 | -| md_complex | 1858.77 | 0.5663 | 17658 | -| large:json_complex | 243.87 | 4.2579 | 2349 | -| large:css_complex | 247.65 | 4.1402 | 2417 | -| large:ts_complex | 5.73 | 179.6819 | 64 | -| large:html_complex | 56.14 | 18.5677 | 539 | -| large:svelte_complex | 13.36 | 76.3735 | 131 | -| large:md_complex | 7.64 | 132.1847 | 76 | - -**Total samples benchmarked:** 12 -**Average ops/sec:** 5948.67 +**Average ops/sec:** 5862.43 ## Browser Benchmark Results diff --git a/package.json b/package.json index a29d6c5a..ed25a737 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,8 @@ "preview": "vite preview", "deploy": "gro deploy", "benchmark": "gro run benchmark/run_benchmarks.ts", - "benchmark-compare": "gro run benchmark/compare/run_compare.ts", - "update-generated-fixtures": "gro src/test/fixtures/update" + "benchmark:compare": "gro run benchmark/compare/run_compare.ts", + "fixtures:update": "gro src/test/fixtures/update" }, "type": "module", "engines": { diff --git a/src/routes/library.ts b/src/routes/library.ts index b634eff6..a7e91a65 100644 --- a/src/routes/library.ts +++ b/src/routes/library.ts @@ -30,8 +30,8 @@ export const library_json: LibraryJson = { preview: 'vite preview', deploy: 'gro deploy', benchmark: 'gro run benchmark/run_benchmarks.ts', - 'benchmark-compare': 'gro run benchmark/compare/run_compare.ts', - 'update-generated-fixtures': 'gro src/test/fixtures/update', + 'benchmark:compare': 'gro run benchmark/compare/run_compare.ts', + 'fixtures:update': 'gro src/test/fixtures/update', }, type: 'module', engines: { From e24cecc0c34fa11bbd938fbedec4c0699301bafc Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Wed, 10 Dec 2025 09:45:25 -0500 Subject: [PATCH 04/10] wip --- benchmark/benchmarks.ts | 2 +- benchmark/compare/compare.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmark/benchmarks.ts b/benchmark/benchmarks.ts index ff9b3e85..6f5a083b 100644 --- a/benchmark/benchmarks.ts +++ b/benchmark/benchmarks.ts @@ -13,7 +13,7 @@ export interface BenchmarkResult { name: string; ops_per_sec: number; mean_time: number; - samples: number | undefined; + samples: number; } export const run_benchmark = async (filter?: string): Promise> => { diff --git a/benchmark/compare/compare.ts b/benchmark/compare/compare.ts index 0b18f625..97a824a6 100644 --- a/benchmark/compare/compare.ts +++ b/benchmark/compare/compare.ts @@ -1,4 +1,4 @@ -// TODO this is a workaround for eslint failng without `"benchmark/**/*.ts"` in tsconfig.json +// TODO this is a workaround for eslint failing without `"benchmark/**/*.ts"` in tsconfig.json // This allows CI to pass without running `npm install` for the benchmarks. // @ts-nocheck From 6403ddb7df0fc9fa9a7be8cb409582933822f3da Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Wed, 10 Dec 2025 16:47:27 -0500 Subject: [PATCH 05/10] wip --- package-lock.json | 86 +++++++++++++++-------------------------------- package.json | 2 +- 2 files changed, 29 insertions(+), 59 deletions(-) diff --git a/package-lock.json b/package-lock.json index 20a37809..1d39470d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@changesets/changelog-git": "^0.2.1", "@fuzdev/fuz_css": "^0.42.1", "@fuzdev/fuz_ui": "^0.172.0", - "@fuzdev/fuz_util": "file:../fuz_util", + "@fuzdev/fuz_util": "^0.43.0", "@ryanatkn/eslint-config": "^0.9.0", "@ryanatkn/gro": "^0.181.0", "@sveltejs/adapter-static": "^3.0.10", @@ -51,61 +51,6 @@ } } }, - "../fuz_util": { - "name": "@fuzdev/fuz_util", - "version": "0.42.0", - "dev": true, - "license": "MIT", - "devDependencies": { - "@changesets/changelog-git": "^0.2.1", - "@fuzdev/fuz_code": "^0.38.0", - "@fuzdev/fuz_css": "^0.42.1", - "@fuzdev/fuz_ui": "^0.172.0", - "@ryanatkn/eslint-config": "^0.9.0", - "@ryanatkn/gro": "^0.181.0", - "@sveltejs/adapter-static": "^3.0.10", - "@sveltejs/kit": "^2.49.1", - "@sveltejs/package": "^2.5.7", - "@sveltejs/vite-plugin-svelte": "^6.2.1", - "@types/node": "^24.10.1", - "dequal": "^2.0.3", - "eslint": "^9.39.1", - "eslint-plugin-svelte": "^3.13.1", - "esm-env": "^1.2.2", - "fast-deep-equal": "^3.1.3", - "prettier": "^3.7.4", - "prettier-plugin-svelte": "^3.4.0", - "svelte": "^5.45.6", - "svelte-check": "^4.3.4", - "tslib": "^2.8.1", - "typescript": "^5.9.3", - "typescript-eslint": "^8.48.1", - "vitest": "^4.0.15", - "zod": "^4.1.13" - }, - "engines": { - "node": ">=22.15" - }, - "funding": { - "url": "https://www.ryanatkn.com/funding" - }, - "peerDependencies": { - "@types/node": "^24", - "esm-env": "^1.2.2", - "zod": "^4.0.14" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "esm-env": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, "node_modules/@changesets/changelog-git": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.2.1.tgz", @@ -839,8 +784,33 @@ } }, "node_modules/@fuzdev/fuz_util": { - "resolved": "../fuz_util", - "link": true + "version": "0.43.0", + "resolved": "https://registry.npmjs.org/@fuzdev/fuz_util/-/fuz_util-0.43.0.tgz", + "integrity": "sha512-sEtQCC0ag8uS+cYvxi8QsJyL53dIpTLVRmr8GbHgjFvLmqnGD36PYvIniiIgDWwfqOPYNm3bQ2RnXplfE0DGLg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.15" + }, + "funding": { + "url": "https://www.ryanatkn.com/funding" + }, + "peerDependencies": { + "@types/node": "^24", + "esm-env": "^1.2.2", + "zod": "^4.0.14" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "esm-env": { + "optional": true + }, + "zod": { + "optional": true + } + } }, "node_modules/@humanfs/core": { "version": "0.19.1", diff --git a/package.json b/package.json index ed25a737..9f6d3fce 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "@changesets/changelog-git": "^0.2.1", "@fuzdev/fuz_css": "^0.42.1", "@fuzdev/fuz_ui": "^0.172.0", - "@fuzdev/fuz_util": "file:../fuz_util", + "@fuzdev/fuz_util": "^0.43.0", "@ryanatkn/eslint-config": "^0.9.0", "@ryanatkn/gro": "^0.181.0", "@sveltejs/adapter-static": "^3.0.10", From 92de0d29c580810f39e27cc6b0123347800de0fb Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Wed, 10 Dec 2025 16:47:33 -0500 Subject: [PATCH 06/10] wip --- src/routes/library.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/library.ts b/src/routes/library.ts index a7e91a65..9c9db53b 100644 --- a/src/routes/library.ts +++ b/src/routes/library.ts @@ -53,7 +53,7 @@ export const library_json: LibraryJson = { '@changesets/changelog-git': '^0.2.1', '@fuzdev/fuz_css': '^0.42.1', '@fuzdev/fuz_ui': '^0.172.0', - '@fuzdev/fuz_util': 'file:../fuz_util', + '@fuzdev/fuz_util': '^0.43.0', '@ryanatkn/eslint-config': '^0.9.0', '@ryanatkn/gro': '^0.181.0', '@sveltejs/adapter-static': '^3.0.10', From 5b2edb6ff1755dda1eba69548b512203ab01295e Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Wed, 10 Dec 2025 17:06:39 -0500 Subject: [PATCH 07/10] wip --- benchmark/compare/results.md | 120 +++++++++++++++++------------------ 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/benchmark/compare/results.md b/benchmark/compare/results.md index 5a08c7d3..812c7844 100644 --- a/benchmark/compare/results.md +++ b/benchmark/compare/results.md @@ -4,63 +4,63 @@ | Language+Operation+Size | Implementation | % | Ops/sec | Mean Time (ms) | | ----------------------- | --------------- | ---- | -------- | -------------- | -| css tokenize small | fuz_code | 100% | 58435.54 | 0.0174 | -| css tokenize small | prism | 95% | 55478.47 | 0.0183 | -| css tokenize large | fuz_code | 100% | 572.29 | 1.7902 | -| css tokenize large | prism | 96% | 549.77 | 1.8614 | -| css stylize small | fuz_code | 100% | 25824.88 | 0.0393 | -| css stylize small | prism | 93% | 24059.34 | 0.0421 | -| css stylize small | shiki_js | 5% | 1359.65 | 0.7490 | -| css stylize small | shiki_oniguruma | 2% | 632.21 | 1.5908 | -| css stylize large | fuz_code | 100% | 225.48 | 4.4705 | -| css stylize large | prism | 85% | 192.03 | 5.3467 | -| css stylize large | shiki_js | 6% | 13.09 | 76.5671 | -| css stylize large | shiki_oniguruma | 3% | 6.20 | 161.4719 | -| html tokenize small | prism | 100% | 28071.50 | 0.0362 | -| html tokenize small | fuz_code | 80% | 22353.53 | 0.0454 | -| html tokenize large | prism | 100% | 261.66 | 3.8329 | -| html tokenize large | fuz_code | 67% | 175.24 | 5.7740 | -| html stylize small | prism | 100% | 13185.90 | 0.0772 | -| html stylize small | fuz_code | 92% | 12163.60 | 0.0837 | -| html stylize small | shiki_oniguruma | 6% | 794.71 | 1.2666 | -| html stylize small | shiki_js | 6% | 774.19 | 1.3020 | -| html stylize large | prism | 100% | 83.83 | 12.3378 | -| html stylize large | fuz_code | 94% | 79.04 | 12.8017 | -| html stylize large | shiki_oniguruma | 9% | 7.83 | 127.7735 | -| html stylize large | shiki_js | 9% | 7.82 | 127.9444 | -| json tokenize small | prism | 100% | 73749.21 | 0.0138 | -| json tokenize small | fuz_code | 99% | 73235.11 | 0.0140 | -| json tokenize large | prism | 100% | 694.84 | 1.5010 | -| json tokenize large | fuz_code | 99% | 686.16 | 1.5154 | -| json stylize small | fuz_code | 100% | 28875.11 | 0.0354 | -| json stylize small | prism | 92% | 26525.47 | 0.0384 | -| json stylize small | shiki_js | 7% | 1957.01 | 0.5252 | -| json stylize small | shiki_oniguruma | 6% | 1731.06 | 0.5960 | -| json stylize large | fuz_code | 100% | 239.85 | 4.2362 | -| json stylize large | prism | 87% | 207.78 | 5.0337 | -| json stylize large | shiki_js | 8% | 18.99 | 52.7780 | -| json stylize large | shiki_oniguruma | 7% | 17.10 | 58.6602 | -| svelte tokenize small | fuz_code | 100% | 3976.35 | 0.2547 | -| svelte tokenize small | prism | 90% | 3565.41 | 0.2832 | -| svelte tokenize large | fuz_code | 100% | 34.76 | 28.9565 | -| svelte tokenize large | prism | 87% | 30.35 | 33.1966 | -| svelte stylize small | fuz_code | 100% | 2360.10 | 0.4321 | -| svelte stylize small | prism | 86% | 2021.82 | 0.5108 | -| svelte stylize small | shiki_oniguruma | 3% | 61.53 | 16.3099 | -| svelte stylize small | shiki_js | 2% | 50.00 | 20.0518 | -| svelte stylize large | fuz_code | 100% | 13.09 | 76.8902 | -| svelte stylize large | prism | 84% | 11.03 | 91.0119 | -| svelte stylize large | shiki_oniguruma | 5% | 0.63 | 1585.1294 | -| svelte stylize large | shiki_js | 4% | 0.52 | 1916.0590 | -| ts tokenize small | fuz_code | 100% | 8619.08 | 0.1165 | -| ts tokenize small | prism | 90% | 7757.57 | 0.1293 | -| ts tokenize large | fuz_code | 100% | 54.49 | 18.3994 | -| ts tokenize large | prism | 94% | 51.31 | 19.5324 | -| ts stylize small | fuz_code | 100% | 5516.74 | 0.1822 | -| ts stylize small | prism | 88% | 4829.14 | 0.2086 | -| ts stylize small | shiki_oniguruma | 4% | 201.12 | 4.9793 | -| ts stylize small | shiki_js | 3% | 138.64 | 7.2199 | -| ts stylize large | fuz_code | 100% | 33.44 | 30.3301 | -| ts stylize large | prism | 70% | 23.29 | 43.0380 | -| ts stylize large | shiki_oniguruma | 6% | 1.98 | 505.1610 | -| ts stylize large | shiki_js | 4% | 1.37 | 732.2407 | +| css tokenize small | fuz_code | 100% | 63906.00 | 0.0156 | +| css tokenize small | prism | 96% | 61375.19 | 0.0163 | +| css tokenize large | fuz_code | 100% | 625.05 | 1.5999 | +| css tokenize large | prism | 94% | 585.31 | 1.7085 | +| css stylize small | fuz_code | 100% | 27674.88 | 0.0361 | +| css stylize small | prism | 83% | 22930.51 | 0.0436 | +| css stylize small | shiki_js | 5% | 1384.93 | 0.7221 | +| css stylize small | shiki_oniguruma | 2% | 612.31 | 1.6331 | +| css stylize large | fuz_code | 100% | 260.18 | 3.8435 | +| css stylize large | prism | 85% | 222.42 | 4.4960 | +| css stylize large | shiki_js | 6% | 14.57 | 68.6312 | +| css stylize large | shiki_oniguruma | 2% | 5.88 | 169.9533 | +| html tokenize small | prism | 100% | 20538.77 | 0.0487 | +| html tokenize small | fuz_code | 71% | 14635.80 | 0.0683 | +| html tokenize large | prism | 100% | 196.47 | 5.0899 | +| html tokenize large | fuz_code | 69% | 135.55 | 7.3775 | +| html stylize small | prism | 100% | 8268.82 | 0.1209 | +| html stylize small | fuz_code | 95% | 7869.23 | 0.1271 | +| html stylize small | shiki_js | 7% | 577.58 | 1.7314 | +| html stylize small | shiki_oniguruma | 6% | 518.00 | 1.9305 | +| html stylize large | prism | 100% | 69.76 | 14.3339 | +| html stylize large | fuz_code | 85% | 59.32 | 16.8586 | +| html stylize large | shiki_oniguruma | 8% | 5.67 | 176.2921 | +| html stylize large | shiki_js | 7% | 5.22 | 191.4912 | +| json tokenize small | prism | 100% | 70101.75 | 0.0143 | +| json tokenize small | fuz_code | 90% | 62894.89 | 0.0159 | +| json tokenize large | prism | 100% | 730.45 | 1.3690 | +| json tokenize large | fuz_code | 91% | 664.24 | 1.5055 | +| json stylize small | fuz_code | 100% | 28787.97 | 0.0347 | +| json stylize small | prism | 91% | 26155.46 | 0.0382 | +| json stylize small | shiki_js | 7% | 1976.23 | 0.5060 | +| json stylize small | shiki_oniguruma | 6% | 1862.09 | 0.5370 | +| json stylize large | fuz_code | 100% | 258.12 | 3.8741 | +| json stylize large | prism | 90% | 232.71 | 4.2971 | +| json stylize large | shiki_js | 8% | 19.57 | 51.0972 | +| json stylize large | shiki_oniguruma | 7% | 18.65 | 53.6175 | +| svelte tokenize small | fuz_code | 100% | 3591.71 | 0.2784 | +| svelte tokenize small | prism | 94% | 3370.56 | 0.2967 | +| svelte tokenize large | prism | 100% | 34.16 | 29.2750 | +| svelte tokenize large | fuz_code | 89% | 30.24 | 33.0691 | +| svelte stylize small | fuz_code | 100% | 2203.61 | 0.4538 | +| svelte stylize small | prism | 90% | 1993.47 | 0.5016 | +| svelte stylize small | shiki_js | 3% | 66.53 | 15.0300 | +| svelte stylize small | shiki_oniguruma | 3% | 63.37 | 15.7814 | +| svelte stylize large | prism | 100% | 12.80 | 78.1422 | +| svelte stylize large | fuz_code | 93% | 11.87 | 84.2803 | +| svelte stylize large | shiki_js | 5% | 0.66 | 1518.8657 | +| svelte stylize large | shiki_oniguruma | 5% | 0.65 | 1529.7383 | +| ts tokenize small | prism | 100% | 2893.71 | 0.3456 | +| ts tokenize small | fuz_code | 95% | 2737.42 | 0.3653 | +| ts tokenize large | prism | 100% | 19.62 | 50.9801 | +| ts tokenize large | fuz_code | 58% | 11.42 | 87.5380 | +| ts stylize small | fuz_code | 100% | 1847.38 | 0.5413 | +| ts stylize small | prism | 100% | 1838.73 | 0.5439 | +| ts stylize small | shiki_oniguruma | 4% | 80.20 | 12.4684 | +| ts stylize small | shiki_js | 3% | 62.61 | 15.9710 | +| ts stylize large | prism | 100% | 10.57 | 94.6383 | +| ts stylize large | fuz_code | 69% | 7.32 | 136.6118 | +| ts stylize large | shiki_oniguruma | 8% | 0.86 | 1164.1949 | +| ts stylize large | shiki_js | 5% | 0.48 | 2072.6083 | From 45c806c67e74a0cd4b8f466c847bff4325f25c5d Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Wed, 10 Dec 2025 17:20:09 -0500 Subject: [PATCH 08/10] wip --- benchmark/results.md | 71 +++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 24 deletions(-) diff --git a/benchmark/results.md b/benchmark/results.md index 4569f2b4..61b3162c 100644 --- a/benchmark/results.md +++ b/benchmark/results.md @@ -4,33 +4,56 @@ | Sample | Ops/sec | Mean Time (ms) | Samples | |--------|---------|----------------|---------| -| json_complex | 29102.94 | 0.0344 | 97284 | -| css_complex | 27087.28 | 0.0369 | 93104 | -| ts_complex | 1857.77 | 0.5383 | 13182 | -| html_complex | 7668.00 | 0.1304 | 72407 | -| svelte_complex | 2122.21 | 0.4712 | 18851 | -| md_complex | 1922.18 | 0.5202 | 18668 | -| large:json_complex | 255.52 | 3.9135 | 2098 | -| large:css_complex | 251.29 | 3.9794 | 2183 | -| large:ts_complex | 7.39 | 135.2742 | 75 | -| large:html_complex | 56.35 | 17.7476 | 501 | -| large:svelte_complex | 11.04 | 90.6188 | 111 | -| large:md_complex | 7.23 | 138.3028 | 73 | +| json_complex | 28765.42 | 0.0348 | 95760 | +| css_complex | 27819.60 | 0.0359 | 95893 | +| ts_complex | 1765.08 | 0.5665 | 16594 | +| html_complex | 8213.21 | 0.1218 | 66817 | +| svelte_complex | 2078.65 | 0.4811 | 19675 | +| md_complex | 2074.80 | 0.4820 | 14174 | +| large:json_complex | 254.08 | 3.9358 | 2149 | +| large:css_complex | 242.57 | 4.1225 | 1688 | +| large:ts_complex | 7.34 | 136.2749 | 74 | +| large:html_complex | 56.08 | 17.8315 | 460 | +| large:svelte_complex | 11.51 | 86.8893 | 116 | +| large:md_complex | 7.59 | 131.8069 | 76 | + +**Total samples benchmarked:** 12 +**Average ops/sec:** 5941.33 + **Total samples benchmarked:** 12 **Average ops/sec:** 5862.43 ## Browser Benchmark Results -| Language | Implementation | Mean (ms) | Median (ms) | Std Dev | CV | P95 (ms) | Ops/sec | Outliers | Failed | Stability | -| -------- | -------------- | --------- | ----------- | ------- | ----- | -------- | ------- | -------- | ------ | --------- | -| ts | html | 82.39 | 80.95 | 3.98 | 4.8% | 87.60 | 12 | 0/10 | 0 | 100% | -| ts | ranges | 38.74 | 38.60 | 3.02 | 7.8% | 43.80 | 26 | 0/10 | 0 | 100% | -| css | html | 840.65 | 840.20 | 9.26 | 1.1% | 854.80 | 1 | 0/10 | 0 | 90% | -| css | ranges | 14.01 | 14.30 | 0.78 | 5.6% | 14.90 | 71 | 1/10 | 0 | 90% | -| html | html | 62.01 | 64.90 | 9.28 | 15.0% | 71.30 | 16 | 0/10 | 0 | 100% | -| html | ranges | 20.65 | 21.45 | 2.26 | 10.9% | 23.60 | 48 | 0/10 | 0 | 100% | -| json | html | 402.64 | 401.80 | 3.07 | 0.8% | 407.80 | 2 | 3/10 | 0 | 90% | -| json | ranges | 13.29 | 13.40 | 0.74 | 5.6% | 14.20 | 75 | 1/10 | 0 | 90% | -| svelte | html | 175.48 | 166.10 | 21.47 | 12.2% | 218.10 | 6 | 0/10 | 0 | 100% | -| svelte | ranges | 100.58 | 101.70 | 7.36 | 7.3% | 113.70 | 10 | 1/10 | 0 | 100% | +html +90.09ms avg time +22 ops/sec +1.4% CV + +ranges +26.17ms avg time +48 ops/sec +4.8% CV ++244.3% vs baseline + +| Language | Implementation | Mean (ms) | Median (ms) | Std Dev | CV | P75 (ms) | P90 (ms) | P95 (ms) | P99 (ms) | Ops/sec | Outliers | Failed | Stability | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| ts | html | 72.54 | 72.50 | 3.66 | 5.1% | 74.00 | 76.76 | 77.68 | 78.42 | 14 | 0/5 | 0 | 100% | +| ts | ranges | 37.82 | 37.70 | 2.15 | 5.7% | 39.70 | 40.24 | 40.42 | 40.56 | 26 | 0/5 | 0 | 100% | +| css | html | 13.73 | 13.70 | 0.05 | 0.3% | 13.75 | 13.78 | 13.79 | 13.80 | 73 | 2/5 | 0 | 100% | +| css | ranges | 13.80 | 13.80 | 0.00 | 0.0% | 13.80 | 13.80 | 13.80 | 13.80 | 72 | 2/5 | 0 | 100% | +| html | html | 112.80 | 112.60 | 0.53 | 0.5% | 112.88 | 113.37 | 113.54 | 113.67 | 9 | 1/5 | 0 | 100% | +| html | ranges | 15.48 | 15.00 | 1.43 | 9.2% | 15.90 | 17.16 | 17.58 | 17.92 | 65 | 0/5 | 0 | 100% | +| json | html | 188.20 | 188.20 | 0.49 | 0.3% | 188.50 | 188.68 | 188.74 | 188.79 | 5 | 2/5 | 0 | 100% | +| json | ranges | 13.72 | 13.75 | 0.08 | 0.6% | 13.80 | 13.80 | 13.80 | 13.80 | 73 | 1/5 | 0 | 100% | +| svelte | html | 98.42 | 97.80 | 1.66 | 1.7% | 98.87 | 100.27 | 100.73 | 101.11 | 10 | 1/5 | 0 | 100% | +| svelte | ranges | 38.94 | 39.80 | 2.28 | 5.9% | 40.80 | 41.10 | 41.20 | 41.28 | 26 | 0/5 | 0 | 100% | +| md | html | 54.86 | 55.00 | 0.45 | 0.8% | 55.10 | 55.34 | 55.42 | 55.48 | 18 | 0/5 | 0 | 100% | +| md | ranges | 37.24 | 35.90 | 2.79 | 7.5% | 39.30 | 40.68 | 41.14 | 41.51 | 27 | 0/5 | 0 | 100% | + +Legend +CV: Coefficient of Variation (std_dev/mean) - lower is better, <15% is good +P75/P90/P95/P99: Percentiles - X% of measurements were faster than this +Ops/sec: Operations per second (throughput) +Stability: Percentage of iterations with stable system metrics \ No newline at end of file From 270d8fd3d6ab66c3a5052982ef44241e77015159 Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Wed, 10 Dec 2025 17:23:28 -0500 Subject: [PATCH 09/10] wip --- benchmark/results.md | 93 +++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 52 deletions(-) diff --git a/benchmark/results.md b/benchmark/results.md index 61b3162c..dee8f08f 100644 --- a/benchmark/results.md +++ b/benchmark/results.md @@ -2,58 +2,47 @@ ## Benchmark Results -| Sample | Ops/sec | Mean Time (ms) | Samples | -|--------|---------|----------------|---------| -| json_complex | 28765.42 | 0.0348 | 95760 | -| css_complex | 27819.60 | 0.0359 | 95893 | -| ts_complex | 1765.08 | 0.5665 | 16594 | -| html_complex | 8213.21 | 0.1218 | 66817 | -| svelte_complex | 2078.65 | 0.4811 | 19675 | -| md_complex | 2074.80 | 0.4820 | 14174 | -| large:json_complex | 254.08 | 3.9358 | 2149 | -| large:css_complex | 242.57 | 4.1225 | 1688 | -| large:ts_complex | 7.34 | 136.2749 | 74 | -| large:html_complex | 56.08 | 17.8315 | 460 | -| large:svelte_complex | 11.51 | 86.8893 | 116 | -| large:md_complex | 7.59 | 131.8069 | 76 | - -**Total samples benchmarked:** 12 -**Average ops/sec:** 5941.33 - - -**Total samples benchmarked:** 12 -**Average ops/sec:** 5862.43 +| Sample | Ops/sec | Mean Time (ms) | Samples | +| -------------------- | -------- | -------------- | ------- | +| json_complex | 28765.42 | 0.0348 | 95760 | +| css_complex | 27819.60 | 0.0359 | 95893 | +| ts_complex | 1765.08 | 0.5665 | 16594 | +| html_complex | 8213.21 | 0.1218 | 66817 | +| svelte_complex | 2078.65 | 0.4811 | 19675 | +| md_complex | 2074.80 | 0.4820 | 14174 | +| large:json_complex | 254.08 | 3.9358 | 2149 | +| large:css_complex | 242.57 | 4.1225 | 1688 | +| large:ts_complex | 7.34 | 136.2749 | 74 | +| large:html_complex | 56.08 | 17.8315 | 460 | +| large:svelte_complex | 11.51 | 86.8893 | 116 | +| large:md_complex | 7.59 | 131.8069 | 76 | + +**Total samples benchmarked:** 12 **Average ops/sec:** 5941.33 + +**Total samples benchmarked:** 12 **Average ops/sec:** 5862.43 ## Browser Benchmark Results -html -90.09ms avg time -22 ops/sec -1.4% CV - -ranges -26.17ms avg time -48 ops/sec -4.8% CV -+244.3% vs baseline - -| Language | Implementation | Mean (ms) | Median (ms) | Std Dev | CV | P75 (ms) | P90 (ms) | P95 (ms) | P99 (ms) | Ops/sec | Outliers | Failed | Stability | -| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| ts | html | 72.54 | 72.50 | 3.66 | 5.1% | 74.00 | 76.76 | 77.68 | 78.42 | 14 | 0/5 | 0 | 100% | -| ts | ranges | 37.82 | 37.70 | 2.15 | 5.7% | 39.70 | 40.24 | 40.42 | 40.56 | 26 | 0/5 | 0 | 100% | -| css | html | 13.73 | 13.70 | 0.05 | 0.3% | 13.75 | 13.78 | 13.79 | 13.80 | 73 | 2/5 | 0 | 100% | -| css | ranges | 13.80 | 13.80 | 0.00 | 0.0% | 13.80 | 13.80 | 13.80 | 13.80 | 72 | 2/5 | 0 | 100% | -| html | html | 112.80 | 112.60 | 0.53 | 0.5% | 112.88 | 113.37 | 113.54 | 113.67 | 9 | 1/5 | 0 | 100% | -| html | ranges | 15.48 | 15.00 | 1.43 | 9.2% | 15.90 | 17.16 | 17.58 | 17.92 | 65 | 0/5 | 0 | 100% | -| json | html | 188.20 | 188.20 | 0.49 | 0.3% | 188.50 | 188.68 | 188.74 | 188.79 | 5 | 2/5 | 0 | 100% | -| json | ranges | 13.72 | 13.75 | 0.08 | 0.6% | 13.80 | 13.80 | 13.80 | 13.80 | 73 | 1/5 | 0 | 100% | -| svelte | html | 98.42 | 97.80 | 1.66 | 1.7% | 98.87 | 100.27 | 100.73 | 101.11 | 10 | 1/5 | 0 | 100% | -| svelte | ranges | 38.94 | 39.80 | 2.28 | 5.9% | 40.80 | 41.10 | 41.20 | 41.28 | 26 | 0/5 | 0 | 100% | -| md | html | 54.86 | 55.00 | 0.45 | 0.8% | 55.10 | 55.34 | 55.42 | 55.48 | 18 | 0/5 | 0 | 100% | -| md | ranges | 37.24 | 35.90 | 2.79 | 7.5% | 39.30 | 40.68 | 41.14 | 41.51 | 27 | 0/5 | 0 | 100% | - -Legend -CV: Coefficient of Variation (std_dev/mean) - lower is better, <15% is good -P75/P90/P95/P99: Percentiles - X% of measurements were faster than this -Ops/sec: Operations per second (throughput) -Stability: Percentage of iterations with stable system metrics \ No newline at end of file +html 90.09ms avg time 22 ops/sec 1.4% CV + +ranges 26.17ms avg time 48 ops/sec 4.8% CV +244.3% vs baseline + +| Language | Implementation | Mean (ms) | Median (ms) | Std Dev | CV | P75 (ms) | P90 (ms) | P95 (ms) | P99 (ms) | Ops/sec | Outliers | Failed | Stability | +| -------- | -------------- | --------- | ----------- | ------- | ---- | -------- | -------- | -------- | -------- | ------- | -------- | ------ | --------- | +| ts | html | 72.54 | 72.50 | 3.66 | 5.1% | 74.00 | 76.76 | 77.68 | 78.42 | 14 | 0/5 | 0 | 100% | +| ts | ranges | 37.82 | 37.70 | 2.15 | 5.7% | 39.70 | 40.24 | 40.42 | 40.56 | 26 | 0/5 | 0 | 100% | +| css | html | 13.73 | 13.70 | 0.05 | 0.3% | 13.75 | 13.78 | 13.79 | 13.80 | 73 | 2/5 | 0 | 100% | +| css | ranges | 13.80 | 13.80 | 0.00 | 0.0% | 13.80 | 13.80 | 13.80 | 13.80 | 72 | 2/5 | 0 | 100% | +| html | html | 112.80 | 112.60 | 0.53 | 0.5% | 112.88 | 113.37 | 113.54 | 113.67 | 9 | 1/5 | 0 | 100% | +| html | ranges | 15.48 | 15.00 | 1.43 | 9.2% | 15.90 | 17.16 | 17.58 | 17.92 | 65 | 0/5 | 0 | 100% | +| json | html | 188.20 | 188.20 | 0.49 | 0.3% | 188.50 | 188.68 | 188.74 | 188.79 | 5 | 2/5 | 0 | 100% | +| json | ranges | 13.72 | 13.75 | 0.08 | 0.6% | 13.80 | 13.80 | 13.80 | 13.80 | 73 | 1/5 | 0 | 100% | +| svelte | html | 98.42 | 97.80 | 1.66 | 1.7% | 98.87 | 100.27 | 100.73 | 101.11 | 10 | 1/5 | 0 | 100% | +| svelte | ranges | 38.94 | 39.80 | 2.28 | 5.9% | 40.80 | 41.10 | 41.20 | 41.28 | 26 | 0/5 | 0 | 100% | +| md | html | 54.86 | 55.00 | 0.45 | 0.8% | 55.10 | 55.34 | 55.42 | 55.48 | 18 | 0/5 | 0 | 100% | +| md | ranges | 37.24 | 35.90 | 2.79 | 7.5% | 39.30 | 40.68 | 41.14 | 41.51 | 27 | 0/5 | 0 | 100% | + +Legend CV: Coefficient of Variation (std_dev/mean) - lower is better, <15% is +good P75/P90/P95/P99: Percentiles - X% of measurements were faster than this +Ops/sec: Operations per second (throughput) Stability: Percentage of iterations +with stable system metrics From d449a8bccc6dc90db7d1ae3f0aff30c19505ec6c Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Wed, 10 Dec 2025 17:26:09 -0500 Subject: [PATCH 10/10] wip --- benchmark/compare/package-lock.json | 606 ------------------ package.json | 4 +- {benchmark => src/benchmark}/benchmarks.ts | 4 +- .../benchmark}/compare/compare.ts | 6 +- .../benchmark}/compare/package.json | 0 .../benchmark}/compare/results.md | 0 .../benchmark}/compare/run_compare.ts | 4 +- {benchmark => src/benchmark}/results.md | 0 .../benchmark}/run_benchmarks.ts | 2 +- src/routes/library.ts | 4 +- tsconfig.json | 2 +- 11 files changed, 13 insertions(+), 619 deletions(-) delete mode 100644 benchmark/compare/package-lock.json rename {benchmark => src/benchmark}/benchmarks.ts (95%) rename {benchmark => src/benchmark}/compare/compare.ts (97%) rename {benchmark => src/benchmark}/compare/package.json (100%) rename {benchmark => src/benchmark}/compare/results.md (100%) rename {benchmark => src/benchmark}/compare/run_compare.ts (80%) rename {benchmark => src/benchmark}/results.md (100%) rename {benchmark => src/benchmark}/run_benchmarks.ts (81%) diff --git a/benchmark/compare/package-lock.json b/benchmark/compare/package-lock.json deleted file mode 100644 index cba287fd..00000000 --- a/benchmark/compare/package-lock.json +++ /dev/null @@ -1,606 +0,0 @@ -{ - "name": "fuz_code_benchmark", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "fuz_code_benchmark", - "devDependencies": { - "@types/prismjs": "^1.26.5", - "prism-svelte": "^0.5.0", - "prismjs": "^1.30.0", - "shiki": "^3.13.0" - } - }, - "node_modules/@shikijs/core": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.13.0.tgz", - "integrity": "sha512-3P8rGsg2Eh2qIHekwuQjzWhKI4jV97PhvYjYUzGqjvJfqdQPz+nMlfWahU24GZAyW1FxFI1sYjyhfh5CoLmIUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.13.0", - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4", - "hast-util-to-html": "^9.0.5" - } - }, - "node_modules/@shikijs/engine-javascript": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.13.0.tgz", - "integrity": "sha512-Ty7xv32XCp8u0eQt8rItpMs6rU9Ki6LJ1dQOW3V/56PKDcpvfHPnYFbsx5FFUP2Yim34m/UkazidamMNVR4vKg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.13.0", - "@shikijs/vscode-textmate": "^10.0.2", - "oniguruma-to-es": "^4.3.3" - } - }, - "node_modules/@shikijs/engine-oniguruma": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.13.0.tgz", - "integrity": "sha512-O42rBGr4UDSlhT2ZFMxqM7QzIU+IcpoTMzb3W7AlziI1ZF7R8eS2M0yt5Ry35nnnTX/LTLXFPUjRFCIW+Operg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.13.0", - "@shikijs/vscode-textmate": "^10.0.2" - } - }, - "node_modules/@shikijs/langs": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.13.0.tgz", - "integrity": "sha512-672c3WAETDYHwrRP0yLy3W1QYB89Hbpj+pO4KhxK6FzIrDI2FoEXNiNCut6BQmEApYLfuYfpgOZaqbY+E9b8wQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.13.0" - } - }, - "node_modules/@shikijs/themes": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.13.0.tgz", - "integrity": "sha512-Vxw1Nm1/Od8jyA7QuAenaV78BG2nSr3/gCGdBkLpfLscddCkzkL36Q5b67SrLLfvAJTOUzW39x4FHVCFriPVgg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.13.0" - } - }, - "node_modules/@shikijs/types": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.13.0.tgz", - "integrity": "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4" - } - }, - "node_modules/@shikijs/vscode-textmate": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", - "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/prismjs": { - "version": "1.26.5", - "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz", - "integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "dev": true, - "license": "ISC" - }, - "node_modules/ccount": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", - "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities-html4": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", - "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities-legacy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", - "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/comma-separated-tokens": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/devlop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", - "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", - "dev": true, - "license": "MIT", - "dependencies": { - "dequal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/hast-util-to-html": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", - "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "ccount": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-whitespace": "^3.0.0", - "html-void-elements": "^3.0.0", - "mdast-util-to-hast": "^13.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0", - "stringify-entities": "^4.0.0", - "zwitch": "^2.0.4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-whitespace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", - "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/html-void-elements": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", - "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/mdast-util-to-hast": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", - "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@ungap/structured-clone": "^1.0.0", - "devlop": "^1.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "trim-lines": "^3.0.0", - "unist-util-position": "^5.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-encode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", - "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-sanitize-uri": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", - "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", - "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/oniguruma-parser": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz", - "integrity": "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==", - "dev": true, - "license": "MIT" - }, - "node_modules/oniguruma-to-es": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.3.tgz", - "integrity": "sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==", - "dev": true, - "license": "MIT", - "dependencies": { - "oniguruma-parser": "^0.12.1", - "regex": "^6.0.1", - "regex-recursion": "^6.0.2" - } - }, - "node_modules/prism-svelte": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/prism-svelte/-/prism-svelte-0.5.0.tgz", - "integrity": "sha512-db91Bf3pRGKDPz1lAqLFSJXeW13mulUJxhycysFpfXV5MIK7RgWWK2E5aPAa71s8TCzQUXxF5JOV42/iOs6QkA==", - "dev": true, - "license": "MIT" - }, - "node_modules/prismjs": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", - "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/property-information": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", - "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/regex/-/regex-6.0.1.tgz", - "integrity": "sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "regex-utilities": "^2.3.0" - } - }, - "node_modules/regex-recursion": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", - "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", - "dev": true, - "license": "MIT", - "dependencies": { - "regex-utilities": "^2.3.0" - } - }, - "node_modules/regex-utilities": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", - "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", - "dev": true, - "license": "MIT" - }, - "node_modules/shiki": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.13.0.tgz", - "integrity": "sha512-aZW4l8Og16CokuCLf8CF8kq+KK2yOygapU5m3+hoGw0Mdosc6fPitjM+ujYarppj5ZIKGyPDPP1vqmQhr+5/0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/core": "3.13.0", - "@shikijs/engine-javascript": "3.13.0", - "@shikijs/engine-oniguruma": "3.13.0", - "@shikijs/langs": "3.13.0", - "@shikijs/themes": "3.13.0", - "@shikijs/types": "3.13.0", - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4" - } - }, - "node_modules/space-separated-tokens": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/stringify-entities": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", - "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", - "dev": true, - "license": "MIT", - "dependencies": { - "character-entities-html4": "^2.0.0", - "character-entities-legacy": "^3.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/trim-lines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", - "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/unist-util-is": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", - "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-position": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", - "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", - "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit-parents": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", - "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vfile": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", - "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vfile-message": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", - "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/zwitch": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", - "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - } - } -} diff --git a/package.json b/package.json index 9f6d3fce..593ec643 100644 --- a/package.json +++ b/package.json @@ -24,8 +24,8 @@ "test": "gro test", "preview": "vite preview", "deploy": "gro deploy", - "benchmark": "gro run benchmark/run_benchmarks.ts", - "benchmark:compare": "gro run benchmark/compare/run_compare.ts", + "benchmark": "gro run src/benchmark/run_benchmarks.ts", + "benchmark:compare": "gro run src/benchmark/compare/run_compare.ts", "fixtures:update": "gro src/test/fixtures/update" }, "type": "module", diff --git a/benchmark/benchmarks.ts b/src/benchmark/benchmarks.ts similarity index 95% rename from benchmark/benchmarks.ts rename to src/benchmark/benchmarks.ts index 6f5a083b..18eb056a 100644 --- a/benchmark/benchmarks.ts +++ b/src/benchmark/benchmarks.ts @@ -1,7 +1,7 @@ import {Benchmark} from '@fuzdev/fuz_util/benchmark.js'; -import {samples as all_samples} from '../src/test/fixtures/samples/all.js'; -import {syntax_styler_global} from '../src/lib/syntax_styler_global.js'; +import {samples as all_samples} from '../test/fixtures/samples/all.ts'; +import {syntax_styler_global} from '../lib/syntax_styler_global.ts'; /* eslint-disable no-console */ diff --git a/benchmark/compare/compare.ts b/src/benchmark/compare/compare.ts similarity index 97% rename from benchmark/compare/compare.ts rename to src/benchmark/compare/compare.ts index 97a824a6..2a8d6d6b 100644 --- a/benchmark/compare/compare.ts +++ b/src/benchmark/compare/compare.ts @@ -25,9 +25,9 @@ import svelte from 'shiki/langs/svelte.mjs'; import nord from 'shiki/themes/nord.mjs'; // Fuz Code imports -import {samples as all_samples} from '../../src/test/fixtures/samples/all.js'; -import {syntax_styler_global} from '../../src/lib/syntax_styler_global.js'; -import {tokenize_syntax} from '../../src/lib/tokenize_syntax.js'; +import {samples as all_samples} from '../../test/fixtures/samples/all.ts'; +import {syntax_styler_global} from '../../lib/syntax_styler_global.ts'; +import {tokenize_syntax} from '../../lib/tokenize_syntax.ts'; /* eslint-disable no-console */ diff --git a/benchmark/compare/package.json b/src/benchmark/compare/package.json similarity index 100% rename from benchmark/compare/package.json rename to src/benchmark/compare/package.json diff --git a/benchmark/compare/results.md b/src/benchmark/compare/results.md similarity index 100% rename from benchmark/compare/results.md rename to src/benchmark/compare/results.md diff --git a/benchmark/compare/run_compare.ts b/src/benchmark/compare/run_compare.ts similarity index 80% rename from benchmark/compare/run_compare.ts rename to src/benchmark/compare/run_compare.ts index 402b8c86..320b126c 100644 --- a/benchmark/compare/run_compare.ts +++ b/src/benchmark/compare/run_compare.ts @@ -1,5 +1,5 @@ #!/usr/bin/env node -import {run_and_print_comparison} from './compare.js'; +import {run_and_print_comparison} from './compare.ts'; const filter = process.argv[2]; @@ -10,4 +10,4 @@ run_and_print_comparison(filter) .catch((error) => { console.error('comparison benchmark failed:', error); // eslint-disable-line no-console process.exit(1); - }); \ No newline at end of file + }); diff --git a/benchmark/results.md b/src/benchmark/results.md similarity index 100% rename from benchmark/results.md rename to src/benchmark/results.md diff --git a/benchmark/run_benchmarks.ts b/src/benchmark/run_benchmarks.ts similarity index 81% rename from benchmark/run_benchmarks.ts rename to src/benchmark/run_benchmarks.ts index e0362aea..b4d78483 100644 --- a/benchmark/run_benchmarks.ts +++ b/src/benchmark/run_benchmarks.ts @@ -1,5 +1,5 @@ #!/usr/bin/env node -import {run_and_print_benchmark} from './benchmarks.js'; +import {run_and_print_benchmark} from './benchmarks.ts'; const filter = process.argv[2]; diff --git a/src/routes/library.ts b/src/routes/library.ts index 9c9db53b..e0e0511b 100644 --- a/src/routes/library.ts +++ b/src/routes/library.ts @@ -29,8 +29,8 @@ export const library_json: LibraryJson = { test: 'gro test', preview: 'vite preview', deploy: 'gro deploy', - benchmark: 'gro run benchmark/run_benchmarks.ts', - 'benchmark:compare': 'gro run benchmark/compare/run_compare.ts', + benchmark: 'gro run src/benchmark/run_benchmarks.ts', + 'benchmark:compare': 'gro run src/benchmark/compare/run_compare.ts', 'fixtures:update': 'gro src/test/fixtures/update', }, type: 'module', diff --git a/tsconfig.json b/tsconfig.json index bd774357..da6c51f8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -36,6 +36,6 @@ "src/**/*.js", "src/**/*.ts", "src/**/*.svelte", - "benchmark/**/*.ts" + "src/benchmark/**/*.ts*.ts" ] }