Skip to content

Commit f6a8ddd

Browse files
committed
[Test] C++ unit tests for Program::diagnose_adstack_overflow_message + registry
1 parent f6bd45e commit f6a8ddd

1 file changed

Lines changed: 72 additions & 0 deletions

File tree

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#include "gtest/gtest.h"
2+
3+
#include "quadrants/program/program.h"
4+
5+
namespace quadrants::lang {
6+
7+
// `Program::register_adstack_sizing_info` + `lookup_adstack_sizing_info` + `diagnose_adstack_overflow_message`
8+
// exercised in isolation. These are pure host-side data-structure operations, so the test does not need
9+
// `materialize_runtime` or any device backend.
10+
TEST(DiagnoseAdstackOverflow, RegistryAndLookup) {
11+
Program prog(host_arch());
12+
13+
// Two distinct sizing infos. The pointer is just an identity key for `Program::register_*` -
14+
// the test does not deref.
15+
int dummy_a = 0;
16+
int dummy_b = 0;
17+
uint32_t id_a = prog.register_adstack_sizing_info(static_cast<const void *>(&dummy_a), "kernel_a", /*task=*/0,
18+
/*allocated_max_sizes=*/{16, 32});
19+
uint32_t id_b = prog.register_adstack_sizing_info(static_cast<const void *>(&dummy_b), "kernel_b", /*task=*/3,
20+
/*allocated_max_sizes=*/{100});
21+
EXPECT_NE(id_a, 0u);
22+
EXPECT_NE(id_b, 0u);
23+
EXPECT_NE(id_a, id_b);
24+
25+
// Idempotent re-registration: same pointer returns the same id (and updates metadata in place).
26+
uint32_t id_a_redo = prog.register_adstack_sizing_info(static_cast<const void *>(&dummy_a), "kernel_a_v2",
27+
/*task=*/2,
28+
/*allocated_max_sizes=*/{8});
29+
EXPECT_EQ(id_a, id_a_redo);
30+
const auto *entry = prog.lookup_adstack_sizing_info(id_a);
31+
ASSERT_NE(entry, nullptr);
32+
EXPECT_EQ(entry->kernel_name, "kernel_a_v2");
33+
EXPECT_EQ(entry->task_id_in_kernel, 2);
34+
EXPECT_EQ(entry->allocated_max_sizes, std::vector<int>({8}));
35+
36+
// Lookup with id 0 (sentinel) returns nullptr.
37+
EXPECT_EQ(prog.lookup_adstack_sizing_info(0), nullptr);
38+
// Lookup with out-of-range id returns nullptr.
39+
EXPECT_EQ(prog.lookup_adstack_sizing_info(static_cast<uint32_t>(0xfffffffful)), nullptr);
40+
}
41+
42+
// Diagnose with an unknown / sentinel id falls back to the generic dual-cause body without crashing.
43+
// The body must mention BOTH causes (DLPack bypass and Quadrants bug) so the user has actionable
44+
// recovery information regardless of whether the runtime captured the offending task identity.
45+
TEST(DiagnoseAdstackOverflow, GenericFallbackOnUnknownId) {
46+
Program prog(host_arch());
47+
std::string msg = prog.diagnose_adstack_overflow_message(/*task_id=*/0);
48+
EXPECT_NE(msg.find("DLPack"), std::string::npos);
49+
EXPECT_NE(msg.find("Quadrants bug"), std::string::npos);
50+
// No identity-block prefix when there is nothing to look up.
51+
EXPECT_EQ(msg.find("Offending task"), std::string::npos);
52+
}
53+
54+
// Diagnose with a registered id includes the kernel name + offload task index + per-stack allocated
55+
// max_sizes in the identity block prefix.
56+
TEST(DiagnoseAdstackOverflow, EnrichedMessageWithIdentity) {
57+
Program prog(host_arch());
58+
int dummy = 0;
59+
uint32_t id = prog.register_adstack_sizing_info(static_cast<const void *>(&dummy), "compute_grad_diag",
60+
/*task=*/4,
61+
/*allocated_max_sizes=*/{32, 64});
62+
std::string msg = prog.diagnose_adstack_overflow_message(id);
63+
EXPECT_NE(msg.find("Offending task"), std::string::npos);
64+
EXPECT_NE(msg.find("compute_grad_diag"), std::string::npos);
65+
EXPECT_NE(msg.find("offload task #4"), std::string::npos);
66+
EXPECT_NE(msg.find("[32, 64]"), std::string::npos);
67+
// Dual-cause body still present.
68+
EXPECT_NE(msg.find("DLPack"), std::string::npos);
69+
EXPECT_NE(msg.find("Quadrants bug"), std::string::npos);
70+
}
71+
72+
} // namespace quadrants::lang

0 commit comments

Comments
 (0)