perf(push): find the Python-side scale walls all at once, and remove them

The loop the maintainer called out: four scale defects in the PHP transfer
replay, found one per two-hour Joern run, all Python bookkeeping between
engine calls. benchmarks/push/python_overhead.py ends that: the real
replay() on the real PMPro pins, with a JoernBackend whose graphs are stubs
and whose queries answer instantly with rows recorded from the real engine.
Engine time is zero, so everything measured is ours, in about a minute,
under the sampling profiler. Its first pass named two more walls:

- Region discovery re-parsed the ruleset for every region: 89,127 TOML
  parses, 275 s of a 339 s discovery, twice per push. The fact, obligation
  and taxonomy loaders now keep the parsed (immutable) result keyed by each
  file's name, size and mtime -- an edit in place or an added file reloads.
  Discovery 339 s -> 7 s; output digest identical on PMPro.
- affected_context decoded every span's and every line anchor's path for
  every context row -- a changed file has an anchor per unchanged line --
  78% of a stubbed push. Decoded once per call, anchors indexed by line and
  bisected, original order kept. A randomised control compares it against
  the row-by-row matching over 200 contexts (>100 attachments).

Result: the whole stubbed PMPro push, 27,542 answered requests and 2,688
outcomes, runs in 58.5 s of Python. What is left is the engine.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo
This commit is contained in:
Marius Ciepluch
2026-09-23 19:36:32 +02:00
co-authored by Claude Opus 5.5
parent c629fea89a
commit 6b85a60ff1
7 changed files with 338 additions and 15 deletions
+33 -12
View File
@@ -18,6 +18,7 @@ Two restraints are deliberate:
from __future__ import annotations
import bisect
import time
from collections.abc import Mapping, Sequence
from dataclasses import dataclass, replace
@@ -194,6 +195,15 @@ AMBIGUOUS_CORRESPONDENCE = "ambiguous_line_correspondence"
REACHABILITY_BOUNDED = "dynamic_external_or_depth_context_unresolved"
def _anchored_lines(anchors: list[tuple[int, int]] | None, start: int, end: int) -> list[int]:
"""Anchor lines within ``[start, end]``, in the order the change context listed them."""
if not anchors:
return []
low = bisect.bisect_left(anchors, (start, -1))
high = bisect.bisect_right(anchors, (end, float("inf")))
return [line for line, _ in sorted(anchors[low:high], key=lambda item: item[1])]
def _context_path(raw: str, root: Path, resolved_root: Path) -> str | None:
"""A context location's path relative to the root, or ``None`` when it is not a real file under it."""
try:
@@ -272,6 +282,20 @@ def affected_context(
inherited_gap = any(not gap.endswith(":" + AMBIGUOUS_CORRESPONDENCE) for gap in gaps)
renamed = {context.decode_path(r.base_path): context.decode_path(r.head_path) for r in context.renames}
checked: dict[str, bool] = {}
# Decoded ONCE per call. Every row used to decode every span's and every line anchor's path -- a changed file
# has one anchor per unchanged line -- and with the engine stubbed out that was 78% of a whole push. Anchors
# are indexed by line so a row finds its own with two bisections, in their original order.
attachable = changed | set(renamed.values())
spans_by_path: dict[str, list[tuple[str, str, int, int]]] = {}
for span in context.spans:
old_path = context.decode_path(span.path)
match_path = renamed.get(old_path, old_path) if span.side == "base" else old_path
spans_by_path.setdefault(match_path, []).append((span.side, old_path, span.start_line, span.end_line))
anchors_by_path: dict[str, list[tuple[int, int]]] = {}
for index, anchor in enumerate(context.line_correspondences):
anchors_by_path.setdefault(context.decode_path(anchor.head_path), []).append((anchor.head_start_line, index))
for anchors in anchors_by_path.values():
anchors.sort()
# Resolved once per distinct path: the same few changed files recur in every question's rows, and resolving
# them again per row was half of what `affected_context` cost once its quadratic was gone.
resolved: dict[str, str | None] = {}
@@ -319,18 +343,15 @@ def affected_context(
except (ValueError, TypeError, OSError):
local_gaps.append("context_location_unavailable")
continue
evidence = []
for span in context.spans:
old_path = context.decode_path(span.path)
match_path = renamed.get(old_path, old_path) if span.side == "base" else old_path
if match_path != path_text:
continue
if span.side == "base" or (span.start_line <= end and span.end_line >= start):
evidence.append(f"{span.side}_span:{old_path}:{span.start_line}-{span.end_line}")
for anchor in context.line_correspondences:
if context.decode_path(anchor.head_path) == path_text and start <= anchor.head_start_line <= end:
evidence.append(f"unchanged_line:{anchor.head_start_line};lexical_only")
if not evidence or path_text not in changed | set(renamed.values()):
if path_text not in attachable:
continue
evidence = [
f"{side}_span:{old_path}:{span_start}-{span_end}"
for side, old_path, span_start, span_end in spans_by_path.get(path_text, ())
if side == "base" or (span_start <= end and span_end >= start)
]
evidence += [f"unchanged_line:{line};lexical_only" for line in _anchored_lines(anchors_by_path.get(path_text), start, end)]
if not evidence:
continue
function = str(row.get("function", "")) or None
source = QuestionIdentity(identity.unit, identity.language, path_text, function, identity.family)
+19 -1
View File
@@ -90,7 +90,7 @@ class FamilyTaxonomy:
return "lateral"
def load_families(path: Path | None = None, *, require_all: bool = True) -> FamilyTaxonomy:
def _load_families_uncached(path: Path | None = None, *, require_all: bool = True) -> FamilyTaxonomy:
"""Load the taxonomy. ``require_all`` demands the full closed set in order (the shipped file);
a scoped fixture may declare a subset, but never a family outside ``FAMILY_IDS``."""
source = path if path is not None else DEFAULT_FAMILIES_PATH
@@ -192,3 +192,21 @@ __all__ = [
"Relation",
"load_families",
]
# Parsed once per file state; see `semantic.facts.load_facts` for why and for the key.
_FAMILIES_MEMO: dict[tuple[object, ...], FamilyTaxonomy] = {}
def load_families(path: Path | None = None, *, require_all: bool = True) -> FamilyTaxonomy:
"""Load the taxonomy. ``require_all`` demands the full closed set in order (the shipped file);
a scoped fixture may declare a subset, but never a family outside ``FAMILY_IDS``."""
source = path if path is not None else DEFAULT_FAMILIES_PATH
try:
info = source.stat()
except OSError:
return _load_families_uncached(path, require_all=require_all)
key = (str(source.resolve()), info.st_size, info.st_mtime_ns, require_all)
if key not in _FAMILIES_MEMO:
_FAMILIES_MEMO[key] = _load_families_uncached(path, require_all=require_all)
return _FAMILIES_MEMO[key]
+42 -1
View File
@@ -116,7 +116,7 @@ class SemanticFacts:
)
def load_facts(directory: Path | None = None) -> SemanticFacts:
def _load_facts_uncached(directory: Path | None = None) -> SemanticFacts:
root = directory if directory is not None else DEFAULT_FACTS_DIR
if not root.is_dir():
raise FactLoadError(f"semantic fact directory missing: {root}")
@@ -271,3 +271,44 @@ def _sanitizers(value: object, language: str, path: Path) -> list[SanitizerFact]
)
)
return rows
# Parsed once per ruleset STATE, not once per call. Region discovery asks for the family specs of every region,
# and each spec call loaded the facts again: 89,127 TOML parses and 275 s of a 339 s discovery on a WordPress
# plugin, paid twice per push. The key is every fact file's name, size and modification time, so an edited
# ruleset -- a test's fixture, a maintainer's change -- is read again, and the result is immutable, so sharing
# it is safe. A load that fails is not remembered.
_FACTS_MEMO: dict[tuple[object, ...], SemanticFacts] = {}
_LISTED: dict[tuple[str, str], tuple[int, tuple[Path, ...]]] = {}
def _ruleset_state(root: Path, pattern: str) -> tuple[object, ...]:
"""Every matching file's name, size and modification time -- cheaply, because every question asks.
The directory is listed again only when its own stamp moves (a file added, removed or renamed); an edit in
place moves the file's stamp, which is read every time. Globbing and resolving on every call was 7% of a
whole push with the engine stubbed out.
"""
stamp = root.stat().st_mtime_ns
listed = _LISTED.get((str(root), pattern))
if listed is None or listed[0] != stamp:
listed = (stamp, tuple(sorted(root.glob(pattern))))
_LISTED[(str(root), pattern)] = listed
return (str(root), stamp, *((path.name, *_stat_of(path)) for path in listed[1]))
def _stat_of(path: Path) -> tuple[int, int]:
info = path.stat()
return info.st_size, info.st_mtime_ns
def load_facts(directory: Path | None = None) -> SemanticFacts:
root = directory if directory is not None else DEFAULT_FACTS_DIR
if not root.is_dir():
return _load_facts_uncached(directory)
key = _ruleset_state(root, "*.toml")
if key not in _FACTS_MEMO:
_FACTS_MEMO[key] = _load_facts_uncached(directory)
return _FACTS_MEMO[key]
@@ -11,6 +11,8 @@ import tomllib
from dataclasses import dataclass
from pathlib import Path
from ..facts import _ruleset_state
OPERATION_KINDS = ("protected_read", "protected_write", "privileged_action", "security_setting")
DISCHARGER_KINDS = ("path_guard", "identity_constraint", "ownership_check", "non_permissive_value", "validated_input")
PROVENANCE_KINDS = ("authenticated_context", "request_input", "constant", "unknown")
@@ -73,7 +75,7 @@ class ObligationFacts:
)
def load_obligation_facts(directory: Path | None = None) -> ObligationFacts:
def _load_obligation_facts_uncached(directory: Path | None = None) -> ObligationFacts:
root = directory if directory is not None else DEFAULT_OBLIGATION_FACTS_DIR
if not root.is_dir():
raise ObligationFactsError(f"obligation facts directory missing: {root}")
@@ -160,3 +162,17 @@ def _strings(value: object, field: str, path: Path) -> tuple[str, ...]:
if not isinstance(value, list) or not all(isinstance(item, str) and item for item in value):
raise ObligationFactsError(f"{path} has invalid {field} list")
return tuple(str(item) for item in value)
# Parsed once per ruleset state; see `semantic.facts.load_facts` for the measurement and the key.
_OBLIGATION_MEMO: dict[tuple[object, ...], ObligationFacts] = {}
def load_obligation_facts(directory: Path | None = None) -> ObligationFacts:
root = directory if directory is not None else DEFAULT_OBLIGATION_FACTS_DIR
if not root.is_dir():
return _load_obligation_facts_uncached(directory)
key = _ruleset_state(root, "*.toml")
if key not in _OBLIGATION_MEMO:
_OBLIGATION_MEMO[key] = _load_obligation_facts_uncached(directory)
return _OBLIGATION_MEMO[key]