Skip to content

BE-428: HashQL: Simplify traversal tracking to path recording#8498

Open
indietyp wants to merge 29 commits intomainfrom
bm/be-428-hashql-simplify-traversal-tracking-to-path-recording
Open

BE-428: HashQL: Simplify traversal tracking to path recording#8498
indietyp wants to merge 29 commits intomainfrom
bm/be-428-hashql-simplify-traversal-tracking-to-path-recording

Conversation

@indietyp
Copy link
Copy Markdown
Member

@indietyp indietyp commented Mar 2, 2026

🌟 What is the purpose of this PR?

Replaces the traversal extraction transform pass (which rewrote MIR bodies by splicing load statements and creating new locals) with a pure analysis pass that records which entity paths each block accesses as bitsets. Introduces per-block path transfer cost charging so the placement solver can account for data locality when assigning blocks to backends.

🔍 What does this change?

  • Traversal analysis (traversal/analysis/): walks the body, resolves vertex projections via EntityPath::resolve(), records accessed paths as TraversalPathBitSet. No MIR mutation.
  • Per-block cost analysis (cost/analysis.rs): new BasicBlockCostAnalysis combines per-statement costs with a path transfer premium. For each block, charges a transfer premium on targets that are not the natural origin for the accessed paths (e.g., Interpreter pays a premium for Vectors because Embedding is the origin). Premiums are charged once per block, not per statement.
  • BasicBlockCostVec: the placement solver now operates on precomputed per-block costs. PlacementSolverContext takes blocks: &BasicBlockCostVec instead of separate statement costs and assignment arrays.
  • BlockPartitionedVec<T>: generic offset-table-backed per-block storage, extracted from StatementCostVec internals.
  • TraversalLattice: lattice structure carrying VertexType for dataflow analysis over path bitsets.
  • EntityPath::origin(), EntityPath::estimate_size(): per-path origin backend and transfer size estimation.
  • TransferCostConfig: variable-size parameters (properties, embeddings, provenance sizes, per-target cost multiplier).
  • FiniteBitSet::negate() in hashql-core.
  • Removed pass/transform/traversal_extraction/ (the MIR transform and its tests).

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • does not modify any publishable blocks or libraries, or modifications do not need publishing

📜 Does this require a change to the docs?

The changes in this PR:

  • are internal and do not require a docs change

🕸️ Does this require a change to the Turbo Graph?

The changes in this PR:

  • do not affect the execution graph

⚠️ Known issues

Path transfer premiums use pure over-approximation: every non-origin backend pays the full premium with no discounting for co-location. This can over-penalize non-origin assignment when multiple blocks access the same path on the same backend (cross-block dedup is not implemented). This is intentional: separable costs are a prerequisite for the PBQP solver planned in BE-436.

The ideal cost model is non-separable: the first block on a backend pays the full data fetch cost, subsequent co-labeled blocks pay zero ("shared-fetch" / pay-once-per-group). This maps to submodular clique costs in the optimization literature. Two frameworks formalize this:

  • Jegelka et al. 2014 (arXiv:1402.0240, Cooperative Graph Cuts): the "label cost" special case is mathematically identical to shared-fetch. Algorithms include polymatroidal flow (exact for separable surrogates) and semigradient methods. However, all are binary-only (k=2 labels).
  • Kolmogorov et al. 2010 (arXiv:1006.1990, Sum of Submodular Functions): general framework via submodular flow with capacity scaling. Also binary-only.

The multi-label extension via alpha-expansion (Boykov, Veksler, Zabih 2001) reduces k-label to a sequence of binary cooperative cuts (each solvable exactly), but only guarantees a local minimum. Our TransMatrix is not metric, so no global approximation factor holds. For k=3 backends (growing to 6-7), the overhead of iterative cooperative cut calls on ~100-node graphs is not justified when PBQP R1/R2 reductions on the separable over-approximation give exact solutions in microseconds.

Pure over-approximation does not distort the relative ranking between non-origin backends (the premium cancels in pairwise comparisons) but inflates the absolute cost of non-origin assignment, biasing toward origin backends. Intra-block dedup (implemented here) is the first mitigation; cross-block dedup remains an open problem for k > 2 on cyclic graphs.
:

