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
253 lines
6.3 KiB
C++
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));
|
|
}
|