Skip to content

Commit af73e3c

Browse files
authored
Merge pull request #366 from SciSharp/perf-ops
Performance optimization, refactoring and revamping.
2 parents d8df2e9 + 854c2e5 commit af73e3c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1044
-722
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
using System.Runtime.CompilerServices;
2+
#if DEBUG
3+
[assembly: InternalsVisibleTo("TensorFlowNET.UnitTest, PublicKey=00240000048000009400000006020000002400005253413100040000010001004b86c4cb78549b34bab61a3b1800e23bfeb5b3ec390074041536a7e3cbd97f5f04cf0f857155a8928eaa29ebfd11cfbbad3ba70efea7bda3226c6a8d370a4cd303f714486b6ebc225985a638471e6ef571cc92a4613c00b8fa65d61ccee0cbe5f36330c9a01f4183559f1bef24cc2917c6d913e3a541333a1d05d9bed22b38cb")]
4+
#endif

src/TensorFlowNET.Core/Binding.Util.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,13 +178,18 @@ public static float time()
178178

179179
public static IEnumerable<(TKey, TValue)> enumerate<TKey, TValue>(KeyValuePair<TKey, TValue>[] values)
180180
{
181-
foreach (var item in values)
181+
var len = values.Length;
182+
for (var i = 0; i < len; i++)
183+
{
184+
var item = values[i];
182185
yield return (item.Key, item.Value);
186+
}
183187
}
184188

185189
public static IEnumerable<(int, T)> enumerate<T>(IList<T> values)
186190
{
187-
for (int i = 0; i < values.Count; i++)
191+
var len = values.Count;
192+
for (int i = 0; i < len; i++)
188193
yield return (i, values[i]);
189194
}
190195

src/TensorFlowNET.Core/Buffers/Buffer.cs

Lines changed: 80 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,58 +15,116 @@ limitations under the License.
1515
******************************************************************************/
1616

1717
using System;
18+
using System.Runtime.CompilerServices;
1819
using System.Runtime.InteropServices;
20+
using NumSharp.Backends.Unmanaged;
21+
using static Tensorflow.c_api;
1922

2023
namespace Tensorflow
2124
{
25+
/// <summary>
26+
/// Represents a TF_Buffer that can be passed to Tensorflow.
27+
/// </summary>
2228
public class Buffer : DisposableObject
2329
{
24-
private TF_Buffer buffer => Marshal.PtrToStructure<TF_Buffer>(_handle);
30+
private unsafe TF_Buffer buffer
31+
{
32+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
33+
get => *bufferptr;
34+
}
35+
36+
private unsafe TF_Buffer* bufferptr
37+
{
38+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
39+
get => (TF_Buffer*) _handle;
40+
}
2541

26-
public byte[] Data
42+
/// <summary>
43+
/// The memory block representing this buffer.
44+
/// </summary>
45+
/// <remarks>The deallocator is set to null.</remarks>
46+
public UnmanagedMemoryBlock<byte> MemoryBlock
2747
{
28-
get
48+
get
2949
{
30-
var data = new byte[buffer.length];
31-
if (data.Length > 0)
32-
Marshal.Copy(buffer.data, data, 0, data.Length);
33-
return data;
50+
unsafe
51+
{
52+
EnsureNotDisposed();
53+
var buff = (TF_Buffer*) _handle;
54+
return new UnmanagedMemoryBlock<byte>((byte*) buff->data.ToPointer(), (long) buff->length);
55+
}
3456
}
3557
}
3658

37-
public int Length => (int)buffer.length;
38-
39-
public Buffer()
59+
/// <summary>
60+
/// The bytes length of this buffer.
61+
/// </summary>
62+
public ulong Length
4063
{
41-
_handle = c_api.TF_NewBuffer();
64+
get
65+
{
66+
EnsureNotDisposed();
67+
return buffer.length;
68+
}
4269
}
4370

44-
public Buffer(IntPtr handle)
71+
public Buffer() => _handle = TF_NewBuffer();
72+
73+
internal Buffer(IntPtr handle)
4574
{
75+
if (handle == IntPtr.Zero)
76+
throw new ArgumentException("Handle (IntPtr) can't be zero.", nameof(handle));
77+
4678
_handle = handle;
4779
}
4880

49-
public Buffer(byte[] data)
50-
{
51-
var dst = Marshal.AllocHGlobal(data.Length);
52-
Marshal.Copy(data, 0, dst, data.Length);
81+
public Buffer(byte[] data) : this(_toBuffer(data))
82+
{ }
5383

54-
_handle = c_api.TF_NewBufferFromString(dst, (ulong)data.Length);
84+
private static IntPtr _toBuffer(byte[] data)
85+
{
86+
if (data == null)
87+
throw new ArgumentNullException(nameof(data));
5588

56-
Marshal.FreeHGlobal(dst);
89+
unsafe
90+
{
91+
fixed (byte* src = data)
92+
return TF_NewBufferFromString(new IntPtr(src), (ulong) data.LongLength);
93+
}
5794
}
5895

5996
public static implicit operator IntPtr(Buffer buffer)
6097
{
98+
buffer.EnsureNotDisposed();
6199
return buffer._handle;
62100
}
63101

64-
public static implicit operator byte[](Buffer buffer)
102+
public static explicit operator byte[](Buffer buffer) => buffer.ToArray(); //has to be explicit, developer will assume it doesn't cost.
103+
104+
/// <summary>
105+
/// Copies this buffer's contents onto a <see cref="byte"/> array.
106+
/// </summary>
107+
public byte[] ToArray()
65108
{
66-
return buffer.Data;
109+
EnsureNotDisposed();
110+
111+
unsafe
112+
{
113+
var len = buffer.length;
114+
if (len == 0)
115+
return Array.Empty<byte>();
116+
117+
byte[] data = new byte[len];
118+
fixed (byte* dst = data)
119+
System.Buffer.MemoryCopy((void*) bufferptr->data, dst, len, len);
120+
121+
return data;
122+
}
67123
}
68124

69125
protected override void DisposeUnmanagedResources(IntPtr handle)
70-
=> c_api.TF_DeleteBuffer(handle);
126+
{
127+
TF_DeleteBuffer(handle);
128+
}
71129
}
72-
}
130+
}

