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
3ba8e63
master
1#include "stdafx.h" 2#include "TensorsArena.h" 3#include "../D3D/createBuffer.h" 4#include "TempBuffers.h" 5 6static inline uint32_t roundUpPower2 (uint32_t x ) 7{ 8// std::bit_ceil from C++/20 standard library implements runtime dispatch, uses LZCNT when AVX2 is available, otherwise BSR 9// That's not what we want. 10// BSR is only slightly slower than LZCNT: same speed on Intel, on AMD it's 3 versus 1 cycles. 11// defaultNewCapacity function is only called occasionally, that branch is therefore unpredictable. 12assert (x > 1 ); 13unsigned long idx ; 14_BitScanReverse (& idx ,x - 1 ); 15return 2u <<idx ; 16} 17 18uint32_t DirectCompute ::defaultNewCapacity (uint32_t current ,uint32_t requested ) 19{ 20// Implement some reasonable tactics to compute capacity of these buffers 21 22constexpr uint32_t minAlloc = 1024 ;// 1k elements = 4kb of VRAM for FP32 tensors 23constexpr uint32_t allocGranularity = 1u <<14 ;// 16k elements = 64kb of VRAM for FP32 tensors 24 25if (requested > minAlloc ) 26 { 27const uint32_t roundedUpPowerOf2 = roundUpPower2 (requested ); 28 29constexpr uint32_t lowMask = allocGranularity - 1 ; 30constexpr uint32_t highMask = ~lowMask ; 31const uint32_t roundedUpGranularity = (requested + lowMask )& highMask ; 32 33const uint32_t res = std::min (roundedUpPowerOf2 ,roundedUpGranularity ); 34 35assert (res >=requested ); 36return res ; 37 } 38 39return minAlloc ; 40} 41 42using namespace DirectCompute ; 43 44TensorsArena ::ArenaImpl ::ArenaImpl (eDataType dataType ,const sArenaConfig & config ) : 45type (dataType ), 46pfnNewCap (nullptr != config .pfnCapInner ?config .pfnCapInner :& defaultNewCapacity ) 47{ 48pool .reserve (config .initialCapOuter ); 49} 50 51Tensor PooledTensor ::tensor (eDataType type ,const std::array < uint32_t ,4 >& ne ,pfnNewCapacity pfnNewCap ) 52{ 53const uint32_t p1 = ne [0 ]* ne [1 ]; 54const uint32_t p2 = ne [2 ]* ne [3 ]; 55const uint32_t count = p1 * p2 ; 56 57if (count > capacity ) 58 { 59views .clear (); 60const uint32_t newCap = pfnNewCap (capacity ,count ); 61assert (newCap >=count ); 62 63const size_t cb = elementSize (type )* newCap ; 64CComPtr < ID3D11Buffer > buffer ; 65check (createBuffer ( eBufferUse::ReadWrite ,cb ,& buffer ,nullptr ,nullptr ) ); 66check (views .create (buffer ,viewFormat (type ),newCap , true ) ); 67capacity = newCap ; 68 } 69 70TensorShape shape ; 71shape .ne = ne ; 72shape .setDenseStrides (); 73Tensor res {shape ,views }; 74res .dbgSetType (type ); 75return res ; 76} 77 78Tensor TensorsArena ::ArenaImpl ::tensor (const std::array < uint32_t ,4 >& ne ) 79{ 80PooledTensor * res ; 81if (index >=pool .size () ) 82 { 83assert (index == pool .size () ); 84res = & pool .emplace_back (); 85 } 86else 87res = & pool [index ]; 88 89index ++ ; 90return res -> tensor (type ,ne ,pfnNewCap ); 91} 92 93TensorsArena ::TensorsArena (const sArenaConfigs & configs ) : 94arenas {ArenaImpl { eDataType::FP16 ,configs .fp16 },ArenaImpl { eDataType::FP32 ,configs .fp32 } } 95{ 96 static_assert(0 == (uint8_t )eDataType::FP16 ); 97 static_assert(1 == (uint8_t )eDataType::FP32 ); 98} 99 100Tensor TensorsArena ::tensor (eDataType type ,const std::array < uint32_t ,4 >& ne ) 101{ 102ArenaImpl & arena = arenas [ (uint8_t )type ]; 103return arena .tensor (ne ); 104} 105 106void TensorsArena ::reset () 107{ 108for (ArenaImpl & a :arenas ) 109a .reset (); 110} 111 112void TensorsArena ::clear () 113{ 114for (ArenaImpl & a :arenas ) 115a .clear (); 116} 117 118__m128i TensorsArena ::ArenaImpl ::getMemoryUse ()const 119{ 120const size_t cbElement = elementSize (type ); 121size_t countElts = 0 ; 122for (const auto & t :pool ) 123countElts += t .getCapacity (); 124 125const size_t cbVideo = cbElement * countElts ; 126const size_t cbSystem = vectorMemoryUse (pool ); 127return setr_size (cbSystem ,cbVideo ); 128} 129 130__m128i TensorsArena ::getMemoryUse ()const 131{ 132__m128i res = _mm_setzero_si128 (); 133for (const auto & a :arenas ) 134res = _mm_add_epi64 (res ,a .getMemoryUse () ); 135return res ; 136} 137 138HRESULT PooledTensor ::zeroMemory (CComPtr < ID3D11Buffer >& cb ) 139{ 140if (0 == capacity ) 141return S_FALSE ; 142try 143 { 144TempBuffers ::zeroMemory (views ,capacity ,cb ); 145return S_OK ; 146 } 147catch (HRESULT hr ) 148 { 149return hr ; 150 } 151} 152 153HRESULT TensorsArena ::ArenaImpl ::zeroMemory (CComPtr < ID3D11Buffer >& cb ) 154{ 155for (PooledTensor & e :pool ) 156CHECK (e .zeroMemory (cb ) ); 157return S_OK ; 158} 159 160HRESULT TensorsArena ::zeroMemory (CComPtr < ID3D11Buffer >& cb ) 161{ 162for (ArenaImpl & e :arenas ) 163CHECK (e .zeroMemory (cb ) ); 164return S_OK ; 165}