glob: add perf harness and follow warning

This commit is contained in:
ry2009 2025-12-09 00:11:31 -05:00
parent 29ec779216
commit 2b9b91fb9f
2 changed files with 72 additions and 0 deletions

View file

@ -0,0 +1,65 @@
#!/usr/bin/env bun
import fs from "fs/promises"
import os from "os"
import path from "path"
import { performance } from "perf_hooks"
import { Ripgrep } from "../src/file/ripgrep"
const root = await fs.mkdtemp(path.join(os.tmpdir(), "glob-perf-"))
const scaleInput = process.env.GLOB_PERF_SCALE ?? "1"
const scale = Number.isNaN(Number(scaleInput)) ? 1 : Math.max(1, Number(scaleInput))
async function makeTree() {
const branches = 40 * scale
const subs = 12 * scale
const filesPerDir = 40
const content = "x".repeat(256)
const tasks: Promise<unknown>[] = []
for (const b of Array.from({ length: branches }).map((_, i) => i)) {
const base = path.join(root, `dir${b}`)
tasks.push(
fs.mkdir(base, { recursive: true }).then(async () => {
for (const s of Array.from({ length: subs }).map((_, j) => j)) {
const sub = path.join(base, `sub${s}`)
await fs.mkdir(sub, { recursive: true })
for (const f of Array.from({ length: filesPerDir }).map((_, k) => k)) {
await Bun.write(path.join(sub, `file${f}.txt`), content)
}
}
}),
)
}
await Promise.all(tasks)
}
async function makeSymlinkLoop() {
const loopRoot = path.join(root, "loop")
await fs.mkdir(loopRoot, { recursive: true })
await Bun.write(path.join(loopRoot, "loop-file.txt"), "loop")
await fs.symlink(loopRoot, path.join(loopRoot, "cycle"))
}
async function runScan(label: string, follow: boolean) {
const start = performance.now()
const files = await Array.fromAsync(
Ripgrep.files({
cwd: root,
follow,
timeoutMs: 5000,
}),
).catch((e) => {
console.log(`${label}: error ${e}`)
return [] as string[]
})
const ms = Math.round(performance.now() - start)
console.log(`${label}: files=${files.length} time=${ms}ms follow=${follow}`)
}
await makeTree()
await makeSymlinkLoop()
await runScan("no-follow", false)
await runScan("with-follow", true)
await fs.rm(root, { recursive: true, force: true })

View file

@ -14,6 +14,9 @@ const DEFAULT_IGNORE = [
"**/__pycache__/**",
]
const FOLLOW_WARNING =
"Following symlinks can scan large or cyclical directories and may spike CPU. Only enable if you need it."
export const GlobTool = Tool.define("glob", {
description: DESCRIPTION,
parameters: z.object({
@ -87,6 +90,10 @@ export const GlobTool = Tool.define("glob", {
output.push("(Results are truncated. Consider using a more specific path or pattern.)")
}
}
if (params.follow) {
output.push("")
output.push(FOLLOW_WARNING)
}
return {
title: path.relative(Instance.worktree, search),