Skip to content

Commit 3c12513

Browse files
committed
Fix long-standing structural issues with benchmarks. Safe and Huge buffers implement IRetainable, IEquatable. Added more docs on usage #7 #6.
1 parent 5d00a69 commit 3c12513

22 files changed

+528
-217
lines changed

README.md

Lines changed: 151 additions & 21 deletions
Large diffs are not rendered by default.

jemalloc.Api/FixedBuffer.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,10 @@ public bool Free()
193193
{
194194
return false;
195195
}
196+
if(IsRetained)
197+
{
198+
return false;
199+
}
196200
IntPtr p = _Ptr;
197201

198202
if (Interlocked.Exchange(ref p, IntPtr.Zero) != IntPtr.Zero)
@@ -300,7 +304,7 @@ public void VectorSqrt()
300304
private unsafe Span<T> AcquireWriteSpan()
301305
{
302306
Acquire();
303-
return new Span<T>((void*)_Ptr, (int)Length);
307+
return new Span<T>((void*)_Ptr, _Length);
304308
}
305309

306310
public unsafe Span<Vector<T>> AcquireVectorWriteSpan()
@@ -310,7 +314,7 @@ public unsafe Span<Vector<T>> AcquireVectorWriteSpan()
310314
}
311315

312316
[MethodImpl(MethodImplOptions.AggressiveInlining)]
313-
private unsafe ref T Read(int index)
317+
internal unsafe ref T Read(int index)
314318
{
315319
Retain();
316320
// return (T*) (_ptr + byteOffset);
@@ -320,7 +324,7 @@ private unsafe ref T Read(int index)
320324
}
321325

322326

