yum-archive/TaSTT-Whisper

High-performance GPGPU inference of OpenAI's Whisper automatic speech recognition (ASR) model

git clone https://git.yummers.dev/yum-archive/TaSTT-Whisper

KonstantinSource codes8c4603c

master
3.8 KiB138 linesraw
1using System.Runtime.CompilerServices;
2using System.Runtime.ExceptionServices;
3using System.Runtime.InteropServices;
4
5namespace Whisper.Internal
6{
7	/// <summary>Utility class to supply logging function pointer to the C++ library,<br/>
8	/// and provide custom calling conventions to ComLight runtime to convert error messages printed in C++ into .NET exception messages</summary>
9	public static class NativeLogger
10	{
11		internal static void startup() { }
12
13		static NativeLogger()
14		{
15			sink = logSink;
16			sLoggerSetup setup = default;
17			setup.sink = sink;
18			setup.level = eLogLevel.Warning;
19			Library.setupLogger( ref setup );
20		}
21
22		internal static void setup( eLogLevel lvl, eLoggerFlags flags, pfnLogMessage? pfn )
23		{
24			logMessage = pfn;
25
26			sLoggerSetup setup = default;
27			setup.sink = sink;
28			setup.level = lvl;
29			setup.flags = flags;
30			Library.setupLogger( ref setup );
31		}
32
33		// This field is here to protect the function pointer from being collected by the GC
34		static readonly pfnLoggerSink sink;
35
36		static void logSink( IntPtr context, eLogLevel lvl, string message )
37		{
38			if( lvl == eLogLevel.Error )
39				state.setText( message );
40			logMessage?.Invoke( lvl, message );
41		}
42
43		sealed class ThreadState
44		{
45			string? errorText = null;
46			ExceptionDispatchInfo? dispatchInfo = null;
47
48			public void setText( string text ) => errorText = text;
49			public void capture( Exception ex ) => dispatchInfo = ExceptionDispatchInfo.Capture( ex );
50
51			public void clear()
52			{
53				errorText = null;
54				dispatchInfo = null;
55			}
56
57			public void Deconstruct( out string? text, out ExceptionDispatchInfo? edi )
58			{
59				text = errorText;
60				edi = dispatchInfo;
61				errorText = null;
62				dispatchInfo = null;
63			}
64		}
65
66		[ThreadStatic]
67		static ThreadState state = new ThreadState();
68
69		internal static void captureException( Exception ex ) =>
70			state.capture( ex );
71
72		static pfnLogMessage? logMessage = null;
73
74		/// <summary>Called internally by ComLight runtime</summary>
75		[MethodImpl( MethodImplOptions.AggressiveInlining )]
76		public static void prologue()
77		{
78			// https://stackoverflow.com/a/2043505/126995
79			if( null != state )
80				state.clear();
81			else
82				createState();
83		}
84
85		[MethodImpl( MethodImplOptions.NoInlining )]
86		static void createState()
87		{
88			state = new ThreadState();
89		}
90
91		/// <summary>Epilogue implementation for unsuccessful status codes</summary>
92		[MethodImpl( MethodImplOptions.NoInlining )]
93		static void throwException( int hr )
94		{
95			// Move state from the thread local object into local variables, and clear that object
96			(string? text, ExceptionDispatchInfo? edi) = state;
97
98			if( null != edi && edi.SourceException.HResult == hr )
99			{
100				// The error comes from a callback, and we have original context of that exception.
101				// Re-throw the original exception.
102				// This uses the original error message, and even correctly deals with the stack trace.
103				edi.Throw();
104			}
105
106			if( null != text )
107			{
108				// C++ code has printed an error on the current thread, between prologue and epilogue.
109				// Use that text for the exception message.
110				Exception? ex = Marshal.GetExceptionForHR( hr );
111				throw new ApplicationException( text, ex );
112			}
113
114			// We don’t have any additional info about the exception.
115			// Throw an exception from just the HRESULT code.
116			Marshal.ThrowExceptionForHR( hr );
117		}
118
119		/// <summary>Called internally by ComLight runtime</summary>
120		[MethodImpl( MethodImplOptions.AggressiveInlining )]
121		public static void throwForHR( int hr )
122		{
123			if( hr >= 0 )
124				return; // SUCCEEDED
125			throwException( hr );
126		}
127
128		/// <summary>Called internally by ComLight runtime</summary>
129		[MethodImpl( MethodImplOptions.AggressiveInlining )]
130		public static bool throwAndReturnBool( int hr )
131		{
132			if( hr >= 0 )
133				return 0 == hr;
134			throwException( hr );
135			return false;
136		}
137	}
138}