Revise IDisposable implementation in C# interfaces (#4915)

Revise IDisposable implementation in C# interfaces
This commit is contained in:
Dmitri Smirnov 2020-08-27 09:17:42 -07:00 committed by GitHub
parent 08eb15068c
commit 2b460eaeca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 211 additions and 258 deletions

View file

@ -55,6 +55,7 @@ namespace Microsoft.ML.OnnxRuntime
private NativeMemoryHandler _nativeMemoryManager;
private TensorElementType _elementType;
private OnnxValueType _onnxValueType;
private bool _disposed = false;
private DisposableNamedOnnxValue(string name, Object value, OnnxValueType onnxValueType, TensorElementType elementType, NativeMemoryHandler nativeMemoryManager)
: base(name, value)
@ -264,15 +265,21 @@ namespace Microsoft.ML.OnnxRuntime
protected virtual void Dispose(bool disposing)
{
if(_disposed)
{
return;
}
// dispose managed state (managed objects).
if (disposing)
{
// dispose managed state (managed objects).
if (_nativeMemoryManager != null)
{
_nativeMemoryManager.Dispose();
_nativeMemoryManager = null;
}
}
_disposed = true;
}
public void Dispose()

View file

@ -9,6 +9,7 @@ namespace Microsoft.ML.OnnxRuntime
/// </summary>
public class FixedBufferOnnxValue : IDisposable
{
private bool _disposed = false;
internal MemoryHandle PinnedMemory { get; private set; }
internal OrtValue Value { get; private set; }
internal OnnxValueType OnnxValueType { get; private set; }
@ -46,11 +47,17 @@ namespace Microsoft.ML.OnnxRuntime
protected virtual void Dispose(bool disposing)
{
if(_disposed)
{
return;
}
if (disposing)
{
Value.Dispose();
PinnedMemory.Dispose();
}
_disposed = true;
}
public void Dispose()

View file

@ -21,6 +21,7 @@ namespace Microsoft.ML.OnnxRuntime
private SessionOptions _builtInSessionOptions = null;
private RunOptions _builtInRunOptions = null;
private ModelMetadata _modelMetadata = null;
private bool _disposed = false;
#region Public API
@ -902,27 +903,43 @@ namespace Microsoft.ML.OnnxRuntime
#endregion
#region IDisposable/ no finalizers needed
#region IDisposable
/// <summary>
/// Finalizer. to cleanup session in case it runs
/// and the user forgets to Dispose() of the session
/// </summary>
~InferenceSession()
{
Dispose(false);
}
public void Dispose()
{
GC.SuppressFinalize(this);
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if(_disposed)
{
return;
}
if (disposing)
{
// cleanup managed resources
if (_builtInSessionOptions != null)
{
_builtInSessionOptions.Dispose();
_builtInSessionOptions = null;
}
if (_builtInRunOptions != null)
{
_builtInRunOptions.Dispose();
_builtInRunOptions = null;
}
}
@ -930,11 +947,12 @@ namespace Microsoft.ML.OnnxRuntime
if (_nativeHandle != IntPtr.Zero)
{
NativeMethods.OrtReleaseSession(_nativeHandle);
_nativeHandle = IntPtr.Zero;
}
_disposed = true;
}
#endregion
}

View file

@ -10,9 +10,9 @@ namespace Microsoft.ML.OnnxRuntime
{
private static string GetErrorMessage(IntPtr /*(ONNXStatus*)*/status)
{
// nativeString belongs to status, no need for separate release
IntPtr nativeString = NativeMethods.OrtGetErrorMessage(status);
string str = Marshal.PtrToStringAnsi(nativeString); //assumes charset = ANSI
return str;
return NativeOnnxValueHelper.StringFromNativeUtf8(nativeString);
}
/// <summary>
@ -25,10 +25,16 @@ namespace Microsoft.ML.OnnxRuntime
{
if (nativeStatus != IntPtr.Zero)
{
ErrorCode statusCode = NativeMethods.OrtGetErrorCode(nativeStatus);
string errorMessage = GetErrorMessage(nativeStatus);
NativeMethods.OrtReleaseStatus(nativeStatus);
throw new OnnxRuntimeException(statusCode, errorMessage);
try
{
ErrorCode statusCode = NativeMethods.OrtGetErrorCode(nativeStatus);
string errorMessage = GetErrorMessage(nativeStatus);
throw new OnnxRuntimeException(statusCode, errorMessage);
}
finally
{
NativeMethods.OrtReleaseStatus(nativeStatus);
}
}
}
}

View file

