fix(ui): within-pass progress for the C fn-pointer linking pass (#1300)
Follow-up to #1299: the per-pass bar still parked on one number while a single long pass ran — on C-heavy repos that's the fn-pointer dispatch pass, which sweeps every C/C++ file four times (typedefs, registrations, field propagation, dispatch sites) and dominates the linking phase. The pass now reports a real fraction of its dominant work (scannedFiles / files×4, at the same per-16-files cadence as its cooperative yield), and the orchestrator surfaces instrumented passes' fractions as fractional steps, throttled to whole-percent movement so the UI message volume stays bounded. The mechanism is opt-in per pass — any synthesizer that a real repo shows parking the bar can adopt the same callback. Verified on the 1,342-file C repo from the report: the linking bar now moves through 88→89→90 where it previously sat at 88 for the whole pass; graph byte-identical (50,520 nodes / 148,232 edges). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
ad5300a601
commit
246aee8373
@@ -308,11 +308,29 @@ const INCLUDE_RE = /#[ \t]*include[ \t]+"([^"\n]+)"/g;
|
||||
/** Included files worth scanning for registration tables (e.g. a generated `.def`). */
|
||||
const INCLUDABLE_EXT = /\.(def|inc|h|hh|hpp|hxx|c|cc|cpp|cxx|ipp|tcc|tbl)$/i;
|
||||
|
||||
export async function cFnPointerDispatchEdges(_queries: QueryBuilder, ctx: ResolutionContext, onYield: MaybeYield): Promise<Edge[]> {
|
||||
export async function cFnPointerDispatchEdges(
|
||||
_queries: QueryBuilder,
|
||||
ctx: ResolutionContext,
|
||||
onYield: MaybeYield,
|
||||
onFraction?: (fraction: number) => void
|
||||
): Promise<Edge[]> {
|
||||
let scannedFiles = 0;
|
||||
const files = ctx.getAllFiles().filter((f) => C_CPP_EXT.test(f));
|
||||
if (files.length === 0) return [];
|
||||
|
||||
// Within-pass progress: this is the pass that parks the "Linking dynamic
|
||||
// dispatch" bar on C-heavy repos, so it reports a real fraction of its
|
||||
// dominant work. `files` is swept once per file loop below (passes A, C, D,
|
||||
// E — pass B is node-bound and comparatively brief), reported at the same
|
||||
// per-16-files cadence as the cooperative yield.
|
||||
const FILE_SWEEPS = 4;
|
||||
const tick = async (): Promise<void> => {
|
||||
if ((++scannedFiles & 15) === 0) {
|
||||
onFraction?.(scannedFiles / (files.length * FILE_SWEEPS));
|
||||
await onYield();
|
||||
}
|
||||
};
|
||||
|
||||
// Cache raw + stripped source per file, LRU-BOUNDED. The old unbounded Maps
|
||||
// retained every C/C++ file's raw AND stripped text for the whole pass —
|
||||
// multiple GB on the Linux kernel, one of the two OOM culprits in #1212.
|
||||
@@ -358,7 +376,7 @@ export async function cFnPointerDispatchEdges(_queries: QueryBuilder, ctx: Resol
|
||||
const fnPtrTypedefs = new Set<string>();
|
||||
const fnTypeTypedefs = new Set<string>();
|
||||
for (const file of files) {
|
||||
if ((++scannedFiles & 15) === 0) await onYield();
|
||||
await tick();
|
||||
const s = src(file);
|
||||
if (!s || !s.includes('typedef')) continue;
|
||||
FNPTR_TYPEDEF_RE.lastIndex = 0;
|
||||
@@ -764,7 +782,7 @@ export async function cFnPointerDispatchEdges(_queries: QueryBuilder, ctx: Resol
|
||||
// ---- Pass C: registrations — stream each file (and its qualifying local
|
||||
// includes) through processUnit, one at a time.
|
||||
for (const file of files) {
|
||||
if ((++scannedFiles & 15) === 0) await onYield();
|
||||
await tick();
|
||||
const env = new Map<string, MacroDef>();
|
||||
const objEnv = new Map<string, string>();
|
||||
const defined = new Set<string>();
|
||||
@@ -846,7 +864,7 @@ export async function cFnPointerDispatchEdges(_queries: QueryBuilder, ctx: Resol
|
||||
const FIELD_ASSIGN_RE = /(\w+)\s*(?:->|\.)\s*(\w+)\s*=\s*(\w+)\s*(?:->|\.)\s*(\w+)/g;
|
||||
const propagations: { to: string; from: string }[] = [];
|
||||
for (const file of files) {
|
||||
if ((++scannedFiles & 15) === 0) await onYield();
|
||||
await tick();
|
||||
const s = src(file);
|
||||
if (!s || !s.includes('=')) continue;
|
||||
for (const fn of ctx.getNodesInFile(file)) {
|
||||
@@ -897,7 +915,7 @@ export async function cFnPointerDispatchEdges(_queries: QueryBuilder, ctx: Resol
|
||||
const edges: Edge[] = [];
|
||||
const seen = new Set<string>();
|
||||
for (const file of files) {
|
||||
if ((++scannedFiles & 15) === 0) await onYield();
|
||||
await tick();
|
||||
const s = src(file);
|
||||
if (!s) continue;
|
||||
for (const fn of ctx.getNodesInFile(file)) {
|
||||
|
||||
Reference in New Issue
Block a user