diff --git a/Src/ILGPU/Backends/ArgumentMapper.cs b/Src/ILGPU/Backends/ArgumentMapper.cs index b19ec8b79..d5bccb64b 100644 --- a/Src/ILGPU/Backends/ArgumentMapper.cs +++ b/Src/ILGPU/Backends/ArgumentMapper.cs @@ -27,7 +27,7 @@ namespace ILGPU.Backends /// can be accessed by the native kernel. /// /// Members of this class are not thread safe. - public abstract class ArgumentMapper + public abstract class ArgumentMapper : ICache { #region Nested Types @@ -526,6 +526,15 @@ protected Type MapType(Type type) } } + /// + /// Clears internal caches. + /// + /// The clear mode. + public void ClearCache(ClearCacheMode mode) + { + typeMapping.Clear(); + } + #endregion } } diff --git a/Src/ILGPU/Backends/Backend.cs b/Src/ILGPU/Backends/Backend.cs index 59054b199..8752f1184 100644 --- a/Src/ILGPU/Backends/Backend.cs +++ b/Src/ILGPU/Backends/Backend.cs @@ -43,7 +43,7 @@ public enum TargetPlatform /// /// Represents a general ILGPU backend. /// - public abstract class Backend : DisposeBase + public abstract class Backend : DisposeBase, ICache { #region Nested Types @@ -460,6 +460,16 @@ protected static TargetPlatform GetPlatform(TargetPlatform? platform) in BackendContext backendContext, in KernelSpecialization specialization); + /// + /// Clears all internal caches. + /// + /// The clear mode. + /// This method is not thread-safe. + public void ClearCache(ClearCacheMode mode) + { + ArgumentMapper?.ClearCache(mode); + } + #endregion #region IDisposable diff --git a/Src/ILGPU/Context.Constants.cs b/Src/ILGPU/Context.Constants.cs index 303595ebd..4a3d56e38 100644 --- a/Src/ILGPU/Context.Constants.cs +++ b/Src/ILGPU/Context.Constants.cs @@ -18,10 +18,15 @@ partial class Context /// public const string RuntimeAssemblyName = "ILGPURuntime"; + /// + /// Represents the general ILGPU assembly name. + /// + public const string AssemblyName = "ILGPU"; + /// /// Represents the general ILGPU assembly module name. /// - public const string AssemblyModuleName = "ILGPU.dll"; + public const string FullAssemblyModuleName = AssemblyName + ".dll"; /// /// The ILGPU assembly file extension. diff --git a/Src/ILGPU/Context.cs b/Src/ILGPU/Context.cs index b21833fa2..cb9ddccef 100644 --- a/Src/ILGPU/Context.cs +++ b/Src/ILGPU/Context.cs @@ -32,7 +32,7 @@ namespace ILGPU /// Represents the main ILGPU context. /// /// Members of this class are thread safe. - public sealed partial class Context : DisposeBase + public sealed partial class Context : DisposeBase, ICache { #region Static @@ -129,8 +129,9 @@ static Context() private PTXContextData ptxContextData; private readonly object assemblyLock = new object(); - private readonly AssemblyBuilder assemblyBuilder; - private readonly ModuleBuilder moduleBuilder; + private int assemblyVersion = 0; + private AssemblyBuilder assemblyBuilder; + private ModuleBuilder moduleBuilder; private volatile int typeBuilderIdx = 0; /// @@ -195,13 +196,9 @@ public Context(ContextFlags flags, OptimizationLevel optimizationLevel) TransformerConfiguration.Transformed, Flags); - // Initialize assembly and module builder - var assemblyName = new AssemblyName(RuntimeAssemblyName); - assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); - moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); - - // Initialize context-dependent information - ptxContextData = new PTXContextData(this); + // Initialize assembly builder and context data + ReloadAssemblyBuilder(); + ReloadContextData(); } #endregion @@ -257,6 +254,31 @@ public Context(ContextFlags flags, OptimizationLevel optimizationLevel) #region Methods + /// + /// Reloads the assembly builder. + /// + private void ReloadAssemblyBuilder() + { + var assemblyName = new AssemblyName(RuntimeAssemblyName) + { + Version = new Version(1, assemblyVersion++), + }; + assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly( + assemblyName, + AssemblyBuilderAccess.RunAndCollect); + moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); + } + + /// + /// Reloads context-dependent information. + /// + private void ReloadContextData() + { + Dispose(ref ptxContextData); + + ptxContextData = new PTXContextData(this); + } + /// /// Returns true if the current context has the given flags. /// @@ -346,6 +368,24 @@ public Task BeginCodeGenerationAsync(IRContext irCon return Task.Run(() => BeginCodeGeneration(irContext)); } + /// + /// Clears internal caches. However, this does not affect individual accelerator caches. + /// + /// The clear mode. + /// + /// This method is not thread-safe. + /// + public void ClearCache(ClearCacheMode mode) + { + mainContext.ClearCache(mode); + typeContext.ClearCache(mode); + debugInformationManager.ClearCache(mode); + defaultILBackend.ClearCache(mode); + + ReloadAssemblyBuilder(); + ReloadContextData(); + } + #endregion #region Runtime Assembly diff --git a/Src/ILGPU/ContextFlags.cs b/Src/ILGPU/ContextFlags.cs index a6d055373..962790552 100644 --- a/Src/ILGPU/ContextFlags.cs +++ b/Src/ILGPU/ContextFlags.cs @@ -128,6 +128,8 @@ public enum ContextFlags : int /// /// However, IR nodes, type information and debug information will still /// be cached, since they are used for different kernel compilation operations. + /// If you want to clear those caches as well, you will have to clear them + /// manually using . /// DisableKernelCaching = 1 << 24, diff --git a/Src/ILGPU/Frontend/DebugInformation/DebugInformationManager.cs b/Src/ILGPU/Frontend/DebugInformation/DebugInformationManager.cs index ce9a30e62..a9ab5476c 100644 --- a/Src/ILGPU/Frontend/DebugInformation/DebugInformationManager.cs +++ b/Src/ILGPU/Frontend/DebugInformation/DebugInformationManager.cs @@ -24,7 +24,7 @@ namespace ILGPU.Frontend.DebugInformation /// /// Represents a debug-information manager. /// - public sealed class DebugInformationManager : DisposeBase + public sealed class DebugInformationManager : DisposeBase, ICache { #region Constants @@ -203,7 +203,7 @@ public bool Load(Assembly assembly, out AssemblyDebugInformation assemblyDebugIn #region Instance - private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim( + private readonly ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim( LockRecursionPolicy.SupportsRecursion); private readonly Dictionary pdbFiles = new Dictionary(); private readonly HashSet lookupDirectories = new HashSet(); @@ -432,6 +432,44 @@ public MethodScopeEnumerator LoadScopes(MethodBase methodBase) return MethodScopeEnumerator.Empty; } + /// + /// Clears cached debug information. + /// + /// The clear mode. + public void ClearCache(ClearCacheMode mode) + { + cacheLock.EnterWriteLock(); + try + { + if (mode == ClearCacheMode.Everything) + { + foreach (var debugInformation in assemblies.Values) + debugInformation.Dispose(); + assemblies.Clear(); + } + else + { + // Do not dispose system assemblies + var assembliesToRemove = new List(assemblies.Count); + foreach (var assembly in assemblies.Keys) + { + if (assembly.FullName.StartsWith(Context.AssemblyName, StringComparison.OrdinalIgnoreCase)) + continue; + assembliesToRemove.Add(assembly); + } + foreach (var assemblyToRemove in assembliesToRemove) + { + assemblies[assemblyToRemove].Dispose(); + assemblies.Remove(assemblyToRemove); + } + } + } + finally + { + cacheLock.ExitWriteLock(); + } + } + #endregion #region IDisposable @@ -441,10 +479,8 @@ public MethodScopeEnumerator LoadScopes(MethodBase methodBase) Justification = "Dispose method will be invoked by a helper method")] protected override void Dispose(bool disposing) { - foreach (var assembly in assemblies.Values) - assembly.Dispose(); - assemblies.Clear(); - Dispose(ref cacheLock); + ClearCache(ClearCacheMode.Everything); + cacheLock.Dispose(); } #endregion diff --git a/Src/ILGPU/ICache.cs b/Src/ILGPU/ICache.cs new file mode 100644 index 000000000..c0181a8ba --- /dev/null +++ b/Src/ILGPU/ICache.cs @@ -0,0 +1,44 @@ +// ----------------------------------------------------------------------------- +// ILGPU +// Copyright (c) 2016-2019 Marcel Koester +// www.ilgpu.net +// +// File: ICache.cs +// +// This file is part of ILGPU and is distributed under the University of +// Illinois Open Source License. See LICENSE.txt for details +// ----------------------------------------------------------------------------- + +namespace ILGPU +{ + /// + /// Specifies which resources should be removed from the cache. + /// + public enum ClearCacheMode : int + { + /// + /// Removes all non-ILGPU objects form the caches. + /// + Default = 0, + + /// + /// Removes everything from the caches. + /// + Everything = 1, + } + + /// + /// Represents an object that contains internal caches. + /// + public interface ICache + { + /// + /// Clears all internal caches. + /// + /// The clear mode. + /// + /// Implementations of this method are not guaranteed to be thread-safe. + /// + void ClearCache(ClearCacheMode mode); + } +} diff --git a/Src/ILGPU/IR/IRContext.cs b/Src/ILGPU/IR/IRContext.cs index 543c283da..9b98d2f95 100644 --- a/Src/ILGPU/IR/IRContext.cs +++ b/Src/ILGPU/IR/IRContext.cs @@ -30,7 +30,7 @@ namespace ILGPU.IR /// /// Represents an IR context. /// - public sealed partial class IRContext : DisposeBase + public sealed partial class IRContext : DisposeBase, ICache { #region Nested Types @@ -554,9 +554,16 @@ public void GC() } /// - /// Clears this context and removes all nodes + /// Clears cached IR nodes. /// - public void Clear() + [Obsolete("Use ClearCache(ClearCacheMode.Everything) instead")] + public void Clear() => ClearCache(ClearCacheMode.Everything); + + /// + /// Clears cached IR nodes. + /// + /// The clear mode. + public void ClearCache(ClearCacheMode mode) { irLock.EnterWriteLock(); try diff --git a/Src/ILGPU/IR/Transformations/Inliner.cs b/Src/ILGPU/IR/Transformations/Inliner.cs index f9b34d61f..169948449 100644 --- a/Src/ILGPU/IR/Transformations/Inliner.cs +++ b/Src/ILGPU/IR/Transformations/Inliner.cs @@ -53,7 +53,7 @@ public sealed class Inliner : OrderedTransformation if ((source.MethodImplementationFlags & MethodImplAttributes.AggressiveInlining) == MethodImplAttributes.AggressiveInlining || - source.Module.Name == Context.AssemblyModuleName) + source.Module.Name == Context.FullAssemblyModuleName) method.AddFlags(MethodFlags.Inline); } diff --git a/Src/ILGPU/IR/Types/IRTypeContext.cs b/Src/ILGPU/IR/Types/IRTypeContext.cs index 029b51900..b4b56d074 100644 --- a/Src/ILGPU/IR/Types/IRTypeContext.cs +++ b/Src/ILGPU/IR/Types/IRTypeContext.cs @@ -253,7 +253,7 @@ public TypeNode CreateType(Type type, MemoryAddressSpace addressSpace) } /// - /// Specializes the address space of the given . + /// Specializes the address space of the given . /// /// The source type. /// The new address space. @@ -334,6 +334,47 @@ private T CreateType(T type) } } + /// + /// Clears all internal caches. + /// + /// The clear mode. + public override void ClearCache(ClearCacheMode mode) + { + base.ClearCache(mode); + + typeLock.EnterWriteLock(); + try + { + unifiedTypes.Clear(); + + unifiedTypes.Add(VoidType, VoidType); + unifiedTypes.Add(StringType, StringType); + + foreach (var basicType in BasicValueTypes) + { + var type = GetPrimitiveType(basicType); + unifiedTypes.Add(type, type); + } + + unifiedTypes.Add(IndexType, IndexType); + } + finally + { + typeLock.ExitWriteLock(); + } + } + + #endregion + + #region IDisposable + + /// + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + typeLock.Dispose(); + } + #endregion } } diff --git a/Src/ILGPU/IR/Types/TypeInformationManager.cs b/Src/ILGPU/IR/Types/TypeInformationManager.cs index 2ba5d3995..ac0583f67 100644 --- a/Src/ILGPU/IR/Types/TypeInformationManager.cs +++ b/Src/ILGPU/IR/Types/TypeInformationManager.cs @@ -23,7 +23,7 @@ namespace ILGPU.IR.Types /// /// Represents a context that manages type information. /// - public class TypeInformationManager : DisposeBase + public class TypeInformationManager : DisposeBase, ICache { #region Nested Types @@ -157,6 +157,18 @@ public override string ToString() /// Constructs a new type context. /// public TypeInformationManager() + { + InitIntrinsicTypeInformation(); + } + + #endregion + + #region Methods + + /// + /// Initializes intrinsic type information. + /// + private void InitIntrinsicTypeInformation() { AddTypeInfo(typeof(bool), false); @@ -177,10 +189,6 @@ public TypeInformationManager() AddTypeInfo(typeof(string), false); } - #endregion - - #region Methods - /// /// Resolves type information for the given type. /// @@ -314,14 +322,16 @@ private TypeInformation CreateCompoundTypeInfo(Type type) } /// - /// Clears the cached type information. + /// Clears all internal caches. /// - public void Clear() + /// The clear mode. + public virtual void ClearCache(ClearCacheMode mode) { cachingLock.EnterWriteLock(); try { typeInfoMapping.Clear(); + InitIntrinsicTypeInformation(); } finally { diff --git a/Src/ILGPU/Runtime/Accelerator.cs b/Src/ILGPU/Runtime/Accelerator.cs index 37e4fc97e..ffe68a06e 100644 --- a/Src/ILGPU/Runtime/Accelerator.cs +++ b/Src/ILGPU/Runtime/Accelerator.cs @@ -39,7 +39,7 @@ public enum AcceleratorType /// Represents a general abstract accelerator. /// /// Members of this class are not thread safe. - public abstract partial class Accelerator : DisposeBase + public abstract partial class Accelerator : DisposeBase, ICache { #region Static @@ -368,6 +368,19 @@ public void Synchronize() /// protected abstract void SynchronizeInternal(); + /// + /// Clears all internal caches. + /// + /// The clear mode. + public void ClearCache(ClearCacheMode mode) + { + lock (syncRoot) + { + Backend.ClearCache(mode); + ClearKernelCache_SyncRoot(); + } + } + #endregion #region Occupancy diff --git a/Src/ILGPU/Runtime/KernelCache.cs b/Src/ILGPU/Runtime/KernelCache.cs index 42baf3ce9..3455cfe14 100644 --- a/Src/ILGPU/Runtime/KernelCache.cs +++ b/Src/ILGPU/Runtime/KernelCache.cs @@ -317,8 +317,9 @@ private void InitKernelCache() /// /// This method is invoked in the scope of the locked object. private bool RequestKernelCacheGC_SyncRoot => - (compiledKernelCache.Count % NumberNewKernelsUntilGC) == 0 || - (kernelCache.Count % NumberNewKernelsUntilGC) == 0; + KernelCacheEnabled && + ((compiledKernelCache.Count % NumberNewKernelsUntilGC) == 0 || + (kernelCache.Count % NumberNewKernelsUntilGC) == 0); #endregion @@ -435,6 +436,17 @@ public CompiledKernel CompileKernel(MethodInfo method, KernelSpecialization spec return Backend.Compile(method, specialization); } + /// + /// Clears the internal cache cache. + /// + private void ClearKernelCache_SyncRoot() + { + if (!KernelCacheEnabled) + return; + compiledKernelCache.Clear(); + kernelCache.Clear(); + } + /// /// GC method to clean disposed kernels. /// diff --git a/Src/ILGPU/Runtime/MemoryBufferCache.cs b/Src/ILGPU/Runtime/MemoryBufferCache.cs index d0182fcc2..c2afe35ae 100644 --- a/Src/ILGPU/Runtime/MemoryBufferCache.cs +++ b/Src/ILGPU/Runtime/MemoryBufferCache.cs @@ -24,7 +24,7 @@ namespace ILGPU.Runtime /// buffer will be freed and a new buffer will be allocated. /// /// Members of this class are not thread safe. - public sealed class MemoryBufferCache : AcceleratorObject + public sealed class MemoryBufferCache : AcceleratorObject, ICache { #region Instance @@ -139,6 +139,15 @@ public unsafe void CopyFrom(AcceleratorStream stream, T source, Index sourceI } } + /// + /// Clears all internal caches. + /// + /// The clear mode. + public void ClearCache(ClearCacheMode mode) + { + Dispose(ref cache); + } + #endregion #region IDisposable @@ -146,7 +155,7 @@ public unsafe void CopyFrom(AcceleratorStream stream, T source, Index sourceI /// protected override void Dispose(bool disposing) { - Dispose(ref cache); + ClearCache(ClearCacheMode.Everything); } #endregion