@ -21,7 +21,6 @@ namespace Microsoft.ML.OnnxRuntime
internal class NativeOnnxTensorMemory<T> : MemoryManager<T>, NativeMemoryHandler
{
private bool _disposed;
private int _referenceCount;
private IntPtr _onnxValueHandle; // pointer to onnxvalue object in native
private IntPtr _dataBufferPointer; // pointer to mutable tensor data in native memory
private string[] _dataBufferAsString; // string tensor values copied into managed memory
@ -35,6 +34,7 @@ namespace Microsoft.ML.OnnxRuntime
Type type = null;
int width = 0;
_onnxValueHandle = onnxValueHandle;
_disposed = false;
IntPtr typeAndShape = IntPtr.Zero;
NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorTypeAndShape(onnxValueHandle, out typeAndShape));
try
@ -119,16 +119,8 @@ namespace Microsoft.ML.OnnxRuntime
public IntPtr Handle { get { return _onnxValueHandle; } }
public void Dispose()
{
GC.SuppressFinalize(this);
Dispose(true);
}
public bool IsDisposed => _disposed;
protected bool IsRetained => _referenceCount > 0;
public int[] Dimensions => _dimensions;
public int Rank => _dimensions.Length;
@ -172,53 +164,35 @@ namespace Microsoft.ML.OnnxRuntime
{
throw new ArgumentOutOfRangeException(nameof(elementIndex));
}
Retain();
return new MemoryHandle((void*)((int)_dataBufferPointer + elementIndex * _elementWidth)); //could not use Unsafe.Add
}
}
public override void Unpin()
// MemoryHandle returned above by Pin() should be disposed.
// Unpin() is purely to satisfy the interface.
// TODO: This class needs work. It is not clear what happens
// if the MemoryHandle remains alive and this class gets Disposed.
public override void Unpin() { }
public void Dispose()
{
Release();
}
private bool Release()
{
int newRefCount = Interlocked.Decrement(ref _referenceCount);
if (newRefCount < 0)
{
throw new InvalidOperationException("Unmatched Release/Retain");
}
return newRefCount != 0;
}
private void Retain()
{
if (IsDisposed)
{
throw new ObjectDisposedException(nameof(NativeOnnxTensorMemory<T>));
}
Interlocked.Increment(ref _referenceCount);
Dispose(true);
GC.SuppressFinalize(this);
}
protected override void Dispose(bool disposing)
{
if (_disposed)
if(_disposed)
{
return;
}
if (disposing)
if (_onnxValueHandle != IntPtr.Zero)
{
// do managed objects cleanup
NativeMethods.OrtReleaseValue(_onnxValueHandle);
_onnxValueHandle = IntPtr.Zero;
}
NativeMethods.OrtReleaseValue(_onnxValueHandle);
_disposed = true;
}

View file

@ -51,31 +51,13 @@ namespace Microsoft.ML.OnnxRuntime
private OnnxRuntime() //Problem: it is not possible to pass any option for a Singleton
:base(IntPtr.Zero, true)
{
handle = IntPtr.Zero;
try
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateEnv(LogLevel.Warning, @"CSharpOnnxRuntime", out handle));
}
catch (OnnxRuntimeException e)
{
if (handle != IntPtr.Zero)
{
Delete(handle);
handle = IntPtr.Zero;
}
throw e;
}
}
private static void Delete(IntPtr nativePtr)
{
NativeMethods.OrtReleaseEnv(nativePtr);
NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateEnv(LogLevel.Warning, @"CSharpOnnxRuntime", out handle));
}
protected override bool ReleaseHandle()
{
Delete(handle);
NativeMethods.OrtReleaseEnv(handle);
handle = IntPtr.Zero;
return true;
}
}

View file