src/TensorFlowNET.Core/DisposableObject.cs

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ limitations under the License.
1616

1717
using System;
1818
using System.Collections.Generic;
19+
using System.Diagnostics.CodeAnalysis;
20+
using System.Runtime.CompilerServices;
1921
using System.Text;
2022

2123
namespace Tensorflow
@@ -26,27 +28,33 @@ namespace Tensorflow
2628
public abstract class DisposableObject : IDisposable
2729
{
2830
protected IntPtr _handle;
31+
protected bool _disposed;
2932

30-
protected DisposableObject() { }
33+
[SuppressMessage("ReSharper", "UnusedMember.Global")]
34+
protected DisposableObject()
35+
{ }
3136

32-
protected DisposableObject(IntPtr handle)
37+
protected DisposableObject(IntPtr handle)
3338
=> _handle = handle;
3439

40+
[SuppressMessage("ReSharper", "InvertIf")]
3541
private void internal_dispose(bool disposing)
3642
{
37-
if (disposing)
38-
{
39-
// free unmanaged resources (unmanaged objects) and override a finalizer below.
40-
if (_handle != IntPtr.Zero)
41-
{
42-
// dispose managed state (managed objects).
43-
DisposeManagedResources();
43+
if (_disposed)
44+
return;
45+
46+
_disposed = true;
4447

45-
// set large fields to null.
46-
DisposeUnmanagedResources(_handle);
48+
//first handle managed, they might use the unmanaged resources.
49+
if (disposing)
50+
// dispose managed state (managed objects).
51+
DisposeManagedResources();
4752

48-
_handle = IntPtr.Zero;
49-
}
53+
//free unmanaged memory
54+
if (_handle != IntPtr.Zero)
55+
{
56+
DisposeUnmanagedResources(_handle);
57+
_handle = IntPtr.Zero;
5058
}
5159
}
5260

@@ -55,28 +63,33 @@ private void internal_dispose(bool disposing)
5563
/// </summary>
5664
/// <remarks>Equivalent to what you would perform inside <see cref="Dispose()"/></remarks>
5765
protected virtual void DisposeManagedResources()
58-
{
59-
}
66+
{ }
6067

6168
/// <summary>
6269
/// Dispose any unmanaged resources related to given <paramref name="handle"/>.
6370
/// </summary>
6471
protected abstract void DisposeUnmanagedResources(IntPtr handle);
6572

66-
// override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
6773
~DisposableObject()
6874
{
69-
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
7075
internal_dispose(false);
7176
}
7277

73-
// This code added to correctly implement the disposable pattern.
7478
public void Dispose()
7579
{
76-
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
7780
internal_dispose(true);
78-
// uncomment the following line if the finalizer is overridden above.
7981
GC.SuppressFinalize(this);
8082
}
83+
84+
/// <summary>
85+
/// If <see cref="_handle"/> is <see cref="IntPtr.Zero"/> then throws <see cref="ObjectDisposedException"/>
86+
/// </summary>
87+
/// <exception cref="ObjectDisposedException">When <see cref="_handle"/> is <see cref="IntPtr.Zero"/></exception>
88+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
89+
protected void EnsureNotDisposed()
90+
{
91+
if (_disposed)
92+
throw new ObjectDisposedException($"Unable to access disposed object, Type: {GetType().Name}");
93+
}
8194
}
8295
}

src/TensorFlowNET.Core/Eager/Context.cs

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@
22

