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
15dbcac
master
1#pragma once 2#include <stdint.h> 3#include <array> 4#include <smmintrin.h> 5 6struct ggml_tensor ; 7using HRESULT = long ; 8 9namespace DirectCompute 10{ 11// This POD structure describes the shape of a tensor. 12// It’s used for both GPU tensors in VRAM, and tensors in system memory used by the Hybrid model. 13struct TensorShape 14 { 15// Count of elements, up to 4 coordinates 16// The unused coordinates are set to 1 17std ::array < uint32_t ,4 > ne ; 18 19// Strides of the tensor 20// For a dense row-major tensor, these numbers are [ 1, ne[0], ne[0]*ne[1], ne[0]*ne[1]*ne[2] ] 21// Note that unlike GGML code, these numbers are expressed in elements not bytes, but the meaning is the same 22// GPU matrices reshaped into panels are keeping different values here: [ 0, panelSize, panelSize * panelsCount, panelSize * panelsCount * ne[ 2 ] ] 23std ::array < uint32_t ,4 > nb ; 24 25TensorShape (); 26TensorShape ( const TensorShape & that ); 27void operator = ( const TensorShape & that ); 28HRESULT create ( const ggml_tensor & ggml ); 29TensorShape ( const ggml_tensor & ggml ); 30 31__m128i __vectorcall sizeVec () const 32{ 33return load ( ne ); 34} 35__m128i __vectorcall stridesVec () const 36{ 37return load ( nb ); 38} 39 40uint32_t countRows () const 41{ 42return ne [ 1 ] * ne [ 2 ] * ne [ 3 ]; 43} 44 45uint32_t countElements () const 46{ 47// return ne[ 0 ] * countRows(); 48const __m128i a = sizeVec (); 49const __m128i b = _mm_srli_si128 ( a , 4 ); 50const __m128i p2 = _mm_mul_epu32 ( a , b ); 51uint64_t res = (uint64_t) _mm_extract_epi64 ( p2 , 1 ); 52res *= (uint64_t) _mm_cvtsi128_si64 ( p2 ); 53assert ( 0 == ( res >> 32 ) ); 54return ( uint32_t ) res ; 55} 56 57// Compute strides from sizes, assuming dense row-major memory layout of the tensor 58void setDenseStrides (); 59 60bool isMatrix () const 61{ 62// return ne[ 2 ] == 1 && ne[ 3 ] == 1; 63const uint64_t num = * ( const uint64_t * ) & ne [ 2 ]; 64return num == 0x100000001ull ; 65} 66bool isVector () const 67{ 68return 1 == ne [ 1 ] && isMatrix (); 69} 70 71// True of this tensor is dense and row-major 72bool isContinuous () const 73{ 74/* return 1 == nb[ 0 ] && 75nb[ 1 ] == nb[ 0 ] * ne[ 0 ] && 76nb[ 2 ] == nb[ 1 ] * ne[ 1 ] && 77nb[ 3 ] == nb[ 2 ] * ne[ 2 ]; */ 78 79const __m128i nbv = stridesVec (); 80const __m128i nev = sizeVec (); 81__m128i tmp = _mm_mullo_epi32 ( nbv , nev ); // Vertical product of int32 lanes 82tmp = _mm_shuffle_epi32 ( tmp, _MM_SHUFFLE ( 2 , 1 , 0 , 0 ) ); // Shift left by 1 int32 lane 83tmp = _mm_insert_epi32 ( tmp, 1 , 0 ); // Reset X lane to 1 84return vectorEqual ( tmp , nbv ); 85} 86 87// Reset all fields to zero 88void setZero () 89{ 90const __m128i z = _mm_setzero_si128 (); 91_mm_storeu_si128 ( ( __m128i * )ne. data (), z ); 92_mm_storeu_si128 ( ( __m128i * )nb. data (), z ); 93} 94}; 95 96// True when two tensors have equal count of elements 97inline bool isSameShape ( const TensorShape & t0, const TensorShape & t1 ) 98{ 99__m128i a = t0. sizeVec (); 100__m128i b = t1. sizeVec (); 101return vectorEqual ( a, b ); 102} 103 104// True when two tensors have equal count of elements, and equal VRAM layout too 105inline bool isSameShapeAndLayout ( const TensorShape & t0, const TensorShape & t1 ) 106{ 107__m128i a, b, x; 108a = t0. sizeVec (); 109b = t1. sizeVec (); 110x = _mm_xor_si128 ( a, b ); 111 112a = t0. stridesVec (); 113b = t1. stridesVec (); 114x = _mm_or_si128 ( x, _mm_xor_si128 ( a, b ) ); 115return ( bool ) _mm_testz_si128 ( x, x ); 116} 117 118// True when we can multiply two tensors of the provided shapes 119bool canMulMat ( const TensorShape & t0, const TensorShape & t1 ); 120}