-
-
Save bawNg/de0610e571cc75b07718e6bd1da9bc37 to your computer and use it in GitHub Desktop.
Initial rough changes to reduce heap allocations
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
LibuvSharp/ByteBufferAllocatorBase.cs | 2 ++ | |
LibuvSharp/Common.cs | 16 ++++++---- | |
LibuvSharp/CopyingByteBufferAllocator.cs | 6 +--- | |
LibuvSharp/Internal/BufferPin.cs | 4 ++- | |
LibuvSharp/Internal/CallbackPermaRequest.cs | 5 ++- | |
LibuvSharp/LibuvSharp.net3.5.csproj | 9 +++++- | |
LibuvSharp/UVStream.cs | 39 +++++++++++++---------- | |
LibuvSharp/UVTimer.cs | 48 +++++++++++++---------------- | |
8 files changed, 73 insertions(+), 56 deletions(-) | |
diff --git a/LibuvSharp/ByteBufferAllocatorBase.cs b/LibuvSharp/ByteBufferAllocatorBase.cs | |
index 47af9b4..64e59d2 100644 | |
--- a/LibuvSharp/ByteBufferAllocatorBase.cs | |
+++ b/LibuvSharp/ByteBufferAllocatorBase.cs | |
@@ -8,6 +8,8 @@ namespace LibuvSharp | |
internal Handle.alloc_callback_unix AllocCallbackUnix { get; set; } | |
internal Handle.alloc_callback_win AllocCallbackWin { get; set; } | |
+ public virtual byte[] Buffer => null; | |
+ | |
public ByteBufferAllocatorBase() | |
{ | |
AllocCallbackUnix = AllocUnix; | |
diff --git a/LibuvSharp/Common.cs b/LibuvSharp/Common.cs | |
index b7ddb14..03b72e0 100644 | |
--- a/LibuvSharp/Common.cs | |
+++ b/LibuvSharp/Common.cs | |
@@ -1,4 +1,5 @@ | |
using System; | |
+using System.Buffers; | |
using System.Net; | |
using System.Runtime.InteropServices; | |
using System.Collections.Generic; | |
@@ -101,17 +102,20 @@ namespace LibuvSharp | |
unsafe internal static IPEndPoint GetIPEndPoint(IntPtr sockaddr, bool map) | |
{ | |
- sockaddr *sa = (sockaddr *)sockaddr; | |
- byte[] addr = new byte[64]; | |
+ sockaddr* sa = (sockaddr*)sockaddr; | |
+ byte[] addr = ArrayPool<byte>.Shared.Rent(64); | |
+ | |
int r; | |
- if (sa->sin_family == 2) { | |
+ if (sa->sin_family == 2) | |
r = uv_ip4_name(sockaddr, addr, (IntPtr)addr.Length); | |
- } else { | |
+ else | |
r = uv_ip6_name(sockaddr, addr, (IntPtr)addr.Length); | |
- } | |
+ | |
Ensure.Success(r); | |
- IPAddress ip = IPAddress.Parse(System.Text.Encoding.ASCII.GetString(addr, 0, strlen(addr))); | |
+ IPAddress ip = new IPAddress(addr); | |
+ | |
+ ArrayPool<byte>.Shared.Return(addr, true); | |
var bytes = ip.GetAddressBytes(); | |
if (map && ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6 && IsMapping(bytes)) { | |
diff --git a/LibuvSharp/CopyingByteBufferAllocator.cs b/LibuvSharp/CopyingByteBufferAllocator.cs | |
index f78896b..d4557da 100644 | |
--- a/LibuvSharp/CopyingByteBufferAllocator.cs | |
+++ b/LibuvSharp/CopyingByteBufferAllocator.cs | |
@@ -7,11 +7,7 @@ namespace LibuvSharp | |
{ | |
BufferPin pin; | |
- public byte[] Buffer { | |
- get { | |
- return pin.Buffer; | |
- } | |
- } | |
+ public override byte[] Buffer => pin.Buffer; | |
public override int Alloc(int size, out IntPtr ptr) | |
{ | |
diff --git a/LibuvSharp/Internal/BufferPin.cs b/LibuvSharp/Internal/BufferPin.cs | |
index 7ac7b62..aa76796 100644 | |
--- a/LibuvSharp/Internal/BufferPin.cs | |
+++ b/LibuvSharp/Internal/BufferPin.cs | |
@@ -1,4 +1,5 @@ | |
using System; | |
+using System.Buffers; | |
using System.Runtime.InteropServices; | |
namespace LibuvSharp | |
@@ -9,7 +10,7 @@ namespace LibuvSharp | |
public GCHandle GCHandle { get; protected set; } | |
public BufferPin(int count) | |
- : this(new byte[count]) | |
+ : this(ArrayPool<byte>.Shared.Rent(count)) | |
{ | |
} | |
@@ -59,6 +60,7 @@ namespace LibuvSharp | |
GCHandle.Free(); | |
} | |
Pointer = IntPtr.Zero; | |
+ ArrayPool<byte>.Shared.Return(Buffer, true); | |
} | |
public IntPtr Pointer { get; protected set; } | |
diff --git a/LibuvSharp/Internal/CallbackPermaRequest.cs b/LibuvSharp/Internal/CallbackPermaRequest.cs | |
index 339b85d..e59bdb9 100644 | |
--- a/LibuvSharp/Internal/CallbackPermaRequest.cs | |
+++ b/LibuvSharp/Internal/CallbackPermaRequest.cs | |
@@ -1,4 +1,5 @@ | |
using System; | |
+using System.Runtime.InteropServices; | |
namespace LibuvSharp | |
{ | |
@@ -14,7 +15,9 @@ namespace LibuvSharp | |
{ | |
} | |
- public Action<int, CallbackPermaRequest> Callback { get; set; } | |
+ public Action<int, CallbackPermaRequest> Callback; | |
+ public GCHandle GcHandle; | |
+ public Action<Exception> WriteCallback; | |
protected void End(IntPtr ptr, int status) | |
{ | |
diff --git a/LibuvSharp/LibuvSharp.net3.5.csproj b/LibuvSharp/LibuvSharp.net3.5.csproj | |
index ac98b59..fa4fc9a 100644 | |
--- a/LibuvSharp/LibuvSharp.net3.5.csproj | |
+++ b/LibuvSharp/LibuvSharp.net3.5.csproj | |
@@ -36,11 +36,14 @@ | |
<Reference Include="System" /> | |
</ItemGroup> | |
<ItemGroup> | |
+ <Compile Include="ArrayPool.cs" /> | |
<Compile Include="AssemblyInfo.cs" /> | |
<Compile Include="AsyncCallback.cs" /> | |
<Compile Include="AsyncWatcher.cs" /> | |
<Compile Include="CallbackHandle.cs" /> | |
<Compile Include="Common.cs" /> | |
+ <Compile Include="DefaultArrayPool.cs" /> | |
+ <Compile Include="DefaultArrayPoolBucket.cs" /> | |
<Compile Include="Handle.cs" /> | |
<Compile Include="HandleBase.cs" /> | |
<Compile Include="IBindable.cs" /> | |
@@ -65,9 +68,13 @@ | |
<Compile Include="ITrySendExtensions.cs" /> | |
<Compile Include="ITryWrite.cs" /> | |
<Compile Include="ITryWriteExtensions.cs" /> | |
+ <Compile Include="Platform.cs" /> | |
+ <Compile Include="PlatformHelper.cs" /> | |
<Compile Include="Prepare.cs" /> | |
<Compile Include="Loop.cs" /> | |
<Compile Include="net35/Tuple.cs" /> | |
+ <Compile Include="Spinlock.cs" /> | |
+ <Compile Include="Spinwait.cs" /> | |
<Compile Include="Udp.cs" /> | |
<Compile Include="Tcp.cs" /> | |
<Compile Include="Exceptions.cs" /> | |
@@ -125,4 +132,4 @@ | |
</ItemGroup> | |
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> | |
<ItemGroup /> | |
-</Project> | |
+</Project> | |
\ No newline at end of file | |
diff --git a/LibuvSharp/UVStream.cs b/LibuvSharp/UVStream.cs | |
index ba36fa6..0b6c995 100644 | |
--- a/LibuvSharp/UVStream.cs | |
+++ b/LibuvSharp/UVStream.cs | |
@@ -58,6 +58,7 @@ namespace LibuvSharp | |
: base(loop, handle) | |
{ | |
stream = (uv_stream_t *)(handle.ToInt64() + Handle.Size(HandleType.UV_HANDLE)); | |
+ writeCallback = WriteCallback; | |
} | |
internal UVStream(Loop loop, int size) | |
@@ -133,7 +134,7 @@ namespace LibuvSharp | |
Close(); | |
} | |
} else { | |
- OnData(ByteBufferAllocator.Retrieve(size.ToInt32())); | |
+ OnData(new ArraySegment<byte>(ByteBufferAllocator.Buffer, 0, (int)nread)); | |
} | |
} | |
@@ -182,35 +183,41 @@ namespace LibuvSharp | |
PendingWrites++; | |
- GCHandle datagchandle = GCHandle.Alloc(data.Array, GCHandleType.Pinned); | |
- CallbackPermaRequest cpr = new CallbackPermaRequest(RequestType.UV_WRITE); | |
- cpr.Callback = (status, cpr2) => { | |
- datagchandle.Free(); | |
- PendingWrites--; | |
+ var datagchandle = GCHandle.Alloc(data.Array, GCHandleType.Pinned); | |
- Ensure.Success(status, callback); | |
- | |
- if (PendingWrites == 0) { | |
- OnDrain(); | |
- } | |
- }; | |
+ var cpr = new CallbackPermaRequest(RequestType.UV_WRITE); //TODO: pool and reuse requests | |
+ cpr.Callback = writeCallback; | |
+ cpr.WriteCallback = callback; | |
+ cpr.GcHandle = datagchandle; | |
var ptr = (IntPtr)(datagchandle.AddrOfPinnedObject().ToInt64() + index); | |
int r; | |
if (UV.isUnix) { | |
- UnixBufferStruct[] buf = new UnixBufferStruct[1]; | |
- buf[0] = new UnixBufferStruct(ptr, count); | |
+ UnixBufferStruct[] buf = { new UnixBufferStruct(ptr, count) }; | |
r = uv_write_unix(cpr.Handle, NativeHandle, buf, 1, CallbackPermaRequest.CallbackDelegate); | |
} else { | |
- WindowsBufferStruct[] buf = new WindowsBufferStruct[1]; | |
- buf[0] = new WindowsBufferStruct(ptr, count); | |
+ WindowsBufferStruct[] buf = { new WindowsBufferStruct(ptr, count) }; | |
r = uv_write_win(cpr.Handle, NativeHandle, buf, 1, CallbackPermaRequest.CallbackDelegate); | |
} | |
Ensure.Success(r); | |
} | |
+ private Action<int, CallbackPermaRequest> writeCallback; | |
+ void WriteCallback(int status, CallbackPermaRequest cpr) | |
+ { | |
+ cpr.GcHandle.Free(); | |
+ var pending_writes = --PendingWrites; | |
+ | |
+ Ensure.Success(status, cpr.WriteCallback); | |
+ | |
+ if (pending_writes == 0) | |
+ { | |
+ OnDrain(); | |
+ } | |
+ } | |
+ | |
public void Shutdown(Action<Exception> callback) | |
{ | |
CheckDisposed(); | |
diff --git a/LibuvSharp/UVTimer.cs b/LibuvSharp/UVTimer.cs | |
index ee7e70a..a17f1e1 100644 | |
--- a/LibuvSharp/UVTimer.cs | |
+++ b/LibuvSharp/UVTimer.cs | |
@@ -25,14 +25,21 @@ namespace LibuvSharp | |
Action onehit; | |
+ Action callback; | |
+ Action<int> callback1; | |
+ | |
+ int iterations; | |
+ int totalIterations; | |
+ | |
public UVTimer() | |
- : this(Loop.Constructor) | |
+ : this(Loop.Constructor, 1) | |
{ | |
} | |
- public UVTimer(Loop loop) | |
+ public UVTimer(Loop loop, int iteration_count) | |
: base(loop, HandleType.UV_TIMER, uv_timer_init) | |
{ | |
+ totalIterations = iteration_count; | |
} | |
public ulong LongRepeat { | |
@@ -87,13 +94,16 @@ namespace LibuvSharp | |
cb(); | |
} | |
- if (Tick != null) { | |
- Tick(); | |
+ if (callback1 != null) { | |
+ var i = ++iterations; | |
+ callback1(i); | |
+ if (i >= totalIterations) Close(); | |
+ } else { | |
+ callback?.Invoke(); | |
+ if (totalIterations > 0) Close(); | |
} | |
} | |
- public event Action Tick; | |
- | |
public void Start(ulong repeat) | |
{ | |
Start(0, repeat); | |
@@ -135,13 +145,8 @@ namespace LibuvSharp | |
public static UVTimer Once(Loop loop, TimeSpan timeout, Action callback) | |
{ | |
- var timer = new UVTimer(loop); | |
- timer.Tick += () => { | |
- if (callback != null) { | |
- callback(); | |
- } | |
- timer.Close(); | |
- }; | |
+ var timer = new UVTimer(loop, 1); | |
+ timer.callback = callback; | |
timer.Start(timeout, TimeSpan.Zero); | |
return timer; | |
} | |
@@ -153,17 +158,8 @@ namespace LibuvSharp | |
public static UVTimer Times(Loop loop, int times, TimeSpan repeat, Action<int> callback) | |
{ | |
- var timer = new UVTimer(loop); | |
- int i = 0; | |
- timer.Tick += () => { | |
- i++; | |
- if (callback != null) { | |
- callback(i); | |
- } | |
- if (i >= times) { | |
- timer.Close(); | |
- } | |
- }; | |
+ var timer = new UVTimer(loop, times); | |
+ timer.callback1 = callback; | |
timer.Start(repeat, repeat); | |
return timer; | |
} | |
@@ -175,8 +171,8 @@ namespace LibuvSharp | |
public static UVTimer Every(Loop loop, TimeSpan repeat, Action callback) | |
{ | |
- var timer = new UVTimer(loop); | |
- timer.Tick += callback; | |
+ var timer = new UVTimer(loop, 0); | |
+ timer.callback = callback; | |
timer.Start(repeat, repeat); | |
return timer; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment