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
6.6 KiB263 linesraw
1#include "stdafx.h"
2#include "TraceWriter.h"
3#include <atlfile.h>
4#include <atlcoll.h>
5#include <atlstr.h>
6#include "TraceStructures.h"
7#include "../../ML/Tensor.h"
8#include "../../CPU/Tensor.h"
9#include <Shlobj.h>
10using namespace Tracing;
11
12namespace
13{
14	static HRESULT createDir( LPCTSTR pathFile )
15	{
16		LPCWSTR fn = PathFindFileName( pathFile );
17		if( fn == pathFile )
18			return E_FAIL;
19
20		const int cc = (int)( fn - pathFile );
21		CString dir{ pathFile, cc };
22		if( PathIsDirectory( dir ) )
23			return S_OK;
24		const int status = SHCreateDirectoryEx( nullptr, dir, nullptr );
25		if( 0 == status )
26			return S_OK;
27		return HRESULT_FROM_WIN32( status );
28	}
29
30	class TraceFileWriter
31	{
32		CAtlFile file;
33		// Concatenated strings, including the 0 terminators
34		std::vector<char> stringsData;
35		// Index = string ID, value = start offset into stringsData
36		std::vector<uint32_t> stringsIndex;
37		// Hash map to unduplicate these strings
38		CAtlMap<CStringA, uint32_t> stringsHash;
39
40		uint32_t addString( const CStringA& s )
41		{
42			auto p = stringsHash.Lookup( s );
43			if( p != nullptr )
44				return p->m_value;
45
46			const uint32_t off = (uint32_t)stringsData.size();
47			const char* rsi = s;
48			stringsData.insert( stringsData.end(), rsi, rsi + s.GetLength() + 1 );
49			stringsIndex.push_back( off );
50
51			const uint32_t newId = (uint32_t)stringsHash.GetCount();
52			stringsHash.SetAt( s, newId );
53			return newId;
54		}
55
56		void addString( sTraceItem& rdi, const ItemName& name )
57		{
58			rdi.countFormatArgs = name.countArgs;
59			rdi.stringIndex = addString( name.pointer );
60			rdi.formatArgs = name.args;
61		}
62
63		std::vector<sTraceItem> items;
64		uint64_t offset = 0;
65
66	public:
67
68		HRESULT create( LPCTSTR path )
69		{
70			CHECK( createDir( path ) );
71			CHECK( file.Create( path, GENERIC_WRITE, 0, CREATE_ALWAYS ) );
72
73			constexpr uint64_t cbHeader = sizeof( sFileHeader );
74			CHECK( file.SetSize( cbHeader ) );
75			CHECK( file.Seek( 0, SEEK_END ) );
76			offset = 0;
77
78			return S_OK;
79		}
80
81		HRESULT buffer( const ItemName& name, const void* rsi, size_t length, eDataType dt )
82		{
83			sTraceItem& rdi = items.emplace_back();
84			const uint64_t cb = rdi.buffer( offset, length, dt );
85			addString( rdi, name );
86			assert( cb <= UINT_MAX );
87			CHECK( file.Write( rsi, (DWORD)cb ) );
88			offset += cb;
89			return S_OK;
90		}
91
92		HRESULT tensor( const ItemName& name, const void* rsi, __m128i size, __m128i strides, eDataType dt )
93		{
94			sTraceItem& rdi = items.emplace_back();
95			const uint64_t cb = rdi.tensor( offset, size, strides, dt );
96			addString( rdi, name );
97			assert( cb <= UINT_MAX );
98			CHECK( file.Write( rsi, (DWORD)cb ) );
99			offset += cb;
100			return S_OK;
101		}
102
103		HRESULT close()
104		{
105			if( !file )
106				return S_FALSE;
107
108			const uint32_t cbStringsData = (uint32_t)stringsData.size();
109			const uint32_t cbStringsIndex = (uint32_t)( stringsIndex.size() * 4 );
110			if( !stringsIndex.empty() )
111				CHECK( file.Write( stringsIndex.data(), cbStringsIndex ) );
112			if( !stringsData.empty() )
113				CHECK( file.Write( stringsData.data(), cbStringsData ) );
114
115			const uint32_t cbItems = (uint32_t)items.size() * (uint32_t)sizeof( sTraceItem );
116			if( !items.empty() )
117				CHECK( file.Write( items.data(), cbItems ) );
118			CHECK( file.Seek( 0, FILE_BEGIN ) );
119
120			sFileHeader header;
121			memset( &header, 0, sizeof( header ) );
122			header.magic = header.correctMagic;
123			header.cbItem = sizeof( sTraceItem );
124			header.countItems = (uint32_t)items.size();
125			header.bytesPayload = offset;
126			header.countStrings = (uint32_t)stringsIndex.size();
127			header.bytesStrings = cbStringsData + cbStringsIndex;
128			CHECK( file.Write( &header, sizeof( header ) ) );
129			CHECK( file.Flush() );
130			file.Close();
131
132			return S_OK;
133		}
134	};
135
136	class TraceWriter : public iTraceWriter
137	{
138		TraceFileWriter file;
139
140		HRESULT buffer( const ItemName& name, const void* rsi, size_t length, eDataType dt ) override final
141		{
142			return file.buffer( name, rsi, length, dt );
143		}
144
145		HRESULT tensor( const ItemName& name, const void* rsi, __m128i size, __m128i strides, eDataType dt ) override final
146		{
147			return file.tensor( name, rsi, size, strides, dt );
148		}
149
150	public:
151
152		TraceWriter( LPCTSTR path )
153		{
154			check( file.create( path ) );
155		}
156
157		~TraceWriter()
158		{
159			check( file.close() );
160		}
161	};
162}
163
164std::unique_ptr<iTraceWriter> iTraceWriter::create( LPCTSTR path )
165{
166	return std::make_unique<TraceWriter>( path );
167}
168
169namespace
170{
171	static std::vector<float> tempFp32;
172	static std::vector<uint16_t> tempFp16;
173
174	template<class E>
175	inline const void* ptr( const std::vector<E>& vec )
176	{
177		return vec.empty() ? nullptr : vec.data();
178	}
179}
180
181HRESULT iTraceWriter::tensor( const ItemName& name, const DirectCompute::Tensor& source )
182{
183	const __m128i size = source.sizeVec();
184	const __m128i strides = source.stridesVec();
185	const eDataType dt = source.getType();
186	if( dt == eDataType::FP32 )
187	{
188		source.download( tempFp32 );
189		return tensor( name, ptr( tempFp32 ), size, strides, eDataType::FP32 );
190	}
191	else if( dt == eDataType::FP16 )
192	{
193		source.download( tempFp16 );
194		return tensor( name, ptr( tempFp16 ), size, strides, eDataType::FP16 );
195	}
196	return E_NOTIMPL;
197}
198
199HRESULT iTraceWriter::tensor( const ItemName& name, const CpuCompute::Tensor& source )
200{
201	const __m128i size = source.sizeVec();
202	const __m128i strides = source.stridesVec();
203	const eDataType dt = source.type();
204
205	if( dt == eDataType::FP32 )
206		return tensor( name, source.fp32(), size, strides, eDataType::FP32 );
207	else if( dt == eDataType::FP16 )
208		return tensor( name, source.fp16(), size, strides, eDataType::FP16 );
209	else
210		return E_NOTIMPL;
211}
212
213#if BUILD_BOTH_VERSIONS
214#include "../../source/ggml.h"
215HRESULT __declspec( noinline ) iTraceWriter::tensor( const ItemName& name, const ggml_tensor& source )
216{
217	__m128i size = load16( source.ne );
218	__m128i strides = _mm_setr_epi32(
219		(int)(uint32_t)source.nb[ 0 ],
220		(int)(uint32_t)source.nb[ 1 ],
221		(int)(uint32_t)source.nb[ 2 ],
222		(int)(uint32_t)source.nb[ 3 ] );
223
224	const __m128i ones = _mm_set1_epi32( 1 );
225	switch( source.n_dims )
226	{
227	case 0:
228		size = ones;
229		break;
230	case 1:
231		size = _mm_blend_epi16( size, ones, 0b11111100 );
232		break;
233	case 2:
234		size = _mm_blend_epi16( size, ones, 0b11110000 );
235		break;
236	case 3:
237		size = _mm_blend_epi16( size, ones, 0b11000000 );
238		break;
239	case 4:
240		break;
241	default:
242		return E_INVALIDARG;
243	}
244
245	const ggml_type dt = source.type;
246	switch( dt )
247	{
248	case GGML_TYPE_F16:
249		strides = _mm_srli_epi32( strides, 1 );
250		return tensor( name, source.data, size, strides, eDataType::FP16 );
251	case GGML_TYPE_F32:
252		strides = _mm_srli_epi32( strides, 2 );
253		return tensor( name, source.data, size, strides, eDataType::FP32 );
254	default:
255		return E_NOTIMPL;
256}
257}
258#else
259HRESULT iTraceWriter::tensor( const ItemName& name, const ggml_tensor& source )
260{
261	return E_NOTIMPL;
262}
263#endif