Skip to main content

performance

Performance rules and known hot paths for this codebase. Use before touching impl/query_*.ml, impl/transact.ml, impl/db.ml, impl/storage.ml, impl/pull_api.ml, impl/entity.ml, or any code that loops over datoms, query rows, or index contents.

소스 정보

저장소
logseq/datascript-ocaml
최근 소스 활동
2026년 10월 2일 07:03
감지된 SKILL.md 언어
영어
스타
5
포크
0

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
performance
description
Performance rules and known hot paths for this codebase. Use before touching impl/query_*.ml, impl/transact.ml, impl/db.ml, impl/storage.ml, impl/pull_api.ml, impl/entity.ml, or any code that loops over datoms, query rows, or index contents.
# Performance Measured profile (large Logseq graphs): queries returning 30k–70k rows dominate; GC ~26%, List ops ~10%. The rules below keep new code off the quadratic paths and keep hot paths allocation-light. ## Index access discipline - Never walk a whole index (`datoms db Eavt ()`, unbounded `Avet ~a` slices) or materialize `entity`/`ent_of_id` inside loops when a bounded seek suffices. Prefer `~e`/`~a`/`~v`-constrained `datoms` queries and datom-level checks. - Whole-index work belongs only in inherently whole-db operations: `diff`, export, serialize/restore, GC (`collect_garbage`), checksum/validate. - `index_datoms_seq`/`reverse_index_datoms_seq` stream without materializing; `visible_index_datoms`/`raw_index_datoms_list` copy the full index — use the seq variants inside loops. ## List anti-patterns banned on hot paths Per-datom, per-row, per-block loops must not contain: - `xs @ [x]`, `List.append`, `List.concat` inside folds/loops — O(n²). Cons onto a reversed accumulator, or use `Hashtbl`-keyed groups / `Queue` / `Rrbvec`, then `List.rev`/`concat` once at the end. - `List.mem` / `List.assoc` / `List.find` / `List.exists` / `List.nth` inside a loop over a growing or large collection — build a `Hashtbl`/Set once, then O(1) lookups. - `List.length` recomputed per iteration — hoist it or thread a counter. - `List.filter`/`map` chains that re-traverse large data when one fold suffices. - `List.sort`/`List.sort_uniq` where a `Hashtbl` dedup or a min-fold applies (e.g. sorting only to take `List.hd`). - `List.combine`/`List.split`/`Array.to_list`/`List.of_seq`/`List.of_array` per row — keep arrays positional, hash the key→index map once. - Non-tail recursion over unbounded lists (stack depth risk at 100k+). Cheap-constant exceptions: fixed small lists like `Schema.schema_fields` (10 elements) — `List.mem` on them is fine. ## Known hot paths (audit Oct 2026) - `impl/query_where.ml` — join/scan loops; `relation.rows` is `query_result array list` with typed-hash dedup already — keep it that way. - `impl/query_api.ml:295` — `collect_find_specs` + `List.combine`/`Array.to_list` per result row; precompute a `Hashtbl attr→index` per query instead. - `impl/db.ml` — `diff` (whole-DB; pairwise scans now `(e,a)`→values Hashtbls), `eavt_datoms`, `remove_facts_from_duplicate_tables`/ `refresh_indexes_with_tx_data` (retract rebuilds now batched per tx — keep them batched), `find_active_datom_by_fact` (min-fold, keep it). - `impl/transact.ml:754` — `dedupe_facts` now Hashtbl buckets on upsert-merge; order must stay first-occurrence. - `impl/storage.ml` — `collect_garbage` (live set is a Hashtbl), `tail_datom_count` (concat-to-count). - `impl/entity.ml:48` — `raw_forward_entity_attrs` assoc/remove_assoc grouping per datom → O(D²) on wide entities. - `impl/pull_api.ml:492/513/604` — `List.mem` ancestry check per recursion level. - `impl/conn.ml:150,178` — `storage_tail @ [report.tx_data]` per tx. ## Checklist before submitting - For each `List.` call inside a loop: what is the input size at this call site, and who reaches it from a public endpoint (`transact`, `q`, `pull`, `entity`, `datoms`, `diff`, storage GC)? - Whole-db scans only in diff/export/restore/GC/checksum. - Allocations: avoid `map|>filter|>map` chains and intermediate lists on >1k-item data; fuse into a single fold. - Verify no `Seq` was forced into a `List` where streaming suffices.
GitHub에서 보기