323-
private unsafe ref T Write(int index, ref T value)
327+
internal unsafe ref T Write(int index, ref T value)
324328
{
325329
Retain();
326330
ref T v = ref Unsafe.Add(ref Unsafe.AsRef<T>(_Ptr.ToPointer()), index);

jemalloc.Api/FixedUtf8String.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,8 @@ public FixedUtf8String Substring(int index, int length)
247247

248248
public int IndexOf(uint codePoint) => Span.IndexOf(codePoint);
249249

250+
public int IndexOf(string s) => Span.IndexOf(new Utf8Span(Encoding.UTF8.GetBytes(s)));
251+
250252
public int LastIndexOf(FixedUtf8String value) => Span.LastIndexOf(value.Span);
251253

252254
public int LastIndexOf(uint codePoint) => Span.LastIndexOf(codePoint);

jemalloc.Api/HugeBuffer.cs

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Buffers;
23
using System.Collections;
34
using System.Collections.Generic;
45
using System.Diagnostics;
@@ -12,7 +13,7 @@
1213

1314
namespace jemalloc
1415
{
15-
public abstract class HugeBuffer<T> : SafeHandle, IEnumerable<T> where T : struct
16+
public abstract class HugeBuffer<T> : SafeHandle, IRetainable, IDisposable, IEquatable<HugeBuffer<T>>, IEnumerable<T> where T : struct, IEquatable<T>
1617
{
1718
#region Constructors
1819
protected HugeBuffer(ulong length, params T[] values) : base(IntPtr.Zero, true)
@@ -45,6 +46,32 @@ protected override bool ReleaseHandle()
4546
public override bool IsInvalid => handle == IntPtr.Zero;
4647
#endregion
4748

49+
#region Implemented members
50+
51+
public void Retain() => Acquire();
52+
53+
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
54+
public bool Release()
55+
{
56+
57+
if (IsNotAllocated || IsInvalid || RefCount == 0)
58+
{
59+
return false;
60+
}
61+
else
62+
{
63+
Jem.DecrementRefCount(handle);
64+
DangerousRelease();
65+
return true;
66+
}
67+
}
68+
69+
public bool Equals(HugeBuffer<T> other)
70+
{
71+
return this.handle == other.handle && this.Length == other.Length;
72+
}
73+
#endregion
74+
4875
#region Properties
4976
public ulong Length { get; protected set; }
5077

@@ -56,6 +83,17 @@ protected override bool ReleaseHandle()
5683

5784
public bool IsValid => !IsInvalid;
5885

86+
public int RefCount
87+
{
88+
get
89+
{
90+
ThrowIfNotAllocatedOrInvalid();
91+
return Jem.GetRefCount(handle);
92+
}
93+
}
94+
95+
public bool IsRetained => RefCount > 0;
96+
5997
public bool IsVectorizable { get; protected set; }
6098

6199
#endregion
@@ -75,15 +113,6 @@ public bool Acquire()
75113
return success;
76114
}
77115

78-
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
79-
public void Release()
80-
{
81-
if (IsNotAllocated || IsInvalid)
82-
return;
83-
DangerousRelease();
84-
Jem.DecrementRefCount(handle);
85-
}
86-
87116
protected unsafe ref T DangerousAsRef(ulong index)
88117
{
89118
ThrowIfNotAllocatedOrInvalid();
@@ -225,7 +254,10 @@ public unsafe void VectorMultiply(T value)
225254
Span<T> sFil = new Span<T>(fill);
226255
sFil.Fill(value);
227256
Vector<T> fillVector = sFil.NonPortableCast<T, Vector<T>>()[0];
228-
segmentVectorSpan[0] = Vector.Multiply(segmentVectorSpan[0], fillVector);
257+
for (int i = 0; i < segmentVectorSpan.Length; i++)
258+
{
259+
segmentVectorSpan[i] = Vector.Multiply(segmentVectorSpan[i], fillVector);
260+
}
229261
}
230262
Release();
231263
}

jemalloc.Api/JemApi.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -544,9 +544,11 @@ internal static string GetCallerDetails(CallerInformation c)
544544
#endregion
545545

546546
#region jemalloc Statistics
547-
public static UInt64 AllocatedPages => GetMallCtlUInt64("stats.allocated");
548-
public static UInt64 ActivePages => GetMallCtlUInt64("stats.active");
547+
public static UInt64 AllocatedBytes => GetMallCtlUInt64("stats.allocated");
548+
public static UInt64 ActiveBytes => GetMallCtlUInt64("stats.active");
549549
public static UInt64 MappedBytes => GetMallCtlUInt64("stats.mapped");
550+
public static UInt64 ResidentBytes => GetMallCtlUInt64("stats.resident");
551+
550552
#endregion
551553

552554
#region Allocations ledgers

jemalloc.Api/MemoryRef.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Buffers;
4+
using System.Text;
5+
6+
namespace jemalloc
7+
{
8+
public readonly ref struct MemoryRef<T> where T : struct
9+
{
10+
internal MemoryRef(Guid guid, MemoryHandle h)
11+
{
12+
Id = guid;
13+
Handle = h;
14+
}
15+
private readonly Guid Id;
16+
private readonly MemoryHandle Handle;
17+
public bool Release()
18+
{
19+
return false;
20+
}
21+
}
22+
}

jemalloc.Api/SafeBuffer.cs

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Buffers;
23
using System.Collections;
34
using System.Collections.Generic;
45
using System.Diagnostics;
@@ -12,7 +13,7 @@
1213

1314
namespace jemalloc
1415
{
15-
public abstract class SafeBuffer<T> : SafeHandle, IEnumerable<T> where T : struct, IEquatable<T>
16+
public abstract class SafeBuffer<T> : SafeHandle, IRetainable, IDisposable, IEquatable<SafeBuffer<T>>, IEnumerable<T> where T : struct, IEquatable<T>
1617
{
1718
#region Constructors
1819
protected SafeBuffer(int length, params T[] values) : base(IntPtr.Zero, true)
@@ -45,6 +46,31 @@ protected override bool ReleaseHandle()
4546
public override bool IsInvalid => handle == IntPtr.Zero;
4647
#endregion
4748

49+
#region Implemented members
50+
public void Retain() => Acquire();
51+
52+
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
53+
public bool Release()
54+
{
55+
56+
if (IsNotAllocated || IsInvalid || RefCount == 0)
57+
{
58+
return false;
59+
}
60+
else
61+
{
62+
Jem.DecrementRefCount(handle);
63+
DangerousRelease();
64+
return true;
65+
}
66+
}
67+
68+
public bool Equals(SafeBuffer<T> other)
69+
{
70+
return this.handle == other.handle && this.Length == other.Length;
71+
}
72+
#endregion
73+
4874
#region Properties
4975
public int Length { get; protected set; }
5076

@@ -56,6 +82,17 @@ protected override bool ReleaseHandle()
5682

5783
public bool IsValid => !IsInvalid;
5884

85+
public int RefCount
86+
{
87+
get
88+
{
89+
ThrowIfNotAllocatedOrInvalid();
90+
return Jem.GetRefCount(handle);
91+
}
92+
}
93+
94+
public bool IsRetained => RefCount > 0;
95+
5996
public bool IsVectorizable { get; protected set; }
6097
#endregion
6198

@@ -74,15 +111,6 @@ public bool Acquire()
74111
return success;
75112
}
76113

77-
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
78-
public void Release()
79-
{
80-
if (IsNotAllocated || IsInvalid)
81-
return;
82-
Jem.DecrementRefCount(handle);
83-
DangerousRelease();
84-
}
85-
86114
protected unsafe ref T DangerousAsRef(int index)
87115
{
88116
ThrowIfNotAllocatedOrInvalid();

jemalloc.Api/jemalloc.Api.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<RootNamespace>jemalloc</RootNamespace>
77
<LangVersion>latest</LangVersion>
88
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
9-
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
9+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
1010
<PackageId>jemalloc.NET</PackageId>
1111
<Version>0.2.0-alpha</Version>
1212
<Authors>Allister Beharry</Authors>

jemalloc.Benchmarks/BenchmarkStatisticColumn.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,11 @@ public bool IsAvailable(Summary summary)
9393
public override string ToString() => ColumnName;
9494
#endregion
9595

96-
#region Fields
97-
98-
#endregion
99-
10096
#region Available columns
101-
public static readonly IColumn PrivateMemory = new BenchmarkStatisticColumn("PrivateMemory", "Private memory allocated (native and managed, inclusive, 1KB = 1024B)");
102-
97+
public static readonly IColumn PrivateMemory = new BenchmarkStatisticColumn("PrivateMemory", "Total memory allocated for process(native and managed, 1KB = 1024B)");
98+
public static readonly IColumn WorkingSet = new BenchmarkStatisticColumn("WorkingSet", "Memory that is currently being used by process(native and managed, 1KB = 1024B)");
99+
public static readonly IColumn JemAllocated = new BenchmarkStatisticColumn("JemAllocated", "Total memory allocated by jemalloc(native only, inclusive, 1KB = 1024B)");
100+
public static readonly IColumn JemResident = new BenchmarkStatisticColumn("JemResident", "Resident memory allocated by jemalloc(native only, inclusive, 1KB = 1024B)");
103101
#endregion
104102
}
105103
}

jemalloc.Benchmarks/Benchmarks/FixedBufferVsManagedArray.cs

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,39 @@ namespace jemalloc.Benchmarks
1212
public class FixedBufferVsManagedArrayBenchmark<T> : JemBenchmark<T, int> where T : struct, IEquatable<T>, IComparable<T>, IConvertible
1313
{
1414
public int ArraySize => Parameter;
15+
public readonly T fill = typeof(T) == typeof(TestUDT) ?
16+
JemUtil.ValToGenericStruct<TestUDT, T>(TestUDT.MakeTestRecord(JemUtil.Rng)) : GM<T>.Random();
17+
public readonly (T factor, T max) mul = GM<T>.RandomMultiplyFactorAndValue();
1518

1619
[GlobalSetup]
1720
public override void GlobalSetup()
1821
{
22+
DebugInfoThis();
1923
base.GlobalSetup();
2024
Info($"Array size is {ArraySize}.");
21-
}
22-
23-
24-
#region Fill
25-
[GlobalSetup(Target = nameof(FillManagedArray))]
26-
public void FillSetup()
27-
{
28-
InfoThis();
29-
T fill = GM<T>.Random();
30-
Info($"Array fill value is {fill}.");
31-
SetValue("fill", fill);
32-
SetValue("managedArray", new T[ArraySize]);
25+
T[] managedArray = new T[ArraySize];
26+
SetValue("managedArray", managedArray);
3327
FixedBuffer<T> nativeArray = new FixedBuffer<T>(ArraySize);
3428
nativeArray.Acquire();
3529
SetValue("nativeArray", nativeArray);
30+
if (Operation == Operation.FILL)
31+
{
32+
Info($"Array fill value is {fill}.");
33+
SetValue("fill", fill);
34+
}
35+
else if (Operation == Operation.MATH)
36+
{
37+
Info($"Array fill value is {mul.max}.");
38+
nativeArray.Fill(mul.max);
39+
new Span<T>(managedArray).Fill(mul.max);
40+
SetValue("fill", mul.max);
41+
Info($"Array multiply factor is {mul.factor}.");
42+
SetValue("mul", mul.factor);
43+
}
3644
}
3745

46+
47+
#region Fill
3848
[Benchmark(Description = "Fill a managed array with a single value.")]
3949
[BenchmarkCategory("Fill")]
4050
public void FillManagedArray()
@@ -80,7 +90,7 @@ public void FillFixedBufferWithCreate()
8090
}
8191

8292
[GlobalCleanup(Target = nameof(FillFixedBufferWithCreate))]
83-
public void ValidateAndCleanupFillArray()
93+
public void FillValidateAndCleanup()
8494
{
8595
InfoThis();
8696
T[] managedArray = GetValue<T[]>("managedArray");
@@ -105,27 +115,6 @@ public void ValidateAndCleanupFillArray()
105115
#endregion
106116

107117
#region Arithmetic
108-
[GlobalSetup(Target = nameof(ArithmeticMutiplyManagedArray))]
109-
public void ArithmeticMutiplyGlobalSetup()
110-
{
111-
InfoThis();
112-
(T mul, T fill) = GM<T>.RandomMultiplyFactorAndValue();
113-
FixedBuffer<T> na = new FixedBuffer<T>(ArraySize);
114-
T[] ma = new T[ArraySize];
115-
Info($"Array fill value is {fill}.");
116-
Info($"Array mul value is {mul}.");
117-
na.Fill(fill);
118-
for (int i = 0; i < ma.Length; i++)
119-
{
120-
ma[i] = fill;
121-
}
122-
na.Acquire();
123-
SetValue("fill", fill);
124-
SetValue("mul", mul);
125-
SetValue("managedArray", ma);
126-
SetValue("nativeArray", na);
127-
}
128-
129118
[Benchmark(Description = "Multiply all values of a managed array with a single value.")]
130119
[BenchmarkCategory("Arithmetic")]
131120
public void ArithmeticMutiplyManagedArray()
@@ -145,6 +134,7 @@ public void ArithmeticMutiplyManagedArray()
145134
[BenchmarkCategory("Arithmetic")]
146135
public void ArithmeticMultiplyNativeArray()
147136
{
137+
DebugInfoThis();
148138
T mul = GetValue<T>("mul");
149139
T fill = GetValue<T>("fill");
150140
FixedBuffer<T> array = GetValue<FixedBuffer<T>>("nativeArray");

0 commit comments

Comments
 (0)