From a79382b15eccc2f99cc1a99a9244a30c29f0b449 Mon Sep 17 00:00:00 2001 From: Meinrad Recheis Date: Sat, 13 Jul 2019 20:31:07 +0200 Subject: [PATCH] Tensor: made the deallocator functions static (they should not have access to anything anyway) --- .../Tensors/Tensor.Creation.cs | 261 +++++++----------- 1 file changed, 94 insertions(+), 167 deletions(-) diff --git a/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs b/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs index 50aa178a..a1bbe23a 100644 --- a/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs +++ b/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs @@ -36,8 +36,8 @@ namespace Tensorflow public Tensor(IntPtr handle) { _handle = handle; - } - + } + #if _REGEN %types=["sbyte", "byte", "short", "ushort", "int", "uint", "long", "ulong", "float", "double", "Complex"] %foreach types% @@ -65,26 +65,18 @@ namespace Tensorflow { var v = (#1*)Marshal.AllocHGlobal(sizeof(#1)); *v = value; - Deallocator deallocator = (IntPtr values, IntPtr len, ref DeallocatorArgs arg) => { - if (arg.deallocator_called) - return; - Marshal.FreeHGlobal(values); - arg.deallocator_called = true; - //_handle = IntPtr.Zero; - }; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(#1)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(#1), deallocator: deallocator, ref _deallocatorArgs); + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(#1)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(#1), deallocator: hGlobalDeallocator, ref _deallocatorArgs); } % #else - - - + + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(sbyte[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(sbyte)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(sbyte)), new long[]{data.Length}, data, Marshal.SizeOf()); } /// @@ -102,23 +94,15 @@ namespace Tensorflow { var v = (sbyte*)Marshal.AllocHGlobal(sizeof(sbyte)); *v = value; - Deallocator deallocator = (IntPtr values, IntPtr len, ref DeallocatorArgs arg) => - { - if (arg.deallocator_called) - return; - Marshal.FreeHGlobal(values); - arg.deallocator_called = true; - //_handle = IntPtr.Zero; - }; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(sbyte)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(sbyte), deallocator: deallocator, ref _deallocatorArgs); - } - + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(sbyte)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(sbyte), deallocator: hGlobalDeallocator, ref _deallocatorArgs); + } + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(byte[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(byte)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(byte)), new long[]{data.Length}, data, Marshal.SizeOf()); } /// @@ -136,23 +120,15 @@ namespace Tensorflow { var v = (byte*)Marshal.AllocHGlobal(sizeof(byte)); *v = value; - Deallocator deallocator = (IntPtr values, IntPtr len, ref DeallocatorArgs arg) => - { - if (arg.deallocator_called) - return; - Marshal.FreeHGlobal(values); - arg.deallocator_called = true; - //_handle = IntPtr.Zero; - }; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(byte)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(byte), deallocator: deallocator, ref _deallocatorArgs); - } - + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(byte)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(byte), deallocator: hGlobalDeallocator, ref _deallocatorArgs); + } + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(short[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(short)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(short)), new long[]{data.Length}, data, Marshal.SizeOf()); } /// @@ -170,23 +146,15 @@ namespace Tensorflow { var v = (short*)Marshal.AllocHGlobal(sizeof(short)); *v = value; - Deallocator deallocator = (IntPtr values, IntPtr len, ref DeallocatorArgs arg) => - { - if (arg.deallocator_called) - return; - Marshal.FreeHGlobal(values); - arg.deallocator_called = true; - //_handle = IntPtr.Zero; - }; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(short)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(short), deallocator: deallocator, ref _deallocatorArgs); - } - + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(short)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(short), deallocator: hGlobalDeallocator, ref _deallocatorArgs); + } + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(ushort[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(ushort)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(ushort)), new long[]{data.Length}, data, Marshal.SizeOf()); } /// @@ -204,23 +172,15 @@ namespace Tensorflow { var v = (ushort*)Marshal.AllocHGlobal(sizeof(ushort)); *v = value; - Deallocator deallocator = (IntPtr values, IntPtr len, ref DeallocatorArgs arg) => - { - if (arg.deallocator_called) - return; - Marshal.FreeHGlobal(values); - arg.deallocator_called = true; - //_handle = IntPtr.Zero; - }; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(ushort)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(ushort), deallocator: deallocator, ref _deallocatorArgs); - } - + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(ushort)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(ushort), deallocator: hGlobalDeallocator, ref _deallocatorArgs); + } + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(int[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(int)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(int)), new long[]{data.Length}, data, Marshal.SizeOf()); } /// @@ -238,23 +198,15 @@ namespace Tensorflow { var v = (int*)Marshal.AllocHGlobal(sizeof(int)); *v = value; - Deallocator deallocator = (IntPtr values, IntPtr len, ref DeallocatorArgs arg) => - { - if (arg.deallocator_called) - return; - Marshal.FreeHGlobal(values); - arg.deallocator_called = true; - //_handle = IntPtr.Zero; - }; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(int)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(int), deallocator: deallocator, ref _deallocatorArgs); - } - + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(int)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(int), deallocator: hGlobalDeallocator, ref _deallocatorArgs); + } + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(uint[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(uint)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(uint)), new long[]{data.Length}, data, Marshal.SizeOf()); } /// @@ -272,23 +224,15 @@ namespace Tensorflow { var v = (uint*)Marshal.AllocHGlobal(sizeof(uint)); *v = value; - Deallocator deallocator = (IntPtr values, IntPtr len, ref DeallocatorArgs arg) => - { - if (arg.deallocator_called) - return; - Marshal.FreeHGlobal(values); - arg.deallocator_called = true; - //_handle = IntPtr.Zero; - }; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(uint)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(uint), deallocator: deallocator, ref _deallocatorArgs); - } - + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(uint)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(uint), deallocator: hGlobalDeallocator, ref _deallocatorArgs); + } + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(long[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(long)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(long)), new long[]{data.Length}, data, Marshal.SizeOf()); } /// @@ -306,23 +250,15 @@ namespace Tensorflow { var v = (long*)Marshal.AllocHGlobal(sizeof(long)); *v = value; - Deallocator deallocator = (IntPtr values, IntPtr len, ref DeallocatorArgs arg) => - { - if (arg.deallocator_called) - return; - Marshal.FreeHGlobal(values); - arg.deallocator_called = true; - //_handle = IntPtr.Zero; - }; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(long)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(long), deallocator: deallocator, ref _deallocatorArgs); - } - + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(long)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(long), deallocator: hGlobalDeallocator, ref _deallocatorArgs); + } + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(ulong[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(ulong)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(ulong)), new long[]{data.Length}, data, Marshal.SizeOf()); } /// @@ -340,23 +276,15 @@ namespace Tensorflow { var v = (ulong*)Marshal.AllocHGlobal(sizeof(ulong)); *v = value; - Deallocator deallocator = (IntPtr values, IntPtr len, ref DeallocatorArgs arg) => - { - if (arg.deallocator_called) - return; - Marshal.FreeHGlobal(values); - arg.deallocator_called = true; - //_handle = IntPtr.Zero; - }; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(ulong)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(ulong), deallocator: deallocator, ref _deallocatorArgs); - } - + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(ulong)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(ulong), deallocator: hGlobalDeallocator, ref _deallocatorArgs); + } + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(float[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(float)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(float)), new long[]{data.Length}, data, Marshal.SizeOf()); } /// @@ -374,23 +302,15 @@ namespace Tensorflow { var v = (float*)Marshal.AllocHGlobal(sizeof(float)); *v = value; - Deallocator deallocator = (IntPtr values, IntPtr len, ref DeallocatorArgs arg) => - { - if (arg.deallocator_called) - return; - Marshal.FreeHGlobal(values); - arg.deallocator_called = true; - //_handle = IntPtr.Zero; - }; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(float)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(float), deallocator: deallocator, ref _deallocatorArgs); - } - + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(float)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(float), deallocator: hGlobalDeallocator, ref _deallocatorArgs); + } + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(double[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(double)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(double)), new long[]{data.Length}, data, Marshal.SizeOf()); } /// @@ -408,23 +328,15 @@ namespace Tensorflow { var v = (double*)Marshal.AllocHGlobal(sizeof(double)); *v = value; - Deallocator deallocator = (IntPtr values, IntPtr len, ref DeallocatorArgs arg) => - { - if (arg.deallocator_called) - return; - Marshal.FreeHGlobal(values); - arg.deallocator_called = true; - //_handle = IntPtr.Zero; - }; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(double)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(double), deallocator: deallocator, ref _deallocatorArgs); - } - + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(double)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(double), deallocator: hGlobalDeallocator, ref _deallocatorArgs); + } + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(Complex[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(Complex)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(Complex)), new long[]{data.Length}, data, Marshal.SizeOf()); } /// @@ -442,15 +354,7 @@ namespace Tensorflow { var v = (Complex*)Marshal.AllocHGlobal(sizeof(Complex)); *v = value; - Deallocator deallocator = (IntPtr values, IntPtr len, ref DeallocatorArgs arg) => - { - if (arg.deallocator_called) - return; - Marshal.FreeHGlobal(values); - arg.deallocator_called = true; - //_handle = IntPtr.Zero; - }; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(Complex)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(Complex), deallocator: deallocator, ref _deallocatorArgs); + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(Complex)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(Complex), deallocator: hGlobalDeallocator, ref _deallocatorArgs); } #endif @@ -534,23 +438,13 @@ namespace Tensorflow return new Tensor(UTF8Encoding.UTF8.GetBytes(nd.Data(0)), TF_DataType.TF_STRING); default: throw new NotImplementedException($"Marshal.Copy failed for {nd.dtype.Name}."); - } - - // Free the original buffer and set flag - Deallocator deallocator = (IntPtr values, IntPtr len, ref DeallocatorArgs args) => - { - if (args.deallocator_called) - return; - Marshal.FreeHGlobal(values); - args.deallocator_called = true; - }; - + } var tfHandle = c_api.TF_NewTensor(dataType, dims, dims.Length, dotHandle, (UIntPtr)buffersize, - deallocator, + hGlobalDeallocator, ref _deallocatorArgs); return tfHandle; @@ -621,22 +515,55 @@ namespace Tensorflow // get a handle to the pinned array which we will pass on to the tensor computation engine to use var gcHandle = GCHandle.Alloc(data, GCHandleType.Pinned); _deallocatorArgs = new DeallocatorArgs() { gc_handle = GCHandle.ToIntPtr(gcHandle) }; - // Free the original buffer and set flag - Deallocator deallocator = (IntPtr ptr, IntPtr len, ref DeallocatorArgs args) => - { - if (args.deallocator_called || args.gc_handle==IntPtr.Zero) - return; - // note: since the ptr given to tensorflow is just the addr of the pinned object we can not directly free it! we need to free the gcHandle instead - GCHandle.FromIntPtr(args.gc_handle).Free(); - args.deallocator_called = true; - }; - if (shape == null || shape.Length == 0) - return TF_NewTensor(dt, new long[0], 0, gcHandle.AddrOfPinnedObject() + start * element_size, (UIntPtr)(count * element_size), deallocator, ref _deallocatorArgs); + return TF_NewTensor(dt, new long[0], 0, gcHandle.AddrOfPinnedObject() + start * element_size, (UIntPtr)(count * element_size), gcHandleDeallocator, ref _deallocatorArgs); else - return TF_NewTensor(dt, shape, shape.Length, gcHandle.AddrOfPinnedObject() + start * element_size, (UIntPtr)(count * element_size), deallocator, ref _deallocatorArgs); + return TF_NewTensor(dt, shape, shape.Length, gcHandle.AddrOfPinnedObject() + start * element_size, (UIntPtr)(count * element_size), gcHandleDeallocator, ref _deallocatorArgs); } private DeallocatorArgs _deallocatorArgs = new DeallocatorArgs() { gc_handle = IntPtr.Zero }; + + // note: they must be assigned to a static variable in order to work as unmanaged callbacks + static Deallocator hGlobalDeallocator = FreeHGlobalMemory; + static Deallocator gcHandleDeallocator = FreeGCHandle; + + [MonoPInvokeCallback(typeof(Deallocator))] + internal static void FreeHGlobalMemory(IntPtr dataPtr, IntPtr len, ref DeallocatorArgs args) + { + if (args.deallocator_called) + return; + Marshal.FreeHGlobal(dataPtr); + args.deallocator_called = true; + } + + [MonoPInvokeCallback(typeof(Deallocator))] + internal static void FreeGCHandle(IntPtr dataPtr, IntPtr len, ref DeallocatorArgs args) + { + if (args.deallocator_called || args.gc_handle == IntPtr.Zero) + return; + // note: since the ptr given to tensorflow is just the addr of the pinned object we can not directly free it! we need to free the gcHandle instead + GCHandle.FromIntPtr(args.gc_handle).Free(); + args.deallocator_called = true; + } + } + + /// + /// This attribute can be applied to callback functions that will be invoked + /// from unmanaged code to managed code. + /// + /// + /// + /// [TensorFlow.MonoPInvokeCallback (typeof (BufferReleaseFunc))] + /// internal static void MyFreeFunc (IntPtr data, IntPtr length){..} + /// + /// + public sealed class MonoPInvokeCallbackAttribute : Attribute + { + /// + /// Use this constructor to annotate the type of the callback function that + /// will be invoked from unmanaged code. + /// + /// T. + public MonoPInvokeCallbackAttribute(Type t) { } } }