weirflow 0.1.0

GPU-first dataflow analysis primitives for Vyre and Santh compiler pipelines.
Documentation
use super::super::{DirectIfdsKey, DirectResidentIfdsBatch, DirectResidentIfdsGraphKey};
use crate::ifds_gpu::IfdsResidentDispatch;

impl<R> DirectResidentIfdsBatch<R>
where
    R: Clone,
{
    /// Solve many seed sets against an already cached direct-resident graph key.
    ///
    /// This is the steady-state hot path after one successful
    /// [`Self::solve_many_with_graph_key_into`] call has validated the edge
    /// families and populated the resident CSR cache. It does not accept graph
    /// edge slices, so it cannot accidentally rebuild or re-hash invariant CSR
    /// inputs inside a measured repeated-query loop.
    pub fn solve_cached_with_graph_key<D>(
        &mut self,
        dispatch: &D,
        graph_key: DirectResidentIfdsGraphKey,
        seed_sets: &[&[(u32, u32, u32)]],
        max_iterations: u32,
    ) -> Result<Vec<Vec<u32>>, String>
    where
        D: IfdsResidentDispatch<Resource = R>,
    {
        let mut results = crate::staging_reserve::reserved_vec(
            seed_sets.len(),
            "direct resident IFDS cached-key result row",
        )?;
        self.solve_cached_with_graph_key_into(
            dispatch,
            graph_key,
            seed_sets,
            max_iterations,
            &mut results,
        )?;
        Ok(results)
    }

    /// Solve many seed sets into caller-owned result rows against an already
    /// cached direct-resident graph key.
    pub fn solve_cached_with_graph_key_into<D>(
        &mut self,
        dispatch: &D,
        graph_key: DirectResidentIfdsGraphKey,
        seed_sets: &[&[(u32, u32, u32)]],
        max_iterations: u32,
        results: &mut Vec<Vec<u32>>,
    ) -> Result<(), String>
    where
        D: IfdsResidentDispatch<Resource = R>,
    {
        if seed_sets.is_empty() {
            results.clear();
            return Ok(());
        }
        if seed_sets.iter().all(|seed_facts| seed_facts.is_empty()) {
            crate::dispatch_decode::require_positive_iterations(
                "weir direct resident IFDS cached-key solve into",
                max_iterations,
            )?;
            super::resize_and_clear_result_slots(results, seed_sets.len())?;
            return Ok(());
        }
        let key = DirectIfdsKey {
            backend_id: dispatch.resident_backend_id(),
            backend_version: dispatch.resident_backend_version(),
            num_procs: graph_key.num_procs,
            blocks_per_proc: graph_key.blocks_per_proc,
            facts_per_proc: graph_key.facts_per_proc,
            graph_hash: graph_key.graph_hash,
        };
        if !self.entries.contains_key(&key) {
            return Err(
                "weir direct resident IFDS graph key is not cached for this backend. Fix: call solve_many_with_graph_key_into once with the graph edge families before using the cached-key hot path."
                    .to_string(),
            );
        }
        self.hits = self
            .hits
            .checked_add(1)
            .ok_or_else(|| {
                "weir direct resident IFDS cached-key hit counter overflowed u64. Fix: rebuild the direct resident batch facade before reuse."
                    .to_string()
            })?;
        let retained_bytes = self
            .entries
            .get(&key)
            .ok_or_else(|| {
                "weir direct resident IFDS batch cache lookup failed before cached-key telemetry"
                    .to_string()
            })?
            .retained_bytes;
        self.record_warm_graph_reuse(retained_bytes)?;
        self.touch_key(&key)?;
        let resident = &self
            .entries
            .get(&key)
            .ok_or_else(|| {
                "weir direct resident IFDS batch cache lookup failed after cached-key hit"
                    .to_string()
            })?
            .graph;
        self.solver.solve_resident_prepared_many_into(
            dispatch,
            resident,
            seed_sets,
            max_iterations,
            results,
        )?;
        self.record_resident_solve_batch(seed_sets)
    }
}