perf(javascript): index native Evidence links by observed digest
Build each side's digest-to-Evidence index once instead of scanning native observations for every comparison item. Retain every exact match and avoid linking subjectless Evidence to nodes lacking content identity. Comparison and relationship regressions pass. Isolated alternating unprofiled runs at 2,000 nodes and observations per side have conventional medians 379.924 ms before and 246.466 ms after; the complete 4,000-item outputs match byte-for-byte. Timings are bounded workload evidence, not whole-suite performance. Flameox profile: flameox://evidence/7dca714833dc3d254a75704670a81de656b4b31d4b77a72236eecb82459b3d86
This commit is contained in:
1 parent
f1c58cc53f
commit
87d5ec93d5
2 files changed
+176
-19
No files matched your search
@@ -23,14 +23,27 @@ interface ItemContext {
|
||||
readonly rightGraph: JavaScriptApplicationGraph;
|
||||
readonly leftEvidenceId: string;
|
||||
readonly rightEvidenceId: string;
|
||||
readonly leftNativeEvidence: readonly Evidence[];
|
||||
readonly rightNativeEvidence: readonly Evidence[];
|
||||
readonly leftNativeEvidenceByDigest: ReadonlyMap<string, readonly string[]>;
|
||||
readonly rightNativeEvidenceByDigest: ReadonlyMap<string, readonly string[]>;
|
||||
readonly pairByLeft: ReadonlyMap<string, string>;
|
||||
readonly pairByRight: ReadonlyMap<string, string>;
|
||||
readonly leftRelationships: RelationshipIndex;
|
||||
readonly rightRelationships: RelationshipIndex;
|
||||
}
|
||||
|
||||
type ItemContextInput = Omit<
|
||||
ItemContext,
|
||||
| "leftNativeEvidenceByDigest"
|
||||
| "rightNativeEvidenceByDigest"
|
||||
| "pairByLeft"
|
||||
| "pairByRight"
|
||||
| "leftRelationships"
|
||||
| "rightRelationships"
|
||||
> & {
|
||||
readonly leftNativeEvidence: readonly Evidence[];
|
||||
readonly rightNativeEvidence: readonly Evidence[];
|
||||
};
|
||||
|
||||
interface IndexedRelationship {
|
||||
readonly direction: "in" | "out";
|
||||
readonly relation: ApplicationEdge["relation"];
|
||||
@@ -66,10 +79,7 @@ type ComparisonItemSemantic<
|
||||
/** Classify matched, unmatched, and ambiguous nodes without inventing absence. */
|
||||
export const classifyJavaScriptApplicationVersions = (
|
||||
matching: ApplicationVersionMatchingProjection,
|
||||
context: Omit<
|
||||
ItemContext,
|
||||
"pairByLeft" | "pairByRight" | "leftRelationships" | "rightRelationships"
|
||||
>,
|
||||
context: ItemContextInput,
|
||||
): ApplicationVersionItemProjection => {
|
||||
const pairByLeft = new Map(
|
||||
matching.pairs.map(({ left, right }) => [
|
||||
@@ -84,7 +94,14 @@ export const classifyJavaScriptApplicationVersions = (
|
||||
]),
|
||||
);
|
||||
const fullContext: ItemContext = {
|
||||
...context,
|
||||
leftGraph: context.leftGraph,
|
||||
rightGraph: context.rightGraph,
|
||||
leftEvidenceId: context.leftEvidenceId,
|
||||
rightEvidenceId: context.rightEvidenceId,
|
||||
leftNativeEvidenceByDigest: indexNativeEvidence(context.leftNativeEvidence),
|
||||
rightNativeEvidenceByDigest: indexNativeEvidence(
|
||||
context.rightNativeEvidence,
|
||||
),
|
||||
pairByLeft,
|
||||
pairByRight,
|
||||
leftRelationships: indexRelationships(context.leftGraph),
|
||||
@@ -426,24 +443,33 @@ const itemEvidenceLinks = (
|
||||
...new Set([
|
||||
context.leftEvidenceId,
|
||||
context.rightEvidenceId,
|
||||
...nativeLinks(left, context.leftNativeEvidence),
|
||||
...nativeLinks(right, context.rightNativeEvidence),
|
||||
...nativeLinks(left, context.leftNativeEvidenceByDigest),
|
||||
...nativeLinks(right, context.rightNativeEvidenceByDigest),
|
||||
]),
|
||||
].sort(compareUnicodeCodePoints);
|
||||
|
||||
const nativeLinks = (
|
||||
node: ApplicationNode | undefined,
|
||||
evidenceByDigest: ReadonlyMap<string, readonly string[]>,
|
||||
): readonly string[] => {
|
||||
const identity = node === undefined ? null : contentIdentity(node);
|
||||
if (identity === null) return [];
|
||||
const digest = identity.replace(/^content:/u, "");
|
||||
return evidenceByDigest.get(digest) ?? [];
|
||||
};
|
||||
|
||||
const indexNativeEvidence = (
|
||||
evidence: readonly Evidence[],
|
||||
): string[] => {
|
||||
const digest =
|
||||
node === undefined
|
||||
? null
|
||||
: contentIdentity(node)?.replace(/^content:/u, "");
|
||||
return digest === null
|
||||
? []
|
||||
: evidence
|
||||
.filter(({ subject }) => subject?.digest.sha256 === digest)
|
||||
.map(({ evidence_id: id }) => id);
|
||||
): ReadonlyMap<string, readonly string[]> => {
|
||||
const evidenceByDigest = new Map<string, string[]>();
|
||||
for (const { evidence_id: id, subject } of evidence) {
|
||||
const digest = subject?.digest.sha256;
|
||||
if (digest === undefined) continue;
|
||||
const ids = evidenceByDigest.get(digest);
|
||||
if (ids === undefined) evidenceByDigest.set(digest, [id]);
|
||||
else ids.push(id);
|
||||
}
|
||||
return evidenceByDigest;
|
||||
};
|
||||
|
||||
const pairLimitations = (
|
||||
|
||||
Reference in new issue
Block a user