@ -37,10 +37,9 @@ namespace Microsoft.ML.OnnxRuntime
/// to pre-allocated memory. In that case, the instance of OrtMemoryInfo contains the information about the allocator
/// used to allocate the underlying memory.
/// </summary>
public class OrtMemoryInfo : IDisposable
public class OrtMemoryInfo : SafeHandle
{
private static readonly Lazy<OrtMemoryInfo> _defaultCpuAllocInfo = new Lazy<OrtMemoryInfo>(CreateCpuMemoryInfo);
private IntPtr _pointer;
private readonly bool _owned; // false if we are exposing OrtMemoryInfo from an allocator which owns it
private static OrtMemoryInfo CreateCpuMemoryInfo()
@ -66,10 +65,12 @@ namespace Microsoft.ML.OnnxRuntime
{
get
{
return _pointer;
return handle;
}
}
public override bool IsInvalid { get { return handle == IntPtr.Zero; } }
/// <summary>
/// This allocator takes an native pointer to already existing
/// instance of OrtMemoryInfo. That instance may either be owned or not
@ -78,8 +79,8 @@ namespace Microsoft.ML.OnnxRuntime
/// </summary>
/// <param name="allocInfo"></param>
internal OrtMemoryInfo(IntPtr allocInfo, bool owned)
: base(allocInfo, true)
{
_pointer = allocInfo;
_owned = owned;
}
@ -100,6 +101,7 @@ namespace Microsoft.ML.OnnxRuntime
/// <param name="deviceId">Device id</param>
/// <param name="memoryType">Memory type</param>
public OrtMemoryInfo(byte[] utf8AllocatorName, OrtAllocatorType allocatorType, int deviceId, OrtMemType memoryType)
: base(IntPtr.Zero, true)
{
using (var pinnedName = new PinnedGCHandle(GCHandle.Alloc(utf8AllocatorName, GCHandleType.Pinned)))
{
@ -107,7 +109,7 @@ namespace Microsoft.ML.OnnxRuntime
allocatorType,
deviceId,
memoryType,
out _pointer));
out handle));
}
_owned = true;
}
@ -132,7 +134,7 @@ namespace Microsoft.ML.OnnxRuntime
get
{
IntPtr utf8Name = IntPtr.Zero;
NativeApiStatus.VerifySuccess(NativeMethods.OrtMemoryInfoGetName(_pointer, out utf8Name));
NativeApiStatus.VerifySuccess(NativeMethods.OrtMemoryInfoGetName(handle, out utf8Name));
return NativeOnnxValueHelper.StringFromNativeUtf8(utf8Name);
}
}
@ -145,7 +147,7 @@ namespace Microsoft.ML.OnnxRuntime
get
{
int id = 0;
NativeApiStatus.VerifySuccess(NativeMethods.OrtMemoryInfoGetId(_pointer, out id));
NativeApiStatus.VerifySuccess(NativeMethods.OrtMemoryInfoGetId(handle, out id));
return id;
}
}
@ -159,7 +161,7 @@ namespace Microsoft.ML.OnnxRuntime
public OrtMemType GetMemoryType()
{
OrtMemType memoryType = OrtMemType.Default;
NativeApiStatus.VerifySuccess(NativeMethods.OrtMemoryInfoGetMemType(_pointer, out memoryType));
NativeApiStatus.VerifySuccess(NativeMethods.OrtMemoryInfoGetMemType(handle, out memoryType));
return memoryType;
}
@ -170,7 +172,7 @@ namespace Microsoft.ML.OnnxRuntime
public OrtAllocatorType GetAllocatorType()
{
OrtAllocatorType allocatorType = OrtAllocatorType.ArenaAllocator;
NativeApiStatus.VerifySuccess(NativeMethods.OrtMemoryInfoGetType(_pointer, out allocatorType));
NativeApiStatus.VerifySuccess(NativeMethods.OrtMemoryInfoGetType(handle, out allocatorType));
return allocatorType;
}
@ -191,7 +193,7 @@ namespace Microsoft.ML.OnnxRuntime
return true;
}
int result = -1;
NativeApiStatus.VerifySuccess(NativeMethods.OrtCompareMemoryInfo(_pointer, other._pointer, out result));
NativeApiStatus.VerifySuccess(NativeMethods.OrtCompareMemoryInfo(handle, other.Pointer, out result));
return (result == 0);
}
@ -200,25 +202,19 @@ namespace Microsoft.ML.OnnxRuntime
return Pointer.ToInt32();
}
#region IDisposable Support
protected virtual void Dispose(bool disposing)
#region SafeHandle
protected override bool ReleaseHandle()
{
if (disposing)
// If this instance exposes OrtMemoryInfo that belongs
// to the allocator then the allocator owns it
if (_owned)
{
if (_owned)
{
NativeMethods.OrtReleaseMemoryInfo(_pointer);
}
_pointer = IntPtr.Zero;
NativeMethods.OrtReleaseMemoryInfo(handle);
}
handle = IntPtr.Zero;
return true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// We intentionally do not provider an finalizer for the class
#endregion
}
@ -230,8 +226,11 @@ namespace Microsoft.ML.OnnxRuntime
/// lifespan of the allocation. Or, if you prefer, all OrtMemoryAllocation instances must be
/// disposed of before the corresponding allocator instances are disposed of.
/// </summary>
public class OrtMemoryAllocation : IDisposable
public class OrtMemoryAllocation : SafeHandle
{
// This allocator is used to free this allocation
// This also prevents OrtAllocator GC/finalization in case
// the user forgets to Dispose() of this allocation
private OrtAllocator _allocator;
/// <summary>
@ -245,16 +244,18 @@ namespace Microsoft.ML.OnnxRuntime
/// <param name="pointer"></param>
/// <param name="size"></param>
internal OrtMemoryAllocation(OrtAllocator allocator, IntPtr pointer, uint size)
: base(pointer, true)
{
_allocator = allocator;
Pointer = pointer;
Size = size;
}
/// <summary>
/// Internal accessor to call native methods
/// </summary>
internal IntPtr Pointer { get; private set; }
internal IntPtr Pointer { get { return handle; } }
public override bool IsInvalid { get { return handle == IntPtr.Zero; } }
/// <summary>
/// Returns the size of the allocation
@ -268,24 +269,14 @@ namespace Microsoft.ML.OnnxRuntime
return _allocator.Info;
}
}
#region IDisposable Support
protected virtual void Dispose(bool disposing)
#region SafeHandle
protected override bool ReleaseHandle()
{
if (disposing)
{
if (_allocator != null)
{
_allocator.FreeMemory(Pointer);
}
Pointer = IntPtr.Zero;
}
_allocator.FreeMemory(handle);
handle = IntPtr.Zero;
return true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
@ -294,10 +285,9 @@ namespace Microsoft.ML.OnnxRuntime
/// This allocator enables you to allocate memory from the internal
/// memory pools including device allocations. Useful for binding.
/// </summary>
public class OrtAllocator : IDisposable
public class OrtAllocator : SafeHandle
{
private static readonly Lazy<OrtAllocator> _defaultInstance = new Lazy<OrtAllocator>(GetDefaultCpuAllocator);
private IntPtr _pointer;
private readonly bool _owned;
private static OrtAllocator GetDefaultCpuAllocator()
@ -324,19 +314,21 @@ namespace Microsoft.ML.OnnxRuntime
{
get
{
return _pointer;
return handle;
}
}
public override bool IsInvalid { get { return handle == IntPtr.Zero; } }
/// <summary>
/// Internal constructor wraps existing native allocators
/// </summary>
/// <param name="allocator"></param>
/// <param name="owned"></param>
internal OrtAllocator(IntPtr allocator, bool owned)
: base(allocator, true)
{
this._pointer = allocator;
this._owned = owned;
_owned = owned;
}
/// <summary>
@ -348,8 +340,9 @@ namespace Microsoft.ML.OnnxRuntime
/// <param name="session"></param>
/// <param name="memInfo"></param>
public OrtAllocator(InferenceSession session, OrtMemoryInfo memInfo)
: base(IntPtr.Zero, true)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateAllocator(session.Handle, memInfo.Pointer, out _pointer));
NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateAllocator(session.Handle, memInfo.Pointer, out handle));
_owned = true;
}
@ -361,7 +354,7 @@ namespace Microsoft.ML.OnnxRuntime
get
{
IntPtr memoryInfo = IntPtr.Zero;
NativeApiStatus.VerifySuccess(NativeMethods.OrtAllocatorGetInfo(_pointer, out memoryInfo));
NativeApiStatus.VerifySuccess(NativeMethods.OrtAllocatorGetInfo(handle, out memoryInfo));
// This serves as an exposure of memory_info owned by the allocator
return new OrtMemoryInfo(memoryInfo, false);
}
@ -375,7 +368,7 @@ namespace Microsoft.ML.OnnxRuntime
public OrtMemoryAllocation Allocate(uint size)
{
IntPtr allocation = IntPtr.Zero;
NativeApiStatus.VerifySuccess(NativeMethods.OrtAllocatorAlloc(_pointer, (UIntPtr)size, out allocation));
NativeApiStatus.VerifySuccess(NativeMethods.OrtAllocatorAlloc(handle, (UIntPtr)size, out allocation));
return new OrtMemoryAllocation(this, allocation, size);
}
@ -385,29 +378,21 @@ namespace Microsoft.ML.OnnxRuntime
/// <param name="allocation"></param>
internal void FreeMemory(IntPtr allocation)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtAllocatorFree(_pointer, allocation));
NativeApiStatus.VerifySuccess(NativeMethods.OrtAllocatorFree(handle, allocation));
}
#region IDisposable Support
protected virtual void Dispose(bool disposing)
#region SafeHandle
protected override bool ReleaseHandle()
{
if (disposing)
// Singleton default allocator is not owned
if (_owned)
{
if (_owned)
{
NativeMethods.OrtReleaseAllocator(_pointer);
}
_pointer = IntPtr.Zero;
NativeMethods.OrtReleaseAllocator(handle);
}
handle = IntPtr.Zero;
return true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// We intentionally do not provider an finalizer for the class
#endregion
}
}

