39 #define CHECK_EQ(actual, expected, msg) \
43 auto _e = (expected); \
46 fprintf(stderr, " FAIL %s:%d %s: got %lld expected %lld\n", \
47 __FILE__, __LINE__, msg, \
48 (long long)_a, (long long)_e); \
52 #define RUN_TEST(fn) \
54 int before = g_failures; \
55 fprintf(stderr, "[RUN ] %s\n", #fn); \
57 fprintf(stderr, "[%s] %s\n", \
58 (g_failures == before) ? "PASS" : "FAIL", #fn); \
71 const size_t addr = 0x1234'5678'9abc'0000ULL;
72 const uint64_t
value = 0xdeadbeefcafef00dULL;
74 *GetOrCreateShadowAddress<0>(
sm, addr) =
value;
75 uint64_t readback = *GetOrCreateShadowAddress<0>(
sm, addr);
83 const size_t base = 0x1000'0000ULL;
84 for (
int i = 0; i < 4096; ++i) {
85 *GetOrCreateShadowAddress<0>(
sm, base + i * 8) = uint64_t{
static_cast<uint64_t
>(i)} * 7 + 3;
87 for (
int i = 0; i < 4096; ++i) {
88 uint64_t v = *GetOrCreateShadowAddress<0>(
sm, base + i * 8);
89 CHECK_EQ(v, uint64_t{
static_cast<uint64_t
>(i)} * 7 + 3,
"same-page slot");
97 const size_t addrs[] = {
104 const int n =
sizeof(addrs) /
sizeof(addrs[0]);
105 for (
int i = 0; i < n; ++i) {
106 *GetOrCreateShadowAddress<0>(
sm, addrs[i]) = 0xa5a5a5a5'00000000ULL | i;
108 for (
int i = 0; i < n; ++i) {
109 uint64_t v = *GetOrCreateShadowAddress<0>(
sm, addrs[i]);
110 CHECK_EQ(v, 0xa5a5a5a5'00000000ULL | i,
"cross-page slot");
119 const size_t addr = 0xcafeb0ba'0000ULL;
120 *GetOrCreateShadowAddress<0>(
sm, addr) = 0x5a;
121 *GetOrCreateShadowAddress<1>(
sm, addr) = 0xdeadbeef;
122 CHECK_EQ(*GetOrCreateShadowAddress<0>(
sm, addr), 0x5a,
"type-0 slot");
123 CHECK_EQ(*GetOrCreateShadowAddress<1>(
sm, addr), 0xdeadbeef,
"type-1 slot");
131 const size_t addr = 0x0f0f'0000'1234ULL;
132 const uint64_t
value = 0x1122334455667788ULL;
134 *GetOrCreateShadowAddress<0>(
sm, addr) =
value;
136 uint64_t via_base = std::get<0>(page)[
PAGE_OFFSET(addr)];
137 CHECK_EQ(via_base,
value,
"write via free-fn observed via base-fn");
143 const size_t addr = 0x0e0e'ffff'5678ULL;
144 const uint64_t
value = 0x8899aabbccddeeffULL;
148 uint64_t via_free = *GetOrCreateShadowAddress<0>(
sm, addr);
149 CHECK_EQ(via_free,
value,
"write via base-fn observed via free-fn");
157 const size_t addr = 0x2222'3333'4444ULL;
158 uint64_t* p1 = GetOrCreateShadowAddress<0>(
sm, addr);
159 uint64_t* p2 = GetOrCreateShadowAddress<0>(
sm, addr);
160 CHECK_EQ(p1 == p2,
true,
"pointer stability across calls");
168 const size_t base = 0x8000'0000ULL;
169 for (
int i = 0; i < 256; ++i) {
170 *GetOrCreateShadowAddress<0>(
sm, base + i * 8) = 0xf00d0000ULL + i;
172 for (
int i = 0; i < 256; ++i) {
173 CHECK_EQ(*GetOrCreateShadowAddress<0>(
sm, base + i * 8),
174 0xf00d0000ULL + i,
"init-pattern slot");
185 const size_t addr = 0x1234'5678'9abc'0000ULL;
186 const uint64_t
value = 0xdeadbeefcafef00dULL;
188 *GetOrCreateShadowAddress<0>(
sm, addr) =
value;
189 uint64_t readback = *GetOrCreateShadowAddress<0>(
sm, addr);
195 const size_t addr = 0x0f0f'0000'1234ULL;
196 const uint64_t
value = 0x1122334455667788ULL;
198 *GetOrCreateShadowAddress<0>(
sm, addr) =
value;
200 uint64_t via_base = std::get<0>(page)[
PAGE_OFFSET(addr)];
201 CHECK_EQ(via_base,
value,
"concurrent: write via free-fn observed via base-fn");
206 const size_t addr = 0xcafeb0ba'0000ULL;
207 *GetOrCreateShadowAddress<0>(
sm, addr) = 0x5a;
208 *GetOrCreateShadowAddress<1>(
sm, addr) = 0xdeadbeef;
209 CHECK_EQ(*GetOrCreateShadowAddress<0>(
sm, addr), 0x5a,
"type-0 slot (concurrent)");
210 CHECK_EQ(*GetOrCreateShadowAddress<1>(
sm, addr), 0xdeadbeef,
"type-1 slot (concurrent)");
218 const int nthreads = 8;
219 const int per_thread = 1024;
220 const size_t stride = 0x100'0000ULL;
222 std::atomic<int> mismatches{0};
224 auto writer = [&](
int tid) {
225 for (
int i = 0; i < per_thread; ++i) {
226 size_t addr = (
size_t)tid * stride + (
size_t)i * 8;
227 *GetOrCreateShadowAddress<0>(
sm, addr) = (uint64_t)tid * 1000000ULL + i;
230 std::vector<std::thread> ts;
231 ts.reserve(nthreads);
232 for (
int t = 0; t < nthreads; ++t)
233 ts.emplace_back(writer, t);
237 auto reader = [&](
int tid) {
238 for (
int i = 0; i < per_thread; ++i) {
239 size_t addr = (
size_t)tid * stride + (
size_t)i * 8;
240 uint64_t v = *GetOrCreateShadowAddress<0>(
sm, addr);
241 if (v != (uint64_t)tid * 1000000ULL + i)
242 mismatches.fetch_add(1);
246 for (
int t = 0; t < nthreads; ++t)
247 ts.emplace_back(reader, t);
251 CHECK_EQ(mismatches.load(), 0,
"concurrent multi-thread write/read mismatches");
265 const size_t base = 0x7ff0'0000'0000ULL;
267 for (
int i = 0; i < n; ++i) {
268 FakeHandle* slot = GetOrCreateShadowAddress<0>(
sm, base + i);
270 slot->path = 0xabc00000u + (uint32_t)i;
272 for (
int i = 0; i < n; ++i) {
273 FakeHandle
h = *GetOrCreateShadowAddress<0>(
sm, base + i);
274 CHECK_EQ((
int)
h.type, 2,
"data-centric shape type persisted");
275 CHECK_EQ(
h.path, 0xabc00000u + (uint32_t)i,
"data-centric shape path persisted");
static ConcurrentShadowMemory< DataHandle_t > sm
uint8_t value[MAX_WRITE_OP_LENGTH]
std::tuple< Args[SHADOW_PAGE_SIZE]... > ShadowTuple
#define PAGE_OFFSET(addr)
static void test_shadow_multi_type_tuple()
static void test_shadow_write_read_single()
static void test_concurrent_free_fn_matches_base_fn()
static void test_concurrent_write_read_single()
static void test_shadow_init_pattern()
static void test_concurrent_init_pattern_data_centric_shape()
static void test_shadow_multiple_pages()
static void test_concurrent_multi_type_tuple()
static void test_shadow_multiple_addresses_same_page()
static void test_concurrent_multi_thread()
static void test_shadow_pointer_stable()
static void test_shadow_base_fn_matches_free_fn()
static void test_shadow_free_fn_matches_base_fn()
#define CHECK_EQ(actual, expected, msg)