Skip to content

Commit ceaa09c

Browse files
committed
Remove AllocationReferenceHolder.
1 parent c3dd96b commit ceaa09c

17 files changed

+208
-142
lines changed

src/TensorFlowNET.Console/MemoryMonitor.cs

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
using System;
22
using System.Diagnostics;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using NumSharp;
36
using static Tensorflow.Binding;
47

58
namespace Tensorflow
@@ -9,26 +12,35 @@ public class MemoryMonitor
912
public void WarmUp()
1013
{
1114
print($"tensorflow native version: v{tf.VERSION}");
15+
var a = tf.constant(np.ones(10, 10));
16+
var b = tf.Variable(a);
17+
var c = tf.Variable(b);
18+
var d = b * c;
19+
print(d.numpy());
20+
21+
GC.WaitForPendingFinalizers();
22+
GC.Collect();
23+
Thread.Sleep(1000);
1224
}
1325

1426
public void Execute(int epoch, int iterate, Action<int> process)
1527
{
16-
/*GC.Collect();
17-
GC.WaitForPendingFinalizers();
18-
GC.Collect();*/
19-
2028
print($"{process.Method.Name} started...");
21-
for (int i = 0; i < epoch; i++)
29+
30+
// new thread to run
31+
Task.Run(() =>
2232
{
23-
var initialMemory = Process.GetCurrentProcess().PrivateMemorySize64;// GC.GetTotalMemory(true);
24-
process(iterate);
25-
var finalMemory = Process.GetCurrentProcess().PrivateMemorySize64; //GC.GetTotalMemory(true);
26-
print($"Epoch {i}: {Format(finalMemory - initialMemory)}.");
27-
}
33+
for (int i = 0; i < epoch; i++)
34+
{
35+
var initialMemory = Process.GetCurrentProcess().PrivateMemorySize64;// GC.GetTotalMemory(true);
36+
process(iterate);
37+
var finalMemory = Process.GetCurrentProcess().PrivateMemorySize64; //GC.GetTotalMemory(true);
38+
print($"Epoch {i}: {Format(finalMemory - initialMemory)}.");
2839

29-
GC.Collect();
30-
GC.WaitForPendingFinalizers();
31-
GC.Collect();
40+
GC.Collect();
41+
GC.WaitForPendingFinalizers();
42+
}
43+
}).Wait();
3244

3345
print($"Total {process.Method.Name} usage {Format(Process.GetCurrentProcess().PrivateMemorySize64)}");
3446
}

src/TensorFlowNET.Console/MemoryTestingCases.cs

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,7 @@ public Action<int> Constant
2121
public Action<int> Constant2x3
2222
=> (iterate) =>
2323
{
24-
var nd = np.array(new byte[,]
25-
{
26-
{1, 2, 3},
27-
{4, 5, 6}
28-
});
24+
var nd = np.arange(1000).reshape(10, 100);
2925
for (int i = 0; i < iterate; i++)
3026
{
3127
var tensor = tf.constant(nd);
@@ -38,7 +34,8 @@ public Action<int> Variable
3834
{
3935
for (int i = 0; i < iterate; i++)
4036
{
41-
var tensor = tf.Variable(3112.0f);
37+
var nd = np.arange(128 * 128 * 3).reshape(128, 128, 3);
38+
var variable = tf.Variable(nd);
4239
}
4340
};
4441

@@ -66,5 +63,51 @@ public Action<int> Gradient
6663
var grad = tape.gradient(loss, w);
6764
}
6865
};
66+
67+
public Action<int> Conv2dWithVariable
68+
=> (iterate) =>
69+
{
70+
for (int i = 0; i < iterate; i++)
71+
{
72+
var input = array_ops.zeros((10, 32, 32, 3), dtypes.float32);
73+
var filter = tf.Variable(array_ops.zeros((3, 3, 3, 32), dtypes.float32));
74+
var strides = new[] { 1, 1, 1, 1 };
75+
var dilations = new[] { 1, 1, 1, 1 };
76+
77+
var results = tf.Runner.TFE_FastPathExecute(tf.Context, tf.Context.DeviceName,
78+
"Conv2D", null,
79+
null,
80+
input, filter,
81+
"strides", strides,
82+
"use_cudnn_on_gpu", true,
83+
"padding", "VALID",
84+
"explicit_paddings", new int[0],
85+
"data_format", "NHWC",
86+
"dilations", dilations);
87+
}
88+
};
89+
90+
public Action<int> Conv2dWithTensor
91+
=> (iterate) =>
92+
{
93+
for (int i = 0; i < iterate; i++)
94+
{
95+
var input = array_ops.zeros((10, 32, 32, 3), dtypes.float32);
96+
var filter = array_ops.zeros((3, 3, 3, 32), dtypes.float32);
97+
var strides = new[] { 1, 1, 1, 1 };
98+
var dilations = new[] { 1, 1, 1, 1 };
99+
100+
var results = tf.Runner.TFE_FastPathExecute(tf.Context, tf.Context.DeviceName,
101+
"Conv2D", null,
102+
null,
103+
input, filter,
104+
"strides", strides,
105+
"use_cudnn_on_gpu", true,
106+
"padding", "VALID",
107+
"explicit_paddings", new int[0],
108+
"data_format", "NHWC",
109+
"dilations", dilations);
110+
}
111+
};
69112
}
70113
}