View file

@ -14,27 +14,28 @@ namespace Microsoft.ML.OnnxRuntime
/// that piece of memory to an input name and shape and onnxruntime will use that as input.
/// Other traditional inputs can also be bound that already exists as Tensors
/// </summary>
public class OrtIoBinding : IDisposable
public class OrtIoBinding : SafeHandle
{
private IntPtr _handle;
/// <summary>
/// Use InferenceSession.CreateIoBinding()
/// </summary>
/// <param name="session"></param>
internal OrtIoBinding(InferenceSession session)
: base(IntPtr.Zero, true)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateIoBinding(session.Handle, out _handle));
NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateIoBinding(session.Handle, out handle));
}
internal IntPtr Handle
{
get
{
return _handle;
return handle;
}
}
public override bool IsInvalid { get { return handle == IntPtr.Zero; } }
/// <summary>
/// Bind a piece of pre-allocated native memory as a OrtValue Tensor with a given shape
/// to an input with a given name. The model will read the specified input from that memory
@ -114,7 +115,7 @@ namespace Microsoft.ML.OnnxRuntime
{
var utf8NamePinned = GCHandle.Alloc(NativeOnnxValueHelper.StringToZeroTerminatedUtf8(name), GCHandleType.Pinned);
using (var pinnedName = new PinnedGCHandle(utf8NamePinned))
NativeApiStatus.VerifySuccess(NativeMethods.OrtBindOutputToDevice(_handle, pinnedName.Pointer, memInfo.Pointer));
NativeApiStatus.VerifySuccess(NativeMethods.OrtBindOutputToDevice(handle, pinnedName.Pointer, memInfo.Pointer));
}
/// <summary>
@ -130,11 +131,11 @@ namespace Microsoft.ML.OnnxRuntime
{
if (isInput)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtBindInput(_handle, pinnedName.Pointer, ortValue));
NativeApiStatus.VerifySuccess(NativeMethods.OrtBindInput(handle, pinnedName.Pointer, ortValue));
}
else
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtBindOutput(_handle, pinnedName.Pointer, ortValue));
NativeApiStatus.VerifySuccess(NativeMethods.OrtBindOutput(handle, pinnedName.Pointer, ortValue));
}
}
}
@ -149,7 +150,7 @@ namespace Microsoft.ML.OnnxRuntime
IntPtr lengths = IntPtr.Zero;
UIntPtr count = UIntPtr.Zero;
var allocator = OrtAllocator.DefaultInstance;
NativeApiStatus.VerifySuccess(NativeMethods.OrtGetBoundOutputNames(_handle, allocator.Pointer, out buffer, out lengths, out count));
NativeApiStatus.VerifySuccess(NativeMethods.OrtGetBoundOutputNames(handle, allocator.Pointer, out buffer, out lengths, out count));
if(count.Equals(UIntPtr.Zero))
{
@ -193,7 +194,7 @@ namespace Microsoft.ML.OnnxRuntime
IntPtr ortValues = IntPtr.Zero;
UIntPtr count = UIntPtr.Zero;
var allocator = OrtAllocator.DefaultInstance;
NativeApiStatus.VerifySuccess(NativeMethods.OrtGetBoundOutputValues(_handle, allocator.Pointer, out ortValues, out count));
NativeApiStatus.VerifySuccess(NativeMethods.OrtGetBoundOutputValues(handle, allocator.Pointer, out ortValues, out count));
if(count.Equals(UIntPtr.Zero))
{
@ -225,7 +226,7 @@ namespace Microsoft.ML.OnnxRuntime
/// </summary>
public void ClearBoundInputs()
{
NativeMethods.OrtClearBoundInputs(_handle);
NativeMethods.OrtClearBoundInputs(handle);
}
/// <summary>
@ -233,25 +234,17 @@ namespace Microsoft.ML.OnnxRuntime
/// </summary>
public void ClearBoundOutputs()
{
NativeMethods.OrtClearBoundOutputs(_handle);
NativeMethods.OrtClearBoundOutputs(handle);
}
#region Disposable Support
protected virtual void Dispose(bool disposing)
#region SafeHandle
protected override bool ReleaseHandle()
{
if(disposing)
{
NativeMethods.OrtReleaseIoBinding(_handle);
_handle = IntPtr.Zero;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
NativeMethods.OrtReleaseIoBinding(handle);
handle = IntPtr.Zero;
return true;
}
// No need for the finalizer
#endregion
}
}

View file

@ -22,20 +22,24 @@ namespace Microsoft.ML.OnnxRuntime
/// <summary>
/// Represents a disposable OrtValue
/// </summary>
public class OrtValue : IDisposable
public class OrtValue : SafeHandle
{
/// <summary>
/// Use factory methods to instantiate
/// </summary>
/// <param name="handle"></param>
/// <param name="owned">Default true, own the raw handle</param>
/// <param name="owned">Default true, own the raw handle
/// However, we use this class to expose OrtValue that is owned by DisposableNamedOnnxValue
/// </param>
internal OrtValue(IntPtr handle, bool owned = true)
: base(handle, true)
{
Handle = handle;
IsOwned = owned;
}
internal IntPtr Handle { get; private set; }
internal IntPtr Handle { get { return handle; } }
public override bool IsInvalid { get { return handle == IntPtr.Zero; } }
#region NamedOnnxValue/DisposableOnnxValue accommodations
@ -54,10 +58,10 @@ namespace Microsoft.ML.OnnxRuntime
/// <returns></returns>
internal IntPtr Disown()
{
var handle = Handle;
Handle = IntPtr.Zero;
var ret = Handle;
handle = IntPtr.Zero;
IsOwned = false;
return handle;
return ret;
}
internal bool IsOwned { get; private set; }
@ -337,28 +341,18 @@ namespace Microsoft.ML.OnnxRuntime
return ortValue;
}
#region Disposable Support
protected virtual void Dispose(bool disposing)
#region SafeHandle
protected override bool ReleaseHandle()
{
if (disposing)
// We have to surrender ownership to some legacy classes
// Or we never had that ownership to begin with
if (IsOwned)
{
// We have to surrender ownership to some legacy classes
// Or we never had that ownership to begin with
if (Handle != IntPtr.Zero)
{
if (IsOwned)
{
NativeMethods.OrtReleaseValue(Handle);
}
// Prevent use after disposal
Handle = IntPtr.Zero;
}
NativeMethods.OrtReleaseValue(handle);
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
// Prevent use after disposal
handle = IntPtr.Zero;
return true;
}
// No need for the finalizer
#endregion

View file

@ -6,23 +6,25 @@ using System.Runtime.InteropServices;
namespace Microsoft.ML.OnnxRuntime
{
/// Sets various runtime options.
public class RunOptions : IDisposable
public class RunOptions : SafeHandle
{
private IntPtr _nativePtr;
internal IntPtr Handle
{
get
{
return _nativePtr;
return handle;
}
}
public RunOptions()
public RunOptions()
:base(IntPtr.Zero, true)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateRunOptions(out _nativePtr));
NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateRunOptions(out handle));
}
public override bool IsInvalid { get { return handle == IntPtr.Zero; } }
/// <summary>
/// Log Severity Level for the session logs. Default = ORT_LOGGING_LEVEL_WARNING
/// </summary>
@ -34,7 +36,7 @@ namespace Microsoft.ML.OnnxRuntime
}
set
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtRunOptionsSetRunLogSeverityLevel(_nativePtr, value));
NativeApiStatus.VerifySuccess(NativeMethods.OrtRunOptionsSetRunLogSeverityLevel(handle, value));
_logSeverityLevel = value;
}
}
@ -52,7 +54,7 @@ namespace Microsoft.ML.OnnxRuntime
}
set
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtRunOptionsSetRunLogVerbosityLevel(_nativePtr, value));
NativeApiStatus.VerifySuccess(NativeMethods.OrtRunOptionsSetRunLogVerbosityLevel(handle, value));
_logVerbosityLevel = value;
}
}
@ -67,14 +69,14 @@ namespace Microsoft.ML.OnnxRuntime
{
string tag = null;
IntPtr tagPtr = IntPtr.Zero;
NativeApiStatus.VerifySuccess(NativeMethods.OrtRunOptionsGetRunTag(_nativePtr, out tagPtr));
NativeApiStatus.VerifySuccess(NativeMethods.OrtRunOptionsGetRunTag(handle, out tagPtr));
tag = Marshal.PtrToStringAnsi(tagPtr); // assume ANSI string
// should not release the memory of the tagPtr, because it returns the c_str() of the std::string being used inside RunOptions C++ class
return tag;
}
set
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtRunOptionsSetRunTag(_nativePtr, value));
NativeApiStatus.VerifySuccess(NativeMethods.OrtRunOptionsSetRunTag(handle, value));
}
}
@ -93,12 +95,12 @@ namespace Microsoft.ML.OnnxRuntime
{
if (!_terminate && value)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtRunOptionsSetTerminate(_nativePtr));
NativeApiStatus.VerifySuccess(NativeMethods.OrtRunOptionsSetTerminate(handle));
_terminate = true;
}
else if (_terminate && !value)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtRunOptionsUnsetTerminate(_nativePtr));
NativeApiStatus.VerifySuccess(NativeMethods.OrtRunOptionsUnsetTerminate(handle));
_terminate = false;
}
}
@ -106,21 +108,13 @@ namespace Microsoft.ML.OnnxRuntime
private bool _terminate = false; //value set to default value of the C++ RunOptions
#region IDisposable
#region SafeHandle
public void Dispose()
protected override bool ReleaseHandle()
{
GC.SuppressFinalize(this);
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
NativeMethods.OrtReleaseRunOptions(_nativePtr);
}
NativeMethods.OrtReleaseRunOptions(handle);
handle = IntPtr.Zero;
return true;
}
#endregion

