aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2023-03-28 00:30:25 -0400
committerLibravatar vnugent <public@vaughnnugent.com>2023-03-28 00:30:25 -0400
commitcf45636b6216d1b2beaec83bb129a1927f24f608 (patch)
tree97553ecbff6189602c24ad0d600005ecc9f5086c
parent0fe1b687531710071d7c5a85cc59577481a06c9b (diff)
Readme and spelling
-rw-r--r--lib/NativeHeapApi/README.md20
-rw-r--r--lib/NativeHeapApi/src/NativeHeapApi.h6
-rw-r--r--lib/Utils/README.md42
-rw-r--r--lib/Utils/src/Memory/Diagnostics/HeapStatistics.cs2
-rw-r--r--lib/Utils/src/Memory/NativeHeap.cs12
-rw-r--r--lib/WinRpMalloc/src/dllmain.c2
6 files changed, 56 insertions, 28 deletions
diff --git a/lib/NativeHeapApi/README.md b/lib/NativeHeapApi/README.md
index 5341e63..36d3a6e 100644
--- a/lib/NativeHeapApi/README.md
+++ b/lib/NativeHeapApi/README.md
@@ -6,21 +6,27 @@ Contains necessary API header files for user defined heap dlls. Contains the req
You may copy the [NativeHeapApi.h](src/NativeHeapApi.h) header file into your project and begin implementing the heap methods defined in the header file.
-You must define a constant called **HEAP_METHOD_EXPORT** that defines the method calling convention for proper dll loading for your given platform. On windows, this defaults to `__declspec(dllexport)`.
+You must define a constant called **HEAP_METHOD_EXPORT** that defines the method decordation for proper dll loading for your given platform. On windows, this defaults to `__declspec(dllexport)`.
-When the `heapCreate` method is called, a mutable structure pointer is passed as an argument and expected to be updated by your create method. The VNLib.Utils library implements two types of heaps, a global/shared heap and "private" or "first class" heaps exposed by the Memory namespace. Consumers are allowed to create a private heap to use at will.
+You may optionally define a constant **HEAP_METHOD_CC**, which defines the method calling convention. For a windows target, this defaults to __stdcall, as P/Invoke uses the stdcall calling convention. On other platforms this expands to nothimg and P/Invoke uses the CDECL, the default on most platforms.
-### UnmanagedHeapFlags structure
+When the `heapCreate` method is called, a mutable structure pointer is passed as an argument and expected to be updated by your create method. The VNLib.Utils library implements two types of heaps, a global/shared heap and "private" or "first class" heaps exposed by the Memory namespace. Consumers are allowed to create a private heap to use at will.
-`UnmanagedHeapFlags.HeapPointer` - Set your heap pointer that will be passed to all heap methods
+### Heap architecture
-`UnmanagedHeapFlags.CreationFlags` - Managed creation flags, that may be read and written. The managed heap implementation will observe the result after the `heapCreate` method returns.
+To understand the VNLib.Utils heap architecture, please see the Utils [readme](../Utils/README.md).
-`UnmanagedHeapFlags.Flags` - Generic flags passed by the caller directly to the heapCreate method, not observed or modified by the managed library in any way.
+### UnmanagedHeapDescriptor structure
+
+`UnmanagedHeapDescriptor.HeapPointer` - Set your heap pointer that will be passed to all heap methods
+
+`UnmanagedHeapDescriptor.CreationFlags` - Managed creation flags, that may be read and written. The managed heap implementation will observe the result after the `heapCreate` method returns.
+
+`UnmanagedHeapDescriptor.Flags` - Generic flags passed by the caller directly to the heapCreate method, not observed or modified by the managed library in any way.
### Example Create
``` c
-HEAP_METHOD_EXPORT ERRNO heapCreate(UnmanagedHeapFlags* flags)
+HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapCreate(UnmanagedHeapDescriptor* flags)
{
//Check flags
if (flags->CreationFlags & HEAP_CREATION_IS_SHARED)
diff --git a/lib/NativeHeapApi/src/NativeHeapApi.h b/lib/NativeHeapApi/src/NativeHeapApi.h
index 00ca2b8..5deca31 100644
--- a/lib/NativeHeapApi/src/NativeHeapApi.h
+++ b/lib/NativeHeapApi/src/NativeHeapApi.h
@@ -80,12 +80,12 @@ typedef void* ERRNO;
/// <summary>
/// A structure for heap initialization
/// </summary>
-typedef struct UnmanagedHeapFlags
+typedef struct UnmanagedHeapDescriptor
{
LPVOID HeapPointer;
HeapCreationFlags CreationFlags;
ERRNO Flags;
-} UnmanagedHeapFlags;
+} UnmanagedHeapDescriptor;
/// <summary>
/// The heap creation method. You must set the flags->HeapPointer = your heap
@@ -93,7 +93,7 @@ typedef struct UnmanagedHeapFlags
/// </summary>
/// <param name="flags">Creation flags passed by the caller to create the heap. This structure will be initialized, and may be modified</param>
/// <returns>A boolean value that indicates the result of the operation</returns>
-HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapCreate(UnmanagedHeapFlags* flags);
+HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapCreate(UnmanagedHeapDescriptor* flags);
/// <summary>
/// Destroys a previously created heap
diff --git a/lib/Utils/README.md b/lib/Utils/README.md
index 60a65c5..888ac3e 100644
--- a/lib/Utils/README.md
+++ b/lib/Utils/README.md
@@ -1,6 +1,6 @@
# VNLib.Utils
-A .NET 6 /C# library for common .NET operation optimizations.
+A .NET 6 /C# library for common .NET operation and memory optimizations.
namespaces
- VNLib.Utils.Async - Provides classes for asynchronous access synchronization and some asynchronous collections
@@ -17,21 +17,43 @@ namespaces
Debug build w/ symbols & xml docs, release builds, NuGet packages, and individually packaged source code are available on my [website](https://www.vaughnnugent.com/resources/software). All tar-gzip (.tgz) files will have an associated .sha384 appended checksum of the desired download file.
### Recommended 3rd Party Libs
-
This library does not *require* any direct dependencies, however there are some optional ones that are desired for higher performance code. This library does not, modify, contribute, or affect the functionality of any of the 3rd party libraries recommended below.
-[**RPMalloc**](https://github.com/mjansson/rpmalloc) By Mattias Jansson - VNlib.Utils.Memory (and sub-classes) may load and bind function calls to this native library determined by environment variables. To use RPMalloc as the default unmanaged allocator simply add the dynamic library to the native lib search path, such as in the executable directory, and set the allocator environment variable as instructed below.
+[**RPMalloc**](https://github.com/mjansson/rpmalloc) By Mattias Jansson - VNlib.Utils.Memory (and sub-classes) may load and bind function calls to this native library determined by environment variables. To use RPMalloc as the default unmanaged allocator simply add the dynamic library to the native lib search path, such as in the executable directory, and set the allocator environment variable as instructed below. I maintain a compatible Windows x64 [dll library](../WinRpMalloc/README.md) on my website and in this repository, that conforms to the [NativeHeap](../NativeHeapApi/README.md) api required for runtime loading.
+
+## Memory
+
+### Native Memory details and allocator selection
+Allocator selection has been updated to abstract the unmanaged heap loading to accommodate user defined memory allocators. A new class called the [NativeHeap](src/Memory/NativeHeap.cs) is the abstraction layer between your dll and the managed heap environment.
+
+There are two types of heap architectures that are in use within the Memory namespace. Global/Shared and Private/First Class. They generally make the following assumptions
+
+**Shared Heap** - Prefers performance over isolation, consumers expect calls to have minimal multi-threaded performance penalties at the cost of isolation
+**Private Heap** - Prefers isolation over performance, consumers assume calls may have multi-threaded performance penalties for the benefit of isolation.
+
+On heap creation, the `UnmanagedHeapDescriptor` structure's `HeapCreationFlags` will have the IsShared flag set if the desired heap is the global heap, or a private heap in the absence of said flag. By default **ALL** heaps are assumed **not** thread safe, and synchronization is provided by the `UnmanagedHeapBase` class, and as such, the UseSynchronization flag is always present when using the `InitializeNewHeapForProcess` method call.
+
+#### Note for heap implementers
+Implementers may decide to clear the UseSynchronization flag if they know their implementation is thread safe, or are using their own synchronization method. Generally I would recommend letting the `UnmanagedHeapBase` class fallback to managed synchronization if your heap implementation requires synchronization, because the runtime *generally* provides the best performance for managed code (in my experience.) but you should do your own performance testing for your use case.
+
+Please use the [NativeHeapApi readme](../NativeHeapApi/README.md) for further instruction and implementation details.
+
+#### Note for consumers
+The [MemoryUtil](src/Memory/MemoryUtil.cs) class allows for consumers to allocate a "private" heaps on demand or a global/shared heap for the library consumer (see AssemblyLoadContext for static class details). When creating private heaps the MemoryUtil class exposes a method called `InitializeNewHeapForProcess` which will create a new "private" heap on demand using the same configuration variables as the shared global heap (shared heap calls the same method internally). All heaps, private or shared are assumed to be **thread safe** when using this method. When calling `NativeHeap.LoadHeap` directly, you may disable thread safety and "roll your own" if you prefer. Understand that the heap implementation may override your requests, understand your heap's implementation if you choose to use this method.
+
+Most VNLib libraries use the Shared heap for performance reasons, and in some cases private heaps for isolation, such as HTTP or TCP libraries, however they generally prefer performance over isolation and will choose the highest performance implementation.
+### Runtime allocator selection
+Setting the `VNLIB_SHARED_HEAP_FILE_PATH` environment variable will instruct the `InitializeNewHeapForProcess` method to load the native heap library at the given path, it may be an absolute path to the DLL file or a dll file name in a "safe" directory. It must conform to the NativeHeapApi, otherwise loading will fail. Understand that loading is deferred to the first access of the `MemoryUtil.Shared` property (this is subject to change) so don't be confused when seeing deferred debugging messages instead of a type initialization failure. This is also done to avoid Loader Lock contention issues, because we can.
-### Allocator selection via environment variables
-Valid allocator value for the `VNLIB_SHARED_HEAP_TYPE` environment variable:
-- "win32" - for win32 based private heaps (only valid if using the Microsoft Windows operating system)
-- "rpmalloc" - to load the RPMalloc native library if compiled for your platform
-- none - the default value, will attempt to load the win32 private heap Kernel32 library, otherwise, the native ProcessHeap() cross platform allocator
+#### MemoryUtil fallbacks
+If you don't want to use a custom heap implementation, the library has safe fallbacks for all platforms. On Windows the PrivateHeap api is used by default. The shared heap, again, prefers performance and will use the process heap returned from `GetProcessHeap()`, instead of creating a private heap that requires synchronization penalties. On all other platforms the fallback will be the .NET NativeMemory allocator, which is cross platform, but does **not** actually implement a "private" heap. So that means on non-Windows platforms unless you select your own heap, isolation is not an option.
-#### Heap Diagnostics
-The Memory.Diagnostics namespace was added to provide a wrapper for tracking IUnmanagedHeap memory allocations. Diagnostics can be enabled for the SharedHeap by setting the `VNLIB_SHARED_HEAP_DIAGNOSTICS` environment variable to "1". When enabled, calling MemoryUtil.GetSharedHeapStats() will return the heap's current statistics, otherwise an empty struct is returned. The SharedHeap diagnostics are disabled by default.
+### Heap Diagnostics
+The Memory.Diagnostics namespace was added to provide a wrapper for tracking IUnmanagedHeap memory allocations. Diagnostics can be enabled for the SharedHeap by setting the `VNLIB_SHARED_HEAP_DIAGNOSTICS` environment variable to "1". When enabled, calling MemoryUtil.GetSharedHeapStats() will return the heap's current statistics, otherwise an empty struct is returned. The Shared heap diagnostics are disabled by default.
+### Other notes
+Generally for internal library data structures that require memory allocation, a constructor override or a static method will consume a heap instance so you may pass your own heap instance or the Shared heap.
## Usage
A usage breakdown would be far to lengthy for this library, and instead I intend to keep valid and comprehensive documentation in Visual Studio XML documentation files included in this project's src directory.
diff --git a/lib/Utils/src/Memory/Diagnostics/HeapStatistics.cs b/lib/Utils/src/Memory/Diagnostics/HeapStatistics.cs
index 5d7d3f1..918f432 100644
--- a/lib/Utils/src/Memory/Diagnostics/HeapStatistics.cs
+++ b/lib/Utils/src/Memory/Diagnostics/HeapStatistics.cs
@@ -25,7 +25,7 @@
namespace VNLib.Utils.Memory.Diagnostics
{
/// <summary>
- /// A structures that represents the current/last captures
+ /// A structure that represents the current/last captured
/// statistics of the monitored heap
/// </summary>
public readonly record struct HeapStatistics
diff --git a/lib/Utils/src/Memory/NativeHeap.cs b/lib/Utils/src/Memory/NativeHeap.cs
index 30a65ae..5fc24b5 100644
--- a/lib/Utils/src/Memory/NativeHeap.cs
+++ b/lib/Utils/src/Memory/NativeHeap.cs
@@ -58,8 +58,8 @@ namespace VNLib.Utils.Memory
public unsafe static NativeHeap LoadHeap(string dllPath, DllImportSearchPath searchPath, HeapCreation creationFlags, ERRNO flags)
{
//Create a flags structure
- UnmanagedHeapFlags hf;
- UnmanagedHeapFlags* hFlags = &hf;
+ UnmanagedHeapDescriptor hf;
+ UnmanagedHeapDescriptor* hFlags = &hf;
//Set defaults
hFlags->Flags = flags;
@@ -70,7 +70,7 @@ namespace VNLib.Utils.Memory
return LoadHeapCore(dllPath, searchPath, hFlags);
}
- private unsafe static NativeHeap LoadHeapCore(string path, DllImportSearchPath searchPath, UnmanagedHeapFlags* flags)
+ private unsafe static NativeHeap LoadHeapCore(string path, DllImportSearchPath searchPath, UnmanagedHeapDescriptor* flags)
{
//Try to load the library
SafeLibraryHandle library = SafeLibraryHandle.LoadLibrary(path, searchPath);
@@ -120,7 +120,7 @@ namespace VNLib.Utils.Memory
private FreeDelegate FreeMethod;
private DestroyHeapDelegate Destroy;
- private unsafe NativeHeap(UnmanagedHeapFlags* flags, HeapMethods methodTable) :base(flags->InternalFlags, true)
+ private unsafe NativeHeap(UnmanagedHeapDescriptor* flags, HeapMethods methodTable) :base(flags->InternalFlags, true)
{
//Store heap pointer
handle = flags->HeapPointer;
@@ -176,7 +176,7 @@ namespace VNLib.Utils.Memory
* Delegate methods match the native header impl for unmanaged heaps
*/
- unsafe delegate ERRNO CreateHeapDelegate(UnmanagedHeapFlags* createFlags);
+ unsafe delegate ERRNO CreateHeapDelegate(UnmanagedHeapDescriptor* createFlags);
delegate IntPtr AllocDelegate(IntPtr handle, nuint elements, nuint alignment, [MarshalAs(UnmanagedType.Bool)] bool zero);
@@ -187,7 +187,7 @@ namespace VNLib.Utils.Memory
delegate ERRNO DestroyHeapDelegate(IntPtr heap);
[StructLayout(LayoutKind.Sequential)]
- record struct UnmanagedHeapFlags
+ record struct UnmanagedHeapDescriptor
{
public IntPtr HeapPointer;
diff --git a/lib/WinRpMalloc/src/dllmain.c b/lib/WinRpMalloc/src/dllmain.c
index adcf3e6..58f5538 100644
--- a/lib/WinRpMalloc/src/dllmain.c
+++ b/lib/WinRpMalloc/src/dllmain.c
@@ -52,7 +52,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
//Define the heap methods
-HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapCreate(UnmanagedHeapFlags* flags)
+HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapCreate(UnmanagedHeapDescriptor* flags)
{
//Check flags
if (flags->CreationFlags & HEAP_CREATION_IS_SHARED)