For contributors — how XLOG’s GPU execution works internally.
XLOG’s deterministic runtime keeps its control logic on the CPU and its data on the GPU. The CPU-side executor walks the internal query plan (an RIR plan — the runtime’s internal representation of a query). For each plan operator it picks an eligible CUDA kernel and runs it on the GPU. The relations produced along the way stay in GPU memory as CUDA buffers. The kernels cover scans, filters, joins, groupby (grouped aggregation), arithmetic expressions, recursive delta steps (one round of a recursive rule), and specialized multiway join routes.
Deterministic dataflow: an RIR plan tree enters the host executor, which dispatches Scan, Filter, Join, and GroupBy/Distinct kernel families inside the GPU-resident plane; results accumulate in the columnar versioned relation store, which loops back to feed the next operator or fixpoint round.

The host executor walks the RIR plan and dispatches one kernel family per operator; relations stay in the device-resident store, which feeds the next operator or fixpoint round (one iteration of the recursive loop, repeated until no new rows appear).

Host Control, Device Data

The split is deliberate: the CPU decides what to run, the GPU holds the data and does the work. xlog-runtime::Executor runs on the host and manages:
  • relation names, relation IDs, generations, and schemas;
  • a RelationStore backed by CudaBuffer values;
  • runtime statistics and join-selectivity observations;
  • persistent build-side join indexes;
  • dispatch counters for optimized routes (per-route counters that record when a specialized kernel actually ran — see What To Verify);
  • recursive SCC state for seed, delta, and merge phases. A SCC (strongly connected component) is a group of rules that depend on each other recursively; the runtime evaluates each such group in seed, delta, and merge phases.
xlog-cuda::CudaKernelProvider owns the device-facing operations. It loads CUDA artifacts, allocates tracked slices, launches kernels, and records transfer telemetry where a path needs a no-host-transfer assertion. So the executor itself is not GPU-resident. The relation state and the kernel workspaces are.

RIR Evaluation

The executor turns each RIR plan operator into GPU work that writes a relation buffer: “Semi-naive” here means each recursive round processes only the rows newly derived in the previous round, not the whole relation again. The correctness rule is row-set parity: an optimized path must return exactly the same rows as the ordinary route. An optimized path is allowed to decline — fall back to the ordinary route — when a shape, width, budget, or gate does not match.

Predicate And Arithmetic Masks

A filter does not delete rows in place. It lowers into a mask pipeline that marks which rows survive, then compacts them:
  1. Arithmetic expression kernels produce temporary columns.
  2. Typed comparison kernels produce boolean masks (one bit per row: keep or drop).
  3. Boolean mask kernels combine predicates with and, or, and not.
  4. Stream compaction writes the filtered output buffer.
The runtime supports scalar integer, floating, boolean, and symbol comparisons, matching the types represented in RIR and the CUDA provider kernels. Float ordering behaves as the corresponding filter tests and kernels define, and support extends only as far as those cover.

Joins And Recursion

The ordinary join is always the baseline path. For certain rule shapes the runtime can route to a faster specialized kernel instead:
  • hash joins for normal binary joins;
  • nested-loop joins for small eligible products;
  • WCOJ for recognized triangle, 4-cycle, and clique shapes;
  • Free Join for broader multiway bodies;
  • factorized recursive-delta routing for recursive rules (a compressed representation of the per-round delta).
The Free Join and factorized recursive-delta routes have been available since 0.10.0. Every optimized route has its own dispatch counter — for example separate counters for WCOJ, Free Join, fused aggregate, and factorized-delta. These let you tell “the answer matched” apart from “the optimized route actually fired,” since the two are not the same thing.

Ingestion And Diagnostics

Two runtime surfaces sit next to the core evaluation loop rather than inside it: bulk graph loading and delta diagnostics.
  • xlog_gpu::biokg::StreamingGraphRelationLoader streams JSONL, CSV, and N-Triples graph rows into typed edge records, with bounded-memory telemetry.
  • DeltaPlannerTelemetry reports cache reuse, fallback decisions, affected SCCs, recomputed SCCs, and estimated versus measured delta behavior.
  • pyxlog exposes planner telemetry through diagnostic result payloads.
Use these surfaces when investigating data loading and incremental behavior. Use the dispatch counters and transfer telemetry (below) when investigating GPU execution.

What To Verify

A matching final result does not prove that an optimized GPU route ran — the fallback route returns the same rows. To prove a workload used the intended GPU path, check:
  • the route counter for the optimized dispatch (was it greater than zero?);
  • kill-switch parity: disable the optimized route and confirm the fallback returns the same rows;
  • transfer telemetry, for any no-host-transfer claim;
  • CUDA-required validation, when the claim depends on actual GPU execution.
Final result equality alone is not enough to prove an optimized GPU route fired.