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
8c4603c
master
1#include <stdafx.h> 2#include <atomic> 3#include "Tensor.h" 4using namespace CpuCompute ; 5 6#if TENSOR_INTERNAL_ALLOC 7namespace 8{ 9// This structure is immediately before the payload of every tensor which has an internally-allocated memory buffer 10class alignas(32 )sTensorMemoryHeader 11 { 12 std::atomic_ptrdiff_t refCounter ; 13public : 14// Reset the counter to the specified value 15void reset (ptrdiff_t rc ) 16 { 17refCounter = rc ; 18 } 19// Increment the ref.counter 20void increment () 21 { 22refCounter ++ ; 23 } 24// Decrement the ref.counter, and return true if it reached zero as the result 25bool decrement () 26 { 27ptrdiff_t val = -- refCounter ; 28assert (val >=0 ); 29return 0 == val ; 30 } 31 }; 32 33inline sTensorMemoryHeader * getMemBlockHeader (void * pv ) 34 { 35assert (nullptr != pv ); 36uint8_t * pb = (uint8_t * )pv ; 37 static_assert(sizeof (sTensorMemoryHeader )== 32 ); 38return (sTensorMemoryHeader * )(pb - sizeof (sTensorMemoryHeader ) ); 39 } 40 41inline void releaseBlock (sTensorMemoryHeader * pointer ) 42 { 43assert (nullptr != pointer ); 44_aligned_free (pointer ); 45 } 46 47inline void * allocateBlock (size_t cb ,ptrdiff_t initialRefCounter = 1 ) 48 { 49cb += sizeof (sTensorMemoryHeader ); 50void * pv = _aligned_malloc (cb ,32 ); 51if (nullptr == pv ) 52return nullptr ; 53 54sTensorMemoryHeader * header = (sTensorMemoryHeader * )pv ; 55header -> reset (initialRefCounter ); 56return ( (uint8_t * )pv )+ sizeof (sTensorMemoryHeader ); 57 } 58} 59 60void Tensor ::deallocate () 61{ 62if (ownsMemory && nullptr != m_data ) 63 { 64sTensorMemoryHeader * const header = getMemBlockHeader (m_data ); 65if (header -> decrement () ) 66 { 67// This tensor is the last one which had a reference to that block of memory 68// Release the memory back to the heap 69releaseBlock (header ); 70 } 71 } 72ownsMemory = false; 73 74TensorShape ::setZero (); 75m_data = nullptr ; 76m_type = (eDataType )0xFF ; 77} 78#endif 79 80Tensor ::Tensor (const Tensor & that ) 81{ 82store (ne ,that .sizeVec () ); 83store (nb ,that .stridesVec () ); 84m_data = that .m_data ; 85m_type = that .m_type ; 86#if TENSOR_INTERNAL_ALLOC 87if (that .ownsMemory && nullptr != m_data ) 88 { 89getMemBlockHeader (m_data )-> increment (); 90ownsMemory = true; 91 } 92else 93ownsMemory = false; 94#endif 95} 96 97Tensor ::Tensor (Tensor && that )noexcept 98{ 99store (ne ,that .sizeVec () ); 100store (nb ,that .stridesVec () ); 101m_data = that .m_data ; 102m_type = that .m_type ; 103#if TENSOR_INTERNAL_ALLOC 104ownsMemory = that .ownsMemory ; 105that .ownsMemory = false; 106#endif 107that .m_data = nullptr ; 108} 109 110void Tensor ::operator= (const Tensor & that ) 111{ 112assert (this != & that ); 113#if TENSOR_INTERNAL_ALLOC 114deallocate (); 115#endif 116 117store (ne ,that .sizeVec () ); 118store (nb ,that .stridesVec () ); 119m_data = that .m_data ; 120m_type = that .m_type ; 121#if TENSOR_INTERNAL_ALLOC 122if (that .ownsMemory && nullptr != m_data ) 123 { 124getMemBlockHeader (m_data )-> increment (); 125ownsMemory = true; 126 } 127else 128ownsMemory = false; 129#endif 130} 131 132void Tensor ::operator= (Tensor && that )noexcept 133{ 134assert (this != & that ); 135#if TENSOR_INTERNAL_ALLOC 136deallocate (); 137#endif 138store (ne ,that .sizeVec () ); 139store (nb ,that .stridesVec () ); 140m_data = that .m_data ; 141m_type = that .m_type ; 142that .m_data = nullptr ; 143#if TENSOR_INTERNAL_ALLOC 144ownsMemory = that .ownsMemory ; 145that .ownsMemory = false; 146#endif 147} 148 149HRESULT Tensor ::create (eDataType type ,const std::array < uint32_t ,4 >& sizeElements ,iMemoryAllocator * alloc ) 150{ 151const size_t len = (size_t )sizeElements [0 ]* sizeElements [1 ]* sizeElements [2 ]* sizeElements [3 ]; 152const size_t cbElement = DirectCompute ::elementSize (type ); 153const size_t cb = len * cbElement ; 154 155#if TENSOR_INTERNAL_ALLOC 156deallocate (); 157#endif 158 159store (ne ,load (sizeElements ) ); 160TensorShape ::setDenseStrides (); 161this -> m_type = type ; 162 163if (nullptr != alloc ) 164 { 165#if TENSOR_INTERNAL_ALLOC 166ownsMemory = false; 167#endif 168m_data = alloc -> allocate (cb ,32 ); 169if (nullptr == m_data ) 170return E_OUTOFMEMORY ; 171return S_OK ; 172 } 173else 174 { 175#if TENSOR_INTERNAL_ALLOC 176m_data = allocateBlock (cb ,1 ); 177if (nullptr == m_data ) 178return E_OUTOFMEMORY ; 179ownsMemory = true; 180return S_OK ; 181#else 182return E_POINTER ; 183#endif 184 } 185} 186 187namespace 188{ 189static HRESULT arrayFromList ( std::array < uint32_t ,4 >& arr , std::initializer_list < uint32_t > list ) 190 { 191const size_t dims = list .size (); 192if (dims == 0 || dims > 4 ) 193return E_INVALIDARG ; 194 195for (size_t i = 0 ;i < dims ;i ++ ) 196 { 197uint32_t u = list .begin ()[i ]; 198if (u == 0 ) 199return E_INVALIDARG ; 200arr [i ]= u ; 201 } 202 203for (size_t i = dims ;i < 4 ;i ++ ) 204arr [i ]= 1 ; 205 206return S_OK ; 207 } 208} 209 210HRESULT Tensor ::create (eDataType type , std::initializer_list < uint32_t > sizeElements ,iMemoryAllocator * alloc ) 211{ 212 std::array < uint32_t ,4 > arr ; 213CHECK (arrayFromList (arr ,sizeElements ) ); 214 215return create (type ,arr ,alloc ); 216} 217 218Tensor ::Tensor (void * pointer ,eDataType type , std::initializer_list < uint32_t > size ) 219{ 220if (nullptr == pointer ) 221throw E_POINTER ; 222check (arrayFromList (ne ,size ) ); 223TensorShape ::setDenseStrides (); 224m_data = pointer ; 225m_type = type ; 226#if TENSOR_INTERNAL_ALLOC 227ownsMemory = false; 228#endif 229} 230 231Tensor ::Tensor (void * pointer ,eDataType type ,uint32_t length )noexcept 232{ 233// size = [ length, 1, 1, 1 ] 234const __m128i one = _mm_set1_epi32 (1 ); 235__m128i v = _mm_insert_epi32 (one , (int )length ,0 ); 236store (ne ,v ); 237// stride = [ 1, length, length, length ] 238v = _mm_shuffle_epi32 (v ,_MM_SHUFFLE (0 ,0 ,0 ,1 ) ); 239store (nb ,v ); 240 241m_data = pointer ; 242m_type = type ; 243#if TENSOR_INTERNAL_ALLOC 244ownsMemory = false; 245#endif 246} 247 248Tensor Tensor ::fromData (void * pointer ,eDataType type ,uint32_t length ) 249{ 250HRESULT hr = E_UNEXPECTED ; 251if (nullptr != pointer ) 252 { 253if (0 != length ) 254return Tensor {pointer ,type ,length }; 255else 256hr = E_INVALIDARG ; 257 } 258else 259hr = E_POINTER ; 260throw hr ; 261} 262 263HRESULT Tensor ::attach (void * pointer ,eDataType type , std::initializer_list < uint32_t > sizeElements ) 264{ 265if (nullptr == pointer ) 266return E_POINTER ; 267 268 std::array < uint32_t ,4 > arr ; 269CHECK (arrayFromList (arr ,sizeElements ) ); 270 271#if TENSOR_INTERNAL_ALLOC 272deallocate (); 273#endif 274store (ne ,load (arr ) ); 275TensorShape ::setDenseStrides (); 276 277m_data = pointer ; 278this -> m_type = type ; 279#if TENSOR_INTERNAL_ALLOC 280ownsMemory = false; 281#endif 282return S_OK ; 283} 284 285Tensor Tensor ::reshape3d (uint32_t ne0 ,uint32_t ne1 ,uint32_t ne2 )const 286{ 287if ( !isContinuous () ) 288throw E_NOTIMPL ; 289if (countElements ()!= ne0 * ne1 * ne2 ) 290throw E_INVALIDARG ; 291 292Tensor res = * this ; 293res .ne = {ne0 ,ne1 ,ne2 ,1 }; 294res .setDenseStrides (); 295return res ; 296} 297 298#if TENSOR_GGML_COMPAT 299static const __m128i s_maskAlignment16 = _mm_set1_epi64x (1 ); 300static const __m128i s_maskAlignment32 = _mm_set1_epi64x (3 ); 301 302bool isAlignedProperly (__m128i r0 ,__m128i r1 ,__m128i mask ) 303{ 304__m128i test = _mm_or_si128 (r0 ,r1 ); 305return (bool )_mm_testz_si128 (test ,mask ); 306} 307 308Tensor ::Tensor (const ggml_tensor * ggml ) 309{ 310store (ne ,load16 (ggml -> ne ) ); 311 312__m128i r0 = load16 ( (const int * )& ggml -> nb [0 ] ); 313__m128i r1 = load16 ( (const int * )& ggml -> nb [2 ] ); 314// Divide from bytes into elements by right-shifting the 64-bit integers in these vectors 315switch (ggml -> type ) 316 { 317case GGML_TYPE_F16 : 318assert (isAlignedProperly (r0 ,r1 ,s_maskAlignment16 ) ); 319r0 = _mm_srli_epi64 (r0 ,1 ); 320r1 = _mm_srli_epi64 (r1 ,1 ); 321m_type = eDataType::FP16 ; 322break ; 323 324case GGML_TYPE_F32 : 325assert (isAlignedProperly (r0 ,r1 ,s_maskAlignment32 ) ); 326r0 = _mm_srli_epi64 (r0 ,2 ); 327r1 = _mm_srli_epi64 (r1 ,2 ); 328m_type = eDataType::FP32 ; 329break ; 330 331case GGML_TYPE_I32 : 332assert (isAlignedProperly (r0 ,r1 ,s_maskAlignment32 ) ); 333r0 = _mm_srli_epi64 (r0 ,2 ); 334r1 = _mm_srli_epi64 (r1 ,2 ); 335m_type = eDataType::U32 ; 336break ; 337 338default : 339throw E_INVALIDARG ; 340 } 341// downcast uint64_t into uint32_t in a single vector 342r0 = _mm_shuffle_epi32 (r0 ,_MM_SHUFFLE (3 ,3 ,2 ,0 ) ); 343r1 = _mm_shuffle_epi32 (r1 ,_MM_SHUFFLE (2 ,0 ,3 ,3 ) ); 344store (nb ,_mm_blend_epi16 (r0 ,r1 ,0b11110000 ) ); 345 346m_data = ggml -> data ; 347} 348 349ggml_tensor Tensor ::ggml ()const 350{ 351ggml_tensor res ; 352memset (& res ,0 ,sizeof (ggml_tensor ) ); 353 354const __m128i size = sizeVec (); 355store16 (res .ne ,size ); 356 357const __m128i one = _mm_set1_epi32 (1 ); 358const uint32_t maskOnes = (uint32_t )_mm_movemask_ps (_mm_castsi128_ps (_mm_cmpeq_epi32 (size ,one ) ) ); 359const uint32_t maskNotOnes = maskOnes ^0b1111 ; 360unsigned long idx ; 361if (_BitScanReverse (& idx ,maskNotOnes ) ) 362res .n_dims = (int )idx + 1 ; 363else 364res .n_dims = 0 ; 365 366const __m128i strides = stridesVec (); 367// Upcast strides from u32 to u64 368const __m128i zero = _mm_setzero_si128 (); 369__m128i r0 = _mm_unpacklo_epi32 (strides ,zero ); 370__m128i r1 = _mm_unpackhi_epi32 (strides ,zero ); 371// Scale from elements into bytes with left shift vector instructions 372switch (m_type ) 373 { 374case eDataType::FP16 : 375r0 = _mm_slli_epi64 (r0 ,1 ); 376r1 = _mm_slli_epi64 (r1 ,1 ); 377res .type = GGML_TYPE_F16 ; 378break ; 379case eDataType::FP32 : 380r0 = _mm_slli_epi64 (r0 ,2 ); 381r1 = _mm_slli_epi64 (r1 ,2 ); 382res .type = GGML_TYPE_F32 ; 383break ; 384case eDataType::U32 : 385r0 = _mm_slli_epi64 (r0 ,2 ); 386r1 = _mm_slli_epi64 (r1 ,2 ); 387res .type = GGML_TYPE_I32 ; 388break ; 389default : 390throw OLE_E_BLANK ; 391 } 392 393store16 (& res .nb [0 ],r0 ); 394store16 (& res .nb [2 ],r1 ); 395 396res .data = m_data ; 397return res ; 398} 399 400GgmlTensorView ::GgmlTensorView (const Tensor & t ) :tensor (t .ggml () ) {} 401#endif