🛡 What tests cover this?

  • Unit tests for BasicBlockCostAnalysis covering: no vertex access, single origin/non-origin paths, multiple path accumulation, composite path expansion, restricted target domains, cross-block independence
  • Unit tests for TraversalAnalysisVisitor covering path resolution from MIR projections
  • Unit tests for EntityPathBitSet covering composite swallowing, lattice operations, normalization
  • Existing solver tests updated to use BasicBlockCostVec; new path_premiums_influence_placement and provenance_variants_produce_different_premiums integration tests
  • End-to-end mixed_postgres_embedding_interpreter test verifying three-backend splitting

❓ How to test this?

  1. cargo nextest run --package hashql-mir
  2. cargo test --package hashql-mir --doc

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 2, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hash Ready Ready Preview, Comment Mar 20, 2026 8:19am
petrinaut Ready Ready Preview, Comment Mar 20, 2026 8:19am
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
hashdotdesign Ignored Ignored Preview Mar 20, 2026 8:19am
hashdotdesign-tokens Ignored Ignored Preview Mar 20, 2026 8:19am

@augmentcode
Copy link
Copy Markdown

augmentcode bot commented Mar 2, 2026

This pull request is too large for Augment to review. The PR exceeds the maximum size limit of 100000 tokens (approximately 400000 characters) for automated code review. Please consider breaking this PR into smaller, more focused changes.

@github-actions github-actions bot added the area/libs Relates to first-party libraries/crates/packages (area) label Mar 2, 2026
TimDiekmann
TimDiekmann previously approved these changes Mar 26, 2026
@indietyp indietyp force-pushed the bm/be-428-hashql-simplify-traversal-tracking-to-path-recording branch from 2346ece to 5e31131 Compare March 31, 2026 20:56
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 31, 2026

Deployment failed with the following error:

Invalid request: `attribution.gitUser` should NOT have additional property `isBot`.

@github-actions github-actions bot dismissed TimDiekmann’s stale review March 31, 2026 20:57

Latest approval commit 2346ece is not an ancestor of 5e31131, indicating rewritten history after approval

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Unbounded premiums become impossible placements
    • I changed unbounded transfer midpoint fallback from ApproxCost::INF to finite Cost::MAX-equivalent and added a regression test to ensure unbounded path premiums stay finite.
  • ✅ Fixed: insert_range trusts inconsistent domain size
    • I added an explicit capacity assertion in FiniteBitSet::insert_range to reject oversized domain_size inputs and added a panic regression test.

Create PR

Or push these changes by commenting:

@cursor push 361796ea03
Preview (361796ea03)
diff --git a/libs/@local/hashql/core/src/id/bit_vec/finite.rs b/libs/@local/hashql/core/src/id/bit_vec/finite.rs
--- a/libs/@local/hashql/core/src/id/bit_vec/finite.rs
+++ b/libs/@local/hashql/core/src/id/bit_vec/finite.rs
@@ -230,6 +230,8 @@
         I: [const] Id,
         T: [const] FiniteBitSetIntegral,
     {
+        assert!(domain_size <= T::MAX_DOMAIN_SIZE as usize);
+
         let Some((start, end)) = inclusive_start_end(bounds, domain_size) else {
             return;
         };
@@ -620,6 +622,13 @@
     }
 
     #[test]
