From 4291c57322a4e709f51a44416da747dc715e6ad9 Mon Sep 17 00:00:00 2001 From: Hariharan Seshadri Date: Wed, 21 Oct 2020 10:32:13 -0700 Subject: [PATCH] [C# and Python APIs] Expose knobs to enable/disable platform telemetry collection (#5481) --- .../InferenceSession.cs | 4 +- .../Microsoft.ML.OnnxRuntime/NativeMethods.cs | 9 +++ .../Microsoft.ML.OnnxRuntime/OnnxRuntime.cs | 77 ++++++++++++++----- .../InferenceTest.cs | 12 +++ docs/CSharp_API.md | 66 ++++++++++++++++ docs/Privacy.md | 3 +- onnxruntime/__init__.py | 4 +- .../python/onnxruntime_pybind_state.cc | 6 ++ .../test/python/onnxruntime_test_python.py | 7 ++ 9 files changed, 163 insertions(+), 25 deletions(-) diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/InferenceSession.cs b/csharp/src/Microsoft.ML.OnnxRuntime/InferenceSession.cs index f32f19f069836..9bd81a0c4bd4b 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/InferenceSession.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/InferenceSession.cs @@ -676,7 +676,7 @@ public ulong ProfilingStartTimeNs private void Init(string modelPath, SessionOptions options) { - var envHandle = OnnxRuntime.Handle; + var envHandle = OrtEnv.Handle; var session = IntPtr.Zero; NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateSession(envHandle, NativeMethods.GetPlatformSerializedString(modelPath), options.Handle, out session)); @@ -685,7 +685,7 @@ private void Init(string modelPath, SessionOptions options) private void Init(byte[] modelData, SessionOptions options) { - var envHandle = OnnxRuntime.Handle; + var envHandle = OrtEnv.Handle; var session = IntPtr.Zero; NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateSessionFromArray(envHandle, modelData, (UIntPtr)modelData.Length, options.Handle, out session)); diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/NativeMethods.cs b/csharp/src/Microsoft.ML.OnnxRuntime/NativeMethods.cs index 692ba0b671afe..4b9562c30f8cd 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/NativeMethods.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/NativeMethods.cs @@ -202,6 +202,9 @@ static NativeMethods() OrtCreateEnv = (DOrtCreateEnv)Marshal.GetDelegateForFunctionPointer(api_.CreateEnv, typeof(DOrtCreateEnv)); OrtReleaseEnv = (DOrtReleaseEnv)Marshal.GetDelegateForFunctionPointer(api_.ReleaseEnv, typeof(DOrtReleaseEnv)); + OrtEnableTelemetryEvents = (DOrtEnableTelemetryEvents)Marshal.GetDelegateForFunctionPointer(api_.EnableTelemetryEvents, typeof(DOrtEnableTelemetryEvents)); + OrtDisableTelemetryEvents = (DOrtDisableTelemetryEvents)Marshal.GetDelegateForFunctionPointer(api_.DisableTelemetryEvents, typeof(DOrtDisableTelemetryEvents)); + OrtGetErrorCode = (DOrtGetErrorCode)Marshal.GetDelegateForFunctionPointer(api_.GetErrorCode, typeof(DOrtGetErrorCode)); OrtGetErrorMessage = (DOrtGetErrorMessage)Marshal.GetDelegateForFunctionPointer(api_.GetErrorMessage, typeof(DOrtGetErrorMessage)); OrtReleaseStatus = (DOrtReleaseStatus)Marshal.GetDelegateForFunctionPointer(api_.ReleaseStatus, typeof(DOrtReleaseStatus)); @@ -332,6 +335,12 @@ static NativeMethods() public delegate void DOrtReleaseEnv(IntPtr /*(OrtEnv*)*/ env); public static DOrtReleaseEnv OrtReleaseEnv; + public delegate IntPtr /* OrtStatus* */DOrtEnableTelemetryEvents(IntPtr /*(OrtEnv*)*/ env); + public static DOrtEnableTelemetryEvents OrtEnableTelemetryEvents; + + public delegate IntPtr /* OrtStatus* */DOrtDisableTelemetryEvents(IntPtr /*(OrtEnv*)*/ env); + public static DOrtDisableTelemetryEvents OrtDisableTelemetryEvents; + #endregion Runtime/Environment API #region Status API diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/OnnxRuntime.cs b/csharp/src/Microsoft.ML.OnnxRuntime/OnnxRuntime.cs index 09f6c5a4a3ee0..209484d8abba6 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/OnnxRuntime.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/OnnxRuntime.cs @@ -38,41 +38,77 @@ public enum OrtLanguageProjection } /// - /// This class intializes the process-global ONNX runtime - /// C# API users do not need to access this, thus kept as internal + /// This class initializes the process-global ONNX Runtime environment instance (OrtEnv) /// - internal sealed class OnnxRuntime : SafeHandle + public sealed class OrtEnv : SafeHandle { - private static readonly Lazy _instance = new Lazy(()=> new OnnxRuntime()); - - internal static IntPtr Handle // May throw exception in every access, if the constructor have thrown an exception + private static readonly Lazy _instance = new Lazy(()=> new OrtEnv()); + + #region private methods + private OrtEnv() //Problem: it is not possible to pass any option for a Singleton + : base(IntPtr.Zero, true) { - get + NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateEnv(LogLevel.Warning, @"CSharpOnnxRuntime", out handle)); + try { - return _instance.Value.handle; + NativeApiStatus.VerifySuccess(NativeMethods.OrtSetLanguageProjection(handle, OrtLanguageProjection.ORT_PROJECTION_CSHARP)); + } + catch (OnnxRuntimeException e) + { + ReleaseHandle(); + throw e; } } + #endregion - public override bool IsInvalid + #region internal methods + /// + /// Returns a handle to the native `OrtEnv` instance held by the singleton C# `OrtEnv` instance + /// Exception caching: May throw an exception on every call, if the `OrtEnv` constructor threw an exception + /// during lazy initialization + /// + internal static IntPtr Handle { get { - return (handle == IntPtr.Zero); + return _instance.Value.handle; } } + #endregion + + #region public methods - private OnnxRuntime() //Problem: it is not possible to pass any option for a Singleton - :base(IntPtr.Zero, true) + /// + /// Returns an instance of OrtEnv + /// It returns the same instance on every call - `OrtEnv` is singleton + /// + public static OrtEnv Instance() { return _instance.Value; } + + /// + /// Enable platform telemetry collection where applicable + /// (currently only official Windows ORT builds have telemetry collection capabilities) + /// + public void EnableTelemetryEvents() { - NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateEnv(LogLevel.Warning, @"CSharpOnnxRuntime", out handle)); - try - { - NativeApiStatus.VerifySuccess(NativeMethods.OrtSetLanguageProjection(handle, OrtLanguageProjection.ORT_PROJECTION_CSHARP)); - } - catch (OnnxRuntimeException e) + NativeApiStatus.VerifySuccess(NativeMethods.OrtEnableTelemetryEvents(Handle)); + } + + /// + /// Disable platform telemetry collection + /// + public void DisableTelemetryEvents() + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtDisableTelemetryEvents(Handle)); + } + + #endregion + + #region SafeHandle + public override bool IsInvalid + { + get { - ReleaseHandle(); - throw e; + return (handle == IntPtr.Zero); } } @@ -82,5 +118,6 @@ protected override bool ReleaseHandle() handle = IntPtr.Zero; return true; } + #endregion } } \ No newline at end of file diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests/InferenceTest.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests/InferenceTest.cs index 76945366e3e2d..c41e650f375e5 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests/InferenceTest.cs +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests/InferenceTest.cs @@ -164,6 +164,18 @@ public void TestRunOptions() } } + [Fact] + public void EnablingAndDisablingTelemetryEventCollection() + { + var ortEnvInstance = OrtEnv.Instance(); + ortEnvInstance.DisableTelemetryEvents(); + + // no-op on non-Windows builds + // may be no-op on certain Windows builds based on build configuration + + ortEnvInstance.EnableTelemetryEvents(); + } + [Fact] public void CanCreateAndDisposeSessionWithModelPath() { diff --git a/docs/CSharp_API.md b/docs/CSharp_API.md index 2d54da49c0822..38ba2a1678514 100644 --- a/docs/CSharp_API.md +++ b/docs/CSharp_API.md @@ -92,10 +92,37 @@ var session = new InferenceSession("model.onnx", SessionOptions.MakeSessionOptio ``` ## API Reference + +### OrtEnv +```cs +class OrtEnv +``` +Holds some methods which can be used to tune the ONNX Runtime's runime environment + +#### Constructor +No public constructor available. + +#### Methods +```cs +static OrtEnv Instance(); +``` +Returns an instance of the singlton class `OrtEnv`. + +```cs +void EnableTelemetryEvents(); +``` +Enables platform-specific telemetry collection where applicable. Please see [Privacy](./Privacy.md) for more details. + +```cs +void DisableTelemetryEvents(); +``` +Disables platform-specific telemetry collection. Please see [Privacy](./Privacy.md) for more details. + ### InferenceSession ```cs class InferenceSession: IDisposable ``` + The runtime representation of an ONNX model #### Constructor @@ -239,5 +266,44 @@ class OnnxRuntimeException: Exception; The type of Exception that is thrown in most of the error conditions related to Onnx Runtime. +### ModelMetadata +```cs +class ModelMetadata +``` +Encapsulates some metadata about the ONNX model. +#### Constructor +No public constructor available. + +The `ModelMetadata` instance for an ONNX model may be obtained by querying the `ModelMetadata` property of an `InferenceSession` instance. + +#### Properties +```cs +string ProducerName; +``` +Holds the producer name of the ONNX model. + +```cs +string GraphName; +``` +Holds the graph name of the ONNX model. + +```cs +string Domain; +``` +Holds the opset domain of the ONNX model. + +```cs +string Description; +``` +Holds the description of the ONNX model. +```cs +long Version; +``` +Holds the version of the ONNX model. + +```cs +Dictionary CustomMetadataMap; +``` +Holds a dictionary containing key-value pairs of custom metadata held by the ONNX model. diff --git a/docs/Privacy.md b/docs/Privacy.md index 034a892ac3bb9..fcc8468b7fa9f 100644 --- a/docs/Privacy.md +++ b/docs/Privacy.md @@ -17,4 +17,5 @@ Currently telemetry is only implemented for Windows builds and is turned **ON** The Windows provider uses the [TraceLogging](https://docs.microsoft.com/en-us/windows/win32/tracelogging/trace-logging-about) API for its implementation. This enables ONNX Runtime trace events to be collected by the operating system, and based on user consent, this data may be periodically sent to Microsoft servers following GDPR and privacy regulations for anonymity and data access controls. Windows ML and onnxruntime C APIs allow Trace Logging to be turned on/off (see [API pages](../README.md#api-documentation) for details). -For information on how to enable and disable telemetry, see [C API: Telemetry](./C_API.md#telemetry). +For information on how to enable and disable telemetry, see [C API: Telemetry](./C_API.md#telemetry). +There are equivalent APIs in the C#, Python, and Java language bindings as well. diff --git a/onnxruntime/__init__.py b/onnxruntime/__init__.py index 4caf6595cf373..c22fc52c08b94 100644 --- a/onnxruntime/__init__.py +++ b/onnxruntime/__init__.py @@ -11,8 +11,8 @@ __author__ = "Microsoft" from onnxruntime.capi._pybind_state import get_all_providers, get_available_providers, get_device, set_seed, \ - RunOptions, SessionOptions, set_default_logger_severity, NodeArg, ModelMetadata, GraphOptimizationLevel, \ - ExecutionMode, ExecutionOrder, OrtDevice, SessionIOBinding + RunOptions, SessionOptions, set_default_logger_severity, enable_telemetry_events, disable_telemetry_events, \ + NodeArg, ModelMetadata, GraphOptimizationLevel, ExecutionMode, ExecutionOrder, OrtDevice, SessionIOBinding try: from onnxruntime.capi._pybind_state import set_cuda_mem_limit, set_cuda_device_id diff --git a/onnxruntime/python/onnxruntime_pybind_state.cc b/onnxruntime/python/onnxruntime_pybind_state.cc index a9ed3ee113d9b..1609aee0a4cc2 100644 --- a/onnxruntime/python/onnxruntime_pybind_state.cc +++ b/onnxruntime/python/onnxruntime_pybind_state.cc @@ -815,6 +815,12 @@ void addGlobalMethods(py::module& m, const Environment& env) { m.def( "get_available_providers", []() -> const std::vector& { return GetAvailableProviders(); }, "Return list of available Execution Providers available in this installed version of Onnxruntime."); + m.def( + "enable_telemetry_events", []() -> void { platform_env.GetTelemetryProvider().EnableTelemetryEvents(); }, + "Enables platform-specific telemetry collection where applicable."); + m.def( + "disable_telemetry_events", []() -> void { platform_env.GetTelemetryProvider().DisableTelemetryEvents(); }, + "Disables platform-specific telemetry collection."); #ifdef USE_NUPHAR m.def("set_nuphar_settings", [](const std::string& str) { diff --git a/onnxruntime/test/python/onnxruntime_test_python.py b/onnxruntime/test/python/onnxruntime_test_python.py index b0291b2d19f07..ea4eb61ec96c6 100644 --- a/onnxruntime/test/python/onnxruntime_test_python.py +++ b/onnxruntime/test/python/onnxruntime_test_python.py @@ -35,6 +35,13 @@ def testGetProviders(self): sess = onnxrt.InferenceSession(get_name("mul_1.onnx")) self.assertTrue('CPUExecutionProvider' in sess.get_providers()) + def testEnablingAndDisablingTelemetry(self): + onnxrt.disable_telemetry_events() + + # no-op on non-Windows builds + # may be no-op on certain Windows builds based on build configuration + onnxrt.enable_telemetry_events() + def testSetProviders(self): if 'CUDAExecutionProvider' in onnxrt.get_available_providers(): sess = onnxrt.InferenceSession(get_name("mul_1.onnx"))