mirror of
				https://github.com/Ryujinx/Ryujinx.git
				synced 2025-10-31 21:02:50 +00:00 
			
		
		
		
	Add a simple Pools Limiter. (#1830)
* Added support for offline invalidation, via PPTC, of low cq translations replaced by high cq translations; both on a single run and between runs. Added invalidation of .cache files in the event of reuse on a different user operating system. Added .info and .cache files invalidation in case of a failed stream decompression. Nits. * InternalVersion = 1712; * Nits. * Address comment. * Get rid of BinaryFormatter. Nits. * Move Ptc.LoadTranslations(). Nits. * Nits. * Fixed corner cases (in case backup copies have to be used). Added save logs. * Not core fixes. * Complement to the previous commit. Added load logs. Removed BinaryFormatter leftovers. * Add LoadTranslations log. * Nits. * Removed the search and management of LowCq overlapping functions. * Final increment of .info and .cache flags. * Nit. * Free up memory allocated by Pools during any PPTC translations at boot time. * Nit due to rebase. * Add a simple Pools Limiter. * Nits. * Fix missing JumpTable.RegisterFunction() due to rebase. Clear MemoryStreams as soon as possible, when they are no longer needed. * Code cleaning. * Nit for retrigger Checks. * Update Ptc.cs * Contextual refactoring of Translator. Ignore resetting of pools for DirectCallStubs. * Nit for retrigger Checks.
This commit is contained in:
		
							parent
							
								
									e57b140429
								
							
						
					
					
						commit
						68f6b79fd3
					
				| @ -1,13 +1,13 @@ | ||||
| using System; | ||||
| using System.Collections.Concurrent; | ||||
| using System.Collections.Generic; | ||||
| using System.Threading; | ||||
| 
 | ||||
| namespace ARMeilleure.Common | ||||
| { | ||||
|     class ThreadStaticPool<T> where T : class, new() | ||||
|     { | ||||
|         private const int PoolSizeIncrement = 200; | ||||
|         private const int ChunkSizeLimit = 1000; // even | ||||
|         private const int PoolSizeIncrement = 200; // > 0 | ||||
| 
 | ||||
|         [ThreadStatic] | ||||
|         private static ThreadStaticPool<T> _instance; | ||||
| @ -25,11 +25,11 @@ namespace ARMeilleure.Common | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static ConcurrentDictionary<int, Stack<ThreadStaticPool<T>>> _pools = new ConcurrentDictionary<int, Stack<ThreadStaticPool<T>>>(); | ||||
|         private static ConcurrentDictionary<int, Stack<ThreadStaticPool<T>>> _pools = new(); | ||||
| 
 | ||||
|         private static Stack<ThreadStaticPool<T>> GetPools(int groupId) | ||||
|         { | ||||
|             return _pools.GetOrAdd(groupId, x => new Stack<ThreadStaticPool<T>>()); | ||||
|             return _pools.GetOrAdd(groupId, (groupId) => new()); | ||||
|         } | ||||
| 
 | ||||
|         public static void PreparePool(int groupId) | ||||
| @ -41,19 +41,20 @@ namespace ARMeilleure.Common | ||||
|                 var pools = GetPools(groupId); | ||||
|                 lock (pools) | ||||
|                 { | ||||
|                     _instance = (pools.Count != 0) ? pools.Pop() : new ThreadStaticPool<T>(PoolSizeIncrement * 2); | ||||
|                     _instance = (pools.Count != 0) ? pools.Pop() : new(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public static void ReturnPool(int groupId) | ||||
|         { | ||||
|             // Reset and return the pool for this thread to the specified group. | ||||
|             // Reset, limit if necessary, and return the pool for this thread to the specified group. | ||||
| 
 | ||||
|             var pools = GetPools(groupId); | ||||
|             lock (pools) | ||||
|             { | ||||
|                 _instance.Clear(); | ||||
|                 _instance.ChunkSizeLimiter(); | ||||
|                 pools.Push(_instance); | ||||
| 
 | ||||
|                 _instance = null; | ||||
| @ -66,58 +67,75 @@ namespace ARMeilleure.Common | ||||
| 
 | ||||
|             foreach (var pools in _pools.Values) | ||||
|             { | ||||
|                 foreach (var instance in pools) | ||||
|                 { | ||||
|                     instance.Dispose(); | ||||
|                 } | ||||
| 
 | ||||
|                 pools.Clear(); | ||||
|             } | ||||
| 
 | ||||
|             _pools.Clear(); | ||||
|         } | ||||
| 
 | ||||
|         private T[] _pool; | ||||
|         private int _poolUsed = -1; | ||||
|         private int _poolSize; | ||||
|         private List<T[]> _pool; | ||||
|         private int _chunkIndex = -1; | ||||
|         private int _poolIndex = -1; | ||||
| 
 | ||||
|         public ThreadStaticPool(int initialSize) | ||||
|         private ThreadStaticPool() | ||||
|         { | ||||
|             _pool = new T[initialSize]; | ||||
|             _pool = new(ChunkSizeLimit * 2); | ||||
| 
 | ||||
|             for (int i = 0; i < initialSize; i++) | ||||
|             { | ||||
|                 _pool[i] = new T(); | ||||
|             } | ||||
| 
 | ||||
|             _poolSize = initialSize; | ||||
|             AddChunkIfNeeded(); | ||||
|         } | ||||
| 
 | ||||
|         public T Allocate() | ||||
|         { | ||||
|             int index = Interlocked.Increment(ref _poolUsed); | ||||
| 
 | ||||
|             if (index >= _poolSize) | ||||
|             if (++_poolIndex >= PoolSizeIncrement) | ||||
|             { | ||||
|                 IncreaseSize(); | ||||
|                 AddChunkIfNeeded(); | ||||
| 
 | ||||
|                 _poolIndex = 0; | ||||
|             } | ||||
| 
 | ||||
|             return _pool[index]; | ||||
|             return _pool[_chunkIndex][_poolIndex]; | ||||
|         } | ||||
| 
 | ||||
|         private void IncreaseSize() | ||||
|         private void AddChunkIfNeeded() | ||||
|         { | ||||
|             _poolSize += PoolSizeIncrement; | ||||
| 
 | ||||
|             T[] newArray = new T[_poolSize]; | ||||
|             Array.Copy(_pool, 0, newArray, 0, _pool.Length); | ||||
| 
 | ||||
|             for (int i = _pool.Length; i < _poolSize; i++) | ||||
|             if (++_chunkIndex >= _pool.Count) | ||||
|             { | ||||
|                 newArray[i] = new T(); | ||||
|             } | ||||
|                 T[] pool = new T[PoolSizeIncrement]; | ||||
| 
 | ||||
|             Interlocked.Exchange(ref _pool, newArray); | ||||
|                 for (int i = 0; i < PoolSizeIncrement; i++) | ||||
|                 { | ||||
|                     pool[i] = new T(); | ||||
|                 } | ||||
| 
 | ||||
|                 _pool.Add(pool); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void Clear() | ||||
|         { | ||||
|             _poolUsed = -1; | ||||
|             _chunkIndex = 0; | ||||
|             _poolIndex = -1; | ||||
|         } | ||||
| 
 | ||||
|         private void ChunkSizeLimiter() | ||||
|         { | ||||
|             if (_pool.Count >= ChunkSizeLimit) | ||||
|             { | ||||
|                 int newChunkSize = ChunkSizeLimit / 2; | ||||
| 
 | ||||
|                 _pool.RemoveRange(newChunkSize, _pool.Count - newChunkSize); | ||||
|                 _pool.Capacity = ChunkSizeLimit * 2; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private void Dispose() | ||||
|         { | ||||
|             _pool.Clear(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -34,8 +34,6 @@ namespace ARMeilleure.Translation | ||||
|                 _indirectCallStubPtr     = Marshal.GetFunctionPointerForDelegate<GuestFunction>(GenerateIndirectCallStub(false)); | ||||
|                 _indirectTailCallStubPtr = Marshal.GetFunctionPointerForDelegate<GuestFunction>(GenerateIndirectCallStub(true)); | ||||
| 
 | ||||
|                 Translator.ResetPools(); | ||||
| 
 | ||||
|                 _initialized = true; | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @ -98,7 +98,6 @@ namespace ARMeilleure.Translation.PTC | ||||
|             ClearMemoryStreams(); | ||||
|             PtcJumpTable.Clear(); | ||||
| 
 | ||||
|             PtcProfiler.Stop(); | ||||
|             PtcProfiler.Wait(); | ||||
|             PtcProfiler.ClearEntries(); | ||||
| 
 | ||||
| @ -345,6 +344,8 @@ namespace ARMeilleure.Translation.PTC | ||||
| 
 | ||||
|         private static void Save(string fileName) | ||||
|         { | ||||
|             int translatedFuncsCount; | ||||
| 
 | ||||
|             using (MemoryStream stream = new MemoryStream()) | ||||
|             using (MD5 md5 = MD5.Create()) | ||||
|             { | ||||
| @ -361,6 +362,11 @@ namespace ARMeilleure.Translation.PTC | ||||
| 
 | ||||
|                 PtcJumpTable.Serialize(stream, PtcJumpTable); | ||||
| 
 | ||||
|                 translatedFuncsCount = GetInfosEntriesCount(); | ||||
| 
 | ||||
|                 ClearMemoryStreams(); | ||||
|                 PtcJumpTable.Clear(); | ||||
| 
 | ||||
|                 stream.Seek((long)hashSize, SeekOrigin.Begin); | ||||
|                 byte[] hash = md5.ComputeHash(stream); | ||||
| 
 | ||||
| @ -388,7 +394,7 @@ namespace ARMeilleure.Translation.PTC | ||||
| 
 | ||||
|             long fileSize = new FileInfo(fileName).Length; | ||||
| 
 | ||||
|             Logger.Info?.Print(LogClass.Ptc, $"Saved Translation Cache (size: {fileSize} bytes, translated functions: {GetInfosEntriesCount()})."); | ||||
|             Logger.Info?.Print(LogClass.Ptc, $"Saved Translation Cache (size: {fileSize} bytes, translated functions: {translatedFuncsCount})."); | ||||
|         } | ||||
| 
 | ||||
|         private static void WriteHeader(MemoryStream stream) | ||||
| @ -709,10 +715,10 @@ namespace ARMeilleure.Translation.PTC | ||||
| 
 | ||||
|             threads.Clear(); | ||||
| 
 | ||||
|             _loggerEvent.Set(); | ||||
| 
 | ||||
|             Translator.ResetPools(); | ||||
| 
 | ||||
|             _loggerEvent.Set(); | ||||
| 
 | ||||
|             PtcJumpTable.Initialize(jumpTable); | ||||
| 
 | ||||
|             PtcJumpTable.ReadJumpTable(jumpTable); | ||||
| @ -736,7 +742,7 @@ namespace ARMeilleure.Translation.PTC | ||||
|             Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {profiledFuncsToTranslateCount} functions translated"); | ||||
|         } | ||||
| 
 | ||||
|         internal static void WriteInfoCodeReloc(ulong address, ulong guestSize, bool highCq, PtcInfo ptcInfo) | ||||
|         internal static void WriteInfoCodeRelocUnwindInfo(ulong address, ulong guestSize, bool highCq, PtcInfo ptcInfo) | ||||
|         { | ||||
|             lock (_lock) | ||||
|             { | ||||
|  | ||||
| @ -201,15 +201,14 @@ namespace ARMeilleure.Translation | ||||
|         { | ||||
|             ArmEmitterContext context = new ArmEmitterContext(memory, jumpTable, address, highCq, Aarch32Mode.User); | ||||
| 
 | ||||
|             PrepareOperandPool(highCq); | ||||
|             PrepareOperationPool(highCq); | ||||
| 
 | ||||
|             Logger.StartPass(PassName.Decoding); | ||||
| 
 | ||||
|             Block[] blocks = Decoder.Decode(memory, address, mode, highCq, singleBlock: false); | ||||
| 
 | ||||
|             Logger.EndPass(PassName.Decoding); | ||||
| 
 | ||||
|             PreparePool(highCq); | ||||
| 
 | ||||
|             Logger.StartPass(PassName.Translation); | ||||
| 
 | ||||
|             EmitSynchronization(context); | ||||
| @ -240,23 +239,33 @@ namespace ARMeilleure.Translation | ||||
|             if (Ptc.State == PtcState.Disabled) | ||||
|             { | ||||
|                 func = Compiler.Compile<GuestFunction>(cfg, argTypes, OperandType.I64, options); | ||||
| 
 | ||||
|                 ReturnPool(highCq); | ||||
|             } | ||||
|             else | ||||
|             else using (PtcInfo ptcInfo = new PtcInfo()) | ||||
|             { | ||||
|                 using (PtcInfo ptcInfo = new PtcInfo()) | ||||
|                 { | ||||
|                     func = Compiler.Compile<GuestFunction>(cfg, argTypes, OperandType.I64, options, ptcInfo); | ||||
|                 func = Compiler.Compile<GuestFunction>(cfg, argTypes, OperandType.I64, options, ptcInfo); | ||||
| 
 | ||||
|                     Ptc.WriteInfoCodeReloc(address, funcSize, highCq, ptcInfo); | ||||
|                 } | ||||
|                 ReturnPool(highCq); | ||||
| 
 | ||||
|                 Ptc.WriteInfoCodeRelocUnwindInfo(address, funcSize, highCq, ptcInfo); | ||||
|             } | ||||
| 
 | ||||
|             ReturnOperandPool(highCq); | ||||
|             ReturnOperationPool(highCq); | ||||
| 
 | ||||
|             return new TranslatedFunction(func, funcSize, highCq); | ||||
|         } | ||||
| 
 | ||||
|         internal static void PreparePool(bool highCq) | ||||
|         { | ||||
|             PrepareOperandPool(highCq); | ||||
|             PrepareOperationPool(highCq); | ||||
|         } | ||||
| 
 | ||||
|         internal static void ReturnPool(bool highCq) | ||||
|         { | ||||
|             ReturnOperandPool(highCq); | ||||
|             ReturnOperationPool(highCq); | ||||
|         } | ||||
| 
 | ||||
|         internal static void ResetPools() | ||||
|         { | ||||
|             ResetOperandPools(); | ||||
|  | ||||
| @ -40,6 +40,8 @@ namespace Ryujinx.Memory | ||||
|             } | ||||
| 
 | ||||
|             Size = size; | ||||
| 
 | ||||
|             GC.AddMemoryPressure((long)Size); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
| @ -281,6 +283,8 @@ namespace Ryujinx.Memory | ||||
|             if (ptr != IntPtr.Zero) | ||||
|             { | ||||
|                 MemoryManagement.Free(ptr); | ||||
| 
 | ||||
|                 GC.RemoveMemoryPressure((long)Size); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 LDj3SNuD
						LDj3SNuD