OverviewFilesCommitsIssuesDocsReleasesPeers

atomspace-gpu / tests / persist / gpu / test_incoming.cu

80 lines · cu ref:
/*
 * test_incoming.cu — standalone test for GpuAtomTable incoming-set index (Phase 2a).
 *
 * Slots: a=0 b=1 c=2 (nodes);
 *        L1=3 (a,b)  L2=4 (b,c)  L3=5 (a,b,c)  L4=6 (L1,c)  [link-of-link]
 * Expected incoming sets (link-slots referencing each atom):
 *   a:{3,5}  b:{3,4,5}  c:{4,5,6}  L1:{6}  L2:{}  L3:{}  L4:{}
 *
 * Build: nvcc -DHAVE_CUDA -I../../.. test_incoming.cu \
 *        ../../../opencog/persist/gpu/GpuAtomTable.cu -arch=sm_75 -o test_incoming
 */
#include "opencog/persist/gpu/GpuAtomTable.h"
#include <cstdio>
#include <vector>
#include <algorithm>

static int fails = 0;
static void check_set(const char* name, GpuAtomTable* t, uint32_t slot,
                      std::vector<uint32_t> expect)
{
    uint32_t buf[64]; uint32_t count = 0;
    cuda_fetch_incoming(t, slot, buf, 64, &count);
    std::vector<uint32_t> got(buf, buf + (count < 64 ? count : 64));
    std::sort(got.begin(), got.end());
    std::sort(expect.begin(), expect.end());
    if (got == expect) { printf("PASS  incoming(%s) = {", name);
        for (auto x : got) printf("%u ", x); printf("}\n"); }
    else { fails++; printf("FAIL  incoming(%s): got {", name);
        for (auto x : got) printf("%u ", x); printf("} expected {");
        for (auto x : expect) printf("%u ", x); printf("}\n"); }
}

int main()
{
    printf("=== Phase 2a: GpuAtomTable incoming-set index ===\n\n");
    GpuAtomTable t;
    if (cuda_table_alloc(&t) != 0) { printf("alloc failed\n"); return 1; }

    cuda_store_node(&t, 0, 1, "a", 1);
    cuda_store_node(&t, 1, 1, "b", 1);
    cuda_store_node(&t, 2, 1, "c", 1);
    uint32_t L1[] = {0,1};      cuda_store_link(&t, 3, 2, L1, 2);
    uint32_t L2[] = {1,2};      cuda_store_link(&t, 4, 2, L2, 2);
    uint32_t L3[] = {0,1,2};    cuda_store_link(&t, 5, 2, L3, 3);
    uint32_t L4[] = {3,2};      cuda_store_link(&t, 6, 2, L4, 2); // contains link L1

    if (cuda_table_build_incoming(&t) != 0) { printf("build_incoming failed\n"); return 1; }
    printf("atom_count=%u  in_pool_used=%u  in_built=%u\n\n",
           t.atom_count, t.in_pool_used, t.in_built);

    check_set("a",  &t, 0, {3,5});
    check_set("b",  &t, 1, {3,4,5});
    check_set("c",  &t, 2, {4,5,6});
    check_set("L1", &t, 3, {6});
    check_set("L2", &t, 4, {});
    check_set("L3", &t, 5, {});
    check_set("L4", &t, 6, {});

    // GPU-resident JOIN: intersect incoming sets entirely on the GPU.
    {
        uint32_t buf[64]; uint32_t cnt;
        auto chk = [&](const char* nm, uint32_t a, uint32_t b, std::vector<uint32_t> exp) {
            cnt = 0; cuda_intersect_incoming(&t, a, b, buf, 64, &cnt);
            std::vector<uint32_t> got(buf, buf + (cnt < 64 ? cnt : 64));
            std::sort(got.begin(), got.end()); std::sort(exp.begin(), exp.end());
            if (got == exp) { printf("PASS  intersect(%s) = {", nm);
                for (auto x : got) printf("%u ", x); printf("}\n"); }
            else { fails++; printf("FAIL  intersect(%s)\n", nm); }
        };
        chk("a,b", 0, 1, {3,5});   // links containing both a and b: L1,L3
        chk("b,c", 1, 2, {4,5});   // L2,L3
        chk("a,c", 0, 2, {5});     // only L3 contains both a and c
    }

    cuda_table_free(&t);
    printf("\n%s\n", fails ? "SOME CHECKS FAILED" :
        "ALL CHECKS PASSED - incoming-set index works on the real GpuAtomTable.");
    return fails ? 1 : 0;
}