weirflow 0.1.0

GPU-first dataflow analysis primitives for Vyre and Santh compiler pipelines.
Documentation
use super::*;

#[test]
fn resident_solver_polls_changed_flag_before_downloading_final_frontier() {
    let dispatch = FakeResidentDispatch::new_with_program_graph_buffers(2);
    let prepared = ResidentPreparedIfdsCsr {
        shape: IfdsShape {
            num_procs: 1,
            blocks_per_proc: 33,
            facts_per_proc: 1,
            edge_count: 0,
        },
        node_count: 33,
        words: 2,
        pg_nodes: 0,
        row_ptr: 1,
        col_idx: 2,
        pg_edge_kind_mask: 3,
        pg_node_tags: 4,
    };
    let reached = solve_resident_prepared_via(&dispatch, &prepared, &[(0, 0, 0)], 4)
        .expect("fake resident solver should converge");
    assert_eq!(reached, vec![0]);
    assert_eq!(dispatch.dispatches.get(), 2);
    assert_eq!(
            *dispatch.downloads.borrow(),
            vec![4, 4, 8],
            "resident solve must download only changed flags per iteration, then the final frontier once"
        );
}

#[test]
fn resident_solver_download_bytes_scale_with_iterations_not_frontier_words() {
    let dispatch = FakeResidentDispatch::new_with_program_graph_buffers(6);
    let node_count = 32_768;
    let words = ifds_words(node_count);
    let prepared = ResidentPreparedIfdsCsr {
        shape: IfdsShape {
            num_procs: 1024,
            blocks_per_proc: 32,
            facts_per_proc: 1,
            edge_count: 0,
        },
        node_count,
        words,
        pg_nodes: 0,
        row_ptr: 1,
        col_idx: 2,
        pg_edge_kind_mask: 3,
        pg_node_tags: 4,
    };
    let reached = solve_resident_prepared_via(&dispatch, &prepared, &[(0, 0, 0)], 16)
        .expect("fake resident solver should converge");
    assert_eq!(reached, vec![0]);
    assert_eq!(dispatch.dispatches.get(), 6);
    let downloads = dispatch.downloads.borrow();
    assert_eq!(downloads.len(), 7);
    assert_eq!(&downloads[..6], &[4, 4, 4, 4, 4, 4]);
    assert_eq!(downloads[6], words * 4);
    let downloaded_before_final: usize = downloads[..6].iter().sum();
    assert_eq!(
        downloaded_before_final, 24,
        "resident solve must poll one u32 changed flag per iteration, not download the frontier"
    );
    assert!(
        dispatch
            .uploaded_lengths
            .borrow()
            .iter()
            .any(|&len| len == 4),
        "resident solve must explicitly reset the changed flag before each primitive step"
    );
}

#[test]
fn resident_many_solver_defaults_to_parallel_batch() {
    let dispatch = FakeResidentDispatch::new_with_program_graph_buffers(1);
    let prepared = ResidentPreparedIfdsCsr {
        shape: IfdsShape {
            num_procs: 1,
            blocks_per_proc: 4,
            facts_per_proc: 1,
            edge_count: 0,
        },
        node_count: 4,
        words: 1,
        pg_nodes: 0,
        row_ptr: 1,
        col_idx: 2,
        pg_edge_kind_mask: 3,
        pg_node_tags: 4,
    };
    let seed_a = [(0, 0, 0)];
    let seed_b = [(0, 1, 0)];
    let got =
        solve_resident_prepared_many_via(&dispatch, &prepared, &[&seed_a[..], &seed_b[..]], 8)
            .expect("fake resident batch solver should converge");
    assert_eq!(got, vec![vec![0], vec![1024]]);
    assert_eq!(
        dispatch.dispatches.get(),
        2,
        "default multi-query solve must process each seed set through the single-query CUDA release path"
    );
    assert_eq!(
        dispatch.sequence_read_ranges_calls.get(),
        0,
        "default multi-query solve must avoid the broken resident sequence launcher on CUDA"
    );
    assert_eq!(
        dispatch.buffers.borrow().len(),
        7,
        "default multi-query solve must allocate one frontier matrix and one changed flag"
    );
    assert_eq!(
            *dispatch.downloads.borrow(),
            vec![4, 4, 4, 4],
            "default multi-query solve should poll changed flags through the single-query CUDA release path"
        );
}