Skip to content

Instantly share code, notes, and snippets.

@bawNg
Last active April 10, 2016 09:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bawNg/de0610e571cc75b07718e6bd1da9bc37 to your computer and use it in GitHub Desktop.
Save bawNg/de0610e571cc75b07718e6bd1da9bc37 to your computer and use it in GitHub Desktop.
Initial rough changes to reduce heap allocations
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