diff options
| author | TSR Berry <20988865+TSRBerry@users.noreply.github.com> | 2023-04-08 01:22:00 +0200 |
|---|---|---|
| committer | Mary <thog@protonmail.com> | 2023-04-27 23:51:14 +0200 |
| commit | cee712105850ac3385cd0091a923438167433f9f (patch) | |
| tree | 4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /Ryujinx.Tests/Memory | |
| parent | cd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff) | |
Move solution and projects to src
Diffstat (limited to 'Ryujinx.Tests/Memory')
| -rw-r--r-- | Ryujinx.Tests/Memory/MockMemoryManager.cs | 53 | ||||
| -rw-r--r-- | Ryujinx.Tests/Memory/PartialUnmaps.cs | 469 |
2 files changed, 0 insertions, 522 deletions
diff --git a/Ryujinx.Tests/Memory/MockMemoryManager.cs b/Ryujinx.Tests/Memory/MockMemoryManager.cs deleted file mode 100644 index eeecf419..00000000 --- a/Ryujinx.Tests/Memory/MockMemoryManager.cs +++ /dev/null @@ -1,53 +0,0 @@ -using ARMeilleure.Memory; -using System; - -namespace Ryujinx.Tests.Memory -{ - internal class MockMemoryManager : IMemoryManager - { - public int AddressSpaceBits => throw new NotImplementedException(); - - public IntPtr PageTablePointer => throw new NotImplementedException(); - - public MemoryManagerType Type => MemoryManagerType.HostMappedUnsafe; - -#pragma warning disable CS0067 - public event Action<ulong, ulong> UnmapEvent; -#pragma warning restore CS0067 - - public ref T GetRef<T>(ulong va) where T : unmanaged - { - throw new NotImplementedException(); - } - - public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false) - { - throw new NotImplementedException(); - } - - public bool IsMapped(ulong va) - { - throw new NotImplementedException(); - } - - public T Read<T>(ulong va) where T : unmanaged - { - throw new NotImplementedException(); - } - - public T ReadTracked<T>(ulong va) where T : unmanaged - { - throw new NotImplementedException(); - } - - public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null) - { - throw new NotImplementedException(); - } - - public void Write<T>(ulong va, T value) where T : unmanaged - { - throw new NotImplementedException(); - } - } -} diff --git a/Ryujinx.Tests/Memory/PartialUnmaps.cs b/Ryujinx.Tests/Memory/PartialUnmaps.cs deleted file mode 100644 index b805969d..00000000 --- a/Ryujinx.Tests/Memory/PartialUnmaps.cs +++ /dev/null @@ -1,469 +0,0 @@ -using ARMeilleure.Signal; -using ARMeilleure.Translation; -using NUnit.Framework; -using Ryujinx.Common.Memory.PartialUnmaps; -using Ryujinx.Cpu; -using Ryujinx.Cpu.Jit; -using Ryujinx.Memory; -using Ryujinx.Memory.Tests; -using Ryujinx.Memory.Tracking; -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Threading; - -namespace Ryujinx.Tests.Memory -{ - [TestFixture] - internal class PartialUnmaps - { - private static Translator _translator; - - private (MemoryBlock virt, MemoryBlock mirror, MemoryEhMeilleure exceptionHandler) GetVirtual(ulong asSize) - { - MemoryAllocationFlags asFlags = MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible; - - var addressSpace = new MemoryBlock(asSize, asFlags); - var addressSpaceMirror = new MemoryBlock(asSize, asFlags); - - var tracking = new MemoryTracking(new MockVirtualMemoryManager(asSize, 0x1000), 0x1000); - var exceptionHandler = new MemoryEhMeilleure(addressSpace, addressSpaceMirror, tracking); - - return (addressSpace, addressSpaceMirror, exceptionHandler); - } - - private int CountThreads(ref PartialUnmapState state) - { - int count = 0; - - ref var ids = ref state.LocalCounts.ThreadIds; - - for (int i = 0; i < ids.Length; i++) - { - if (ids[i] != 0) - { - count++; - } - } - - return count; - } - - private void EnsureTranslator() - { - // Create a translator, as one is needed to register the signal handler or emit methods. - _translator ??= new Translator(new JitMemoryAllocator(), new MockMemoryManager(), true); - } - - [Test] - // Memory aliasing tests fail on CI at the moment. - [Platform(Exclude = "MacOsX")] - public void PartialUnmap([Values] bool readOnly) - { - // Set up an address space to test partial unmapping. - // Should register the signal handler to deal with this on Windows. - ulong vaSize = 0x100000; - - // The first 0x100000 is mapped to start. It is replaced from the center with the 0x200000 mapping. - var backing = new MemoryBlock(vaSize * 2, MemoryAllocationFlags.Mirrorable); - - (MemoryBlock unusedMainMemory, MemoryBlock memory, MemoryEhMeilleure exceptionHandler) = GetVirtual(vaSize * 2); - - EnsureTranslator(); - - ref var state = ref PartialUnmapState.GetRef(); - - Thread testThread = null; - bool shouldAccess = true; - - try - { - // Globally reset the struct for handling partial unmap races. - PartialUnmapState.Reset(); - bool error = false; - - // Create a large mapping. - memory.MapView(backing, 0, 0, vaSize); - - if (readOnly) - { - memory.Reprotect(0, vaSize, MemoryPermission.Read); - } - - if (readOnly) - { - // Write a value to the physical memory, then try to read it repeately from virtual. - // It should not change. - testThread = new Thread(() => - { - int i = 12345; - backing.Write(vaSize - 0x1000, i); - - while (shouldAccess) - { - if (memory.Read<int>(vaSize - 0x1000) != i) - { - error = true; - shouldAccess = false; - } - } - }); - } - else - { - // Repeatedly write and check the value on the last page of the mapping on another thread. - testThread = new Thread(() => - { - int i = 0; - while (shouldAccess) - { - memory.Write(vaSize - 0x1000, i); - if (memory.Read<int>(vaSize - 0x1000) != i) - { - error = true; - shouldAccess = false; - } - - i++; - } - }); - } - - testThread.Start(); - - // Create a smaller mapping, covering the larger mapping. - // Immediately try to write to the part of the larger mapping that did not change. - // Do this a lot, with the smaller mapping gradually increasing in size. Should not crash, data should not be lost. - - ulong pageSize = 0x1000; - int mappingExpandCount = (int)(vaSize / (pageSize * 2)) - 1; - ulong vaCenter = vaSize / 2; - - for (int i = 1; i <= mappingExpandCount; i++) - { - ulong start = vaCenter - (pageSize * (ulong)i); - ulong size = pageSize * (ulong)i * 2; - - ulong startPa = start + vaSize; - - memory.MapView(backing, startPa, start, size); - } - - // On Windows, this should put unmap counts on the thread local map. - if (OperatingSystem.IsWindows()) - { - // One thread should be present on the thread local map. Trimming should remove it. - Assert.AreEqual(1, CountThreads(ref state)); - } - - shouldAccess = false; - testThread.Join(); - - Assert.False(error); - - string test = null; - - try - { - test.IndexOf('1'); - } - catch (NullReferenceException) - { - // This shouldn't freeze. - } - - if (OperatingSystem.IsWindows()) - { - state.TrimThreads(); - - Assert.AreEqual(0, CountThreads(ref state)); - } - - /* - * Use this to test invalid access. Can't put this in the test suite unfortunately as invalid access crashes the test process. - * memory.Reprotect(vaSize - 0x1000, 0x1000, MemoryPermission.None); - * //memory.UnmapView(backing, vaSize - 0x1000, 0x1000); - * memory.Read<int>(vaSize - 0x1000); - */ - } - finally - { - // In case something failed, we want to ensure the test thread is dead before disposing of the memory. - shouldAccess = false; - testThread?.Join(); - - exceptionHandler.Dispose(); - unusedMainMemory.Dispose(); - memory.Dispose(); - backing.Dispose(); - } - } - - [Test] - // Memory aliasing tests fail on CI at the moment. - [Platform(Exclude = "MacOsX")] - public unsafe void PartialUnmapNative() - { - - // Set up an address space to test partial unmapping. - // Should register the signal handler to deal with this on Windows. - ulong vaSize = 0x100000; - - // The first 0x100000 is mapped to start. It is replaced from the center with the 0x200000 mapping. - var backing = new MemoryBlock(vaSize * 2, MemoryAllocationFlags.Mirrorable); - - (MemoryBlock mainMemory, MemoryBlock unusedMirror, MemoryEhMeilleure exceptionHandler) = GetVirtual(vaSize * 2); - - EnsureTranslator(); - - ref var state = ref PartialUnmapState.GetRef(); - - // Create some state to be used for managing the native writing loop. - int stateSize = Unsafe.SizeOf<NativeWriteLoopState>(); - var statePtr = Marshal.AllocHGlobal(stateSize); - Unsafe.InitBlockUnaligned((void*)statePtr, 0, (uint)stateSize); - - ref NativeWriteLoopState writeLoopState = ref Unsafe.AsRef<NativeWriteLoopState>((void*)statePtr); - writeLoopState.Running = 1; - writeLoopState.Error = 0; - - try - { - // Globally reset the struct for handling partial unmap races. - PartialUnmapState.Reset(); - - // Create a large mapping. - mainMemory.MapView(backing, 0, 0, vaSize); - - var writeFunc = TestMethods.GenerateDebugNativeWriteLoop(); - IntPtr writePtr = mainMemory.GetPointer(vaSize - 0x1000, 4); - - Thread testThread = new Thread(() => - { - writeFunc(statePtr, writePtr); - }); - - testThread.Start(); - - // Create a smaller mapping, covering the larger mapping. - // Immediately try to write to the part of the larger mapping that did not change. - // Do this a lot, with the smaller mapping gradually increasing in size. Should not crash, data should not be lost. - - ulong pageSize = 0x1000; - int mappingExpandCount = (int)(vaSize / (pageSize * 2)) - 1; - ulong vaCenter = vaSize / 2; - - for (int i = 1; i <= mappingExpandCount; i++) - { - ulong start = vaCenter - (pageSize * (ulong)i); - ulong size = pageSize * (ulong)i * 2; - - ulong startPa = start + vaSize; - - mainMemory.MapView(backing, startPa, start, size); - } - - writeLoopState.Running = 0; - testThread.Join(); - - Assert.False(writeLoopState.Error != 0); - } - finally - { - Marshal.FreeHGlobal(statePtr); - - exceptionHandler.Dispose(); - mainMemory.Dispose(); - unusedMirror.Dispose(); - backing.Dispose(); - } - } - - [Test] - // Only test in Windows, as this is only used on Windows and uses Windows APIs for trimming. - [Platform("Win")] - [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")] - public void ThreadLocalMap() - { - PartialUnmapState.Reset(); - ref var state = ref PartialUnmapState.GetRef(); - - bool running = true; - var testThread = new Thread(() => - { - PartialUnmapState.GetRef().RetryFromAccessViolation(); - while (running) - { - Thread.Sleep(1); - } - }); - - testThread.Start(); - Thread.Sleep(200); - - Assert.AreEqual(1, CountThreads(ref state)); - - // Trimming should not remove the thread as it's still active. - state.TrimThreads(); - Assert.AreEqual(1, CountThreads(ref state)); - - running = false; - - testThread.Join(); - - // Should trim now that it's inactive. - state.TrimThreads(); - Assert.AreEqual(0, CountThreads(ref state)); - } - - [Test] - // Only test in Windows, as this is only used on Windows and uses Windows APIs for trimming. - [Platform("Win")] - public unsafe void ThreadLocalMapNative() - { - EnsureTranslator(); - - PartialUnmapState.Reset(); - - ref var state = ref PartialUnmapState.GetRef(); - - fixed (void* localMap = &state.LocalCounts) - { - var getOrReserve = TestMethods.GenerateDebugThreadLocalMapGetOrReserve((IntPtr)localMap); - - for (int i = 0; i < ThreadLocalMap<int>.MapSize; i++) - { - // Should obtain the index matching the call #. - Assert.AreEqual(i, getOrReserve(i + 1, i)); - - // Check that this and all previously reserved thread IDs and struct contents are intact. - for (int j = 0; j <= i; j++) - { - Assert.AreEqual(j + 1, state.LocalCounts.ThreadIds[j]); - Assert.AreEqual(j, state.LocalCounts.Structs[j]); - } - } - - // Trying to reserve again when the map is full should return -1. - Assert.AreEqual(-1, getOrReserve(200, 0)); - - for (int i = 0; i < ThreadLocalMap<int>.MapSize; i++) - { - // Should obtain the index matching the call #, as it already exists. - Assert.AreEqual(i, getOrReserve(i + 1, -1)); - - // The struct should not be reset to -1. - Assert.AreEqual(i, state.LocalCounts.Structs[i]); - } - - // Clear one of the ids as if it were freed. - state.LocalCounts.ThreadIds[13] = 0; - - // GetOrReserve should now obtain and return 13. - Assert.AreEqual(13, getOrReserve(300, 301)); - Assert.AreEqual(300, state.LocalCounts.ThreadIds[13]); - Assert.AreEqual(301, state.LocalCounts.Structs[13]); - } - } - - [Test] - public void NativeReaderWriterLock() - { - var rwLock = new NativeReaderWriterLock(); - var threads = new List<Thread>(); - - int value = 0; - - bool running = true; - bool error = false; - int readersAllowed = 1; - - for (int i = 0; i < 5; i++) - { - var readThread = new Thread(() => - { - int count = 0; - while (running) - { - rwLock.AcquireReaderLock(); - - int originalValue = Thread.VolatileRead(ref value); - - count++; - - // Spin a bit. - for (int i = 0; i < 100; i++) - { - if (Thread.VolatileRead(ref readersAllowed) == 0) - { - error = true; - running = false; - } - } - - // Should not change while the lock is held. - if (Thread.VolatileRead(ref value) != originalValue) - { - error = true; - running = false; - } - - rwLock.ReleaseReaderLock(); - } - }); - - threads.Add(readThread); - } - - for (int i = 0; i < 2; i++) - { - var writeThread = new Thread(() => - { - int count = 0; - while (running) - { - rwLock.AcquireReaderLock(); - rwLock.UpgradeToWriterLock(); - - Thread.Sleep(2); - count++; - - Interlocked.Exchange(ref readersAllowed, 0); - - for (int i = 0; i < 10; i++) - { - Interlocked.Increment(ref value); - } - - Interlocked.Exchange(ref readersAllowed, 1); - - rwLock.DowngradeFromWriterLock(); - rwLock.ReleaseReaderLock(); - - Thread.Sleep(1); - } - }); - - threads.Add(writeThread); - } - - foreach (var thread in threads) - { - thread.Start(); - } - - Thread.Sleep(1000); - - running = false; - - foreach (var thread in threads) - { - thread.Join(); - } - - Assert.False(error); - } - } -}
\ No newline at end of file |
