diff --git a/packages/storage/src/__tests__/usage-stores.test.ts b/packages/storage/src/__tests__/usage-stores.test.ts index 3df3181327..5e7232656e 100644 --- a/packages/storage/src/__tests__/usage-stores.test.ts +++ b/packages/storage/src/__tests__/usage-stores.test.ts @@ -19,7 +19,7 @@ import assert from 'node:assert/strict'; import { DatabaseSync } from 'node:sqlite'; -import type { UsageScreen, UsageScreenRequest } from '@maka/core/settings'; +import type { UsageScreen, UsageScreenQuery, UsageScreenRequest } from '@maka/core/settings'; import { copyFile, mkdir, @@ -816,7 +816,7 @@ async function withScreenStores( } async function initialScreen( stores: Awaited>, - query = screenQuery, + query: UsageScreenQuery = screenQuery, ) { const result = await stores.readUsageScreen({ kind: 'screen', query }); assert.equal(result.kind, 'screen'); @@ -965,6 +965,198 @@ describe('revision-consistent Usage screen', () => { }); }); + test('matching continuations bound search work even when every timestamp is equal', async () => { + await withScreenStores(async (stores, root) => { + for (let i = 0; i < 512; i++) + await stores.telemetry.recordLlmCall(llmRecord({ id: `matching-${i}` })); + const lease = acquireOperationalStateDatabase(await realpath(root)); + let lowerCalls = 0; + lease.database.function('usage_screen_lower', { deterministic: true }, (value) => { + lowerCalls++; + return String(value).toLowerCase(); + }); + try { + const screen = await initialScreen(stores, { ...screenQuery, search: 'gpt' }); + assert.equal(screen.activityTotal, 512); + assert.ok(lowerCalls <= 672, `count plus first page performed ${lowerCalls} search folds`); + const ids = screen.logs.map((row) => row.id); + let cursor = screen.nextCursor; + while (cursor) { + lowerCalls = 0; + const result = await stores.readUsageScreen({ ...continuation(screen), cursor }); + assert.ok(result.kind === 'activity'); + assert.ok(result.page.logs.length <= 50); + assert.ok(lowerCalls > 0, 'observe search work on the actual reader connection'); + assert.ok(lowerCalls <= 160, `one matching page performed ${lowerCalls} search folds`); + ids.push(...result.page.logs.map((row) => row.id)); + cursor = result.page.nextCursor; + } + assert.equal(ids.length, 512); + assert.equal(new Set(ids).size, 512); + } finally { + lease.close(); + } + }); + }); + + test('an empty search result evaluates historical search fields only once', async () => { + await withScreenStores(async (stores, root) => { + for (let i = 0; i < 120; i++) + await stores.telemetry.recordToolInvocation( + toolRecord({ id: `search-${i}`, modelId: 'model', providerId: 'provider' }), + ); + const lease = acquireOperationalStateDatabase(await realpath(root)); + let lowerCalls = 0; + lease.database.function('usage_screen_lower', { deterministic: true }, (value) => { + lowerCalls++; + return String(value).toLowerCase(); + }); + try { + const screen = await initialScreen(stores, { ...screenQuery, search: 'absent' }); + assert.equal(screen.activityTotal, 0); + assert.deepEqual(screen.logs, []); + assert.equal(screen.nextCursor, null); + assert.equal(screen.byTool[0]?.calls, 120); + assert.ok(lowerCalls > 0, 'observe search work on the actual reader connection'); + assert.ok(lowerCalls <= 363, `empty result performed ${lowerCalls} search folds`); + } finally { + lease.close(); + } + }); + }); + + test('mixed-source pages and counts match the full filtered history at every range boundary', async () => { + await withScreenStores(async (stores, root) => { + const lease = acquireOperationalStateDatabase(await realpath(root)); + const records: Array<{ + ts: number; + source: number; + identity: string; + turnId: string; + model: string; + provider: string; + toolName: string; + status: string; + }> = []; + try { + const canonical = lease.database.prepare(`INSERT INTO usage_model_call_attempts + (attempt_id, completed_at, logical_call_id, session_id, turn_id, call_kind, + provider_id, model_id, latency_ms, status, usage_basis, cost_basis, cost_usd) + VALUES (?, ?, 'logical', 'session', ?, 'main', ?, ?, 1, ?, 'reported', ?, ?)`); + const legacy = lease.database.prepare( + 'INSERT INTO usage_llm_calls(storage_key, id, ts, record_json) VALUES (?, ?, ?, ?)', + ); + const tool = lease.database.prepare( + 'INSERT INTO usage_tool_invocations(storage_key, id, ts, record_json) VALUES (?, ?, ?, ?)', + ); + lease.transaction('write', () => { + for (let source = 0; source < 3; source++) { + for (let i = 0; i < 90; i++) { + const identity = `${['Z', 'é', '中'][i % 3]}-${String(i).padStart(3, '0')}`; + const record = { + ts: i % 11 === 0 ? 0 : i % 7 === 0 ? 50 : 100, + source, + identity, + turnId: `${source}-${i}`, + model: ['ÄModel', 'İModel', 'literal%_', 'other'][i % 4]!, + provider: source === 2 && i % 2 === 0 ? '' : 'Provider', + toolName: source === 2 ? (i % 5 === 0 ? '查找' : 'Read%_') : '', + status: ['success', 'error', 'aborted'][i % 3]!, + }; + records.push(record); + if (source === 0) { + canonical.run( + identity, + record.ts, + record.turnId, + record.provider, + record.model, + ['completed', 'failed', 'aborted'][i % 3]!, + i % 2 === 0 ? 'priced' : 'unpriced', + i % 2 === 0 ? 0 : null, + ); + } else { + (source === 1 ? legacy : tool).run( + identity, + 'duplicate-display-id', + record.ts, + JSON.stringify({ + turnId: record.turnId, + providerId: record.provider || undefined, + modelId: record.model, + toolName: record.toolName, + status: record.status, + durationMs: 1, + }), + ); + } + } + } + lease.database.exec(`INSERT INTO usage_model_call_attempts(attempt_id, completed_at) + VALUES ('unreadable', 100)`); + }); + records.sort( + (left, right) => + right.ts - left.ts || + right.source - left.source || + Buffer.compare(Buffer.from(right.identity), Buffer.from(left.identity)), + ); + for (const range of [ + { from: 0, to: 100 }, + { from: 100, to: 100 }, + { from: 0, to: 50 }, + { from: 101, to: 200 }, + ]) { + const unfiltered = await initialScreen(stores, { ...screenQuery, range }); + for (const [search, status] of [ + ['', 'all'], + ['', 'success'], + ['', 'error'], + ['', 'aborted'], + ['ämodel', 'all'], + ['i̇model', 'error'], + ['%_', 'all'], + ['查找', 'all'], + ['provider', 'all'], + ['absent', 'all'], + ] as const) { + const matching = records.filter( + (row) => + row.ts >= range.from && + row.ts <= range.to && + (status === 'all' || row.status === status) && + [row.model, row.provider, row.toolName].some((field) => + field.toLowerCase().includes(search), + ), + ); + const screen = await initialScreen(stores, { range, search, status }); + assert.equal(screen.activityTotal, matching.length); + assert.deepEqual(screen.summary, unfiltered.summary); + assert.deepEqual(screen.byProvider, unfiltered.byProvider); + assert.deepEqual(screen.byModel, unfiltered.byModel); + assert.deepEqual(screen.byTool, unfiltered.byTool); + const logs = [...screen.logs]; + let cursor = screen.nextCursor; + while (cursor) { + assert.ok(logs.length < matching.length, 'continuation must make progress'); + const result = await stores.readUsageScreen({ ...continuation(screen), cursor }); + assert.ok(result.kind === 'activity'); + assert.ok(result.page.logs.length > 0 && result.page.logs.length <= 50); + logs.push(...result.page.logs); + cursor = result.page.nextCursor; + } + assert.deepEqual( + logs.map((row) => row.turnId), + matching.map((row) => row.turnId), + ); + } + } + } finally { + lease.close(); + } + }); + }); + test('each durable writer, correction, deletion, and rollback fences continuation', async () => { await withScreenStores(async (stores, root) => { await seedScreen(stores); diff --git a/packages/storage/src/usage-screen.ts b/packages/storage/src/usage-screen.ts index d66a752404..6001c6c5d6 100644 --- a/packages/storage/src/usage-screen.ts +++ b/packages/storage/src/usage-screen.ts @@ -33,37 +33,72 @@ import { TelemetryQueryValidationError } from './telemetry-repo.js'; const json = (key: string) => `json_extract(record_json, '$.${key}')`; const num = (key: string) => `COALESCE(${json(key)}, 0)`; -// One relational projection shared by aggregates and activity. Only the selected -// activity page crosses into JavaScript; grouping never decodes history there. -const MODEL_ROWS = ` - SELECT completed_at AS ts, 'canonical' AS source, attempt_id AS identity, +// The three sources share accounting/filter expressions, but activity pages and +// counts select only the rows/columns they need. Aggregates remain range-wide. +const SOURCES = [ + { + name: 'canonical', + table: 'usage_model_call_attempts', + time: 'completed_at', + identity: 'attempt_id', + filters: `provider_id AS provider, model_id AS model, NULL AS toolName, + CASE status WHEN 'completed' THEN 'success' WHEN 'failed' THEN 'error' ELSE 'aborted' END AS status`, + columns: `completed_at AS ts, 'canonical' AS source, attempt_id AS identity, attempt_id AS id, 'model' AS kind, session_id AS sessionId, turn_id AS turnId, - provider_id AS provider, model_id AS model, NULL AS toolName, COALESCE(connection_slug, provider_id) AS connection, COALESCE(input_tokens, 0) AS inputTokens, COALESCE(output_tokens, 0) AS outputTokens, COALESCE(cache_miss_input_tokens, 0) AS cacheMiss, ${CACHE_READ_TOKENS} AS cacheRead, COALESCE(cache_write_input_tokens, 0) AS cacheCreation, COALESCE(reasoning_tokens, 0) AS reasoning, COALESCE(input_tokens, 0) + COALESCE(output_tokens, 0) AS totalTokens, cost_usd AS costUsd, latency_ms AS latencyMs, - CASE status WHEN 'completed' THEN 'success' WHEN 'failed' THEN 'error' ELSE 'aborted' END AS status, - cost_basis AS costBasis, usage_basis AS usageBasis - FROM usage_model_call_attempts WHERE completed_at >= ? AND completed_at <= ? AND cost_basis IS NOT NULL - UNION ALL - SELECT ts, 'legacy', storage_key, id, 'model', ${json('sessionId')}, ${json('turnId')}, - ${json('providerId')}, ${json('modelId')}, NULL, COALESCE(${json('connectionSlug')}, ${json('providerId')}), - ${num('inputTokens')}, ${num('outputTokens')}, ${num('cacheMissInputTokens')}, - MIN(${num('inputTokens')}, ${num('cacheHitInputTokens')}), ${num('cacheWriteInputTokens')}, - ${num('reasoningTokens')}, ${num('totalTokens')}, ${num('costUsd')}, ${num('latencyMs')}, ${json('status')}, NULL, NULL - FROM usage_llm_calls WHERE ts >= ? AND ts <= ?`; -const TOOL_ROWS = ` - SELECT ts, 'tool' AS source, storage_key AS identity, id, 'tool' AS kind, + cost_basis AS costBasis, usage_basis AS usageBasis`, + }, + { + name: 'legacy', + table: 'usage_llm_calls', + time: 'ts', + identity: 'storage_key', + filters: `${json('providerId')} AS provider, ${json('modelId')} AS model, + NULL AS toolName, ${json('status')} AS status`, + columns: `ts, 'legacy' AS source, storage_key AS identity, id, 'model' AS kind, ${json('sessionId')} AS sessionId, ${json('turnId')} AS turnId, - COALESCE(${json('providerId')}, '') AS provider, COALESCE(${json('modelId')}, '') AS model, - ${json('toolName')} AS toolName, '' AS connection, + COALESCE(${json('connectionSlug')}, ${json('providerId')}) AS connection, + ${num('inputTokens')} AS inputTokens, ${num('outputTokens')} AS outputTokens, + ${num('cacheMissInputTokens')} AS cacheMiss, + MIN(${num('inputTokens')}, ${num('cacheHitInputTokens')}) AS cacheRead, + ${num('cacheWriteInputTokens')} AS cacheCreation, ${num('reasoningTokens')} AS reasoning, + ${num('totalTokens')} AS totalTokens, ${num('costUsd')} AS costUsd, + ${num('latencyMs')} AS latencyMs, NULL AS costBasis, NULL AS usageBasis`, + }, + { + name: 'tool', + table: 'usage_tool_invocations', + time: 'ts', + identity: 'storage_key', + filters: `COALESCE(${json('providerId')}, '') AS provider, + COALESCE(${json('modelId')}, '') AS model, ${json('toolName')} AS toolName, + ${json('status')} AS status`, + columns: `ts, 'tool' AS source, storage_key AS identity, id, 'tool' AS kind, + ${json('sessionId')} AS sessionId, ${json('turnId')} AS turnId, + '' AS connection, 0 AS inputTokens, 0 AS outputTokens, 0 AS cacheMiss, 0 AS cacheRead, 0 AS cacheCreation, 0 AS reasoning, 0 AS totalTokens, NULL AS costUsd, - ${num('durationMs')} AS latencyMs, ${json('status')} AS status, NULL AS costBasis, NULL AS usageBasis - FROM usage_tool_invocations WHERE ts >= ? AND ts <= ?`; + ${num('durationMs')} AS latencyMs, NULL AS costBasis, NULL AS usageBasis`, + }, +] as const; +type Source = (typeof SOURCES)[number]; +interface Position { + ts: number; + source: Source['name']; + identity: string; +} + +function rangeRows(source: Source): string { + return `SELECT ${source.columns}, ${source.filters} FROM ${source.table} + WHERE ${source.time} >= ? AND ${source.time} <= ?${source.name === 'canonical' ? ' AND cost_basis IS NOT NULL' : ''}`; +} +const MODEL_ROWS = `${rangeRows(SOURCES[0])} UNION ALL ${rangeRows(SOURCES[1])}`; +const TOOL_ROWS = rangeRows(SOURCES[2]); type Row = Record; const n = (value: unknown): number => Number(value ?? 0); @@ -169,11 +204,17 @@ export function createUsageScreenReader(root: string) { WHERE source.latest_model_call_sequence > COALESCE(checkpoint.applied_through_sequence, -1)`) .get()?.count, ); + // Complete range statistics already counted every readable model/tool + // row. Only activity filters need a separate exact count. + const activityTotal = + !input.query.search && input.query.status === 'all' + ? n(aggregate.totalRequests) + tools.reduce((sum, row) => sum + n(row.calls), 0) + : activityCount(db, input.query); const screen: UsageScreen = { revision, queryIdentity, query: input.query, - activityTotal: activityCount(db, input.query), + activityTotal, summary: { totalRequests: n(aggregate.totalRequests), totalCostUsd: n(aggregate.totalCostUsd), @@ -219,7 +260,9 @@ export function createUsageScreenReader(root: string) { unreadableRecords: unreadable, pendingRepairs: pending, }, - ...activity(db, input.query), + // Count and page share this read snapshot: zero proves there is no + // matching activity, so an empty search needs only one range scan. + ...(activityTotal === 0 ? { logs: [], nextCursor: null } : activity(db, input.query)), }; return { kind: 'screen', screen }; }), @@ -241,8 +284,7 @@ function validateQuery(query: UsageScreenQuery): void { } function activityPredicate(query: UsageScreenQuery) { - const range = [query.range.from, query.range.to]; - const args: (string | number)[] = [...range, ...range, ...range]; + const args: (string | number)[] = []; const filters: string[] = []; if (query.status !== 'all') { filters.push('status = ?'); @@ -258,18 +300,50 @@ function activityPredicate(query: UsageScreenQuery) { return { args, filters }; } +function activitySourceQuery( + source: Source, + query: UsageScreenQuery, + columns: string, + position?: Position, +) { + const bounds = [`${source.time} >= ?`]; + const args: (string | number)[] = [query.range.from]; + if (!position) { + bounds.push(`${source.time} <= ?`); + args.push(query.range.to); + } else if (source.name === position.source) { + // The cursor is validated inside the fixed range. Replacing its redundant + // upper bound lets SQLite seek on both index columns, even on deep pages. + bounds.push(`(${source.time}, ${source.identity}) < (?, ?)`); + args.push(position.ts, position.identity); + } else { + // Source names are ASCII and follow the existing SQLite BINARY ordering. + bounds.push(`${source.time} ${source.name < position.source ? '<=' : '<'} ?`); + args.push(position.ts); + } + if (source.name === 'canonical') bounds.push('cost_basis IS NOT NULL'); + const predicate = activityPredicate(query); + args.push(...predicate.args); + return { + sql: `SELECT * FROM (SELECT ${columns} FROM ${source.table} WHERE ${bounds.join(' AND ')}) + ${predicate.filters.length ? `WHERE ${predicate.filters.join(' AND ')}` : ''}`, + args, + }; +} + function activityCount(db: DatabaseSync, query: UsageScreenQuery): number { - const { args, filters } = activityPredicate(query); + const sources = SOURCES.map((source) => activitySourceQuery(source, query, source.filters)); return n( db - .prepare(`WITH rows AS (${MODEL_ROWS} UNION ALL ${TOOL_ROWS}) - SELECT COUNT(*) AS count FROM rows ${filters.length ? `WHERE ${filters.join(' AND ')}` : ''}`) - .get(...args)?.count, + .prepare( + `SELECT ${sources.map(({ sql }) => `(SELECT COUNT(*) FROM (${sql}))`).join(' + ')} AS count`, + ) + .get(...sources.flatMap(({ args }) => args))?.count, ); } function activity(db: DatabaseSync, query: UsageScreenQuery, cursor?: string) { - const { args, filters } = activityPredicate(query); + let position: Position | undefined; if (cursor) { let value: unknown; try { @@ -300,14 +374,20 @@ function activity(db: DatabaseSync, query: UsageScreenQuery, cursor?: string) { ) { throw new TelemetryQueryValidationError('Invalid Usage cursor position'); } - filters.push('(ts, source, identity) < (?, ?, ?)'); - args.push(value[1], value[2], value[3]); + position = { ts: value[1], source: value[2], identity: value[3] }; } + const sources = SOURCES.map((source) => + activitySourceQuery(source, query, `${source.columns}, ${source.filters}`, position), + ); + // A source's 52nd matching row cannot be in the global first 51. Each local + // ORDER BY matches its index; the final sort sees at most 3 * 51 candidates. const rows = db - .prepare(`WITH rows AS (${MODEL_ROWS} UNION ALL ${TOOL_ROWS}) - SELECT * FROM rows ${filters.length ? `WHERE ${filters.join(' AND ')}` : ''} + .prepare(`WITH candidates AS (${sources + .map(({ sql }) => `SELECT * FROM (${sql} ORDER BY ts DESC, identity DESC LIMIT 51)`) + .join(' UNION ALL ')}) + SELECT * FROM candidates ORDER BY ts DESC, source DESC, identity DESC LIMIT 51`) - .all(...args) as Row[]; + .all(...sources.flatMap(({ args }) => args)) as Row[]; const selected = rows.slice(0, 50); const last = selected.at(-1); // Resolve only this bounded page inside the same read transaction as its diff --git a/scripts/perf/usage-pages.mjs b/scripts/perf/usage-pages.mjs new file mode 100644 index 0000000000..bacad7345e --- /dev/null +++ b/scripts/perf/usage-pages.mjs @@ -0,0 +1,324 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// Build core/storage at both revisions, then pass the baseline checkout path. +// Both real readers run against the same fixture, alternating timed requests. +import assert from 'node:assert/strict'; +import { execFileSync } from 'node:child_process'; +import { mkdtemp, rm } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join, resolve } from 'node:path'; +import { performance } from 'node:perf_hooks'; +import { pathToFileURL } from 'node:url'; +import { acquireOperationalStateDatabase } from '../../packages/storage/dist/operational-state-store.js'; +import { + resolveStorageRoot, + tryAcquireInteractiveRootOwner, + tryAcquireInteractiveRootReader, +} from '../../packages/storage/dist/root-authority.js'; +import { + openInteractiveUsageStoresForRead, + openInteractiveUsageStoresForWrite, +} from '../../packages/storage/dist/usage-stores.js'; +import { removeControlDirectory } from '../../packages/storage/dist/__tests__/fixtures/control-directory-hygiene.js'; +import { report, summarize } from './report.mjs'; + +assert.ok(process.argv[2], 'Pass a built baseline checkout'); +const baselinePath = resolve(process.argv[2]); +const baseline = await import( + pathToFileURL(join(baselinePath, 'packages/storage/dist/usage-stores.js')).href +); +const baselineAuthority = await import( + pathToFileURL(join(baselinePath, 'packages/storage/dist/root-authority.js')).href +); +const baselineDatabase = await import( + pathToFileURL(join(baselinePath, 'packages/storage/dist/operational-state-store.js')).href +); +const rows = []; +const profiles = []; +let sqlite; + +function seed(lease, count, mixed, tied) { + const db = lease.database; + const inserts = [ + db.prepare(`INSERT INTO usage_model_call_attempts + (attempt_id, completed_at, session_id, logical_call_id, turn_id, call_kind, + connection_slug, provider_id, model_id, latency_ms, status, usage_basis, + input_tokens, output_tokens, cost_basis, cost_usd) + VALUES (?, ?, 'session', 'logical', ?, 'main', 'provider', 'provider', ?, 1, + ?, 'reported', 10, 2, 'priced', 0.001)`), + db.prepare('INSERT INTO usage_llm_calls(storage_key, id, ts, record_json) VALUES (?, ?, ?, ?)'), + db.prepare( + 'INSERT INTO usage_tool_invocations(storage_key, id, ts, record_json) VALUES (?, ?, ?, ?)', + ), + ]; + const records = []; + lease.transaction('write', () => { + for (let i = 1; i <= count; i++) { + const source = mixed ? (i - 1) % 3 : 2; + const identity = `key-${String(i).padStart(8, '0')}`; + const ts = tied ? 100 : i; + const turnId = `turn-${i}`; + const model = i % 7 === 0 ? 'ÄModel%_İ' : 'model'; + const status = i % 13 === 0 ? 'error' : 'success'; + const toolName = i % 11 === 0 ? 'Grep' : 'Read'; + if (source === 0) { + inserts[source].run( + identity, + ts, + turnId, + model, + status === 'error' ? 'failed' : 'completed', + ); + } else { + inserts[source].run( + identity, + `display-${i % 5}`, + ts, + JSON.stringify({ + sessionId: 'session', + turnId, + providerId: 'provider', + modelId: model, + toolName, + status, + durationMs: 1, + inputTokens: 10, + outputTokens: 2, + totalTokens: 12, + costUsd: 0.001, + latencyMs: 1, + }), + ); + } + records.push({ ts, source, identity, turnId }); + } + }); + return records.sort( + (a, b) => + b.ts - a.ts || + b.source - a.source || + Buffer.compare(Buffer.from(b.identity), Buffer.from(a.identity)), + ); +} + +function capture(db) { + const prepare = db.prepare; + const statements = []; + let lowerCalls = 0; + db.function('usage_screen_lower', { deterministic: true }, (value) => { + lowerCalls++; + return String(value ?? '').toLowerCase(); + }); + db.prepare = function (sql) { + const statement = prepare.call(this, sql); + for (const method of ['all', 'get']) { + const run = statement[method].bind(statement); + statement[method] = (...args) => { + const before = lowerCalls; + const value = run(...args); + statements.push({ sql, args, lowerCalls: lowerCalls - before }); + return value; + }; + } + return statement; + }; + return () => { + db.prepare = prepare; + db.function('usage_screen_lower', { deterministic: true }, (value) => + String(value ?? '').toLowerCase(), + ); + return { + lowerCalls, + statements: statements.map((statement) => ({ + ...statement, + plan: prepare.call(db, `EXPLAIN QUERY PLAN ${statement.sql}`).all(...statement.args), + })), + }; + }; +} + +for (const [count, mixed, tied] of [ + [1_000, false, false], + [10_000, false, false], + [50_000, false, false], + [50_000, true, true], +]) { + const base = await mkdtemp(join(tmpdir(), 'maka-perf-usage-')); + const capability = await resolveStorageRoot({ path: join(base, 'root'), kind: 'interactive' }); + const owner = await tryAcquireInteractiveRootOwner(capability); + assert.ok(owner); + const writer = await openInteractiveUsageStoresForWrite(owner.lease); + const seedLease = acquireOperationalStateDatabase(capability.canonicalPath); + let records; + try { + records = seed(seedLease, count, mixed, tied); + } finally { + seedLease.close(); + await writer.close(); + await owner.close(); + } + const readerOwner = await tryAcquireInteractiveRootReader(capability); + const oldCapability = await baselineAuthority.resolveStorageRoot({ + path: capability.canonicalPath, + kind: 'interactive', + }); + const oldOwner = await baselineAuthority.tryAcquireInteractiveRootReader(oldCapability); + assert.ok(readerOwner && oldOwner); + const stores = await openInteractiveUsageStoresForRead(readerOwner.lease); + const oldStores = await baseline.openInteractiveUsageStoresForRead(oldOwner.lease); + const lease = acquireOperationalStateDatabase(capability.canonicalPath); + const oldLease = baselineDatabase.acquireOperationalStateDatabase(capability.canonicalPath); + try { + sqlite = lease.database.prepare('SELECT sqlite_version() AS version').get().version; + const scenario = `${count}/${mixed ? 'mixed' : 'tools'}/${tied ? 'tied' : 'spread'}`; + const versions = [ + { name: 'before', db: oldLease.database, read: (input) => oldStores.readUsageScreen(input) }, + { name: 'after', db: lease.database, read: (input) => stores.readUsageScreen(input) }, + ]; + const query = { range: { from: 0, to: count }, search: '', status: 'all' }; + const screens = []; + for (const version of versions) { + const start = performance.now(); + const result = await version.read({ kind: 'screen', query }); + rows.push({ + scenario, + metric: `${version.name}/first-screen-ms`, + ...summarize([performance.now() - start]), + }); + assert.equal(result.kind, 'screen'); + screens.push(result.screen); + } + assert.deepEqual({ ...screens[0], revision: '' }, { ...screens[1], revision: '' }); + const inputs = []; + for (const [name, offset] of [ + ['second-page', 50], + ['middle-page', Math.floor(count / 2)], + ['tail-page', count - 51], + ]) { + const at = records[offset - 1]; + const requests = screens.map((screen) => ({ + kind: 'activity', + query, + revision: screen.revision, + queryIdentity: screen.queryIdentity, + cursor: + name === 'second-page' + ? screen.nextCursor + : Buffer.from( + JSON.stringify([ + screen.queryIdentity, + at.ts, + ['canonical', 'legacy', 'tool'][at.source], + at.identity, + ]), + ).toString('base64url'), + })); + inputs.push({ name, requests }); + for (let i = 0; i < versions.length; i++) { + const result = await versions[i].read(requests[i]); + assert.equal(result.kind, 'activity'); + assert.deepEqual( + result.page.logs.map((log) => log.turnId), + records.slice(offset, offset + 50).map((row) => row.turnId), + ); + } + } + for (const [name, search] of [ + ['screen', ''], + ['no-match-screen', 'absentword'], + ['filtered-screen', 'model'], + ]) { + inputs.push({ + name, + requests: versions.map(() => ({ kind: 'screen', query: { ...query, search } })), + }); + } + const matching = await Promise.all( + versions.map((version) => + version.read({ + kind: 'screen', + query: { ...query, search: 'model' }, + }), + ), + ); + inputs.push({ + name: 'matching-second-page', + requests: matching.map(({ screen }) => ({ + kind: 'activity', + query: screen.query, + revision: screen.revision, + queryIdentity: screen.queryIdentity, + cursor: screen.nextCursor, + })), + }); + for (const { name, requests } of inputs) { + const samples = [[], []]; + for (let repetition = -3; repetition < 15; repetition++) { + for (const i of repetition % 2 === 0 ? [0, 1] : [1, 0]) { + const start = performance.now(); + await versions[i].read(requests[i]); + if (repetition >= 0) samples[i].push(performance.now() - start); + } + } + for (let i = 0; i < versions.length; i++) { + const version = versions[i]; + const timing = summarize(samples[i]); + rows.push({ scenario, metric: `${version.name}/${name}-ms`, ...timing }); + const finish = capture(version.db); + try { + await version.read(requests[i]); + } finally { + profiles.push({ scenario, version: version.name, operation: name, ...finish() }); + } + console.log( + `${scenario} ${version.name}/${name}: ${timing.median.toFixed(3)} ms median, ${timing.p95.toFixed(3)} ms p95`, + ); + } + } + } finally { + oldLease.close(); + lease.close(); + await oldStores.close(); + await stores.close(); + await oldOwner.close(); + await readerOwner.close(); + await removeControlDirectory(capability.rootId); + await rm(base, { recursive: true, force: true }); + } +} +await report( + 'usage-pages', + { + baselineCommit: execFileSync('git', ['-C', baselinePath, 'rev-parse', 'HEAD'], { + encoding: 'utf8', + }).trim(), + currentDiff: execFileSync('git', ['diff', '--stat'], { encoding: 'utf8' }).trim(), + sqlite, + electron: process.versions.electron ?? null, + warmup: 3, + repetitions: 15, + conditions: + 'Same temporary SQLite data, alternating public readUsageScreen facades in one process. First-screen samples use newly opened reader connections, not a cold OS page cache. Warm measurements include lease validation, query preparation and result mapping.', + limits: + 'Synthetic persisted rows, no Host repair, wire encoding/transport or rendering. Deep cursors are supplied from known fixture positions; this does not measure random-page navigation. Full statistics, exact filtered counts and sparse search remain range-sized work. Search callbacks and SQL plans are collected outside timed runs; they are not physical row-visit counters.', + profiles, + }, + rows, +);