33
namespace Tensorflow.Eager
44
{
5-
public class Context : IDisposable
5+
public class Context : DisposableObject
66
{
7-
private IntPtr _handle;
8-
9-
public static int GRAPH_MODE = 0;
10-
public static int EAGER_MODE = 1;
7+
public const int GRAPH_MODE = 0;
8+
public const int EAGER_MODE = 1;
119

1210
public int default_execution_mode;
1311

@@ -17,19 +15,16 @@ public Context(ContextOptions opts, Status status)
1715
status.Check(true);
1816
}
1917

20-
public void Dispose()
21-
{
22-
c_api.TFE_DeleteContext(_handle);
23-
}
18+
/// <summary>
19+
/// Dispose any unmanaged resources related to given <paramref name="handle"/>.
20+
/// </summary>
21+
protected sealed override void DisposeUnmanagedResources(IntPtr handle)
22+
=> c_api.TFE_DeleteContext(_handle);
2423

25-
public bool executing_eagerly()
26-
{
27-
return false;
28-
}
2924

30-
public static implicit operator IntPtr(Context ctx)
31-
{
32-
return ctx._handle;
33-
}
25+
public bool executing_eagerly() => false;
26+
27+
public static implicit operator IntPtr(Context ctx)
28+
=> ctx._handle;
3429
}
3530
}

src/TensorFlowNET.Core/Eager/ContextOptions.cs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,20 @@
33

44
namespace Tensorflow.Eager
55
{
6-
public class ContextOptions : IDisposable //TODO! Eli: Shouldn't this inherieting DisposableObject?
6+
public class ContextOptions : DisposableObject
77
{
8-
private IntPtr _handle;
8+
public ContextOptions() : base(c_api.TFE_NewContextOptions())
9+
{ }
910

10-
public ContextOptions()
11-
{
12-
_handle = c_api.TFE_NewContextOptions();
13-
}
11+
/// <summary>
12+
/// Dispose any unmanaged resources related to given <paramref name="handle"/>.
13+
/// </summary>
14+
protected sealed override void DisposeUnmanagedResources(IntPtr handle)
15+
=> c_api.TFE_DeleteContextOptions(_handle);
1416

15-
public void Dispose()
16-
{
17-
c_api.TFE_DeleteContextOptions(_handle);
18-
}
1917

20-
public static implicit operator IntPtr(ContextOptions opts)
21-
{
22-
return opts._handle;
23-
}
18+
public static implicit operator IntPtr(ContextOptions opts)
19+
=> opts._handle;
2420
}
21+
2522
}

src/TensorFlowNET.Core/Exceptions/KeyError.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Tensorflow
44
{
5-
public class KeyError : Exception
5+
public class KeyError : TensorflowException
66
{
77
public KeyError() : base()
88
{

src/TensorFlowNET.Core/Exceptions/RuntimeError.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Tensorflow
44
{
5-
public class RuntimeError : Exception
5+
public class RuntimeError : TensorflowException
66
{
77
public RuntimeError() : base()
88
{
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System;
2+
using System.Runtime.Serialization;
3+
4+
namespace Tensorflow
5+
{
6+
7+
/// <summary>
8+
/// Serves as a base class to all exceptions of Tensorflow.NET.
9+
/// </summary>
10+
[Serializable]
11+
public class TensorflowException : Exception
12+
{
13+
/// <summary>Initializes a new instance of the <see cref="T:System.Exception"></see> class.</summary>
14+
public TensorflowException()
15+
{ }
16+
17+
/// <summary>Initializes a new instance of the <see cref="T:System.Exception"></see> class with serialized data.</summary>
18+
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"></see> that holds the serialized object data about the exception being thrown.</param>
19+
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext"></see> that contains contextual information about the source or destination.</param>
20+
/// <exception cref="T:System.ArgumentNullException">The <paramref name="info">info</paramref> parameter is null.</exception>
21+
/// <exception cref="T:System.Runtime.Serialization.SerializationException">The class name is null or <see cref="P:System.Exception.HResult"></see> is zero (0).</exception>
22+
protected TensorflowException(SerializationInfo info, StreamingContext context) : base(info, context)
23+
{ }
24+
25+
/// <summary>Initializes a new instance of the <see cref="T:System.Exception"></see> class with a specified error message.</summary>
26+
/// <param name="message">The message that describes the error.</param>
27+
public TensorflowException(string message) : base(message)
28+
{ }
29+
30+
/// <summary>Initializes a new instance of the <see cref="T:System.Exception"></see> class with a specified error message and a reference to the inner exception that is the cause of this exception.</summary>
31+
/// <param name="message">The error message that explains the reason for the exception.</param>
32+
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param>
33+
public TensorflowException(string message, Exception innerException) : base(message, innerException)
34+
{ }
35+
}
36+
}

0 commit comments

Comments
 (0)