MCPcopy Create free account
hub / github.com/ashvardanian/StringZilla / test_memory_utilities

Function test_memory_utilities

scripts/test_stringzilla.cpp:1257–1337  ·  view source on GitHub ↗

* @brief Validates that `sz::memcpy`, `sz::memset`, and `sz::memmove` work similar to their `std::` counterparts. * * Uses a large heap-allocated buffer to ensure that operations optimized for @b larger-than-L2-cache memory * regions are tested. Covers various chunk sizes, overlapping regions, and both forward and backward traversals. */

Source from the content-addressed store, hash-verified

1255 * regions are tested. Covers various chunk sizes, overlapping regions, and both forward and backward traversals.
1256 */
1257void test_memory_utilities(std::size_t max_l2_size = 1024ull * 1024ull) {
1258
1259 // We will be mirroring the operations on both standard and StringZilla strings.
1260 std::string text_stl(max_l2_size, '-');
1261 std::string text_sz(max_l2_size, '-');
1262 expect_equality(text_stl.data(), text_sz.data(), max_l2_size);
1263
1264 // The traditional `memset` and `memcpy` functions are undefined for zero-length buffers and NULL pointers
1265 // for older C standards. However, with the N3322 proposal for C2y, that issue has been resolved.
1266 // https://developers.redhat.com/articles/2024/12/11/making-memcpynull-null-0-well-defined
1267 //
1268 // Let's make sure, that our versions don't trigger any undefined behavior.
1269 sz::memset(NULL, 0, 0);
1270 sz::memcpy(NULL, NULL, 0);
1271 sz::memmove(NULL, NULL, 0);
1272
1273 // First start with simple deterministic tests.
1274 // Let's use `memset` to fill the strings with a pattern like "122333444455555...00000000000011111111111..."
1275 std::size_t count_groups = 0;
1276 for (std::size_t offset = 0, fill_length = 1; offset < max_l2_size;
1277 offset += fill_length, ++fill_length, ++count_groups) {
1278 char fill_value = '0' + fill_length % 10;
1279 fill_length = offset + fill_length > max_l2_size ? max_l2_size - offset : fill_length;
1280 std::memset((void *)(text_stl.data() + offset), fill_value, fill_length);
1281 sz::memset((void *)(text_sz.data() + offset), fill_value, fill_length);
1282 expect_equality(text_stl.data(), text_sz.data(), max_l2_size);
1283 }
1284
1285 // Let's copy those chunks to an empty buffer one by one, validating the overall equivalency after every copy.
1286 std::string copy_stl(max_l2_size, '-');
1287 std::string copy_sz(max_l2_size, '-');
1288 for (std::size_t offset = 0, fill_length = 1; offset < max_l2_size; offset += fill_length, ++fill_length) {
1289 fill_length = offset + fill_length > max_l2_size ? max_l2_size - offset : fill_length;
1290 std::memcpy((void *)(copy_stl.data() + offset), (void *)(text_stl.data() + offset), fill_length);
1291 sz::memcpy((void *)(copy_sz.data() + offset), (void *)(text_sz.data() + offset), fill_length);
1292 expect_equality(copy_stl.data(), copy_sz.data(), max_l2_size);
1293 }
1294 expect_equality(text_stl.data(), copy_stl.data(), max_l2_size);
1295 expect_equality(text_sz.data(), copy_sz.data(), max_l2_size);
1296
1297 // Let's simulate a realistic `memmove` workloads, compacting parts of this buffer, removing all odd values,
1298 // so the buffer will look like "224444666666..."
1299 for (std::size_t offset = 0, fill_length = 1; offset < max_l2_size; offset += fill_length, ++fill_length) {
1300 if (fill_length % 2 == 0) continue; // Skip even chunks
1301 if (offset + fill_length >= max_l2_size) break; // This is the last & there are no more even chunks to shift
1302
1303 // Make sure we don't overflow the buffer
1304 std::size_t next_offset = offset + fill_length;
1305 std::size_t next_fill_length = fill_length + 1;
1306 next_fill_length = next_offset + next_fill_length > max_l2_size ? max_l2_size - next_offset : next_fill_length;
1307
1308 std::memmove((void *)(text_stl.data() + offset), (void *)(text_stl.data() + next_offset), next_fill_length);
1309 sz::memmove((void *)(text_sz.data() + offset), (void *)(text_sz.data() + next_offset), next_fill_length);
1310 expect_equality(text_stl.data(), text_sz.data(), max_l2_size);
1311 }
1312
1313 // Now the opposite workload, expanding the buffer, inserting a dash "-" before every group of equal characters.
1314 // We will need to navigate right-to left to avoid overwriting the groups.

Callers 1

mainFunction · 0.85

Calls 7

expect_equalityFunction · 0.85
resizeMethod · 0.80
memsetFunction · 0.50
memcpyFunction · 0.50
memmoveFunction · 0.50
dataMethod · 0.45
sizeMethod · 0.45

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…