src/TensorFlowNET.Console/Program.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,26 @@ static void Main(string[] args)
1212

1313
// boot .net core 10.5M.
1414
var mm = new MemoryMonitor();
15-
// warm up tensorflow.net 28.5M.
15+
// warm up tensorflow.net 37.3M.
1616
mm.WarmUp();
1717
var cases = new MemoryTestingCases();
1818

1919
int batchSize = 1000;
2020

21+
// 1 million tensor
22+
mm.Execute(10, 100 * batchSize, cases.Constant);
23+
2124
// explaination of constant
2225
mm.Execute(10, 100 * batchSize, cases.Constant2x3);
2326

24-
// 1 million float tensor 68M.
25-
mm.Execute(10, 100 * batchSize, cases.Constant);
27+
// +0M
28+
mm.Execute(10, batchSize, cases.Conv2dWithTensor);
2629

2730
// 100K float variable 84M.
28-
mm.Execute(10, 10 * batchSize, cases.Variable);
31+
mm.Execute(10, batchSize, cases.Variable);
32+
33+
// +45M memory leak
34+
mm.Execute(10, batchSize, cases.Conv2dWithVariable);
2935

3036
// 1 million math add 39M.
3137
mm.Execute(10, 100 * batchSize, cases.MathAdd);

src/TensorFlowNET.Console/Tensorflow.Console.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
<Platforms>AnyCPU;x64</Platforms>
99
</PropertyGroup>
1010

11+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
12+
<DefineConstants>TRACE;DEBUG</DefineConstants>
13+
</PropertyGroup>
14+
1115
<ItemGroup>
1216
<PackageReference Include="SciSharp.TensorFlow.Redist" Version="2.3.1" />
1317
</ItemGroup>

src/TensorFlowNET.Core/DisposableObject.cs

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ namespace Tensorflow
2222
{
2323
/// <summary>
2424
/// Abstract class for disposable object allocated in unmanaged runtime.
25+
/// https://docs.microsoft.com/en-us/dotnet/api/system.idisposable.dispose?redirectedfrom=MSDN&view=net-5.0#System_IDisposable_Dispose
2526
/// </summary>
2627
public abstract class DisposableObject : IDisposable
2728
{
@@ -36,24 +37,31 @@ protected DisposableObject(IntPtr handle)
3637
=> _handle = handle;
3738

3839
[SuppressMessage("ReSharper", "InvertIf")]
39-
private void internal_dispose(bool disposing)
40+
private void Dispose(bool disposing)
4041
{
4142
if (_disposed)
4243
return;
4344

44-
_disposed = true;
45-
4645
//first handle managed, they might use the unmanaged resources.
4746
if (disposing)
47+
{
4848
// dispose managed state (managed objects).
4949
DisposeManagedResources();
50+
}
5051

51-
//free unmanaged memory
52+
// free unmanaged memory
5253
if (_handle != IntPtr.Zero)
5354
{
55+
// Call the appropriate methods to clean up
56+
// unmanaged resources here.
57+
// If disposing is false,
58+
// only the following code is executed.
5459
DisposeUnmanagedResources(_handle);
5560
_handle = IntPtr.Zero;
5661
}
62+
63+
// Note disposing has been done.
64+
_disposed = true;
5765
}
5866

5967
/// <summary>
@@ -68,29 +76,20 @@ protected virtual void DisposeManagedResources()
6876
/// </summary>
6977
protected abstract void DisposeUnmanagedResources(IntPtr handle);
7078

71-
~DisposableObject()
72-
{
73-
internal_dispose(false);
74-
}
75-
7679
public void Dispose()
7780
{
78-
lock (this)
79-
{
80-
internal_dispose(true);
81-
GC.SuppressFinalize(this);
82-
}
81+
Dispose(true);
82+
// This object will be cleaned up by the Dispose method.
83+
// Therefore, you should call GC.SupressFinalize to
84+
// take this object off the finalization queue
85+
// and prevent finalization code for this object
86+
// from executing a second time.
87+
GC.SuppressFinalize(this);
8388
}
8489

85-
/// <summary>
86-
/// If <see cref="_handle"/> is <see cref="IntPtr.Zero"/> then throws <see cref="ObjectDisposedException"/>
87-
/// </summary>
88-
/// <exception cref="ObjectDisposedException">When <see cref="_handle"/> is <see cref="IntPtr.Zero"/></exception>
89-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
90-
protected void EnsureNotDisposed()
90+
~DisposableObject()
9191
{
92-
if (_disposed)
93-
throw new ObjectDisposedException($"Unable to access disposed object, Type: {GetType().Name}");
92+
Dispose(false);
9493
}
9594
}
9695
}

