Added temporary benchmarks

This commit is contained in:
Eric Rumsey 2025-05-30 17:04:22 -05:00
parent 450745011a
commit 0f7ccb2a0a

View File

@ -1,6 +1,6 @@
import { tryCatch, type Result } from '@maxmorozoff/try-catch-tuple'; import { type Result, tryCatch } from '@maxmorozoff/try-catch-tuple'
const encoder = new TextEncoder(); const encoder = new TextEncoder()
export const ANSI = { export const ANSI = {
// Text Styles // Text Styles
@ -51,7 +51,7 @@ export const ANSI = {
CLEAR_TO_END: '\x1B[0J', // From cursor to end of screen CLEAR_TO_END: '\x1B[0J', // From cursor to end of screen
CLEAR_TO_START: '\x1B[1J', // From cursor to beginning of screen CLEAR_TO_START: '\x1B[1J', // From cursor to beginning of screen
CLEAR_BELOW: '\x1B[J', CLEAR_BELOW: '\x1B[J',
}; }
export const ANSI_BUFFERS = { export const ANSI_BUFFERS = {
// Static code buffers // Static code buffers
@ -95,7 +95,7 @@ export const ANSI_BUFFERS = {
CLEAR_TO_END: encoder.encode(ANSI.CLEAR_TO_END), CLEAR_TO_END: encoder.encode(ANSI.CLEAR_TO_END),
CLEAR_TO_START: encoder.encode(ANSI.CLEAR_TO_START), CLEAR_TO_START: encoder.encode(ANSI.CLEAR_TO_START),
CLEAR_BELOW: encoder.encode(ANSI.CLEAR_BELOW), CLEAR_BELOW: encoder.encode(ANSI.CLEAR_BELOW),
}; }
export const ANSI_DYNAMIC = { export const ANSI_DYNAMIC = {
// Cursor Control // Cursor Control
@ -104,49 +104,141 @@ export const ANSI_DYNAMIC = {
CURSOR_DOWN: (x = 1) => encoder.encode(ANSI.CURSOR_DOWN(x)), CURSOR_DOWN: (x = 1) => encoder.encode(ANSI.CURSOR_DOWN(x)),
CURSOR_FORWARD: (x = 1) => encoder.encode(ANSI.CURSOR_FORWARD(x)), CURSOR_FORWARD: (x = 1) => encoder.encode(ANSI.CURSOR_FORWARD(x)),
CURSOR_BACK: (x = 1) => encoder.encode(ANSI.CURSOR_BACK(x)), CURSOR_BACK: (x = 1) => encoder.encode(ANSI.CURSOR_BACK(x)),
}; }
type AnsiBufferKey = keyof typeof ANSI_BUFFERS; type AnsiBufferKey = keyof typeof ANSI_BUFFERS
export async function writeAnsi( export async function writeAnsi(
codes: (AnsiBufferKey | Uint8Array)[], codes: (AnsiBufferKey | Uint8Array)[],
text?: string, text?: string,
autoReset: boolean = true autoReset: boolean = true,
): Promise<Result<number, Error>> { ): Promise<Result<number, Error>> {
const buffers: Uint8Array[] = []; const buffers: Uint8Array[] = []
// Add requested ANSI codes // Add requested ANSI codes
for (const code of codes) { for (const code of codes) {
if (code instanceof Uint8Array) { if (code instanceof Uint8Array) {
buffers.push(code); buffers.push(code)
} else { } else {
buffers.push(ANSI_BUFFERS[code]); buffers.push(ANSI_BUFFERS[code])
} }
} }
// Add optional text // Add optional text
if (text) { if (text) {
buffers.push(encoder.encode(text)); buffers.push(encoder.encode(text))
} }
// Auto-reset if requested // Auto-reset if requested
if (autoReset && !codes.includes('RESET')) { if (autoReset && !codes.includes('RESET')) {
buffers.push(ANSI_BUFFERS.RESET); buffers.push(ANSI_BUFFERS.RESET)
} }
// Combine all buffers into single write // Combine all buffers into single write
const combined = new Uint8Array( const combined = new Uint8Array(
buffers.reduce((acc, buf) => acc + buf.length, 0) buffers.reduce((acc, buf) => acc + buf.length, 0),
); )
let offset = 0; let offset = 0
for (const buf of buffers) { for (const buf of buffers) {
combined.set(buf, offset); combined.set(buf, offset)
offset += buf.length; offset += buf.length
} }
return tryCatch(() => Bun.write(Bun.stdout, combined)); // return tryCatch(() => Bun.write(Bun.stdout, combined))
return tryCatch(() => process.stdout.write(combined))
}
export async function writeAnsi2(
codes: (AnsiBufferKey | Uint8Array)[],
text?: string,
autoReset: boolean = true,
): Promise<Result<number, Error>> {
const buffers: Uint8Array[] = []
// Add requested ANSI codes
for (const code of codes) {
if (code instanceof Uint8Array) {
buffers.push(code)
} else {
buffers.push(ANSI_BUFFERS[code])
}
}
// Add optional text
if (text) {
buffers.push(encoder.encode(text))
}
// Auto-reset if requested
if (autoReset && !codes.includes('RESET')) {
buffers.push(ANSI_BUFFERS.RESET)
}
// Combine all buffers into single write
const combined = new Uint8Array(
buffers.reduce((acc, buf) => acc + buf.length, 0),
)
let offset = 0
for (const buf of buffers) {
combined.set(buf, offset)
offset += buf.length
}
return Bun.write(Bun.stdout, combined)
// return tryCatch(() => process.stdout.write(combined))
} }
// For CommonJS compatibility // For CommonJS compatibility
export default { ANSI, ANSI_BUFFERS, writeAnsi }; export default {ANSI, ANSI_BUFFERS, writeAnsi}
const testNum = 5
// const testCase = [['BG_WHITE', 'BLACK'], 'This is some text']
const testCase =
`${ANSI_BUFFERS.BG_WHITE}${ANSI_BUFFERS.BLACK}This is some text${ANSI_BUFFERS.RESET}`
const testCase2 = `${ANSI.BG_WHITE}${ANSI.BLACK}This is some text`
const bench = async (x, y, n) => {
const a = Bun.nanoseconds()
let i = 0
while (i < n) {
await x(y)
i++
}
const b = Bun.nanoseconds()
return writeAnsi2(['YELLOW'], `${Math.round((b - a) / 1000000)}ms`)
}
const out = async (a, b, c) => {
const one = await a
const two = await b
const three = await c
const log = x => async y => console.log(x, await y)
const diff = x => y => {
if (y < x) return Math.round(((y - x) / y) * 100)
return Math.round(((y - x) / x) * 100)
}
writeAnsi(['RESET', 'CLEAR_SCREEN', ANSI_DYNAMIC.CURSOR_TO(0, 0)])
console.log('')
console.log('---------------')
console.log('Output in milliseconds')
console.log('---------------')
log('ANSI: ')(!one ? '' : one)
log('ANSI_BUFFERS: ')(!two ? '' : two)
log('THREE: ')(!three ? '' : three)
log(`${diff(one)(two)}%`)('faster')
}
out(
bench(x => Bun.write(Bun.stdout, x), testCase, testNum),
bench(x => Bun.write(Bun.stdout, x), testCase2, testNum),
bench(
x => writeAnsi2(...x),
[['BG_WHITE', 'BLACK'], 'This is some text'],
testNum,
),
)