Performance enhancements and benchmarks
This commit is contained in:
parent
0f7ccb2a0a
commit
4151d0335c
@ -1,6 +1,9 @@
|
|||||||
import { type Result, tryCatch } from '@maxmorozoff/try-catch-tuple'
|
import { nanoseconds } from 'bun'
|
||||||
|
|
||||||
const encoder = new TextEncoder()
|
const encoder = new TextEncoder()
|
||||||
|
const emptyBytes = encoder.encode('')
|
||||||
|
type Writer = (x: Uint8Array | Array<Uint8Array>) => Promise<number>
|
||||||
|
const writer: Writer = x => Bun.write(Bun.stdout, x)
|
||||||
|
|
||||||
export const ANSI = {
|
export const ANSI = {
|
||||||
// Text Styles
|
// Text Styles
|
||||||
@ -108,137 +111,110 @@ export const ANSI_DYNAMIC = {
|
|||||||
|
|
||||||
type AnsiBufferKey = keyof typeof ANSI_BUFFERS
|
type AnsiBufferKey = keyof typeof ANSI_BUFFERS
|
||||||
|
|
||||||
export async function writeAnsi(
|
type WriteAnsi = (
|
||||||
codes: (AnsiBufferKey | Uint8Array)[],
|
c: Array<(AnsiBufferKey | Uint8Array)>,
|
||||||
text?: string,
|
t?: string,
|
||||||
autoReset: boolean = true,
|
a?: boolean,
|
||||||
): Promise<Result<number, Error>> {
|
) => Promise<number>
|
||||||
const buffers: Uint8Array[] = []
|
const writeAnsi: WriteAnsi = async (codes, text?, autoReset = true) => {
|
||||||
|
const arr = [
|
||||||
|
...codes,
|
||||||
|
!text ? emptyBytes : encoder.encode(text),
|
||||||
|
autoReset ? ANSI_BUFFERS['RESET'] : emptyBytes,
|
||||||
|
].map(x => x instanceof Uint8Array ? x : ANSI_BUFFERS[x])
|
||||||
|
|
||||||
// Add requested ANSI codes
|
return writer(Buffer.concat(arr))
|
||||||
for (const code of codes) {
|
|
||||||
if (code instanceof Uint8Array) {
|
|
||||||
buffers.push(code)
|
|
||||||
} else {
|
|
||||||
buffers.push(ANSI_BUFFERS[code])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add optional text
|
const writeAnsi1: WriteAnsi = async (codes, text?, autoReset = true) => {
|
||||||
if (text) {
|
const buffers = [
|
||||||
buffers.push(encoder.encode(text))
|
...codes,
|
||||||
}
|
!text ? emptyBytes : encoder.encode(text),
|
||||||
|
autoReset ? ANSI_BUFFERS['RESET'] : emptyBytes,
|
||||||
|
].map(x => x instanceof Uint8Array ? x : ANSI_BUFFERS[x])
|
||||||
|
|
||||||
// Auto-reset if requested
|
// Calculate total length and create combined buffer
|
||||||
if (autoReset && !codes.includes('RESET')) {
|
const totalLength = buffers.reduce((sum, buf) => sum + buf.length, 0)
|
||||||
buffers.push(ANSI_BUFFERS.RESET)
|
const combined = new Uint8Array(totalLength)
|
||||||
}
|
|
||||||
|
|
||||||
// Combine all buffers into single write
|
|
||||||
const combined = new Uint8Array(
|
|
||||||
buffers.reduce((acc, buf) => acc + buf.length, 0),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
// Copy all buffers into the combined array
|
||||||
let offset = 0
|
let offset = 0
|
||||||
for (const buf of buffers) {
|
for (const buffer of buffers) {
|
||||||
combined.set(buf, offset)
|
combined.set(buffer, offset)
|
||||||
offset += buf.length
|
offset += buffer.length
|
||||||
}
|
}
|
||||||
|
|
||||||
// return tryCatch(() => Bun.write(Bun.stdout, combined))
|
return writer(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 bench = async (x, n) => {
|
||||||
// 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()
|
const a = Bun.nanoseconds()
|
||||||
|
|
||||||
let i = 0
|
let i = 0
|
||||||
while (i < n) {
|
while (i < n) {
|
||||||
await x(y)
|
await x()
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
const b = Bun.nanoseconds()
|
const b = Bun.nanoseconds()
|
||||||
return writeAnsi2(['YELLOW'], `${Math.round((b - a) / 1000000)}ms`)
|
return (b - a) / 100000
|
||||||
}
|
}
|
||||||
|
|
||||||
const out = async (a, b, c) => {
|
const one = async () => {
|
||||||
const one = await a
|
await writeAnsi(
|
||||||
const two = await b
|
['BG_CYAN', 'BLACK', 'ITALIC'],
|
||||||
const three = await c
|
'This is the first option I want',
|
||||||
|
|
||||||
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,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
await writeAnsi(
|
||||||
|
['BG_BLUE', 'BLACK', 'BOLD'],
|
||||||
|
'This is the second option I want',
|
||||||
|
)
|
||||||
|
await writeAnsi(
|
||||||
|
['BG_YELLOW', 'BLACK', 'BLINK'],
|
||||||
|
'Now, this is the third and final option',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const two = async () => {
|
||||||
|
await writeAnsi1(
|
||||||
|
['BG_CYAN', 'BLACK', 'ITALIC'],
|
||||||
|
'This is the first option I want',
|
||||||
|
)
|
||||||
|
await writeAnsi1(
|
||||||
|
['BG_BLUE', 'BLACK', 'BOLD'],
|
||||||
|
'This is the second option I want',
|
||||||
|
)
|
||||||
|
await writeAnsi1(
|
||||||
|
['BG_YELLOW', 'BLACK', 'BLINK'],
|
||||||
|
'Now, this is the third and final option',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const test = async () => {
|
||||||
|
const testN = 100000
|
||||||
|
|
||||||
|
await bench(one, 100000)
|
||||||
|
await bench(two, 100000)
|
||||||
|
|
||||||
|
const testTwo = await bench(two, testN)
|
||||||
|
const testOne = await bench(one, testN)
|
||||||
|
|
||||||
|
await writeAnsi(
|
||||||
|
['RESET', ANSI_DYNAMIC.CURSOR_TO(0, 0)],
|
||||||
|
`${ANSI.CLEAR_SCREEN}\n\n`,
|
||||||
|
)
|
||||||
|
await writeAnsi(['BG_YELLOW', 'BLACK'], '---------------\n')
|
||||||
|
await writeAnsi(['BG_YELLOW', 'BOLD', 'BLACK'], '***************\n')
|
||||||
|
await writeAnsi(['BG_YELLOW', 'BLACK'], '---------------\n')
|
||||||
|
await writeAnsi(['BG_YELLOW', 'BLACK'], 'ONE:')
|
||||||
|
await writeAnsi(['BG_YELLOW', 'GREEN'], testOne.toString() + '\n')
|
||||||
|
await writeAnsi(['BG_YELLOW', 'BLACK'], 'TWO:')
|
||||||
|
await writeAnsi(['BG_YELLOW', 'GREEN'], testTwo.toString() + '\n')
|
||||||
|
await writeAnsi(['BG_YELLOW', 'BLACK'], '---------------\n')
|
||||||
|
await writeAnsi(['BG_YELLOW', 'BOLD', 'BLACK'], '***************\n')
|
||||||
|
await writeAnsi(['BG_YELLOW', 'BLACK'], '---------------')
|
||||||
|
await writeAnsi(['RESET'], '\n\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
test()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user