src/TensorFlowNET.Core/Eager/EagerRunner.TFE_Execute.cs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ You may obtain a copy of the License at
1414
limitations under the License.
1515
******************************************************************************/
1616

17+
using System;
1718
using System.Linq;
1819
using Tensorflow.Contexts;
1920
using static Tensorflow.Binding;
@@ -48,16 +49,11 @@ public Tensor[] TFE_ExecuteCancelable(Context ctx,
4849
{
4950
for (int i = 0; i < inputs.Length; ++i)
5051
{
51-
SafeTensorHandleHandle tensor_handle;
52-
switch (inputs[i])
52+
SafeTensorHandleHandle tensor_handle = inputs[i] switch
5353
{
54-
case EagerTensor et:
55-
tensor_handle = et.EagerTensorHandle;
56-
break;
57-
default:
58-
tensor_handle = c_api.TFE_NewTensorHandle(inputs[i], status.Handle);
59-
break;
60-
}
54+
EagerTensor et => et.EagerTensorHandle,
55+
_ => throw new NotImplementedException("")
56+
};
6157
c_api.TFE_OpAddInput(op, tensor_handle, status.Handle);
6258
status.Check(true);
6359
}
@@ -71,7 +67,7 @@ public Tensor[] TFE_ExecuteCancelable(Context ctx,
7167
c_api.TFE_Execute(op, outputs, out num_outputs, status.Handle);
7268
status.Check(true);
7369
}
74-
return outputs.Select(x => new EagerTensor(x)).ToArray();
70+
return outputs.Select(x => new EagerTensor(x, op)).ToArray();
7571
}
7672
}
7773
}

src/TensorFlowNET.Core/Eager/EagerRunner.TFE_FastPathExecute.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ public Tensor[] TFE_FastPathExecute(Context ctx,
158158
c_api.TFE_Execute(op, retVals, out num_retvals, status.Handle);
159159
status.Check(true);
160160

161-
var flat_result = retVals.Select(x => new EagerTensor(x)).ToArray();
161+
var flat_result = retVals.Select(x => new EagerTensor(x, op)).ToArray();
162162

163163
if (op_exec_info.run_callbacks)
164164
{
@@ -182,7 +182,11 @@ SafeOpHandle GetOp(Context ctx, string op_or_function_name, Status status)
182182
183183
status.Check(true);
184184
return op;*/
185-
return c_api.TFE_NewOp(ctx.Handle, op_or_function_name, status.Handle);
185+
var op = c_api.TFE_NewOp(ctx.Handle, op_or_function_name, status.Handle);
186+
#if TRACK_TENSOR_LIFE
187+
print($"New OpHandle 0x{op.DangerousGetHandle().ToString("x16")}");
188+
#endif
189+
return op;
186190
}
187191

188192
bool HasAccumulator()
@@ -219,22 +223,18 @@ bool AddInputToOp(object inputs,
219223
SafeOpHandle op,
220224
Status status)
221225
{
222-
SafeTensorHandleHandle input_handle;
223-
224-
// ConvertToTensor();
225226
var tensor = tf.convert_to_tensor(inputs);
226-
input_handle = tensor.EagerTensorHandle;
227227
flattened_inputs.Add(tensor);
228228

229229
if (add_type_attr && !string.IsNullOrEmpty(input_arg.TypeAttr))
230230
{
231-
var dtype = c_api.TFE_TensorHandleDataType(input_handle);
231+
var dtype = c_api.TFE_TensorHandleDataType(tensor.EagerTensorHandle);
232232
c_api.TFE_OpSetAttrType(op, input_arg.TypeAttr, dtype);
233233
flattened_attrs.Add(input_arg.TypeAttr);
234234
flattened_attrs.Add(dtype);
235235
}
236236

237-
c_api.TFE_OpAddInput(op, input_handle, status.Handle);
237+
c_api.TFE_OpAddInput(op, tensor.EagerTensorHandle, status.Handle);
238238
status.Check(true);
239239

240240
return true;

0 commit comments

Comments
 (0)