| @@ -42,6 +42,30 @@ const { TestNetworkNoAppView } = await import( |
| | devEnv ? pathToFileURL(resolve(root, devEnv, 'dist/index.js')).href : '@atproto/dev-env' |
| | ) |
| | if (devEnv) await migrateOnce(resolve(root, devEnv)) |
| | if (!process.env.KNOTLESS_PDS_FSYNC) await skipFsync(devEnv ? resolve(root, devEnv) : undefined) |
| | |
| | /// The directory of the PDS's compiled modules that the dev-env at `dir` |
| | /// (the npm package when there is none) runs. |
| | function pdsDist(dir) { |
| | const from = dir |
| | ? pathToFileURL(join(dir, 'package.json')) |
| | : import.meta.resolve('@atproto/dev-env') |
| | return dirname(realpathSync(createRequire(from).resolve('@atproto/pds'))) |
| | } |
| | |
| | /// Has the PDS's SQLite databases (an account's, the account manager's, the |
| | /// sequencer's) commit without waiting for the disk: the same modules it |
| | /// loads, patched before it starts. Each commit otherwise waits on an fsync, |
| | /// 20ms on the runner's disk, and a write makes several, which made a push |
| | /// or a pull cost most of a second when the PDS does the rest in a few |
| | /// milliseconds. A test harness has no data to keep through a crash. |
| | /// KNOTLESS_PDS_FSYNC=1 keeps the PDS as it is. |
| | async function skipFsync(dir) { |
| | const { Database } = await import(pathToFileURL(join(pdsDist(dir), 'db/db.js')).href) |
| | const sqlite = Database.sqlite |
| | Database.sqlite = (location, opts) => |
| | sqlite.call(Database, location, { ...opts, pragmas: { ...opts?.pragmas, synchronous: 'OFF' } }) |
| | } |
| | |
| | /// Has the PDS that the dev-env at `dir` runs migrate each account's |
| | /// database on its first opening alone, rather than on every one: the |
| @@ -118,6 +142,72 @@ const net = await TestNetworkNoAppView.create({ |
| | }, |
| | }) |
| | |
| | // PDSSTAT instrumentation (throwaway) |
| | { |
| | const fs = await import('node:fs') |
| | { |
| | const f = join(tmpdir(), `fsb-${process.pid}`) |
| | const fd = fs.openSync(f, 'w') |
| | const t = process.hrtime.bigint() |
| | for (let i = 0; i < 40; i++) { |
| | fs.writeSync(fd, 'x'.repeat(4096)) |
| | fs.fsyncSync(fd) |
| | } |
| | console.error( |
| | `PDSSTAT fsync ${tmpdir()} avg=${(Number(process.hrtime.bigint() - t) / 40e6).toFixed(2)}ms nofsync=${process.env.KNOTLESS_PDS_FSYNC ? 'no' : 'yes'}`, |
| | ) |
| | fs.closeSync(fd) |
| | fs.unlinkSync(f) |
| | } |
| | const { monitorEventLoopDelay } = await import('node:perf_hooks') |
| | const h = monitorEventLoopDelay({ resolution: 5 }) |
| | h.enable() |
| | const stats = new Map() |
| | let inflight = 0 |
| | let maxInflight = 0 |
| | const http = net.pds.server.server |
| | http.prependListener('request', (req, res) => { |
| | const t = process.hrtime.bigint() |
| | inflight++ |
| | maxInflight = Math.max(maxInflight, inflight) |
| | res.on('close', () => { |
| | inflight-- |
| | const ms = Number(process.hrtime.bigint() - t) / 1e6 |
| | const k = `${req.method} ${req.url.split('?')[0].replace(/^\/xrpc\//, '')}` |
| | const e = stats.get(k) ?? [] |
| | e.push(ms) |
| | stats.set(k, e) |
| | }) |
| | }) |
| | const dump = () => { |
| | const rows = [...stats] |
| | .map(([k, v]) => { |
| | v.sort((a, b) => a - b) |
| | const sum = v.reduce((a, b) => a + b, 0) |
| | return { |
| | k, |
| | n: v.length, |
| | sum, |
| | avg: sum / v.length, |
| | p50: v[v.length >> 1], |
| | p95: v[Math.floor(v.length * 0.95)], |
| | max: v[v.length - 1], |
| | } |
| | }) |
| | .sort((a, b) => b.sum - a.sum) |
| | .slice(0, 14) |
| | console.error( |
| | `PDSSTAT maxInflight=${maxInflight} loopLag mean=${(h.mean / 1e6).toFixed(1)}ms p99=${(h.percentile(99) / 1e6).toFixed(1)}ms`, |
| | ) |
| | for (const r of rows) |
| | console.error( |
| | `PDSSTAT ${r.k} n=${r.n} sum=${r.sum.toFixed(0)}ms avg=${r.avg.toFixed(1)} p50=${r.p50.toFixed(1)} p95=${r.p95.toFixed(1)} max=${r.max.toFixed(0)}`, |
| | ) |
| | } |
| | setInterval(dump, 20000).unref() |
| | globalThis.__dump = dump |
| | } |
| | |
| | const accounts = [] |
| | for (const name of names) { |
| | const password = `${name}-password` |
| @@ -183,6 +273,7 @@ console.log( |
| | ) |
| | |
| | const shutdown = async () => { |
| | globalThis.__dump() |
| | await net.close() |
| | process.exit(0) |
| | } |
| |