View file

@ -34,9 +34,8 @@ namespace Microsoft.ML.OnnxRuntime
/// <summary>
/// Holds the options for creating an InferenceSession
/// </summary>
public class SessionOptions : IDisposable
public class SessionOptions : SafeHandle
{
private IntPtr _nativePtr;
private static string[] cudaDelayLoadedLibs = { "cublas64_10.dll", "cudnn64_7.dll", "curand64_10.dll" };
#region Constructor and Factory methods
@ -45,8 +44,9 @@ namespace Microsoft.ML.OnnxRuntime
/// Constructs an empty SessionOptions
/// </summary>
public SessionOptions()
:base(IntPtr.Zero, true)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateSessionOptions(out _nativePtr));
NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateSessionOptions(out handle));
}
/// <summary>
@ -69,8 +69,8 @@ namespace Microsoft.ML.OnnxRuntime
{
CheckCudaExecutionProviderDLLs();
SessionOptions options = new SessionOptions();
NativeMethods.OrtSessionOptionsAppendExecutionProvider_CUDA(options._nativePtr, deviceId);
NativeMethods.OrtSessionOptionsAppendExecutionProvider_CPU(options._nativePtr, 1);
NativeMethods.OrtSessionOptionsAppendExecutionProvider_CUDA(options.Handle, deviceId);
NativeMethods.OrtSessionOptionsAppendExecutionProvider_CPU(options.Handle, 1);
return options;
}
@ -83,7 +83,7 @@ namespace Microsoft.ML.OnnxRuntime
public static SessionOptions MakeSessionOptionWithNupharProvider(String settings = "")
{
SessionOptions options = new SessionOptions();
NativeMethods.OrtSessionOptionsAppendExecutionProvider_Nuphar(options._nativePtr, 1, settings);
NativeMethods.OrtSessionOptionsAppendExecutionProvider_Nuphar(options.Handle, 1, settings);
return options;
}
@ -92,7 +92,7 @@ namespace Microsoft.ML.OnnxRuntime
#region ExecutionProviderAppends
public void AppendExecutionProvider_CPU(int useArena)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtSessionOptionsAppendExecutionProvider_CPU(_nativePtr, useArena));
NativeApiStatus.VerifySuccess(NativeMethods.OrtSessionOptionsAppendExecutionProvider_CPU(handle, useArena));
}
/// <summary>
@ -100,7 +100,7 @@ namespace Microsoft.ML.OnnxRuntime
/// </summary>
public void AppendExecutionProvider_Dnnl(int useArena)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtSessionOptionsAppendExecutionProvider_Dnnl(_nativePtr, useArena));
NativeApiStatus.VerifySuccess(NativeMethods.OrtSessionOptionsAppendExecutionProvider_Dnnl(handle, useArena));
}
/// <summary>
@ -108,7 +108,7 @@ namespace Microsoft.ML.OnnxRuntime
/// </summary>
public void AppendExecutionProvider_CUDA(int deviceId)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtSessionOptionsAppendExecutionProvider_CUDA(_nativePtr, deviceId));
NativeApiStatus.VerifySuccess(NativeMethods.OrtSessionOptionsAppendExecutionProvider_CUDA(handle, deviceId));
}
/// <summary>
@ -116,7 +116,7 @@ namespace Microsoft.ML.OnnxRuntime
/// </summary>
public void AppendExecutionProvider_NGraph(string nGraphBackendType)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtSessionOptionsAppendExecutionProvider_NGraph(_nativePtr, nGraphBackendType));
NativeApiStatus.VerifySuccess(NativeMethods.OrtSessionOptionsAppendExecutionProvider_NGraph(handle, nGraphBackendType));
}
/// <summary>
@ -124,7 +124,7 @@ namespace Microsoft.ML.OnnxRuntime
/// </summary>
public void AppendExecutionProvider_OpenVINO(string deviceId = "")
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtSessionOptionsAppendExecutionProvider_OpenVINO(_nativePtr, deviceId));
NativeApiStatus.VerifySuccess(NativeMethods.OrtSessionOptionsAppendExecutionProvider_OpenVINO(handle, deviceId));
}
/// <summary>
@ -132,7 +132,7 @@ namespace Microsoft.ML.OnnxRuntime
/// </summary>
public void AppendExecutionProvider_Tensorrt(int deviceId)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtSessionOptionsAppendExecutionProvider_Tensorrt(_nativePtr, deviceId));
NativeApiStatus.VerifySuccess(NativeMethods.OrtSessionOptionsAppendExecutionProvider_Tensorrt(handle, deviceId));
}
/// <summary>
@ -140,7 +140,7 @@ namespace Microsoft.ML.OnnxRuntime
/// </summary>
public void AppendExecutionProvider_MIGraphX(int deviceId)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtSessionOptionsAppendExecutionProvider_MIGraphX(_nativePtr, deviceId));
NativeApiStatus.VerifySuccess(NativeMethods.OrtSessionOptionsAppendExecutionProvider_MIGraphX(handle, deviceId));
}
/// <summary>
@ -148,7 +148,7 @@ namespace Microsoft.ML.OnnxRuntime
/// </summary>
public void AppendExecutionProvider_Nnapi()
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtSessionOptionsAppendExecutionProvider_Nnapi(_nativePtr));
NativeApiStatus.VerifySuccess(NativeMethods.OrtSessionOptionsAppendExecutionProvider_Nnapi(handle));
}
/// <summary>
@ -156,7 +156,7 @@ namespace Microsoft.ML.OnnxRuntime
/// </summary>
public void AppendExecutionProvider_Nuphar(string settings = "")
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtSessionOptionsAppendExecutionProvider_Nuphar(_nativePtr, 1, settings));
NativeApiStatus.VerifySuccess(NativeMethods.OrtSessionOptionsAppendExecutionProvider_Nuphar(handle, 1, settings));
}
#endregion //ExecutionProviderAppends
@ -164,7 +164,7 @@ namespace Microsoft.ML.OnnxRuntime
public void RegisterCustomOpLibrary(string libraryPath)
{
IntPtr libraryHandle = IntPtr.Zero;
NativeApiStatus.VerifySuccess(NativeMethods.OrtRegisterCustomOpsLibrary(_nativePtr, libraryPath, out libraryHandle));
NativeApiStatus.VerifySuccess(NativeMethods.OrtRegisterCustomOpsLibrary(handle, libraryPath, out libraryHandle));
}
#endregion
@ -173,11 +173,13 @@ namespace Microsoft.ML.OnnxRuntime
{
get
{
return _nativePtr;
return handle;
}
}
#region Public Properties
public override bool IsInvalid { get { return handle == IntPtr.Zero; } }
/// <summary>
/// Enables the use of the memory allocation patterns in the first Run() call for subsequent runs. Default = true.
/// </summary>
@ -191,19 +193,18 @@ namespace Microsoft.ML.OnnxRuntime
{
if (!_enableMemoryPattern && value)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtEnableMemPattern(_nativePtr));
NativeApiStatus.VerifySuccess(NativeMethods.OrtEnableMemPattern(handle));
_enableMemoryPattern = true;
}
else if (_enableMemoryPattern && !value)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtDisableMemPattern(_nativePtr));
NativeApiStatus.VerifySuccess(NativeMethods.OrtDisableMemPattern(handle));
_enableMemoryPattern = false;
}
}
}
private bool _enableMemoryPattern = true;
/// <summary>
/// Path prefix to use for output of profiling data
/// </summary>
@ -227,12 +228,12 @@ namespace Microsoft.ML.OnnxRuntime
{
if (!_enableProfiling && value)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtEnableProfiling(_nativePtr, NativeMethods.GetPlatformSerializedString(ProfileOutputPathPrefix)));
NativeApiStatus.VerifySuccess(NativeMethods.OrtEnableProfiling(handle, NativeMethods.GetPlatformSerializedString(ProfileOutputPathPrefix)));
_enableProfiling = true;
}
else if (_enableProfiling && !value)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtDisableProfiling(_nativePtr));
NativeApiStatus.VerifySuccess(NativeMethods.OrtDisableProfiling(handle));
_enableProfiling = false;
}
}
@ -252,7 +253,7 @@ namespace Microsoft.ML.OnnxRuntime
{
if (value != _optimizedModelFilePath)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtSetOptimizedModelFilePath(_nativePtr, NativeMethods.GetPlatformSerializedString(value)));
NativeApiStatus.VerifySuccess(NativeMethods.OrtSetOptimizedModelFilePath(handle, NativeMethods.GetPlatformSerializedString(value)));
_optimizedModelFilePath = value;
}
}
@ -274,12 +275,12 @@ namespace Microsoft.ML.OnnxRuntime
{
if (!_enableCpuMemArena && value)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtEnableCpuMemArena(_nativePtr));
NativeApiStatus.VerifySuccess(NativeMethods.OrtEnableCpuMemArena(handle));
_enableCpuMemArena = true;
}
else if (_enableCpuMemArena && !value)
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtDisableCpuMemArena(_nativePtr));
NativeApiStatus.VerifySuccess(NativeMethods.OrtDisableCpuMemArena(handle));
_enableCpuMemArena = false;
}
}
@ -300,7 +301,7 @@ namespace Microsoft.ML.OnnxRuntime
set
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtSetSessionLogId(_nativePtr, value));
NativeApiStatus.VerifySuccess(NativeMethods.OrtSetSessionLogId(handle, value));
_logId = value;
}
}
@ -317,7 +318,7 @@ namespace Microsoft.ML.OnnxRuntime
}
set
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtSetSessionLogSeverityLevel(_nativePtr, value));
NativeApiStatus.VerifySuccess(NativeMethods.OrtSetSessionLogSeverityLevel(handle, value));
_logSeverityLevel = value;
}
}
@ -335,7 +336,7 @@ namespace Microsoft.ML.OnnxRuntime
}
set
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtSetSessionLogVerbosityLevel(_nativePtr, value));
NativeApiStatus.VerifySuccess(NativeMethods.OrtSetSessionLogVerbosityLevel(handle, value));
_logVerbosityLevel = value;
}
}
@ -354,7 +355,7 @@ namespace Microsoft.ML.OnnxRuntime
}
set
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtSetIntraOpNumThreads(_nativePtr, value));
NativeApiStatus.VerifySuccess(NativeMethods.OrtSetIntraOpNumThreads(handle, value));
_intraOpNumThreads = value;
}
}
@ -373,7 +374,7 @@ namespace Microsoft.ML.OnnxRuntime
}
set
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtSetInterOpNumThreads(_nativePtr, value));
NativeApiStatus.VerifySuccess(NativeMethods.OrtSetInterOpNumThreads(handle, value));
_interOpNumThreads = value;
}
}
@ -390,7 +391,7 @@ namespace Microsoft.ML.OnnxRuntime
}
set
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtSetSessionGraphOptimizationLevel(_nativePtr, value));
NativeApiStatus.VerifySuccess(NativeMethods.OrtSetSessionGraphOptimizationLevel(handle, value));
_graphOptimizationLevel = value;
}
}
@ -408,7 +409,7 @@ namespace Microsoft.ML.OnnxRuntime
}
set
{
NativeApiStatus.VerifySuccess(NativeMethods.OrtSetSessionExecutionMode(_nativePtr, value));
NativeApiStatus.VerifySuccess(NativeMethods.OrtSetSessionExecutionMode(handle, value));
_executionMode = value;
}
}
@ -448,21 +449,13 @@ namespace Microsoft.ML.OnnxRuntime
#endregion
#region IDisposable
#region SafeHandle
public void Dispose()
protected override bool ReleaseHandle()
{
GC.SuppressFinalize(this);
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
NativeMethods.OrtReleaseSessionOptions(_nativePtr);
_nativePtr = IntPtr.Zero;
}
NativeMethods.OrtReleaseSessionOptions(handle);
handle = IntPtr.Zero;
return true;
}
#endregion