Files
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

253 lines
6.3 KiB
C++

// Copyright Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
#include "rocjitsu/vm/plugins/race_detector/core/interval_set.h"
#include <gtest/gtest.h>
using namespace rocjitsu::plugins::race_detector;
TEST(IntervalSet, EmptyByDefault) {
IntervalSet s;
EXPECT_TRUE(s.empty());
EXPECT_EQ(s.size(), 0u);
EXPECT_EQ(s.getTotalBytes(), 0);
}
TEST(IntervalSet, SingleAppend) {
IntervalSet s;
s.append(10, 14);
EXPECT_EQ(s.size(), 1u);
EXPECT_EQ(s.getTotalBytes(), 4);
EXPECT_TRUE(s.contains(10));
EXPECT_TRUE(s.contains(13));
EXPECT_FALSE(s.contains(9));
EXPECT_FALSE(s.contains(14));
}
TEST(IntervalSet, AdjacentAppendMerges) {
IntervalSet s;
s.append(0, 4);
s.append(4, 8);
// Adjacent intervals should merge on append.
EXPECT_EQ(s.size(), 1u);
EXPECT_EQ(s.getTotalBytes(), 8);
auto it = s.begin();
EXPECT_EQ(it->start, 0);
EXPECT_EQ(it->end, 8);
}
TEST(IntervalSet, OverlappingAppendMerges) {
IntervalSet s;
s.append(0, 6);
s.append(4, 10);
EXPECT_EQ(s.size(), 1u);
EXPECT_EQ(s.getTotalBytes(), 10);
}
TEST(IntervalSet, NonAdjacentAppendDoesNotMerge) {
IntervalSet s;
s.append(0, 4);
s.append(8, 12);
EXPECT_EQ(s.size(), 2u);
EXPECT_EQ(s.getTotalBytes(), 8);
}
TEST(IntervalSet, OverlappingAppendMergesWithBack) {
// [5,10) then [0,7) overlap → merge to [0,10).
// [20,25) is disjoint → new entry.
// [15,22) overlaps [20,25) → merge to [15,25).
IntervalSet s;
s.append(5, 10);
s.append(0, 7);
EXPECT_EQ(s.size(), 1u);
EXPECT_EQ(s.begin()->start, 0);
EXPECT_EQ(s.begin()->end, 10);
s.append(20, 25);
EXPECT_EQ(s.size(), 2u);
s.append(15, 22);
EXPECT_EQ(s.size(), 2u);
auto it = s.begin();
EXPECT_EQ(it->start, 0);
EXPECT_EQ(it->end, 10);
++it;
EXPECT_EQ(it->start, 15);
EXPECT_EQ(it->end, 25);
}
TEST(IntervalSet, FinalizeIdempotent) {
IntervalSet s;
s.append(0, 4);
s.append(8, 12);
s.finalize();
s.finalize();
EXPECT_EQ(s.size(), 2u);
}
TEST(IntervalSet, MonotonicAppendNoFinalizeNeeded) {
// Simulates the common ds_load_b32 pattern: lane 0 reads [0,4),
// lane 1 reads [4,8), etc. All adjacent, all merge on append.
IntervalSet s;
for (int lane = 0; lane < 32; ++lane) {
s.append(lane * 4, lane * 4 + 4);
}
// Everything merged during append.
EXPECT_EQ(s.size(), 1u);
EXPECT_EQ(s.getTotalBytes(), 128);
EXPECT_EQ(s.begin()->start, 0);
EXPECT_EQ(s.begin()->end, 128);
}
TEST(IntervalSet, StridedNonAdjacentAccess) {
// Stride-8 access: [0,4), [8,12), [16,20), ...
// None should merge on append or finalize.
IntervalSet s;
for (int lane = 0; lane < 32; ++lane) {
s.append(lane * 8, lane * 8 + 4);
}
EXPECT_EQ(s.size(), 32u);
EXPECT_EQ(s.getTotalBytes(), 128);
s.finalize();
EXPECT_EQ(s.size(), 32u);
}
TEST(IntervalSet, ReverseAdjacentAppendMerges) {
// Append in reverse order. Each new interval is adjacent to the back,
// so append merges them all into one.
IntervalSet s;
for (int lane = 31; lane >= 0; --lane) {
s.append(lane * 4, lane * 4 + 4);
}
EXPECT_EQ(s.size(), 1u);
EXPECT_EQ(s.getTotalBytes(), 128);
EXPECT_EQ(s.begin()->start, 0);
EXPECT_EQ(s.begin()->end, 128);
}
TEST(IntervalSet, DisjointReverseRequiresFinalize) {
// Append non-adjacent intervals in reverse order.
// No merging during append; finalize sorts and merges adjacent ones.
IntervalSet s;
s.append(20, 24);
s.append(10, 14);
s.append(0, 4);
EXPECT_EQ(s.size(), 3u);
s.finalize();
EXPECT_EQ(s.size(), 3u);
auto it = s.begin();
EXPECT_EQ(it->start, 0);
EXPECT_EQ((it + 1)->start, 10);
EXPECT_EQ((it + 2)->start, 20);
}
TEST(IntervalSet, ContainsAfterFinalize) {
IntervalSet s;
s.append(20, 24);
s.append(0, 4);
s.finalize();
EXPECT_TRUE(s.contains(0));
EXPECT_TRUE(s.contains(3));
EXPECT_FALSE(s.contains(4));
EXPECT_TRUE(s.contains(20));
EXPECT_FALSE(s.contains(24));
EXPECT_FALSE(s.contains(10));
}
TEST(IntervalSet, RangeBasedFor) {
IntervalSet s;
s.append(0, 4);
s.append(8, 12);
int total = 0;
for (const auto &iv : s) {
total += iv.end - iv.start;
}
EXPECT_EQ(total, 8);
}
TEST(IntervalSet, DuplicateAppend) {
// Appending the same interval twice should merge.
IntervalSet s;
s.append(0, 4);
s.append(0, 4);
EXPECT_EQ(s.size(), 1u);
EXPECT_EQ(s.getTotalBytes(), 4);
}
// --- overlapsRange tests (binary search) ---
TEST(IntervalSet, OverlapsRangeEmpty) {
IntervalSet s;
EXPECT_FALSE(s.overlapsRange(0, 10));
}
TEST(IntervalSet, OverlapsRangeExactMatch) {
IntervalSet s;
s.append(10, 20);
s.finalize();
EXPECT_TRUE(s.overlapsRange(10, 20));
}
TEST(IntervalSet, OverlapsRangePartialOverlap) {
IntervalSet s;
s.append(10, 20);
s.finalize();
// Query overlaps the left edge.
EXPECT_TRUE(s.overlapsRange(5, 15));
// Query overlaps the right edge.
EXPECT_TRUE(s.overlapsRange(15, 25));
// Query is a subset.
EXPECT_TRUE(s.overlapsRange(12, 18));
// Query is a superset.
EXPECT_TRUE(s.overlapsRange(5, 25));
}
TEST(IntervalSet, OverlapsRangeNoOverlap) {
IntervalSet s;
s.append(10, 20);
s.finalize();
// Query is entirely before.
EXPECT_FALSE(s.overlapsRange(0, 10));
// Query is entirely after.
EXPECT_FALSE(s.overlapsRange(20, 30));
// Single byte just before.
EXPECT_FALSE(s.overlapsRange(9, 10));
// Single byte just after.
EXPECT_FALSE(s.overlapsRange(20, 21));
}
TEST(IntervalSet, OverlapsRangeMultipleIntervals) {
// [0,4) [10,14) [20,24)
IntervalSet s;
s.append(0, 4);
s.append(10, 14);
s.append(20, 24);
s.finalize();
// Hits first interval.
EXPECT_TRUE(s.overlapsRange(2, 6));
// Hits middle interval.
EXPECT_TRUE(s.overlapsRange(12, 13));
// Hits last interval.
EXPECT_TRUE(s.overlapsRange(18, 22));
// Falls in gap between first and second.
EXPECT_FALSE(s.overlapsRange(5, 9));
// Falls in gap between second and third.
EXPECT_FALSE(s.overlapsRange(15, 19));
// Before all.
EXPECT_FALSE(s.overlapsRange(-5, 0));
// After all.
EXPECT_FALSE(s.overlapsRange(25, 30));
}
TEST(IntervalSet, OverlapsRangeSingleByte) {
IntervalSet s;
s.append(100, 104);
s.finalize();
// Single-byte query inside.
EXPECT_TRUE(s.overlapsRange(100, 101));
EXPECT_TRUE(s.overlapsRange(103, 104));
// Single-byte query outside.
EXPECT_FALSE(s.overlapsRange(99, 100));
EXPECT_FALSE(s.overlapsRange(104, 105));
}