diff --git a/dotnet/build/common.props b/dotnet/build/common.props
index f852cb7..04acef9 100644
--- a/dotnet/build/common.props
+++ b/dotnet/build/common.props
@@ -14,7 +14,7 @@
1
- 215
+ 216
diff --git a/dotnet/src/Spreads.Native/Mem.cs b/dotnet/src/Spreads.Native/Mem.cs
index 0438232..e6982e9 100644
--- a/dotnet/src/Spreads.Native/Mem.cs
+++ b/dotnet/src/Spreads.Native/Mem.cs
@@ -1,11 +1,55 @@
using System;
using System.Runtime.InteropServices;
+using System.Security;
+using System.Threading.Tasks;
+
+// ReSharper disable UnusedMember.Global
namespace Spreads.Native
{
- public unsafe class Mem
+ [SuppressUnmanagedCodeSecurity]
+ public class Mem
{
private const string NativeLibraryName = UnsafeEx.NativeLibraryName;
+
+ [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true), SuppressUnmanagedCodeSecurity]
+ public unsafe delegate void DeferredFreeFun(bool force, ulong heartbeat, void* arg);
+
+ [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true), SuppressUnmanagedCodeSecurity]
+ public unsafe delegate void OutputFun([MarshalAs(UnmanagedType.LPStr)] string msg, void* arg);
+
+ [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true), SuppressUnmanagedCodeSecurity]
+ public unsafe delegate void ErrorFun(int err, void* arg);
+
+ [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true), SuppressUnmanagedCodeSecurity]
+ public unsafe delegate bool BlockVisitFun(void* heap, void* area, void* block, UIntPtr blockSize, void* arg);
+
+
+ public enum Option
+ {
+ // stable options
+ ShowSrrors,
+ ShowStats,
+ OptionVerbose,
+
+ // the following options are experimental
+ EagerCommit,
+ EagerRegionCommit,
+ ResetDecommits,
+ LargeOsPages, // implies eager commit
+ ReserveHugeOsPages,
+ SegmentCache,
+ PageReset,
+ AbandonedPageReset,
+ SegmentReset,
+ EagerCommitDelay,
+ ResetDelay,
+ UseNumaNodes,
+ OsTag,
+ MaxErrors,
+ Last,
+ EagerPageCommit = EagerCommit
+ }
///
/// Allocate zero-initialized elements of bytes.
@@ -15,14 +59,14 @@ public unsafe class Mem
/// The size of each element.
///
[DllImport(NativeLibraryName, EntryPoint = "spreads_mem_calloc", CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* Calloc(uint count, uint size);
+ public static extern unsafe byte* Calloc(UIntPtr count, UIntPtr size);
///
/// Allocate bytes. Returns a pointer to the allocated memory or NULL if out of memory. Returns a unique pointer if called with size 0.
///
/// The number of bytes to allocate.
[DllImport(NativeLibraryName, EntryPoint = "spreads_mem_malloc", CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* Malloc(uint size);
+ public static extern unsafe byte* Malloc(UIntPtr size);
///
/// Re-allocate memory to bytes.
@@ -35,30 +79,29 @@ public unsafe class Mem
/// pointer to previously allocated memory (or NULL).
/// the new required size in bytes.
[DllImport(NativeLibraryName, EntryPoint = "spreads_mem_realloc", CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* Realloc(byte* p, uint newsize);
+ public static extern unsafe byte* Realloc(byte* p, UIntPtr newsize);
///
/// Free previously allocated memory. The pointer p must have been allocated before (or be NULL).
///
/// pointer to free, or NULL.
[DllImport(NativeLibraryName, EntryPoint = "spreads_mem_free", CallingConvention = CallingConvention.Cdecl)]
- public static extern void Free(byte* p);
-
+ public static extern unsafe void Free(byte* p);
[DllImport(NativeLibraryName, EntryPoint = "spreads_mem_malloc_small",
CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* MallocSmall(uint size);
+ public static extern unsafe byte* MallocSmall(UIntPtr size);
[DllImport(NativeLibraryName, EntryPoint = "spreads_mem_zalloc_small",
CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* ZallocSmall(uint size);
+ public static extern unsafe byte* ZallocSmall(UIntPtr size);
///
/// Allocate zero-initialized size bytes. Returns a pointer to newly allocated zero initialized memory, or NULL if out of memory.
///
/// The size in bytes.
[DllImport(NativeLibraryName, EntryPoint = "spreads_mem_zalloc", CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* Zalloc(uint size);
+ public static extern unsafe byte* Zalloc(UIntPtr size);
///
/// Allocate count elements of size bytes.
@@ -69,7 +112,7 @@ public unsafe class Mem
/// The size of each element.
///
[DllImport(NativeLibraryName, EntryPoint = "spreads_mem_mallocn", CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* Mallocn(uint count, uint size);
+ public static extern unsafe byte* Mallocn(UIntPtr count, UIntPtr size);
///
/// Re-allocate memory to count elements of size bytes.
@@ -81,7 +124,7 @@ public unsafe class Mem
/// The size of each element.
///
[DllImport(NativeLibraryName, EntryPoint = "spreads_mem_reallocn", CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* Reallocn(byte* p, uint count, uint size);
+ public static extern unsafe byte* Reallocn(byte* p, UIntPtr count, UIntPtr size);
///
/// Re-allocate memory to bytes.
@@ -94,9 +137,8 @@ public unsafe class Mem
/// pointer to previously allocated memory (or NULL).
/// the new required size in bytes.
[DllImport(NativeLibraryName, EntryPoint = "spreads_mem_reallocf", CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* Reallocf(byte* p, uint newsize);
-
-
+ public static extern unsafe byte* Reallocf(byte* p, UIntPtr newsize);
+
///
/// Try to re-allocate memory to bytes in place.
/// Returns a pointer to the re-allocated memory of
@@ -110,9 +152,8 @@ public unsafe class Mem
/// the new required size in bytes.
[DllImport(NativeLibraryName, EntryPoint = "spreads_mem_expand",
CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* Expand(byte* p, uint newsize);
-
-
+ public static extern unsafe byte* Expand(byte* p, UIntPtr newsize);
+
///
/// Returns the available bytes in the memory block, or 0 if p was NULL.
/// The returned size can be used to call successfully.
@@ -121,8 +162,7 @@ public unsafe class Mem
/// Pointer to previously allocated memory (or NULL)
[DllImport(NativeLibraryName, EntryPoint = "spreads_mem_usable_size",
CallingConvention = CallingConvention.Cdecl)]
- public static extern ulong UsableSize(byte* p);
-
+ public static extern unsafe ulong UsableSize(byte* p);
///
/// Returns the size n that will be allocated, where n >= size.
@@ -132,7 +172,7 @@ public unsafe class Mem
/// The minimal required size in bytes.
[DllImport(NativeLibraryName, EntryPoint = "spreads_mem_good_size",
CallingConvention = CallingConvention.Cdecl)]
- public static extern ulong GoodSize(uint size);
+ public static extern ulong GoodSize(UIntPtr size);
///
/// Eagerly free memory. Regular code should not have to call this function.
@@ -143,82 +183,301 @@ public unsafe class Mem
/// If true, aggressively return memory to the OS (can be expensive!).
[DllImport(NativeLibraryName, EntryPoint = "spreads_mem_collect", CallingConvention = CallingConvention.Cdecl)]
public static extern void Collect(bool force);
-
-
+
[DllImport(NativeLibraryName, EntryPoint = "spreads_mem_mialloc_version",
CallingConvention = CallingConvention.Cdecl)]
public static extern int MimallocVersion();
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_malloc_aligned",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* MallocAligned(UIntPtr size, UIntPtr alignment);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_malloc_aligned_at",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* MallocAlignedAt(UIntPtr size, UIntPtr alignment, UIntPtr offset);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_zalloc_aligned",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* ZallocAligned(UIntPtr size, UIntPtr alignment);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_zalloc_aligned_at",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* ZallocAlignedAt(UIntPtr size, UIntPtr alignment, UIntPtr offset);
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_calloc_aligned",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* CallocAligned(UIntPtr count, UIntPtr size, UIntPtr alignment);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_calloc_aligned_at",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* CallocAlignedAt(UIntPtr count, UIntPtr size, UIntPtr alignment, UIntPtr offset);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_realloc_aligned",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* ReallocAligned(byte* p, UIntPtr newsize, UIntPtr alignment);
- [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_malloc_aligned",
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_realloc_aligned_at",
CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* MallocAligned(uint size, uint alignment);
+ public static extern unsafe byte* ReallocAlignedAt(byte* p, UIntPtr newsize, UIntPtr alignment,
+ UIntPtr offset);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_rezalloc", CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* Rezalloc(byte* p, UIntPtr newsize);
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_recalloc", CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* Recalloc(byte* p, UIntPtr newcount, UIntPtr size);
- [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_malloc_aligned_at",
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_rezalloc_aligned",
CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* MallocAlignedAt(uint size, uint alignment, uint offset);
+ public static extern unsafe byte* RezallocAligned(byte* p, UIntPtr newsize, UIntPtr alignment);
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_rezalloc_aligned_at",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* RezallocAlignedAt(byte* p, UIntPtr newsize, UIntPtr alignment,
+ UIntPtr offset);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_recalloc_aligned",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* RecallocAligned(byte* p, UIntPtr newcount, UIntPtr size,
+ UIntPtr alignment);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_recalloc_aligned_at",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* RecallocAlignedAt(byte* p, UIntPtr newcount, UIntPtr size,
+ UIntPtr alignment, UIntPtr offset);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_stats_reset",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern void StatsReset();
- [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_zalloc_aligned",
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_stats_merge",
CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* ZallocAligned(uint size, uint alignment);
+ public static extern void StatsMerge();
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_stats_print",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern void StatsPrint();
- [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_zalloc_aligned_at",
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_stats_print_out",
CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* ZallocAlignedAt(uint size, uint alignment, uint offset);
+ public static extern unsafe void StatsPrintOut(OutputFun outputFun, void* arg);
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_register_deferred_free",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe void RegisterDeferredFree(DeferredFreeFun deferredFree, void* arg);
- [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_calloc_aligned",
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_register_output",
CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* CallocAligned(uint count, uint size, uint alignment);
+ public static extern unsafe void RegisterOutput(OutputFun outputFun, void* arg);
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_register_error",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe void RegisterError(OutputFun outputFun, void* arg);
- [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_calloc_aligned_at",
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_option_is_enabled",
CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* CallocAlignedAt(uint count, uint size, uint alignment, uint offset);
+ public static extern bool OptionIsEnabled(Option option);
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_option_enable",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern void OptionEnable(Option option);
- [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_realloc_aligned",
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_option_disable",
CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* ReallocAligned(byte* p, uint newsize, uint alignment);
+ public static extern void OptionDisable(Option option);
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_option_set_enabled",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern void OptionSetEnabled(Option option, bool enabled);
- [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_realloc_aligned_at",
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_option_set_enabled_default",
CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* ReallocAlignedAt(byte* p, uint newsize, uint alignment,
- uint offset);
+ public static extern void OptionSetEnabledDefault(Option option, bool enabled);
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_option_get",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern int OptionGet(Option option);
- [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_rezalloc", CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* Rezalloc(byte* p, uint newsize);
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_option_set",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern void OptionSet(Option option, int value);
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_option_set_default",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern void OptionSetDefault(Option option, int value);
- [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_recalloc", CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* Recalloc(byte* p, uint newcount, uint size);
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_new",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe void* HeapNew();
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_delete",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe void HeapDelete(void* heap);
- [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_rezalloc_aligned",
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_destroy",
CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* RezallocAligned(byte* p, uint newsize, uint alignment);
+ public static extern unsafe void HeapDestroy(void* heap);
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_set_default",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe void* HeapSetDefault(void* heap);
- [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_rezalloc_aligned_at",
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_get_default",
CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* RezallocAlignedAt(byte* p, uint newsize, uint alignment,
- uint offset);
+ public static extern unsafe void* HeapGetDefault();
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_get_backing",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe void* HeapGetBacking();
- [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_recalloc_aligned",
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_visit_blocks",
CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* RecallocAligned(byte* p, uint newcount, uint size,
- uint alignment);
+ public static extern unsafe bool HeapVisitBlocks(void* heap, bool visitAllBlocks, BlockVisitFun visitor,
+ void* arg);
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_is_in_heap_region",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe bool IsInHeapRegion(byte* p);
- [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_recalloc_aligned_at",
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_collect",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe void HeapCollect(void* heap, bool force);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_malloc",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapMalloc(void* heap, UIntPtr size);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_zalloc",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapZalloc(void* heap, UIntPtr size);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_calloc",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapCalloc(void* heap, UIntPtr count, UIntPtr size);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_mallocn",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapMallocn(void* heap, UIntPtr count, UIntPtr size);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_malloc_small",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapMallocSmall(void* heap, UIntPtr size);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_realloc",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapRealloc(void* heap, byte* p, UIntPtr size);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_reallocn",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapReallocn(void* heap, byte* p, UIntPtr count, UIntPtr size);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_reallocf",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapReallocf(void* heap, byte* p, UIntPtr newsize);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_strdup",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapStrdup(void* heap, byte* s);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_strndup",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapStrndup(void* heap, byte* s, UIntPtr n);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_realpath",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapRealpath(void* heap, byte* fname, byte* resolvedName);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_malloc_aligned",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapMallocAligned(void* heap, UIntPtr size, UIntPtr alignment);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_malloc_aligned_at",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapMallocAlignedAt(void* heap, UIntPtr size, UIntPtr alignment,
+ UIntPtr offset);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_zalloc_aligned",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapZallocAligned(void* heap, UIntPtr size, UIntPtr alignment);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_zalloc_aligned_at",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapZallocAlignedAt(void* heap, UIntPtr size, UIntPtr alignment,
+ UIntPtr offset);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_calloc_aligned",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapCallocAligned(void* heap, UIntPtr count, UIntPtr size,
+ UIntPtr alignment);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_calloc_aligned_at",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapCallocAlignedAt(void* heap, UIntPtr count, UIntPtr size,
+ UIntPtr alignment, UIntPtr offset);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_realloc_aligned",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapReallocAligned(void* heap, byte* p, UIntPtr newsize,
+ UIntPtr alignment);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_realloc_aligned_at",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapReallocAlignedAt(void* heap, byte* p, UIntPtr newsize,
+ UIntPtr alignment, UIntPtr offset);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_rezalloc",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapRezalloc(void* heap, byte* p, UIntPtr newsize);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_recalloc",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapRecalloc(void* heap, byte* p, UIntPtr newcount, UIntPtr size);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_rezalloc_aligned",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapRezallocAligned(void* heap, byte* p, UIntPtr newsize,
+ UIntPtr alignment);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_rezalloc_aligned_at",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapRezallocAlignedAt(void* heap, byte* p, UIntPtr newsize,
+ UIntPtr alignment, UIntPtr offset);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_recalloc_aligned",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapRecallocAligned(void* heap, byte* p, UIntPtr newcount,
+ UIntPtr size, UIntPtr alignment);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_recalloc_aligned_at",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe byte* HeapRecallocAlignedAt(void* heap, byte* p, UIntPtr newcount,
+ UIntPtr size, UIntPtr alignment, UIntPtr offset);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_contains_block",
+ CallingConvention = CallingConvention.Cdecl)]
+ public static extern unsafe bool HeapContainsBlock(void* heap, byte* p);
+
+ [DllImport(NativeLibraryName, EntryPoint = "spreads_mem_heap_check_owned",
CallingConvention = CallingConvention.Cdecl)]
- public static extern byte* RecallocAlignedAt(byte* p, uint newcount, uint size,
- uint alignment, uint offset);
+ public static extern unsafe bool HeapCheckOwned(void* heap, byte* p);
+
+
+ // public static Task Gc = Task.Run(async () =>
+ // {
+ // while (true)
+ // {
+ // try
+ // {
+ // Collect(true);
+ // Console.WriteLine("COLLECTED");
+ // }
+ // catch
+ // {
+ // // TODO log
+ // }
+ //
+ // await Task.Delay(500);
+ // }
+ // });
}
}
\ No newline at end of file
diff --git a/dotnet/tests/Spreads.Native.Run/Program.cs b/dotnet/tests/Spreads.Native.Run/Program.cs
index f1b38d4..7787011 100644
--- a/dotnet/tests/Spreads.Native.Run/Program.cs
+++ b/dotnet/tests/Spreads.Native.Run/Program.cs
@@ -25,8 +25,8 @@ private static void Main(string[] args)
// var summary = BenchmarkRunner.Run();
- var test = new Tests.VecTests();
- test.ForEachBench();
+ var test = new Tests.MemTests();
+ test.MimallocAllocFreePerf();
//var offset = UnsafeExTests.Helper.ElemOffset;
//var size = UnsafeExTests.Helper.ElemSize;
diff --git a/dotnet/tests/Spreads.Native.Run/Spreads.Native.Run.csproj b/dotnet/tests/Spreads.Native.Run/Spreads.Native.Run.csproj
index 580467e..56a6106 100644
--- a/dotnet/tests/Spreads.Native.Run/Spreads.Native.Run.csproj
+++ b/dotnet/tests/Spreads.Native.Run/Spreads.Native.Run.csproj
@@ -6,7 +6,7 @@
true
7.2
false
- AnyCPU
+ x64
true
Exe
diff --git a/dotnet/tests/Spreads.Native.Tests.NuGet/Spreads.Native.Tests.NuGet.csproj b/dotnet/tests/Spreads.Native.Tests.NuGet/Spreads.Native.Tests.NuGet.csproj
index be8e314..d5bbe73 100644
--- a/dotnet/tests/Spreads.Native.Tests.NuGet/Spreads.Native.Tests.NuGet.csproj
+++ b/dotnet/tests/Spreads.Native.Tests.NuGet/Spreads.Native.Tests.NuGet.csproj
@@ -18,6 +18,7 @@
+
diff --git a/dotnet/tests/Spreads.Native.Tests/Benchmark.cs b/dotnet/tests/Spreads.Native.Tests/Benchmark.cs
index 7b9b306..742016d 100644
--- a/dotnet/tests/Spreads.Native.Tests/Benchmark.cs
+++ b/dotnet/tests/Spreads.Native.Tests/Benchmark.cs
@@ -12,8 +12,11 @@
namespace Spreads.Native.Tests
{
- // Copy from Spreads.Core, do not edit here
+ // TODO median for Dump() MOPS
+ ///
+ /// A utility to benchmark code snippets inside a using block.
+ ///
public static class Benchmark
{
///
@@ -23,7 +26,9 @@ public static class Benchmark
private static Stopwatch _sw;
private static bool _headerIsPrinted;
- private static readonly ConcurrentDictionary> Stats = new ConcurrentDictionary>();
+
+ private static readonly ConcurrentDictionary> Stats =
+ new ConcurrentDictionary>();
///
/// Returns an structure that starts benchmarking and stops it when its Dispose method is called.
@@ -43,15 +48,42 @@ public static Stat Run(string caseName, long innerLoopCount = 1, bool silent = f
return stat;
}
+ private static double NaiveMedian(ArraySegment sourceNumbers)
+ {
+ //Framework 2.0 version of this method. there is an easier way in F4
+ if (sourceNumbers == null || sourceNumbers.Count == 0)
+ throw new Exception("Median of empty array not defined.");
+
+ //make sure the list is sorted, but use a new array
+ double[] sortedPNumbers = sourceNumbers.ToArray();
+ Array.Sort(sortedPNumbers);
+
+ //get the median
+ int size = sortedPNumbers.Length;
+ int mid = size / 2;
+ double median = (size % 2 != 0)
+ ? (double) sortedPNumbers[mid]
+ : ((double) sortedPNumbers[mid] + (double) sortedPNumbers[mid - 1]) / 2;
+ return median;
+ }
+
private static void PrintHeader(string summary, string caller, int? caseLength = null, string unit = null)
{
-
var len = caseLength ?? 20;
var caseDahes = new string('-', len + 1);
- var dashes = $"{caseDahes,-21}|{new string('-', 8),8}:|{new string('-', 9),9}:|{new string('-', 6),6}:|{new string('-', 6),6}:|{new string('-', 6),6}:|{new string('-', 8),8}:";
+ var dashes =
+ $"{caseDahes,-21}|{new string('-', 8),8}:|{new string('-', 9),9}:|{new string('-', 6),6}:|{new string('-', 6),6}:|{new string('-', 6),6}:|{new string('-', 8),8}:";
Console.WriteLine();
- if (!string.IsNullOrWhiteSpace(caller)) { Console.WriteLine($"**{caller}**"); }
- if (!string.IsNullOrWhiteSpace(summary)) { Console.WriteLine($"*{summary}*"); }
+ if (!string.IsNullOrWhiteSpace(caller))
+ {
+ Console.WriteLine($"**{caller}**");
+ }
+
+ if (!string.IsNullOrWhiteSpace(summary))
+ {
+ Console.WriteLine($"*{summary}*");
+ }
+
Console.WriteLine();
Console.WriteLine(GetHeader(caseLength, unit));
Console.WriteLine(dashes);
@@ -71,7 +103,7 @@ internal static string GetHeader(int? caseLength = null, string unit = null)
///
/// A description of the benchmark that is printed above the table.
/// Overwrite default MOPS unit of measure
- public static void Dump(string summary = "", [CallerMemberName]string caller = "", string unit = null)
+ public static void Dump(string summary = "", [CallerMemberName] string caller = "", string unit = null)
{
var maxLength = Stats.Keys.Select(k => k.Length).Max();
@@ -91,25 +123,28 @@ public static void Dump(string summary = "", [CallerMemberName]string caller = "
Stat GetAverages(KeyValuePair> kvp)
{
if (kvp.Value == null) throw new ArgumentException($"Null stat list for the case: {kvp.Key}");
- if (kvp.Value.Count == 0) throw new InvalidOperationException($"Empty stat list for the case: {kvp.Key}");
+ if (kvp.Value.Count == 0)
+ throw new InvalidOperationException($"Empty stat list for the case: {kvp.Key}");
var skip = kvp.Value.Count > 1
? (kvp.Value.Count >= 10 ? 3 : 1)
: 0;
var values = kvp.Value.Skip(skip).ToList();
- var elapsed = values.Select(l => l._statSnapshot._elapsed).Average();
- var gc0 = values.Select(l => l._statSnapshot._gc0).Average();
- var gc1 = values.Select(l => l._statSnapshot._gc1).Average();
- var gc2 = values.Select(l => l._statSnapshot._gc2).Average();
- var memory = values.Select(l => l._statSnapshot._memory).Average();
+ var elapsed =
+ NaiveMedian(
+ new ArraySegment(values.Select(l => (double) l._statSnapshot.Elapsed).ToArray()));
+ var gc0 = values.Select(l => l._statSnapshot.Gc0).Average();
+ var gc1 = values.Select(l => l._statSnapshot.Gc1).Average();
+ var gc2 = values.Select(l => l._statSnapshot.Gc2).Average();
+ var memory = values.Select(l => l._statSnapshot.Memory).Average();
var result = kvp.Value.First();
- result._statSnapshot._elapsed = (long)elapsed;
- result._statSnapshot._gc0 = gc0;
- result._statSnapshot._gc1 = gc1;
- result._statSnapshot._gc2 = gc2;
- result._statSnapshot._memory = memory;
+ result._statSnapshot.Elapsed = (long) elapsed;
+ result._statSnapshot.Gc0 = gc0;
+ result._statSnapshot.Gc1 = gc1;
+ result._statSnapshot.Gc2 = gc2;
+ result._statSnapshot.Memory = memory;
return result;
}
@@ -120,37 +155,37 @@ Stat GetAverages(KeyValuePair> kvp)
///
public struct Stat : IDisposable
{
- internal readonly string _caseName;
- internal Stopwatch _stopwatch;
- internal long _innerLoopCount;
- internal StatSnapshot _statSnapshot;
+ public string CaseName { get; }
+ public Stopwatch Stopwatch { get; }
+ public long InnerLoopCount { get; }
+ public StatSnapshot _statSnapshot;
internal bool _silent;
private readonly string _unit;
internal Stat(string caseName, Stopwatch sw, long innerLoopCount, bool silent = false, string unit = null)
{
- _caseName = caseName;
- _stopwatch = sw;
- _innerLoopCount = innerLoopCount;
+ CaseName = caseName;
+ Stopwatch = sw;
+ InnerLoopCount = innerLoopCount;
_silent = silent;
_unit = unit;
- _statSnapshot = new StatSnapshot(_stopwatch, true);
+ _statSnapshot = new StatSnapshot(Stopwatch, true);
}
///
public void Dispose()
{
- var statEntry = new StatSnapshot(_stopwatch, false);
- Interlocked.Exchange(ref _sw, _stopwatch);
+ var statEntry = new StatSnapshot(Stopwatch, false);
+ Interlocked.Exchange(ref _sw, Stopwatch);
- _statSnapshot._elapsed = statEntry._elapsed;
- _statSnapshot._gc0 = statEntry._gc0 - _statSnapshot._gc0 - 2;
- _statSnapshot._gc1 = statEntry._gc1 - _statSnapshot._gc1 - 2;
- _statSnapshot._gc2 = statEntry._gc2 - _statSnapshot._gc2 - 2;
- _statSnapshot._memory = statEntry._memory - _statSnapshot._memory;
+ _statSnapshot.Elapsed = statEntry.Elapsed;
+ _statSnapshot.Gc0 = statEntry.Gc0 - _statSnapshot.Gc0;
+ _statSnapshot.Gc1 = statEntry.Gc1 - _statSnapshot.Gc1;
+ _statSnapshot.Gc2 = statEntry.Gc2 - _statSnapshot.Gc2;
+ _statSnapshot.Memory = statEntry.Memory - _statSnapshot.Memory;
- var list = Stats.GetOrAdd(_caseName, (s1) => new List());
+ var list = Stats.GetOrAdd(CaseName, (s1) => new List());
list.Add(this);
if (!_silent && !ForceSilence)
@@ -160,6 +195,7 @@ public void Dispose()
PrintHeader(null, null, unit: _unit);
_headerIsPrinted = true;
}
+
Console.WriteLine(ToString());
}
}
@@ -168,29 +204,36 @@ public void Dispose()
/// Million operations per second.
///
// ReSharper disable once InconsistentNaming
- public double MOPS => Math.Round((_innerLoopCount * 0.001) / _statSnapshot._elapsed, 3);
+ public double MOPS => Math.Round((InnerLoopCount * 0.001) / (_statSnapshot.Elapsed / 10000.0), 3);
+
+ internal StatSnapshot StatSnapshot
+ {
+ get { return _statSnapshot; }
+ }
///
public override string ToString()
{
- var trimmedCaseName = _caseName.Length > 20 ? _caseName.Substring(0, 17) + "..." : _caseName;
- return $"{trimmedCaseName,-20} |{MOPS,8:f2} | {_statSnapshot._elapsed,5} ms | {_statSnapshot._gc0,5:f1} | {_statSnapshot._gc1,5:f1} | {_statSnapshot._gc2,5:f1} | {_statSnapshot._memory / (1024 * 1024.0),5:f3} MB";
+ var trimmedCaseName = CaseName.Length > 20 ? CaseName.Substring(0, 17) + "..." : CaseName;
+ return
+ $"{trimmedCaseName,-20} |{MOPS,8:f2} | {_statSnapshot.Elapsed / 10000.0:N0} ms | {_statSnapshot.Gc0,5:f1} | {_statSnapshot.Gc1,5:f1} | {_statSnapshot.Gc2,5:f1} | {_statSnapshot.Memory / (1024 * 1024.0),5:f3} MB";
}
internal string ToString(int caseAlignmentLength)
{
- var paddedCaseName = _caseName.PadRight(caseAlignmentLength);
- return $"{paddedCaseName,-20} |{MOPS,8:f2} | {_statSnapshot._elapsed,5} ms | {_statSnapshot._gc0,5:f1} | {_statSnapshot._gc1,5:f1} | {_statSnapshot._gc2,5:f1} | {_statSnapshot._memory / (1024 * 1024.0),5:f3} MB";
+ var paddedCaseName = CaseName.PadRight(caseAlignmentLength);
+ return
+ $"{paddedCaseName,-20} |{MOPS,8:f2} | {_statSnapshot.Elapsed / 10000.0:N0} ms | {_statSnapshot.Gc0,5:f1} | {_statSnapshot.Gc1,5:f1} | {_statSnapshot.Gc2,5:f1} | {_statSnapshot.Memory / (1024 * 1024.0),5:f3} MB";
}
}
- internal struct StatSnapshot
+ public struct StatSnapshot
{
- internal long _elapsed;
- internal double _gc0;
- internal double _gc1;
- internal double _gc2;
- internal double _memory;
+ public long Elapsed;
+ public double Gc0;
+ public double Gc1;
+ public double Gc2;
+ public double Memory;
public StatSnapshot(Stopwatch sw, bool start)
{
@@ -200,26 +243,27 @@ public StatSnapshot(Stopwatch sw, bool start)
{
// end of measurement, first stop timer then collect/count
sw.Stop();
- _elapsed = sw.ElapsedMilliseconds;
+ Elapsed = sw.Elapsed.Ticks;
// NB we exclude forced GC from counters,
// by measuring memory before forced GC we could
// calculate uncollected garbage
- _memory = GC.GetTotalMemory(false);
+ Memory = GC.GetTotalMemory(false);
}
- GC.Collect(2, GCCollectionMode.Forced, true);
- GC.WaitForPendingFinalizers();
- GC.Collect(2, GCCollectionMode.Forced, true);
- GC.WaitForPendingFinalizers();
+ //GC.Collect(2, GCCollectionMode.Forced, true);
+ //GC.WaitForPendingFinalizers();
+ //GC.Collect(2, GCCollectionMode.Forced, true);
+ //GC.WaitForPendingFinalizers();
+
- _gc0 = GC.CollectionCount(0);
- _gc1 = GC.CollectionCount(1);
- _gc2 = GC.CollectionCount(2);
+ Gc0 = GC.CollectionCount(0);
+ Gc1 = GC.CollectionCount(1);
+ Gc2 = GC.CollectionCount(2);
if (start)
{
- _memory = GC.GetTotalMemory(false);
+ Memory = GC.GetTotalMemory(false);
// start timer after collecting GC stat
sw.Restart();
}
diff --git a/dotnet/tests/Spreads.Native.Tests/MemTests.cs b/dotnet/tests/Spreads.Native.Tests/MemTests.cs
index f471440..7a15a97 100644
--- a/dotnet/tests/Spreads.Native.Tests/MemTests.cs
+++ b/dotnet/tests/Spreads.Native.Tests/MemTests.cs
@@ -1,4 +1,10 @@
using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Threading;
+using System.Threading.Tasks;
+using HdrHistogram;
using NUnit.Framework;
namespace Spreads.Native.Tests
@@ -18,82 +24,437 @@ public void CouldGetMimallocVersion()
[Test]
public void CouldAllocFree()
{
- var p = Mem.Malloc(123);
- p = Mem.Realloc(p, 456);
- p = Mem.Reallocf(p, 789);
+ var p = Mem.Malloc((UIntPtr) 123);
+ p = Mem.Realloc(p, (UIntPtr) 456);
+ p = Mem.Reallocf(p, (UIntPtr) 789);
Assert.IsTrue(p != null);
Mem.Free(p);
- p = Mem.Calloc(1, 2);
+ p = Mem.Calloc((UIntPtr) 1, (UIntPtr) 2);
Assert.IsTrue(p != null);
Console.WriteLine(Mem.UsableSize(p));
- p = Mem.Recalloc(p, 10, 3);
+ p = Mem.Recalloc(p, (UIntPtr) 10, (UIntPtr) 3);
Assert.IsTrue(p != null);
Console.WriteLine(Mem.UsableSize(p));
- p = Mem.Expand(p, (uint) Mem.UsableSize(p));
+ p = Mem.Expand(p, (UIntPtr) Mem.UsableSize(p));
Assert.IsTrue(p != null);
Mem.Free(p);
Mem.Collect(false);
- p = Mem.MallocSmall(42);
+ p = Mem.MallocSmall((UIntPtr) 42);
Assert.IsTrue(p != null);
Mem.Free(p);
- p = Mem.ZallocSmall(42);
+ p = Mem.ZallocSmall((UIntPtr) 42);
Assert.IsTrue(p != null);
Mem.Free(p);
- p = Mem.Zalloc(42000);
+ p = Mem.Zalloc((UIntPtr) 42000);
Assert.IsTrue(p != null);
- p = Mem.Rezalloc(p, 100000);
+ p = Mem.Rezalloc(p, (UIntPtr) 100000);
Assert.IsTrue(p != null);
Mem.Free(p);
- p = Mem.Mallocn(10, 20);
+ p = Mem.Mallocn((UIntPtr) 10, (UIntPtr) 20);
Assert.IsTrue(p != null);
- p = Mem.Reallocn(p, 100, 20);
+ p = Mem.Reallocn(p, (UIntPtr) 100, (UIntPtr) 20);
Assert.IsTrue(p != null);
Mem.Free(p);
Mem.Collect(true);
- p = Mem.MallocAligned(16 * 17, 16);
+ p = Mem.MallocAligned((UIntPtr) (16 * 17), (UIntPtr) 16);
Assert.IsTrue(p != null);
Console.WriteLine(Mem.UsableSize(p));
- p = Mem.ReallocAligned(p, 16 * 30, 16);
+ p = Mem.ReallocAligned(p, (UIntPtr) (16 * 30), (UIntPtr) 16);
Assert.IsTrue(p != null);
Mem.Free(p);
- p = Mem.MallocAlignedAt(3 + 16 * 17, 16, 3);
+ p = Mem.MallocAlignedAt((UIntPtr) (3 + 16 * 17), (UIntPtr) 16, (UIntPtr) 3);
Assert.IsTrue(p != null);
- p = Mem.ReallocAlignedAt(p, 3 + 16 * 34, 16, 3);
+ p = Mem.ReallocAlignedAt(p, (UIntPtr) (3 + 16 * 34), (UIntPtr) 16, (UIntPtr) 3);
Assert.IsTrue(p != null);
Mem.Free(p);
- p = Mem.ZallocAligned(16 * 17, 16);
+ p = Mem.ZallocAligned((UIntPtr) (16 * 17), (UIntPtr) 16);
Assert.IsTrue(p != null);
- p = Mem.RezallocAligned(p, 16 * 30, 16);
+ p = Mem.RezallocAligned(p, (UIntPtr) (16 * 30), (UIntPtr) 16);
Assert.IsTrue(p != null);
Mem.Free(p);
- p = Mem.ZallocAlignedAt(3 + 16 * 17, 16, 3);
+ p = Mem.ZallocAlignedAt((UIntPtr) (3 + 16 * 17), (UIntPtr) 16, (UIntPtr) 3);
Assert.IsTrue(p != null);
- p = Mem.RezallocAlignedAt(p, 3 + 16 * 34, 16, 3);
+ p = Mem.RezallocAlignedAt(p, (UIntPtr) (3 + 16 * 34), (UIntPtr) 16, (UIntPtr) 3);
Assert.IsTrue(p != null);
Mem.Free(p);
- p = Mem.CallocAligned(17, 16, 16);
+ p = Mem.CallocAligned((UIntPtr) 17, (UIntPtr) 16, (UIntPtr) 16);
Assert.IsTrue(p != null);
- p = Mem.RecallocAligned(p, 34, 16, 16);
+ p = Mem.RecallocAligned(p, (UIntPtr) 34, (UIntPtr) 16, (UIntPtr) 16);
Assert.IsTrue(p != null);
Mem.Free(p);
- p = Mem.CallocAlignedAt(17, 16, 16, 3);
+ p = Mem.CallocAlignedAt((UIntPtr) 17, (UIntPtr) 16, (UIntPtr) 16, (UIntPtr) 3);
Assert.IsTrue(p != null);
- p = Mem.RecallocAlignedAt(p, 34, 16, 16, 3);
+ p = Mem.RecallocAlignedAt(p, (UIntPtr) 34, (UIntPtr) 16, (UIntPtr) 16, (UIntPtr) 3);
Assert.IsTrue(p != null);
Mem.Free(p);
}
+
+ [Test]
+ public void CouldAllocFreeHeap()
+ {
+ var h = Mem.HeapNew();
+
+ var p = Mem.HeapMalloc(h, (UIntPtr) 123);
+ p = Mem.HeapRealloc(h, p, (UIntPtr) 456);
+ p = Mem.HeapReallocf(h, p, (UIntPtr) 789);
+ Assert.IsTrue(p != null);
+ Mem.Free(p);
+
+ p = Mem.HeapCalloc(h, (UIntPtr) 1, (UIntPtr) 2);
+ Assert.IsTrue(p != null);
+ Console.WriteLine(Mem.UsableSize(p));
+ p = Mem.HeapRecalloc(h, p, (UIntPtr) 10, (UIntPtr) 3);
+ Assert.IsTrue(p != null);
+ Console.WriteLine(Mem.UsableSize(p));
+ p = Mem.Expand(p, (UIntPtr) Mem.UsableSize(p));
+ Assert.IsTrue(p != null);
+ Mem.Free(p);
+
+ Mem.HeapCollect(h, false);
+
+ p = Mem.HeapMallocSmall(h, (UIntPtr) 42);
+ Assert.IsTrue(p != null);
+ Mem.Free(p);
+
+ p = Mem.HeapZalloc(h, (UIntPtr) 42000);
+ Assert.IsTrue(p != null);
+ p = Mem.HeapRezalloc(h, p, (UIntPtr) 100000);
+ Assert.IsTrue(p != null);
+ Mem.Free(p);
+
+ p = Mem.HeapMallocn(h, (UIntPtr) 10, (UIntPtr) 20);
+ Assert.IsTrue(p != null);
+ p = Mem.HeapReallocn(h, p, (UIntPtr) 100, (UIntPtr) 20);
+ Assert.IsTrue(p != null);
+ Mem.Free(p);
+
+ Mem.HeapCollect(h, true);
+
+ p = Mem.HeapMallocAligned(h, (UIntPtr) (16 * 17), (UIntPtr) 16);
+ Assert.IsTrue(p != null);
+ Console.WriteLine(Mem.UsableSize(p));
+ p = Mem.HeapReallocAligned(h, p, (UIntPtr) (16 * 30), (UIntPtr) 16);
+ Assert.IsTrue(p != null);
+ Mem.Free(p);
+
+ p = Mem.HeapMallocAlignedAt(h, (UIntPtr) (3 + 16 * 17), (UIntPtr) 16, (UIntPtr) 3);
+ Assert.IsTrue(p != null);
+ p = Mem.HeapReallocAlignedAt(h, p, (UIntPtr) (3 + 16 * 34), (UIntPtr) 16, (UIntPtr) 3);
+ Assert.IsTrue(p != null);
+ Mem.Free(p);
+
+ p = Mem.HeapZallocAligned(h, (UIntPtr) (16 * 17), (UIntPtr) 16);
+ Assert.IsTrue(p != null);
+ p = Mem.HeapRezallocAligned(h, p, (UIntPtr) (16 * 30), (UIntPtr) 16);
+ Assert.IsTrue(p != null);
+ Mem.Free(p);
+
+ p = Mem.HeapZallocAlignedAt(h, (UIntPtr) (3 + 16 * 17), (UIntPtr) 16, (UIntPtr) 3);
+ Assert.IsTrue(p != null);
+ p = Mem.HeapRezallocAlignedAt(h, p, (UIntPtr) (3 + 16 * 34), (UIntPtr) 16, (UIntPtr) 3);
+ Assert.IsTrue(p != null);
+ Mem.Free(p);
+
+ p = Mem.HeapCallocAligned(h, (UIntPtr) 10, (UIntPtr) 16, (UIntPtr) 8);
+ Assert.IsTrue(p != null);
+ p = Mem.HeapRecallocAligned(h, p, (UIntPtr) 20, (UIntPtr) 16, (UIntPtr) 8);
+ Assert.IsTrue(p != null);
+ Mem.Free(p);
+
+ p = Mem.HeapCallocAlignedAt(h, (UIntPtr) 17, (UIntPtr) 16, (UIntPtr) 16, (UIntPtr) 3);
+ Assert.IsTrue(p != null);
+ p = Mem.HeapRecallocAlignedAt(h, p, (UIntPtr) 34, (UIntPtr) 16, (UIntPtr) 16, (UIntPtr) 3);
+ Assert.IsTrue(p != null);
+ Mem.Free(p);
+
+ Mem.HeapDestroy(h);
+ }
+
+ [Test, Explicit]
+ public void MimallocAllocFreePerf()
+ {
+ var h = Mem.HeapNew();
+
+ Mem.OptionSetEnabled(Mem.Option.EagerCommit, true);
+ Mem.OptionSetEnabled(Mem.Option.LargeOsPages, true);
+ Mem.OptionSetEnabled(Mem.Option.ResetDecommits, true);
+ Mem.OptionSetEnabled(Mem.Option.PageReset, true);
+ Mem.OptionSetEnabled(Mem.Option.SegmentReset, true);
+ Mem.OptionSetEnabled(Mem.Option.AbandonedPageReset, true);
+ Mem.OptionSet(Mem.Option.ResetDelay, 0);
+ Mem.OptionSetEnabled(Mem.Option.EagerRegionCommit, true);
+
+ Mem.RegisterOutput((str, arg) => { Console.Write(str); }, null);
+
+ Assert.IsTrue(Mem.OptionIsEnabled(Mem.Option.PageReset));
+
+ var count = 100_000L;
+ var size = 32 * 4096;
+ IntPtr[] ptrs = new IntPtr[count];
+
+ for (int r = 0; r < 4; r++)
+ {
+ Task.Factory.StartNew(() =>
+ {
+ using (Benchmark.Run("Alloc" + r, (long) (count * size / 1000.0)))
+ {
+ for (int i = 0; i < count; i++)
+ {
+ ptrs[i] = (IntPtr) Mem.HeapMalloc(h, (UIntPtr) size);
+ if ((long) (ptrs[i]) % 4096 != 0)
+ {
+ Assert.Fail(((long) (ptrs[i]) % 4096).ToString());
+ // Console.WriteLine((long)(ptrs[i]) % 4096);
+ }
+
+ for (int j = 0; j < size; j += 4096) ((byte*) ptrs[i])[j] = 0;
+ ((byte*) ptrs[i])[size - 1] = 0;
+ }
+ }
+ }
+ , TaskCreationOptions.LongRunning).Wait();
+
+ Task.Factory.StartNew(() =>
+ {
+ using (Benchmark.Run("Free" + r, (long) (count * size / 1000.0)))
+ {
+ for (long i = count - 1; i >= 0; i--)
+ {
+ Mem.Free((byte*) ptrs[i]);
+ }
+
+ // Mem.HeapCollect(h, true);
+ }
+ }
+ , TaskCreationOptions.LongRunning).Wait();
+ }
+
+ Mem.StatsPrint();
+
+ // long x = 0;
+ // while (true)
+ // {
+ // x++;
+ //
+ // ptrs[0] = (IntPtr) Spreads.Native.Mem.Malloc((UIntPtr) size);
+ // Mem.Free((byte*) ptrs[0]);
+ // if (x == long.MaxValue)
+ // break;
+ //
+ // Thread.Sleep(1);
+ // }
+ //
+ // // Spreads.Native.Mem.Collect(false);
+ //
+ //
+ // Thread.Sleep(10000000);
+ }
+
+
+ [Test, Explicit]
+ public void MimallocAllocFreeCallPerf()
+ {
+ Mem.OptionSetEnabled(Mem.Option.EagerCommit, true);
+ Mem.OptionSetEnabled(Mem.Option.LargeOsPages, true);
+ Mem.OptionSetEnabled(Mem.Option.ResetDecommits, true);
+ Mem.OptionSetEnabled(Mem.Option.PageReset, true);
+ Mem.OptionSetEnabled(Mem.Option.SegmentReset, true);
+ Mem.OptionSetEnabled(Mem.Option.AbandonedPageReset, true);
+ // Mem.OptionSet(Mem.Option.ResetDelay, 0);
+ Mem.OptionSetEnabled(Mem.Option.EagerRegionCommit, true);
+
+ var h = Mem.HeapNew();
+
+ var count = 100_000L;
+ var size = 32 * 4096;
+ IntPtr[] ptrs = new IntPtr[count];
+
+ for (int r = 0; r < 4; r++)
+ {
+ using (Benchmark.Run("AllocFree" + r, count))
+ {
+ for (int i = 0; i < count; i++)
+ {
+ ptrs[i] = (IntPtr) Mem.HeapMalloc(h, (UIntPtr) size);
+ for (int j = 0; j < size; j += 4096) ((byte*) ptrs[i])[j] = 0;
+ ((byte*) ptrs[i])[size - 1] = 0;
+ Mem.Free((byte*) ptrs[i]);
+ }
+ }
+ }
+
+ Mem.StatsPrint();
+ }
+
+
+ [Test, Explicit]
+ public void MimallocAllocFreeCallLatency()
+ {
+ Mem.OptionSetEnabled(Mem.Option.EagerCommit, true);
+ Mem.OptionSetEnabled(Mem.Option.LargeOsPages, true);
+ Mem.OptionSetEnabled(Mem.Option.ResetDecommits, true);
+ Mem.OptionSetEnabled(Mem.Option.PageReset, true);
+ Mem.OptionSetEnabled(Mem.Option.SegmentReset, true);
+ Mem.OptionSetEnabled(Mem.Option.AbandonedPageReset, true);
+ // Mem.OptionSet(Mem.Option.ResetDelay, 0);
+ Mem.OptionSetEnabled(Mem.Option.EagerRegionCommit, true);
+
+ Mem.RegisterOutput((str, arg) => { Console.Write(str); }, null);
+
+ var rng = new Random();
+ var allocated = 0L;
+
+ var h = Mem.HeapNew();
+
+ var count = 100_000L;
+ var size = 32 * 4096;
+ IntPtr[] ptrs = new IntPtr[count];
+
+ for (int r = 0; r < 4; r++)
+ {
+ var histogram = new HdrHistogram.LongHistogram(1, 1000000, 1);
+
+ using (Benchmark.Run("AllocFree" + r, count))
+ {
+ for (int i = 0; i < count; i++)
+ {
+ var x = rng.NextDouble();
+ var start = Stopwatch.GetTimestamp();
+ if (allocated < 1000)
+ Allocate();
+ else if (allocated > 2000)
+ Free();
+ else if (((2000 - allocated) / 1000.0 * x) > 0.5)
+ Allocate();
+ else
+ Free();
+
+ var time = Stopwatch.GetTimestamp() - start;
+
+ histogram.RecordValue(time);
+
+ void Allocate()
+ {
+ ptrs[allocated] = (IntPtr) Mem.HeapMalloc(h, (UIntPtr) size);
+ for (int j = 0; j < size; j += 4096) ((byte*) ptrs[allocated])[j] = 0;
+ ((byte*) ptrs[allocated])[size - 1] = 0;
+ allocated++;
+ }
+
+ void Free()
+ {
+ Mem.Free((byte*) ptrs[allocated - 1]);
+ allocated--;
+ }
+ }
+ }
+
+ histogram.OutputPercentileDistribution(Console.Out,
+ outputValueUnitScalingRatio: OutputScalingFactor.TimeStampToMicroseconds);
+ }
+
+ Mem.StatsPrint();
+ }
+
+ [Test, Explicit]
+ public unsafe void MarshalAllocFreePerf()
+ {
+ var count = 100_000L;
+ var size = 32 * 4096;
+ IntPtr[] ptrs = new IntPtr[count];
+
+ for (int r = 0; r < 4; r++)
+ {
+ using (Benchmark.Run("Alloc" + r, (long) (count * size / 1000.0)))
+ {
+ for (int i = 0; i < count; i++)
+ {
+ ptrs[i] = Marshal.AllocHGlobal(size);
+
+ // It's unaligned
+ // if ((long)(ptrs[i]) % 4096 != 0)
+ // Assert.Fail(((long) (ptrs[i]) % 4096).ToString());
+
+ for (int j = 0; j < size; j += 4096) ((byte*) ptrs[i])[j] = 0;
+ ((byte*) ptrs[i])[size - 1] = 0;
+ }
+ }
+
+ using (Benchmark.Run("Free" + r, (long) (count * size / 1000.0)))
+ {
+ for (int i = 0; i < count; i++)
+ {
+ Marshal.FreeHGlobal(ptrs[i]);
+ }
+ }
+ }
+ }
+
+ [Test, Explicit]
+ public unsafe void VirtualAllocFreePerf()
+ {
+ var count = 100_000L;
+ var size = 16 * 4096;
+ IntPtr[] ptrs = new IntPtr[count];
+
+ for (int r = 0; r < 3; r++)
+ {
+ using (Benchmark.Run("Alloc" + r, (long) (count * size / 1000.0)))
+ {
+ for (int i = 0; i < count; i++)
+ {
+ ptrs[i] = Kernel32.VirtualAlloc(IntPtr.Zero, (uint) size,
+ Kernel32.Consts.MEM_COMMIT | Kernel32.Consts.MEM_RESERVE, Kernel32.Consts.PAGE_READWRITE);
+
+ if ((long) (ptrs[i]) % 4096 != 0)
+ Assert.Fail(((long) (ptrs[i]) % 4096).ToString());
+
+ for (int j = 0; j < size; j += 4096) ((byte*) ptrs[i])[j] = 0;
+ ((byte*) ptrs[i])[size - 1] = 0;
+ }
+ }
+
+ using (Benchmark.Run("Free" + r, (long) (count * size / 1000.0)))
+ {
+ for (int i = 0; i < count; i++)
+ {
+ Kernel32.VirtualFree(ptrs[i], 0, Kernel32.Consts.MEM_RELEASE);
+ }
+ }
+ }
+ }
+
+ public static class Kernel32
+ {
+ [DllImport("Kernel32", SetLastError = true)]
+ [SuppressUnmanagedCodeSecurity]
+ internal static extern IntPtr VirtualAlloc([In] IntPtr lpAddress, [In] uint dwSize,
+ [In] int flAllocationType, [In] int flProtect);
+
+ [DllImport("Kernel32", SetLastError = true)]
+ [SuppressUnmanagedCodeSecurity]
+ internal static extern bool VirtualFree([In] IntPtr lpAddress, [In] uint dwSize, [In] int dwFreeType);
+
+ public static class Consts
+ {
+ public const int MEM_COMMIT = 0x00001000;
+ public const int MEM_RESERVE = 0x00002000;
+ public const int MEM_RELEASE = 0x8000;
+ public const int PAGE_READWRITE = 0x04;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/dotnet/tests/Spreads.Native.Tests/Spreads.Native.Tests.csproj b/dotnet/tests/Spreads.Native.Tests/Spreads.Native.Tests.csproj
index 5992d04..8b8bc86 100644
--- a/dotnet/tests/Spreads.Native.Tests/Spreads.Native.Tests.csproj
+++ b/dotnet/tests/Spreads.Native.Tests/Spreads.Native.Tests.csproj
@@ -12,6 +12,7 @@
+
diff --git a/rs/Cargo.toml b/rs/Cargo.toml
index 797de2b..793de2d 100644
--- a/rs/Cargo.toml
+++ b/rs/Cargo.toml
@@ -32,6 +32,7 @@ members = [
debug = true
[profile.release]
-debug = false
+opt-level = 3
lto = true
+debug = false
panic = 'abort'
diff --git a/rs/spreads-mimalloc-sys/build.rs b/rs/spreads-mimalloc-sys/build.rs
index f14d9ae..0bd22d5 100644
--- a/rs/spreads-mimalloc-sys/build.rs
+++ b/rs/spreads-mimalloc-sys/build.rs
@@ -7,6 +7,7 @@ fn main() {
// .use_core()
// .ctypes_prefix("libc")
// .whitelist_function("mi_.*")
+ // .size_t_is_usize(true)
// .rustfmt_bindings(true)
// .generate()
// .expect("Unable to generate bindings");
diff --git a/rs/spreads-mimalloc-sys/mimalloc_wrapper.h b/rs/spreads-mimalloc-sys/mimalloc_wrapper.h
index 9503bb3..910a9c8 100644
--- a/rs/spreads-mimalloc-sys/mimalloc_wrapper.h
+++ b/rs/spreads-mimalloc-sys/mimalloc_wrapper.h
@@ -120,13 +120,13 @@ mi_decl_nodiscard mi_decl_export size_t mi_good_size(size_t size) mi_attr_no
// Internals
// ------------------------------------------------------
-typedef void (mi_cdecl mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
+typedef void mi_deferred_free_fun(bool force, unsigned long long heartbeat, void* arg);
mi_decl_export void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg) mi_attr_noexcept;
-typedef void (mi_cdecl mi_output_fun)(const char* msg, void* arg);
+typedef void mi_output_fun(const char* msg, void* arg);
mi_decl_export void mi_register_output(mi_output_fun* out, void* arg) mi_attr_noexcept;
-typedef void (mi_cdecl mi_error_fun)(int err, void* arg);
+typedef void mi_error_fun(int err, void* arg);
mi_decl_export void mi_register_error(mi_error_fun* fun, void* arg);
mi_decl_export void mi_collect(bool force) mi_attr_noexcept;
@@ -239,7 +239,7 @@ typedef struct mi_heap_area_s {
size_t block_size; // size in bytes of each block
} mi_heap_area_t;
-typedef bool (mi_cdecl mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg);
+typedef bool mi_block_visit_fun(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg);
mi_decl_export bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);
diff --git a/rs/spreads-mimalloc-sys/src/mimalloc.rs b/rs/spreads-mimalloc-sys/src/mimalloc.rs
index c030c3a..33450b7 100644
--- a/rs/spreads-mimalloc-sys/src/mimalloc.rs
+++ b/rs/spreads-mimalloc-sys/src/mimalloc.rs
@@ -51,23 +51,21 @@ extern "C" {
extern "C" {
pub fn mi_good_size(size: usize) -> usize;
}
+pub type mi_deferred_free_fun = ::core::option::Option<
+ unsafe extern "C" fn(force: bool, heartbeat: libc::c_ulonglong, arg: *mut libc::c_void),
+>;
extern "C" {
- pub fn mi_register_deferred_free(
- deferred_free: ::core::option::Option,
- arg: *mut libc::c_void,
- );
+ pub fn mi_register_deferred_free(deferred_free: mi_deferred_free_fun, arg: *mut libc::c_void);
}
+pub type mi_output_fun =
+ ::core::option::Option;
extern "C" {
- pub fn mi_register_output(
- out: ::core::option::Option,
- arg: *mut libc::c_void,
- );
+ pub fn mi_register_output(out: mi_output_fun, arg: *mut libc::c_void);
}
+pub type mi_error_fun =
+ ::core::option::Option;
extern "C" {
- pub fn mi_register_error(
- fun: ::core::option::Option,
- arg: *mut libc::c_void,
- );
+ pub fn mi_register_error(fun: mi_error_fun, arg: *mut libc::c_void);
}
extern "C" {
pub fn mi_collect(force: bool);
@@ -85,10 +83,7 @@ extern "C" {
pub fn mi_stats_print(out: *mut libc::c_void);
}
extern "C" {
- pub fn mi_stats_print_out(
- out: ::core::option::Option,
- arg: *mut libc::c_void,
- );
+ pub fn mi_stats_print_out(out: mi_output_fun, arg: *mut libc::c_void);
}
extern "C" {
pub fn mi_process_init();
@@ -100,10 +95,7 @@ extern "C" {
pub fn mi_thread_done();
}
extern "C" {
- pub fn mi_thread_stats_print_out(
- out: ::core::option::Option,
- arg: *mut libc::c_void,
- );
+ pub fn mi_thread_stats_print_out(out: mi_output_fun, arg: *mut libc::c_void);
}
extern "C" {
pub fn mi_malloc_aligned(size: usize, alignment: usize) -> *mut libc::c_void;
@@ -386,11 +378,93 @@ extern "C" {
extern "C" {
pub fn mi_check_owned(p: *const libc::c_void) -> bool;
}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct mi_heap_area_s {
+ pub blocks: *mut libc::c_void,
+ pub reserved: usize,
+ pub committed: usize,
+ pub used: usize,
+ pub block_size: usize,
+}
+#[test]
+fn bindgen_test_layout_mi_heap_area_s() {
+ assert_eq!(
+ ::core::mem::size_of::(),
+ 40usize,
+ concat!("Size of: ", stringify!(mi_heap_area_s))
+ );
+ assert_eq!(
+ ::core::mem::align_of::(),
+ 8usize,
+ concat!("Alignment of ", stringify!(mi_heap_area_s))
+ );
+ assert_eq!(
+ unsafe { &(*(::core::ptr::null::())).blocks as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(mi_heap_area_s),
+ "::",
+ stringify!(blocks)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::core::ptr::null::())).reserved as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(mi_heap_area_s),
+ "::",
+ stringify!(reserved)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::core::ptr::null::())).committed as *const _ as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(mi_heap_area_s),
+ "::",
+ stringify!(committed)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::core::ptr::null::())).used as *const _ as usize },
+ 24usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(mi_heap_area_s),
+ "::",
+ stringify!(used)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::core::ptr::null::())).block_size as *const _ as usize },
+ 32usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(mi_heap_area_s),
+ "::",
+ stringify!(block_size)
+ )
+ );
+}
+pub type mi_heap_area_t = mi_heap_area_s;
+pub type mi_block_visit_fun = ::core::option::Option<
+ unsafe extern "C" fn(
+ heap: *const mi_heap_t,
+ area: *const mi_heap_area_t,
+ block: *mut libc::c_void,
+ block_size: usize,
+ arg: *mut libc::c_void,
+ ) -> bool,
+>;
extern "C" {
pub fn mi_heap_visit_blocks(
heap: *const mi_heap_t,
visit_all_blocks: bool,
- visitor: ::core::option::Option bool>,
+ visitor: mi_block_visit_fun,
arg: *mut libc::c_void,
) -> bool;
}
diff --git a/rs/src/mem_allocation.rs b/rs/src/mem_allocation.rs
index b1fa516..6f04167 100644
--- a/rs/src/mem_allocation.rs
+++ b/rs/src/mem_allocation.rs
@@ -216,7 +216,7 @@ pub extern "C" fn spreads_mem_good_size(size: usize) -> usize {
#[no_mangle]
pub extern "C" fn spreads_mem_register_deferred_free(
- deferred_free: ::core::option::Option,
+ deferred_free: mi_deferred_free_fun,
arg: *mut libc::c_void,
) {
unsafe {
@@ -225,20 +225,14 @@ pub extern "C" fn spreads_mem_register_deferred_free(
}
#[no_mangle]
-pub extern "C" fn spreads_mem_register_output(
- out: ::core::option::Option,
- arg: *mut libc::c_void,
-) {
+pub extern "C" fn spreads_mem_register_output(out: mi_output_fun, arg: *mut libc::c_void) {
unsafe {
return mi_register_output(out, arg);
}
}
#[no_mangle]
-pub extern "C" fn spreads_mem_register_error(
- fun: ::core::option::Option,
- arg: *mut libc::c_void,
-) {
+pub extern "C" fn spreads_mem_register_error(fun: mi_error_fun, arg: *mut libc::c_void) {
unsafe {
return mi_register_error(fun, arg);
}
@@ -258,6 +252,32 @@ pub extern "C" fn spreads_mem_mialloc_version() -> libc::c_int {
}
}
+#[no_mangle]
+pub extern "C" fn spreads_mem_stats_reset() {
+ unsafe {
+ return mi_stats_reset();
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn spreads_mem_stats_merge() {
+ unsafe {
+ return mi_stats_merge();
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_stats_print() {
+ unsafe {
+ return mi_stats_print(0 as *mut libc::c_void); // out is ignored
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_stats_print_out(out: mi_output_fun, arg: *mut libc::c_void) {
+ unsafe {
+ return mi_stats_print_out(out, arg);
+ }
+}
+
#[no_mangle]
pub extern "C" fn spreads_mem_process_init() {
unsafe {
@@ -277,10 +297,7 @@ pub extern "C" fn spreads_mem_thread_done() {
}
}
#[no_mangle]
-pub extern "C" fn spreads_mem_thread_stats_print_out(
- out: ::core::option::Option,
- arg: *mut libc::c_void,
-) {
+pub extern "C" fn spreads_mem_thread_stats_print_out(out: mi_output_fun, arg: *mut libc::c_void) {
unsafe {
return mi_thread_stats_print_out(out, arg);
}
@@ -360,19 +377,6 @@ pub extern "C" fn spreads_mem_realloc_aligned_at(
}
}
-#[no_mangle]
-pub extern "C" fn spreads_mem_heap_get_default() -> *mut mi_heap_t {
- unsafe {
- return mi_heap_get_default();
- }
-}
-#[no_mangle]
-pub extern "C" fn spreads_mem_heap_get_backing() -> *mut mi_heap_t {
- unsafe {
- return mi_heap_get_backing();
- }
-}
-
#[no_mangle]
pub extern "C" fn spreads_mem_rezalloc(p: *mut libc::c_void, newsize: usize) -> *mut libc::c_void {
unsafe {
@@ -440,25 +444,6 @@ pub extern "C" fn spreads_mem_check_owned(p: *const libc::c_void) -> bool {
return mi_check_owned(p);
}
}
-#[no_mangle]
-pub extern "C" fn spreads_mem_heap_visit_blocks(
- heap: *const mi_heap_t,
- visit_all_blocks: bool,
- visitor: ::core::option::Option bool>,
- arg: *mut libc::c_void,
-) -> bool {
- unsafe {
- return mi_heap_visit_blocks(heap, visit_all_blocks, visitor, arg);
- }
-}
-
-#[no_mangle]
-pub extern "C" fn spreads_mem_is_in_heap_region(p: *const libc::c_void) -> bool {
- unsafe {
- return mi_is_in_heap_region(p);
- }
-}
-
#[no_mangle]
pub extern "C" fn spreads_mem_reserve_huge_os_pages_interleave(
pages: usize,
@@ -508,6 +493,7 @@ pub extern "C" fn spreads_mem_option_disable(option: mi_option_t) {
return mi_option_disable(option);
}
}
+
#[no_mangle]
pub extern "C" fn spreads_mem_option_set_enabled(option: mi_option_t, enable: bool) {
unsafe {
@@ -539,9 +525,354 @@ pub extern "C" fn spreads_mem_option_set_default(option: mi_option_t, value: lib
}
}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_new() -> *mut mi_heap_t {
+ unsafe {
+ return mi_heap_new();
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_delete(heap: *mut mi_heap_t) {
+ unsafe {
+ return mi_heap_delete(heap);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_destroy(heap: *mut mi_heap_t) {
+ unsafe {
+ return mi_heap_destroy(heap);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_set_default(heap: *mut mi_heap_t) -> *mut mi_heap_t {
+ unsafe {
+ return mi_heap_set_default(heap);
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_get_default() -> *mut mi_heap_t {
+ unsafe {
+ return mi_heap_get_default();
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_get_backing() -> *mut mi_heap_t {
+ unsafe {
+ return mi_heap_get_backing();
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_visit_blocks(
+ heap: *const mi_heap_t,
+ visit_all_blocks: bool,
+ visitor: mi_block_visit_fun,
+ arg: *mut libc::c_void,
+) -> bool {
+ unsafe {
+ return mi_heap_visit_blocks(heap, visit_all_blocks, visitor, arg);
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn spreads_mem_is_in_heap_region(p: *const libc::c_void) -> bool {
+ unsafe {
+ return mi_is_in_heap_region(p);
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_collect(heap: *mut mi_heap_t, force: bool) {
+ unsafe {
+ return mi_heap_collect(heap, force);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_malloc(heap: *mut mi_heap_t, size: usize) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_malloc(heap, size);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_zalloc(heap: *mut mi_heap_t, size: usize) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_zalloc(heap, size);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_calloc(
+ heap: *mut mi_heap_t,
+ count: usize,
+ size: usize,
+) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_calloc(heap, count, size);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_mallocn(
+ heap: *mut mi_heap_t,
+ count: usize,
+ size: usize,
+) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_mallocn(heap, count, size);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_malloc_small(
+ heap: *mut mi_heap_t,
+ size: usize,
+) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_malloc_small(heap, size);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_realloc(
+ heap: *mut mi_heap_t,
+ p: *mut libc::c_void,
+ newsize: usize,
+) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_realloc(heap, p, newsize);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_reallocn(
+ heap: *mut mi_heap_t,
+ p: *mut libc::c_void,
+ count: usize,
+ size: usize,
+) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_reallocn(heap, p, count, size);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_reallocf(
+ heap: *mut mi_heap_t,
+ p: *mut libc::c_void,
+ newsize: usize,
+) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_reallocf(heap, p, newsize);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_strdup(
+ heap: *mut mi_heap_t,
+ s: *const libc::c_char,
+) -> *mut libc::c_char {
+ unsafe {
+ return mi_heap_strdup(heap, s);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_strndup(
+ heap: *mut mi_heap_t,
+ s: *const libc::c_char,
+ n: usize,
+) -> *mut libc::c_char {
+ unsafe {
+ return mi_heap_strndup(heap, s, n);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_realpath(
+ heap: *mut mi_heap_t,
+ fname: *const libc::c_char,
+ resolved_name: *mut libc::c_char,
+) -> *mut libc::c_char {
+ unsafe {
+ return mi_heap_realpath(heap, fname, resolved_name);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_malloc_aligned(
+ heap: *mut mi_heap_t,
+ size: usize,
+ alignment: usize,
+) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_malloc_aligned(heap, size, alignment);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_malloc_aligned_at(
+ heap: *mut mi_heap_t,
+ size: usize,
+ alignment: usize,
+ offset: usize,
+) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_malloc_aligned_at(heap, size, alignment, offset);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_zalloc_aligned(
+ heap: *mut mi_heap_t,
+ size: usize,
+ alignment: usize,
+) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_zalloc_aligned(heap, size, alignment);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_zalloc_aligned_at(
+ heap: *mut mi_heap_t,
+ size: usize,
+ alignment: usize,
+ offset: usize,
+) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_zalloc_aligned_at(heap, size, alignment, offset);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_calloc_aligned(
+ heap: *mut mi_heap_t,
+ count: usize,
+ size: usize,
+ alignment: usize,
+) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_calloc_aligned(heap, count, size, alignment);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_calloc_aligned_at(
+ heap: *mut mi_heap_t,
+ count: usize,
+ size: usize,
+ alignment: usize,
+ offset: usize,
+) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_calloc_aligned_at(heap, count, size, alignment, offset);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_realloc_aligned(
+ heap: *mut mi_heap_t,
+ p: *mut libc::c_void,
+ newsize: usize,
+ alignment: usize,
+) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_realloc_aligned(heap, p, newsize, alignment);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_realloc_aligned_at(
+ heap: *mut mi_heap_t,
+ p: *mut libc::c_void,
+ newsize: usize,
+ alignment: usize,
+ offset: usize,
+) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_realloc_aligned_at(heap, p, newsize, alignment, offset);
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_rezalloc(
+ heap: *mut mi_heap_t,
+ p: *mut libc::c_void,
+ newsize: usize,
+) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_rezalloc(heap, p, newsize);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_recalloc(
+ heap: *mut mi_heap_t,
+ p: *mut libc::c_void,
+ newcount: usize,
+ size: usize,
+) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_recalloc(heap, p, newcount, size);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_rezalloc_aligned(
+ heap: *mut mi_heap_t,
+ p: *mut libc::c_void,
+ newsize: usize,
+ alignment: usize,
+) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_rezalloc_aligned(heap, p, newsize, alignment);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_rezalloc_aligned_at(
+ heap: *mut mi_heap_t,
+ p: *mut libc::c_void,
+ newsize: usize,
+ alignment: usize,
+ offset: usize,
+) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_rezalloc_aligned_at(heap, p, newsize, alignment, offset);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_recalloc_aligned(
+ heap: *mut mi_heap_t,
+ p: *mut libc::c_void,
+ newcount: usize,
+ size: usize,
+ alignment: usize,
+) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_recalloc_aligned(heap, p, newcount, size, alignment);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_recalloc_aligned_at(
+ heap: *mut mi_heap_t,
+ p: *mut libc::c_void,
+ newcount: usize,
+ size: usize,
+ alignment: usize,
+ offset: usize,
+) -> *mut libc::c_void {
+ unsafe {
+ return mi_heap_recalloc_aligned_at(heap, p, newcount, size, alignment, offset);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_contains_block(
+ heap: *mut mi_heap_t,
+ p: *const libc::c_void,
+) -> bool {
+ unsafe {
+ return mi_heap_contains_block(heap, p);
+ }
+}
+#[no_mangle]
+pub extern "C" fn spreads_mem_heap_check_owned(
+ heap: *mut mi_heap_t,
+ p: *const libc::c_void,
+) -> bool {
+ unsafe {
+ return mi_heap_check_owned(heap, p);
+ }
+}
+
#[cfg(test)]
mod tests {
+ extern crate alloc;
+
use super::*;
+ use alloc::boxed::Box;
#[test]
fn it_frees_allocated_memory() {
@@ -581,5 +912,35 @@ mod tests {
fn it_could_call_mimalloc() {
let x = spreads_mem_malloc(10);
spreads_mem_free(x);
+ spreads_mem_collect(true);
+ }
+
+ #[test]
+ fn it_could_print_stats() {
+ spreads_mem_stats_print();
+ }
+
+ // A list of C functions that are being imported
+ extern "C" {
+ pub fn printf(format: *const u8, ...) -> i32;
+ }
+
+ #[no_mangle]
+ pub extern "C" fn test_print_out(msg: *const libc::c_char, arg: *mut libc::c_void) {
+ unsafe {
+ printf(msg as *const u8);
+ }
+ }
+
+ #[test]
+ fn it_could_print_out_stats() {
+ // spreads_mem_register_output(Option::Some(test_print_out), 0 as *mut libc::c_void);
+ // spreads_mem_option_set(mi_option_e_mi_option_show_stats, 0);
+ // spreads_mem_option_set_default(mi_option_e_mi_option_show_stats, 0);
+ // spreads_mem_option_set_enabled_default(mi_option_e_mi_option_show_stats, false);
+ spreads_mem_option_disable(mi_option_e_mi_option_show_stats);
+ spreads_mem_option_disable(mi_option_e_mi_option_verbose);
+ // spreads_mem_option_set_enabled(mi_option_e_mi_option_show_stats, false);
+ spreads_mem_stats_print_out(Option::Some(test_print_out), 0 as *mut libc::c_void);
}
}