[PERF] Quadratic (O(N^2)) serialization time for large BOMs — `Bom.validate()` → `register_dependency()` linear scan
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 36/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Ferma
- Stack tecnologico
- python
- Ambito
- performance
Direzione di ricerca
Inizia in cyclonedx/model/bom.py da Bom.validate() e register_dependency(), quindi esamina cyclonedx/output/json.py per confermare il percorso di serializzazione. Esamina la pull request collegata #1007 e aggiungi o esegui un test di regressione/scalabilità che dimostri un comportamento quasi lineare, preservando al contempo un output identico byte per byte.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Environment
cyclonedx-python-lib9.1.0 (the offending code path is unchanged onmain/ 11.x)- Python 3.10, Linux
Description
Serializing a BOM with many components scales quadratically with the number of components, not linearly. For a container SBOM with several thousand components, output_as_string() stalls for minutes, almost entirely inside Bom.validate().
Steps to reproduce
import time
from cyclonedx.model.bom import Bom
from cyclonedx.model.component import Component, ComponentType
from cyclonedx.output import make_outputter
from cyclonedx.schema import OutputFormat, SchemaVersion
for N in (1000, 2000, 4000, 8000):
bom = Bom()
bom.metadata.component = Component(name="root", type=ComponentType.CONTAINER, bom_ref="root")
for i in range(N):
bom.components.add(Component(name=f"c{i}", version="1.0",
type=ComponentType.LIBRARY, bom_ref=f"ref-{i}"))
out = make_outputter(bom=bom, output_format=OutputFormat.JSON,
schema_version=SchemaVersion.V1_6)
t = time.perf_counter(); out.output_as_string()
print(f"N={N}: {time.perf_counter()-t:.2f}s")
Expected vs actual
Expected: time grows roughly linearly with N.
Actual: time grows roughly 4x per 2x N (quadratic):
N=1000: 0.14s
N=2000: 0.48s (x3.4)
N=4000: 1.75s (x3.6)
N=8000: 6.70s (x3.8)
A cProfile run at N=15000 shows ~112M calls to the lambda at cyclonedx/model/bom.py:653.
Root cause
cyclonedx/output/json.py—generate()unconditionally callsbom.validate()during serialization (there is no opt-out).cyclonedx/model/bom.py—Bom.validate()callsself.register_dependency(target=...)once per component (and per service).cyclonedx/model/bom.py—register_dependency()locates the existing entry with a linear scan:
Called once per component over the growing dependency collection, this is O(N²) overall._d = next(filter(lambda _d: _d.ref == target.bom_ref, self.dependencies), None)
Proposed fix
Replace the linear lookup with an indexed (dict[ref -> Dependency]) lookup. In a local benchmark an indexed variant produces byte-identical output and gives ~8x speedup at N=6000 (the gap widens with N). I'm happy to open a PR with the fix and a regression/scaling test.
- Lingua principale
- Python
- Stelle
- 117
- Fork
- 67
- Merge medio
- 21h 9m
- PR unite (30g)
- 3
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di CycloneDX/cyclonedx-python-lib
-
tests: test all model enumsForse di nuovo libera @jkowalleck l’ha presa 126 giorni fa e non c’è nessuna pull request aperta. ApertaQA
CycloneDX/cyclonedx-python-lib#991 · 1 assegnatario ·
-
feat(deps)!: make all de/serialization libraries optionalForse di nuovo libera @Simoh23999 l’ha presa 73 giorni fa e non c’è nessuna pull request aperta. Apertabreaking change dependencies
Difficoltà 5/5 Più di una settimana Idoneità per principianti 35/100
CycloneDX/cyclonedx-python-lib#979 · 2 commenti ·
-
feat: Add support for Component signatureForse già presa @wiebe-vandendriessche l’ha presa 124 giorni fa. Apertaenhancement help wanted schema 1.4
Difficoltà 3/5 1-2 giorni Idoneità per principianti 58/100
CycloneDX/cyclonedx-python-lib#978 · 4 commenti ·
-
chore: have coverage uploaded consitentlyForse di nuovo libera @jkowalleck l’ha presa 172 giorni fa e non c’è nessuna pull request aperta. Apertachore
CycloneDX/cyclonedx-python-lib#966 · 1 assegnatario ·
-
chore: use dependabot cooldown periodForse di nuovo libera @jkowalleck l’ha presa 174 giorni fa e non c’è nessuna pull request aperta. Apertachore
CycloneDX/cyclonedx-python-lib#965 · 1 commento · 1 assegnatario ·
Tutte le issue di CycloneDX/cyclonedx-python-lib
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
KalicoCrew/kalico#1012 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 82/100
esphome/esphome.io#7657 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
VNG-Realisatie/gemma-zaken#2658 ·
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 75/100
I maintainer di solito rispondono entro 1 giorno
-
comp/gateway comp/plugins duplicate P3 type/bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
NousResearch/hermes-agent#137019 ·
I maintainer di solito rispondono entro 1 giorno