+    #[should_panic(expected = "assertion failed")]
+    fn insert_range_domain_size_exceeds_capacity_panics() {
+        let mut set: FiniteBitSet<TestId, u8> = FiniteBitSet::new_empty(8);
+        set.insert_range(.., 9);
+    }
+
+    #[test]
     fn union_combines_bits() {
         let mut a: FiniteBitSet<TestId, u8> = FiniteBitSet::new_empty(8);
         a.insert(TestId::from_usize(0));

diff --git a/libs/@local/hashql/mir/src/pass/execution/cost/analysis.rs b/libs/@local/hashql/mir/src/pass/execution/cost/analysis.rs
--- a/libs/@local/hashql/mir/src/pass/execution/cost/analysis.rs
+++ b/libs/@local/hashql/mir/src/pass/execution/cost/analysis.rs
@@ -1,6 +1,6 @@
 use core::alloc::Allocator;
 
-use super::{ApproxCost, StatementCostVec};
+use super::{ApproxCost, Cost, StatementCostVec};
 use crate::{
     body::basic_block::{BasicBlock, BasicBlockId, BasicBlockSlice, BasicBlockVec},
     pass::{
@@ -124,7 +124,7 @@
         let load = range
             .saturating_mul(config.target_multiplier[target].get())
             .midpoint()
-            .map_or(ApproxCost::INF, From::from);
+            .map_or_else(|| ApproxCost::from(Cost::MAX), ApproxCost::from);
 
         BasicBlockTargetCost { base, load }
     }
@@ -511,6 +511,45 @@
         assert!(interpreter_cost > interpreter_base);
     }
 
+    /// Unbounded transfer-size estimates should stay expensive but finite, so they remain
+    /// valid candidates for solver search.
+    #[test]
+    fn unbounded_path_premium_stays_finite() {
+        let heap = Heap::new();
+        let interner = Interner::new(&heap);
+        let env = Environment::new(&heap);
+
+        let body = body!(interner, env; [graph::read::filter]@0/2 -> ? {
+            decl env: (), vertex: [Opaque sym::path::Entity; ?], val: ?;
+            @proj properties = vertex.properties: ?;
+
+            bb0() {
+                val = load properties;
+                return val;
+            }
+        });
+
+        let targets = make_targets(&body, all_targets());
+        let targets = BasicBlockSlice::from_raw(&targets);
+
+        let costs: TargetArray<StatementCostVec<Global>> =
+            TargetArray::from_fn(|_| StatementCostVec::from_iter([1].into_iter(), Global));
+
+        let analysis = BasicBlockCostAnalysis {
+            vertex: VertexType::Entity,
+            assignments: targets,
+            costs: &costs,
+        };
+
+        let result = analysis.analyze_in(&default_config(), &body.basic_blocks, Global);
+        let bb0 = BasicBlockId::new(0);
+
+        let interpreter_cost = result.cost(bb0, TargetId::Interpreter);
+        let interpreter_base = costs[TargetId::Interpreter].sum_approx(bb0);
+        assert!(interpreter_cost > interpreter_base);
+        assert!(interpreter_cost.is_finite());
+    }
+
     /// Paths across multiple blocks are analyzed independently per block.
     #[test]
     fn paths_across_blocks_independent() {

This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

}
.analyze_in(
&TransferCostConfig::new(InformationRange::full()),
&body.basic_blocks,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unbounded premiums become impossible placements

High Severity

ExecutionAnalysis builds TransferCostConfig with InformationRange::full(), so unbounded paths like EntityPath::Properties produce None from midpoint() and are converted to ApproxCost::INF. Those infinite block costs can make valid cyclic assignments look infeasible during solver search, causing false unsatisfiable placement results.

Additional Locations (1)
Fix in Cursor Fix in Web

I: [const] Id,
T: [const] FiniteBitSetIntegral,
{
let Some((start, end)) = inclusive_start_end(bounds, domain_size) else {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

insert_range trusts inconsistent domain size

Medium Severity

FiniteBitSet::insert_range now accepts an external domain_size but never validates it against T::MAX_DOMAIN_SIZE. If a larger domain is passed, end can exceed the backing width and the T::MAX_DOMAIN_SIZE - 1 - end math underflows, leading to panic or incorrect masking instead of a bounded range insert.

Fix in Cursor Fix in Web

@github-actions
Copy link
Copy Markdown
Contributor

Benchmark results

@rust/hash-graph-benches – Integrations

policy_resolution_large

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2002 $$27.3 \mathrm{ms} \pm 210 \mathrm{μs}\left({\color{gray}-3.658 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.41 \mathrm{ms} \pm 26.4 \mathrm{μs}\left({\color{gray}0.435 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1001 $$12.3 \mathrm{ms} \pm 100.0 \mathrm{μs}\left({\color{gray}-4.343 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 3314 $$42.1 \mathrm{ms} \pm 298 \mathrm{μs}\left({\color{gray}-2.339 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$13.8 \mathrm{ms} \pm 108 \mathrm{μs}\left({\color{gray}-3.676 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 1526 $$23.6 \mathrm{ms} \pm 198 \mathrm{μs}\left({\color{gray}-3.171 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 2078 $$28.2 \mathrm{ms} \pm 157 \mathrm{μs}\left({\color{gray}-1.527 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.69 \mathrm{ms} \pm 22.8 \mathrm{μs}\left({\color{gray}0.075 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 1033 $$13.5 \mathrm{ms} \pm 108 \mathrm{μs}\left({\color{gray}-2.962 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_medium

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 102 $$3.73 \mathrm{ms} \pm 17.6 \mathrm{μs}\left({\color{gray}-1.013 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.93 \mathrm{ms} \pm 16.3 \mathrm{μs}\left({\color{gray}-0.018 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 51 $$3.28 \mathrm{ms} \pm 17.8 \mathrm{μs}\left({\color{gray}-1.253 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 269 $$5.12 \mathrm{ms} \pm 29.3 \mathrm{μs}\left({\color{gray}-0.890 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$3.48 \mathrm{ms} \pm 15.9 \mathrm{μs}\left({\color{gray}-0.590 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 107 $$4.07 \mathrm{ms} \pm 23.4 \mathrm{μs}\left({\color{gray}-0.966 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 133 $$4.42 \mathrm{ms} \pm 32.0 \mathrm{μs}\left({\color{gray}-1.117 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.33 \mathrm{ms} \pm 13.0 \mathrm{μs}\left({\color{gray}-1.248 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 63 $$3.99 \mathrm{ms} \pm 17.6 \mathrm{μs}\left({\color{gray}-2.461 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_none

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2 $$2.65 \mathrm{ms} \pm 10.1 \mathrm{μs}\left({\color{gray}-1.441 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.62 \mathrm{ms} \pm 15.6 \mathrm{μs}\left({\color{gray}-0.861 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1 $$2.71 \mathrm{ms} \pm 13.3 \mathrm{μs}\left({\color{gray}-1.374 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 8 $$2.99 \mathrm{ms} \pm 15.5 \mathrm{μs}\left({\color{gray}-0.703 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.78 \mathrm{ms} \pm 12.7 \mathrm{μs}\left({\color{gray}-0.570 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 3 $$3.07 \mathrm{ms} \pm 13.2 \mathrm{μs}\left({\color{gray}-2.216 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_small

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 52 $$3.04 \mathrm{ms} \pm 13.0 \mathrm{μs}\left({\color{gray}-2.025 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.74 \mathrm{ms} \pm 14.1 \mathrm{μs}\left({\color{gray}-1.216 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 25 $$2.91 \mathrm{ms} \pm 16.1 \mathrm{μs}\left({\color{gray}-0.537 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 94 $$3.48 \mathrm{ms} \pm 18.6 \mathrm{μs}\left({\color{gray}-0.679 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$2.99 \mathrm{ms} \pm 16.8 \mathrm{μs}\left({\color{gray}-1.947 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 26 $$3.24 \mathrm{ms} \pm 18.9 \mathrm{μs}\left({\color{gray}-1.706 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 66 $$3.37 \mathrm{ms} \pm 15.5 \mathrm{μs}\left({\color{gray}-0.992 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.99 \mathrm{ms} \pm 14.9 \mathrm{μs}\left({\color{gray}-2.861 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 29 $$3.32 \mathrm{ms} \pm 23.9 \mathrm{μs}\left({\color{gray}0.419 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_complete

Function Value Mean Flame graphs
entity_by_id;one_depth 1 entities $$44.2 \mathrm{ms} \pm 181 \mathrm{μs}\left({\color{gray}-0.381 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 10 entities $$81.9 \mathrm{ms} \pm 457 \mathrm{μs}\left({\color{gray}-1.087 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 25 entities $$48.1 \mathrm{ms} \pm 214 \mathrm{μs}\left({\color{gray}-1.649 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 5 entities $$51.2 \mathrm{ms} \pm 335 \mathrm{μs}\left({\color{gray}-1.744 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 50 entities $$60.9 \mathrm{ms} \pm 377 \mathrm{μs}\left({\color{gray}0.254 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 1 entities $$45.9 \mathrm{ms} \pm 180 \mathrm{μs}\left({\color{gray}0.284 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 10 entities $$420 \mathrm{ms} \pm 970 \mathrm{μs}\left({\color{gray}-1.728 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 25 entities $$99.4 \mathrm{ms} \pm 535 \mathrm{μs}\left({\color{gray}-2.960 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 5 entities $$89.8 \mathrm{ms} \pm 360 \mathrm{μs}\left({\color{gray}-1.009 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 50 entities $$288 \mathrm{ms} \pm 892 \mathrm{μs}\left({\color{gray}-1.272 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 1 entities $$19.0 \mathrm{ms} \pm 106 \mathrm{μs}\left({\color{gray}-3.149 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 10 entities $$19.5 \mathrm{ms} \pm 105 \mathrm{μs}\left({\color{gray}-2.216 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 25 entities $$19.8 \mathrm{ms} \pm 105 \mathrm{μs}\left({\color{gray}-2.587 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 5 entities $$19.9 \mathrm{ms} \pm 147 \mathrm{μs}\left({\color{gray}-0.546 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 50 entities $$23.5 \mathrm{ms} \pm 145 \mathrm{μs}\left({\color{gray}-3.358 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_linkless

Function Value Mean Flame graphs
entity_by_id 1 entities $$19.2 \mathrm{ms} \pm 116 \mathrm{μs}\left({\color{gray}-2.919 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10 entities $$19.1 \mathrm{ms} \pm 94.5 \mathrm{μs}\left({\color{gray}-1.202 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 100 entities $$19.0 \mathrm{ms} \pm 100 \mathrm{μs}\left({\color{gray}-2.950 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 1000 entities $$19.5 \mathrm{ms} \pm 116 \mathrm{μs}\left({\color{gray}-1.761 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10000 entities $$25.4 \mathrm{ms} \pm 157 \mathrm{μs}\left({\color{gray}-3.563 \mathrm{\%}}\right) $$ Flame Graph

representative_read_entity

Function Value Mean Flame graphs
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/block/v/1 $$34.1 \mathrm{ms} \pm 291 \mathrm{μs}\left({\color{gray}-2.342 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1 $$33.4 \mathrm{ms} \pm 316 \mathrm{μs}\left({\color{gray}-4.870 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1 $$35.0 \mathrm{ms} \pm 321 \mathrm{μs}\left({\color{gray}2.88 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1 $$35.3 \mathrm{ms} \pm 283 \mathrm{μs}\left({\color{gray}3.97 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2 $$33.7 \mathrm{ms} \pm 288 \mathrm{μs}\left({\color{gray}-2.269 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1 $$33.7 \mathrm{ms} \pm 297 \mathrm{μs}\left({\color{gray}-1.283 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1 $$34.2 \mathrm{ms} \pm 300 \mathrm{μs}\left({\color{gray}3.55 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1 $$35.4 \mathrm{ms} \pm 312 \mathrm{μs}\left({\color{red}6.44 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1 $$36.0 \mathrm{ms} \pm 305 \mathrm{μs}\left({\color{red}7.20 \mathrm{\%}}\right) $$ Flame Graph

representative_read_entity_type

Function Value Mean Flame graphs
get_entity_type_by_id Account ID: bf5a9ef5-dc3b-43cf-a291-6210c0321eba $$8.27 \mathrm{ms} \pm 39.8 \mathrm{μs}\left({\color{gray}0.177 \mathrm{\%}}\right) $$ Flame Graph

representative_read_multiple_entities

Function Value Mean Flame graphs
entity_by_property traversal_paths=0 0 $$94.1 \mathrm{ms} \pm 666 \mathrm{μs}\left({\color{gray}0.051 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$144 \mathrm{ms} \pm 664 \mathrm{μs}\left({\color{gray}-2.305 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$102 \mathrm{ms} \pm 694 \mathrm{μs}\left({\color{gray}0.280 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$110 \mathrm{ms} \pm 689 \mathrm{μs}\left({\color{gray}-0.302 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$119 \mathrm{ms} \pm 721 \mathrm{μs}\left({\color{gray}0.035 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$124 \mathrm{ms} \pm 669 \mathrm{μs}\left({\color{gray}-0.749 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=0 0 $$100 \mathrm{ms} \pm 555 \mathrm{μs}\left({\color{gray}-2.161 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$129 \mathrm{ms} \pm 712 \mathrm{μs}\left({\color{gray}0.709 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$108 \mathrm{ms} \pm 683 \mathrm{μs}\left({\color{gray}-0.877 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$116 \mathrm{ms} \pm 497 \mathrm{μs}\left({\color{gray}0.001 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$118 \mathrm{ms} \pm 583 \mathrm{μs}\left({\color{gray}-0.216 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$118 \mathrm{ms} \pm 551 \mathrm{μs}\left({\color{gray}-0.495 \mathrm{\%}}\right) $$

scenarios

Function Value Mean Flame graphs
full_test query-limited $$130 \mathrm{ms} \pm 444 \mathrm{μs}\left({\color{lightgreen}-7.644 \mathrm{\%}}\right) $$ Flame Graph
full_test query-unlimited $$143 \mathrm{ms} \pm 583 \mathrm{μs}\left({\color{lightgreen}-5.305 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-limited $$104 \mathrm{ms} \pm 592 \mathrm{μs}\left({\color{gray}-1.019 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-unlimited $$586 \mathrm{ms} \pm 3.09 \mathrm{ms}\left({\color{gray}4.16 \mathrm{\%}}\right) $$ Flame Graph

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/libs Relates to first-party libraries/crates/packages (area) area/tests New or updated tests type/eng > backend Owned by the @backend team

Development

Successfully merging this pull request may close these issues.

2 participants