Skip to content

Commit 7262633

Browse files
committed
rsx/mm: Add unit tests
1 parent 0c486fb commit 7262633

2 files changed

Lines changed: 139 additions & 0 deletions

File tree

rpcs3/tests/rpcs3_test.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
<ClCompile Include="test_fmt.cpp" />
101101
<ClCompile Include="test_rsx_cfg.cpp" />
102102
<ClCompile Include="test_rsx_fp_asm.cpp" />
103+
<ClCompile Include="test_rsx_mm_queue.cpp" />
103104
<ClCompile Include="test_simple_array.cpp" />
104105
<ClCompile Include="test_address_range.cpp" />
105106
<ClCompile Include="test_sys_fs.cpp" />

rpcs3/tests/test_rsx_mm_queue.cpp

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#include <gtest/gtest.h>
2+
#include "Emu/RSX/Host/MM.cpp"
3+
4+
namespace rsx::MM
5+
{
6+
class MMQueue : public ::testing::Test
7+
{
8+
protected:
9+
static constexpr u32 s_pages = 16;
10+
11+
u64 m_page_size = 0;
12+
u8* m_base = nullptr;
13+
14+
void SetUp() override
15+
{
16+
g_cfg.video.disable_async_host_memory_manager.set(false);
17+
18+
m_page_size = static_cast<u64>(utils::get_page_size());
19+
m_base = static_cast<u8*>(utils::memory_reserve(m_page_size * s_pages));
20+
utils::memory_commit(m_base, m_page_size * s_pages);
21+
22+
g_deferred_mprotect_queue.clear();
23+
}
24+
25+
void TearDown() override
26+
{
27+
g_deferred_mprotect_queue.clear();
28+
utils::memory_release(m_base, m_page_size * s_pages);
29+
}
30+
31+
void* page(u32 index) const
32+
{
33+
return m_base + (index * m_page_size);
34+
}
35+
36+
utils::address_range64 pages(u32 first, u32 count) const
37+
{
38+
return utils::address_range64::start_length(reinterpret_cast<u64>(page(first)), count * m_page_size);
39+
}
40+
41+
void protect(u32 first, u32 count, utils::protection prot)
42+
{
43+
mm_protect(page(first), count * m_page_size, prot);
44+
}
45+
};
46+
47+
TEST_F(MMQueue, DeferredProtectIsQueuedUntilFlush)
48+
{
49+
protect(0, 1, utils::protection::no);
50+
51+
ASSERT_EQ(g_deferred_mprotect_queue.size(), 1u);
52+
EXPECT_EQ(g_deferred_mprotect_queue[0].range, pages(0, 1));
53+
EXPECT_EQ(g_deferred_mprotect_queue[0].prot, utils::protection::no);
54+
55+
mm_flush();
56+
EXPECT_TRUE(g_deferred_mprotect_queue.empty());
57+
}
58+
59+
TEST_F(MMQueue, MergesContiguousBlocks)
60+
{
61+
for (u32 i = 0; i < 4; i++)
62+
{
63+
protect(i, 1, utils::protection::ro);
64+
}
65+
66+
ASSERT_EQ(g_deferred_mprotect_queue.size(), 1u);
67+
EXPECT_EQ(g_deferred_mprotect_queue[0].range, pages(0, 4));
68+
}
69+
70+
TEST_F(MMQueue, MergesOverlappingBlocks)
71+
{
72+
protect(0, 2, utils::protection::ro);
73+
protect(1, 2, utils::protection::ro);
74+
75+
ASSERT_EQ(g_deferred_mprotect_queue.size(), 1u);
76+
EXPECT_EQ(g_deferred_mprotect_queue[0].range, pages(0, 3));
77+
}
78+
79+
TEST_F(MMQueue, DoesNotMergeAcrossProtections)
80+
{
81+
protect(0, 1, utils::protection::ro);
82+
protect(1, 1, utils::protection::no);
83+
84+
ASSERT_EQ(g_deferred_mprotect_queue.size(), 2u);
85+
EXPECT_EQ(g_deferred_mprotect_queue[0].prot, utils::protection::ro);
86+
EXPECT_EQ(g_deferred_mprotect_queue[1].prot, utils::protection::no);
87+
}
88+
89+
TEST_F(MMQueue, SwallowedBlockIsReplaced)
90+
{
91+
protect(2, 1, utils::protection::ro);
92+
protect(1, 3, utils::protection::no);
93+
94+
ASSERT_EQ(g_deferred_mprotect_queue.size(), 1u);
95+
EXPECT_EQ(g_deferred_mprotect_queue[0].range, pages(1, 3));
96+
EXPECT_EQ(g_deferred_mprotect_queue[0].prot, utils::protection::no);
97+
}
98+
99+
TEST_F(MMQueue, UnlockFlushesPrefixAndKeepsTail)
100+
{
101+
protect(0, 1, utils::protection::ro);
102+
protect(3, 2, utils::protection::no);
103+
protect(8, 1, utils::protection::ro);
104+
ASSERT_EQ(g_deferred_mprotect_queue.size(), 3u);
105+
106+
protect(4, 1, utils::protection::rw);
107+
108+
ASSERT_EQ(g_deferred_mprotect_queue.size(), 1u);
109+
EXPECT_EQ(g_deferred_mprotect_queue[0].range, pages(8, 1));
110+
EXPECT_EQ(g_deferred_mprotect_queue[0].prot, utils::protection::ro);
111+
}
112+
113+
TEST_F(MMQueue, UnlockSwallowingWholeQueueLeavesNoResidue)
114+
{
115+
protect(1, 1, utils::protection::ro);
116+
protect(3, 1, utils::protection::no);
117+
ASSERT_EQ(g_deferred_mprotect_queue.size(), 2u);
118+
119+
protect(0, 8, utils::protection::rw);
120+
121+
ASSERT_TRUE(g_deferred_mprotect_queue.empty());
122+
123+
mm_flush();
124+
EXPECT_TRUE(g_deferred_mprotect_queue.empty());
125+
}
126+
127+
TEST_F(MMQueue, FlushByRangeFlushesPrefixOnly)
128+
{
129+
protect(0, 1, utils::protection::ro);
130+
protect(4, 1, utils::protection::no);
131+
protect(8, 1, utils::protection::ro);
132+
133+
mm_flush(rsx::simple_array<utils::address_range64>{ pages(4, 1) });
134+
135+
ASSERT_EQ(g_deferred_mprotect_queue.size(), 1u);
136+
EXPECT_EQ(g_deferred_mprotect_queue[0].range, pages(8, 1));
137+
}
138+
}

0 commit comments

Comments
 (0)