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
10.0 KiB364 linesraw
1#include "stdafx.h"
2#include "../../Whisper/API/iContext.cl.h"
3#include "TraceReader.h"
4#include "../../Whisper/ML/testUtils.h"
5#include "compare.h"
6using namespace Tracing;
7using namespace DirectCompute;
8
9namespace
10{
11	inline const char* cstr( eItemType it )
12	{
13		switch( it )
14		{
15		case eItemType::Buffer: return "Buffer";
16		case eItemType::Tensor: return "Tensor";
17		}
18		throw E_INVALIDARG;
19	}
20	inline const char* cstr( const CStringA& s ) { return s; }
21
22	inline int tensorDims( __m128i vec )
23	{
24		const __m128i one = _mm_set1_epi32( 1 );
25		const uint32_t bitmapOnes = (uint32_t)_mm_movemask_ps( _mm_castsi128_ps( _mm_cmpeq_epi32( vec, one ) ) );
26		const uint32_t bitmapNotOnes = bitmapOnes ^ 0b1111u;
27		unsigned long idx;
28		if( !_BitScanReverse( &idx, bitmapNotOnes ) )
29			return 0;
30		return idx + 1;
31	}
32
33	int printSize( __m128i vec )
34	{
35		const int sz = tensorDims( vec );
36		switch( sz )
37		{
38		case 0:
39			printf( "[ scalar ]" );
40			break;
41		case 1:
42			printf( "[ %i ]", _mm_cvtsi128_si32( vec ) );
43			break;
44		case 2:
45			printf( "[ %i, %i ]", _mm_cvtsi128_si32( vec ), _mm_extract_epi32( vec, 1 ) );
46			break;
47		case 3:
48			printf( "[ %i, %i, %i ]", _mm_cvtsi128_si32( vec ), _mm_extract_epi32( vec, 1 ), _mm_extract_epi32( vec, 2 ) );
49			break;
50		case 4:
51			printf( "[ %i, %i, %i, %i ]", _mm_cvtsi128_si32( vec ), _mm_extract_epi32( vec, 1 ), _mm_extract_epi32( vec, 2 ), _mm_extract_epi32( vec, 3 ) );
52			break;
53		default:
54			throw E_UNEXPECTED;
55		}
56		return sz;
57	}
58
59	class Comparer
60	{
61		TraceReader& readerA;
62		TraceReader& readerB;
63
64		bool diffBuffers( size_t i, const sTraceItem& a, const sTraceItem& b, const CStringA& name )
65		{
66			const size_t lenA = *(const uint64_t*)a.size.data();
67			const size_t lenB = *(const uint64_t*)b.size.data();
68			if( lenA != lenB )
69			{
70				printf( "Buffer %zu \"%s\": different size, %zu in trace A, %zu in trace B\n", i, cstr( name ), lenA, lenB );
71				return false;
72			}
73			if( a.dataType != b.dataType )
74			{
75				printf( "Buffer %zu \"%s\": different data types\n", i, cstr( name ) );
76				return false;
77			}
78
79			switch( a.dataType )
80			{
81			case eDataType::FP32:
82				return buffersFp32( i, name, (const float*)readerA.payload( a ), (const float*)readerB.payload( b ), lenA );
83			}
84			throw E_NOTIMPL;
85		}
86
87		bool diffTensors( size_t i, const sTraceItem& a, const sTraceItem& b, const CStringA& name )
88		{
89			const __m128i ne1 = load( a.size );
90			const __m128i ne2 = load( b.size );
91			if( !vectorEqual( ne1, ne2 ) )
92			{
93				printf( "Tensor %zu \"%s\" - different size: trace A size is ", i, cstr( name ) );
94				printSize( ne1 );
95				printf( ", trace B size is " );
96				printSize( ne2 );
97				printf( "\n" );
98				return false;
99			}
100
101			const __m128i stride1 = load( a.stride );
102			const __m128i stride2 = load( b.stride );
103			if( !vectorEqual( stride1, stride2 ) )
104			{
105				printf( "Tensor %zu \"%s\" - different memory layout\n", i, cstr( name ) );
106				return false;
107			}
108
109			if( a.dataType != b.dataType )
110			{
111				printf( "Tensor %zu \"%s\": different data types\n", i, cstr( name ) );
112				return false;
113			}
114
115			size_t elements = (uint32_t)_mm_cvtsi128_si32( ne1 );
116			elements *= (uint32_t)_mm_extract_epi32( ne1, 1 );
117			elements *= (uint32_t)_mm_extract_epi32( ne1, 2 );
118			elements *= (uint32_t)_mm_extract_epi32( ne1, 3 );
119
120			switch( a.dataType )
121			{
122			case eDataType::FP32:
123				return tensorsFp32( i, name, (const float*)readerA.payload( a ), (const float*)readerB.payload( b ), elements, ne1, stride1 );
124			}
125			throw E_NOTIMPL;
126		}
127
128	protected:
129		virtual bool buffersFp32( size_t idx, const CStringA& name, const float* a, const float* b, size_t length ) = 0;
130		virtual bool tensorsFp32( size_t idx, const CStringA& name, const float* a, const float* b, size_t length, __m128i ne, __m128i nb ) = 0;
131
132	public:
133
134		Comparer( TraceReader& t1, TraceReader& t2 ) :
135			readerA( t1 ), readerB( t2 ) { }
136
137		bool compare( size_t i )
138		{
139			const sTraceItem& a = readerA[ i ];
140			const sTraceItem& b = readerB[ i ];
141			CStringA name1 = readerA.getName( a );
142			CStringA name2 = readerB.getName( b );
143
144			if( a.itemType != b.itemType )
145			{
146				printf( "Item %zu: different type, trace A %s \"%s\", trace B %s \"%s\"\n", i,
147					cstr( a.itemType ), cstr( name1 ), cstr( b.itemType ), cstr( name2 ) );
148				return false;
149			}
150
151			if( name1 != name2 )
152			{
153				printf( "%s %zu: different names, they are \"%s\" and \"%s\"\n", cstr( a.itemType ), i, cstr( name1 ), cstr( name2 ) );
154				return false;
155			}
156
157			switch( a.itemType )
158			{
159			case eItemType::Buffer:
160				return diffBuffers( i, a, b, name1 );
161			case eItemType::Tensor:
162				return diffTensors( i, a, b, name1 );
163			default:
164				throw E_INVALIDARG;
165			}
166		}
167	};
168
169	class PrintSummary : public Comparer
170	{
171		bool buffersFp32( size_t idx, const CStringA& name, const float* a, const float* b, size_t length ) override;
172		bool tensorsFp32( size_t idx, const CStringA& name, const float* a, const float* b, size_t length, __m128i ne, __m128i nb ) override;
173
174	public:
175		PrintSummary( TraceReader& a, TraceReader& b ) : Comparer( a, b ) { }
176	};
177
178	bool PrintSummary::buffersFp32( size_t idx, const CStringA& name, const float* a, const float* b, size_t length )
179	{
180		sTensorDiff diff = computeDiff( a, b, length );
181		printf( "%s %zu \"%s\": ", cstr( eItemType::Buffer ), idx, cstr( name ) );
182		diff.print();
183		return true;
184	}
185
186	bool PrintSummary::tensorsFp32( size_t idx, const CStringA& name, const float* a, const float* b, size_t length, __m128i ne, __m128i nb )
187	{
188		printSize( ne );
189		printf( " " );
190		sTensorDiff diff = computeDiff( a, b, length );
191		printf( "%s %zu \"%s\": ", cstr( eItemType::Tensor ), idx, cstr( name ) );
192		diff.print();
193		return true;
194	}
195
196	class PrintDiff : public Comparer
197	{
198		bool buffersFp32( size_t idx, const CStringA& name, const float* a, const float* b, size_t length ) override;
199		bool tensorsFp32( size_t idx, const CStringA& name, const float* a, const float* b, size_t length, __m128i ne, __m128i nb ) override;
200	public:
201		PrintDiff( TraceReader& a, TraceReader& b ) : Comparer( a, b ) { }
202	};
203
204	bool PrintDiff::buffersFp32( size_t idx, const CStringA& name, const float* A, const float* B, size_t length )
205	{
206		printf( "idx\tA\tB\tA(hex)\tB(hex)\tdiff\n" );
207		for( size_t i = 0; i < length; i++ )
208		{
209			const float a = *A;
210			const float b = *B;
211			__m128 vf = _mm_setr_ps( a, b, 0, 0 );
212			__m128i vi = _mm_castps_si128( vf );
213			const float diff = std::abs( a - b );
214			printf( "%zu\t%g\t%g\t0x%08X\t0x%08X\t%g\n",
215				i, a, b, _mm_cvtsi128_si32( vi ), _mm_extract_epi32( vi, 1 ), diff );
216		}
217		return true;
218	}
219
220	std::array<uint32_t, 4> storeSize( __m128i v )
221	{
222		std::array<uint32_t, 4> a;
223		_mm_storeu_si128( ( __m128i* )a.data(), v );
224		return a;
225	}
226
227	std::array<size_t, 4> storeStrides( __m128i v )
228	{
229		const __m128i zero = _mm_setzero_si128();
230		std::array<size_t, 4> a;
231		_mm_storeu_si128( ( __m128i* ) & a[ 0 ], _mm_unpacklo_epi32( v, zero ) );
232		_mm_storeu_si128( ( __m128i* ) & a[ 2 ], _mm_unpackhi_epi32( v, zero ) );
233		return a;
234	}
235
236	bool PrintDiff::tensorsFp32( size_t idx, const CStringA& name, const float* A, const float* B, size_t length, __m128i ne, __m128i nb )
237	{
238		const int dims = tensorDims( ne );
239		const std::array<uint32_t, 4> size = storeSize( ne );
240		const std::array<size_t, 4> strides = storeStrides( ne );
241		CStringA line;
242		if( dims > 4 )
243			throw E_UNEXPECTED;
244
245		for( int i = 0; i < dims; i++ )
246		{
247			const char c = "xyzw"[ i ];
248			line.AppendChar( c );
249			line.AppendChar( '\t' );
250		}
251		line += "A\tB\tA(hex)\tB(hex)\tdiff\n";
252		printf( "%s", cstr( line ) );
253
254		if( 0 == dims )
255		{
256			const float a = *A;
257			const float b = *B;
258			__m128 vf = _mm_setr_ps( a, b, 0, 0 );
259			__m128i vi = _mm_castps_si128( vf );
260			const float diff = std::abs( a - b );
261			printf( "%g\t%g\t0x%08X\t0x%08X\t%g\n",
262				a, b, _mm_cvtsi128_si32( vi ), _mm_extract_epi32( vi, 1 ), diff );
263			return true;
264		}
265
266		size_t offLayer2 = 0;
267		for( uint32_t w = 0; w < size[ 3 ]; w++, offLayer2 += strides[ 3 ] )
268		{
269			size_t offLayer = offLayer2;
270			for( uint32_t z = 0; z < size[ 2 ]; z++, offLayer += strides[ 2 ] )
271			{
272				size_t offRow = offLayer;
273				for( uint32_t y = 0; y < size[ 1 ]; y++, offRow += strides[ 1 ] )
274				{
275					size_t off = offRow;
276					for( uint32_t x = 0; x < size[ 0 ]; x++, off += strides[ 0 ] )
277					{
278						line.Format( "%i\t", x );
279						if( dims > 1 )
280							line.AppendFormat( "%i\t", y );
281						if( dims > 2 )
282							line.AppendFormat( "%i\t", z );
283						if( dims > 3 )
284							line.AppendFormat( "%i\t", w );
285
286						const float a = A[ off ];
287						const float b = B[ off ];
288						__m128 vf = _mm_setr_ps( a, b, 0, 0 );
289						__m128i vi = _mm_castps_si128( vf );
290						const float diff = std::abs( a - b );
291						line.AppendFormat( "%g\t%g\t0x%08X\t0x%08X\t%g\n",
292							a, b, _mm_cvtsi128_si32( vi ), _mm_extract_epi32( vi, 1 ), diff );
293						printf( "%s", cstr( line ) );
294					}
295				}
296			}
297		}
298		return true;
299	}
300}
301
302HRESULT compareTraces( const CommandLineArgs& arguments )
303{
304	const wchar_t* pathA = arguments.inputs[ 0 ];
305	const wchar_t* pathB = arguments.inputs[ 1 ];
306
307	TraceReader a, b;
308	HRESULT hr = a.open( pathA );
309	if( FAILED( hr ) )
310	{
311		fwprintf( stderr, L"Unable to load trace A from \"%s\"", pathA );
312		printError( hr );
313		return hr;
314	}
315
316	hr = b.open( pathB );
317	if( FAILED( hr ) )
318	{
319		fwprintf( stderr, L"Unable to load trace B from \"%s\"", pathA );
320		printError( hr );
321		return hr;
322	}
323
324	wprintf( L"Trace A:   %s\n", pathA );
325	wprintf( L"Trace B:   %s\n", pathB );
326	const size_t sizeA = a.size();
327	const size_t sizeB = b.size();
328	const size_t count = std::min( sizeA, sizeB );
329
330	if( arguments.printDiff >= 0 )
331	{
332		if( arguments.printDiff >= (int64_t)count )
333		{
334			fprintf( stderr, "Trace A has %zu entries, trace B %zu entries; entry %zu ain't there\n",
335				sizeA, sizeB, (size_t)arguments.printDiff );
336			return E_INVALIDARG;
337		}
338		try
339		{
340			PrintDiff print{ a, b };
341			print.compare( arguments.printDiff );
342			return S_OK;
343		}
344		catch( HRESULT hr )
345		{
346			return hr;
347		}
348	}
349
350	printf( "Trace A has %zu entries, trace B %zu entries, comparing first %zu\n", sizeA, sizeB, count );
351
352	try
353	{
354		PrintSummary print{ a, b };
355		for( size_t i = 0; i < count; i++ )
356			if( !print.compare( i ) )
357				return S_FALSE;
358		return S_OK;
359	}
360	catch( HRESULT hr )
361	{
362		return hr;
363	}
364}