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
aaeab77
master
1#include "stdafx.h" 2#include "ProfileCollection.h" 3#include "GpuProfiler.h" 4#include "../Whisper/WhisperModel.h" 5#include "../D3D/shaderNames.h" 6using namespace Whisper ; 7 8ProfileCollection ::Measure & ProfileCollection ::measure (DirectCompute ::eProfilerBlock which ) 9{ 10uint32_t key = (uint16_t )which ; 11key |=0x20000 ; 12return measures [key ]; 13} 14 15ProfileCollection ::Measure & ProfileCollection ::measure (DirectCompute ::eComputeShader which ) 16{ 17uint32_t key = (uint16_t )which ; 18key |=0x30000 ; 19return measures [key ]; 20} 21 22ProfileCollection ::Measure & ProfileCollection ::measure (eCpuBlock which ) 23{ 24uint32_t key = (uint8_t )which ; 25key |=0x10000 ; 26CComCritSecLock < CComAutoCriticalSection > lock {critSec }; 27return measures [key ]; 28} 29 30#if PROFILER_COLLECT_TAGS 31ProfileCollection ::Measure & ProfileCollection ::measure (DirectCompute ::eComputeShader which ,uint16_t tag ) 32{ 33uint32_t key = (uint8_t )which ; 34key = key <<16 ; 35key |=tag ; 36CComCritSecLock < CComAutoCriticalSection > lock {critSec }; 37return taggedShaders [key ]; 38} 39#endif 40 41namespace 42{ 43using pfnPrintEnum = const char * (* )(uint16_t val ); 44 45static const char * printCpuBlock (uint16_t id ) 46 { 47const eCpuBlock which = (eCpuBlock )id ; 48switch (which ) 49 { 50#define V (x ) case eCpuBlock::x: return #x 51V (LoadModel ); 52V (RunComplete ); 53V (Run ); 54V (Callbacks ); 55V (Spectrogram ); 56V (Sample ); 57V (VAD ); 58V (Encode ); 59V (Decode ); 60V (DecodeStep ); 61V (DecodeLayer ); 62#undef V 63 } 64assert ( false ); 65return nullptr ; 66 } 67 68static const char * printGpuBlock (uint16_t id ) 69 { 70using DirectCompute ::eProfilerBlock ; 71const eProfilerBlock which = (eProfilerBlock )id ; 72 73switch (which ) 74 { 75#define V (x ) case eProfilerBlock::x: return #x 76V (LoadModel ); 77V (Run ); 78V (Encode ); 79V (EncodeLayer ); 80V (Decode ); 81V (DecodeStep ); 82V (DecodeLayer ); 83#undef V 84 } 85assert ( false ); 86return nullptr ; 87 } 88 89static const char * printShader (uint16_t id ) 90 { 91return DirectCompute ::computeShaderName ( (DirectCompute ::eComputeShader )id ); 92 } 93 94static pfnPrintEnum printSectionStart (uint16_t type ) 95 { 96switch (type ) 97 { 98case 1 : 99logInfo (u8" CPU Tasks" ); 100return & printCpuBlock ; 101case 2 : 102logInfo (u8" GPU Tasks" ); 103return & printGpuBlock ; 104case 3 : 105logInfo (u8" Compute Shaders" ); 106return & printShader ; 107default : 108return nullptr ; 109 } 110 } 111 112struct PrintedTime 113 { 114double value ; 115const char * unit ; 116 117PrintedTime (uint64_t ticks ) 118 { 119const double dbl = (double )(int64_t )ticks ; 120if (ticks >=10'000'000 ) 121 { 122value = dbl /1.0E+7 ; 123unit = "seconds" ; 124 } 125else if (ticks >=10'000 ) 126 { 127value = dbl /1.0E+4 ; 128unit = "milliseconds" ; 129 } 130else 131 { 132value = dbl /1.0E+1 ; 133unit = "microseconds" ; 134 } 135 } 136PrintedTime (double dbl ) 137 { 138if (dbl >=10'000'000 ) 139 { 140value = dbl /1.0E+7 ; 141unit = "seconds" ; 142 } 143else if (dbl >=10'000 ) 144 { 145value = dbl /1.0E+4 ; 146unit = "milliseconds" ; 147 } 148else 149 { 150value = dbl /1.0E+1 ; 151unit = "microseconds" ; 152 } 153 } 154 }; 155} 156 157void ProfileCollection ::Measure ::const char * name )const 158{ 159PrintedTime total {totalTicks }; 160if (1 == count ) 161logInfo (u8"%s\t%g %s" ,name ,total .value ,total .unit ); 162else 163 { 164PrintedTime avg = (double )totalTicks / (double )(int64_t )count ; 165logInfo (u8"%s\t%g %s, %zu calls, %g %s average" ,name ,total .value ,total .unit ,count ,avg .value ,avg .unit ); 166 } 167} 168 169#if PROFILER_COLLECT_TAGS 170struct TaggedShaderCmp 171{ 172bool operator()(uint16_t cs ,uint32_t key )const 173 { 174return cs < key >> 16 ; 175 } 176bool operator()(uint32_t key ,uint16_t cs )const 177 { 178return key >>16 < cs ; 179 } 180}; 181 182void ProfileCollection ::TaggedTemp ::const 183{ 184PrintedTime total {ticks }; 185if (1 == count ) 186logInfo (u8" %s\t%g %s" ,name ,total .value ,total .unit ); 187else 188 { 189PrintedTime avg = (double )ticks / (double )(int64_t )count ; 190logInfo (u8" %s\t%g %s, %zu calls, %g %s average" ,name ,total .value ,total .unit ,count ,avg .value ,avg .unit ); 191 } 192} 193#endif 194 195void ProfileCollection ::keysTemp .clear (); 198for (POSITION pos = measures .GetStartPosition ();nullptr != pos ; ) 199 { 200auto * p = measures .GetNext (pos ); 201if (p -> m_value .count == 0 ) 202continue ; 203keysTemp .push_back (p -> m_key ); 204 } 205 206 std::sort (keysTemp .begin (),keysTemp .end () ); 207auto it = std::lower_bound (keysTemp .begin (),keysTemp .end (),0x30000u ); 208if (it != keysTemp .end () ) 209 { 210auto lambda = [this ](uint32_t a ,uint32_t b ) 211 { 212const uint64_t ta = measures .Lookup (a )-> m_value .totalTicks ; 213const uint64_t tb = measures .Lookup (b )-> m_value .totalTicks ; 214return ta > tb ; 215 }; 216 std::stable_sort (it ,keysTemp .end (),lambda ); 217 } 218 219#if PROFILER_COLLECT_TAGS 220taggedKeysTemp .clear (); 221for (POSITION pos = taggedShaders .GetStartPosition ();nullptr != pos ; ) 222 { 223auto * p = taggedShaders .GetNext (pos ); 224if (p -> m_value .count == 0 ) 225continue ; 226taggedKeysTemp .push_back (p -> m_key ); 227 } 228 std::sort (taggedKeysTemp .begin (),taggedKeysTemp .end () ); 229#endif 230 231uint16_t prevKeyType = 0 ; 232pfnPrintEnum pfn = nullptr ; 233for (uint32_t k :keysTemp ) 234 { 235const uint16_t type = (uint16_t )(k >>16 ); 236if (type != prevKeyType ) 237 { 238prevKeyType = type ; 239pfn = printSectionStart (type ); 240 } 241if (pfn == nullptr ) 242continue ; 243const auto * p = measures .Lookup (k ); 244assert (nullptr != p ); 245p -> m_value .pfn ( (uint16_t )k ) ); 246 247#if PROFILER_COLLECT_TAGS 248if (type == 3 ) 249 { 250// Compute shader 251auto range = std::equal_range (taggedKeysTemp .begin (),taggedKeysTemp .end (), (uint16_t )k ,TaggedShaderCmp {} ); 252if (range .first != range .second ) 253 { 254// We have at least 1 tag for that compute shader 255taggedTimes .clear (); 256uint64_t totalTicks = 0 ; 257size_t totalCount = 0 ; 258for (auto it = range .first ;it != range .second ;it ++ ) 259 { 260const uint32_t key = * it ; 261const uint16_t tagId = (uint16_t )key ; 262assert (0 != tagId ); 263const auto * p = taggedShaders .Lookup (key ); 264assert (nullptr != p ); 265 266auto & rdi = taggedTimes .emplace_back (); 267rdi .ticks = p -> m_value .totalTicks ; 268totalTicks += p -> m_value .totalTicks ; 269 270rdi .count = p -> m_value .count ; 271totalCount += p -> m_value .count ; 272 273rdi .name = tagNames [tagId ]; 274 } 275 276assert (totalCount <=p -> m_value .count ); 277if (totalCount < p -> m_value .count ) 278 { 279auto & rdi = taggedTimes .emplace_back (); 280rdi .ticks = p -> m_value .totalTicks - totalTicks ; 281rdi .count = p -> m_value .count - totalCount ; 282rdi .name = tagNames [0 ]; 283 } 284 std::stable_sort (taggedTimes .begin (),taggedTimes .end () ); 285for (const auto & e :taggedTimes ) 286e .#endif 290 } 291} 292 293void ProfileCollection ::reset () 294{ 295for (POSITION pos = measures .GetStartPosition ();nullptr != pos ; ) 296measures .GetNextValue (pos ).reset (); 297} 298 299ProfileCollection ::ProfileCollection (const WhisperModel & model ) 300{ 301const __m128i vals = model .getLoadTimes (); 302 303uint64_t s = (uint64_t )_mm_cvtsi128_si64 (vals ); 304measure ( eCpuBlock::LoadModel ).add (s ); 305 306s = (uint64_t )_mm_extract_epi64 (vals ,1 ); 307measure (DirectCompute ::eProfilerBlock::LoadModel ).add (s ); 308#if PROFILER_COLLECT_TAGS 309// Tag ID 0 means no tag at all. makeTagId() method returns 0 for nullptr name, and starts numbering with 1 for non-empoty tag names 310// Push the tag name corresponding to ID = 0, this way we can index directly with tag IDs. 311tagNames .push_back ("<untagged>" ); 312#endif 313} 314 315uint16_t ProfileCollection ::makeTagId (const char * tag ) 316{ 317#if PROFILER_COLLECT_TAGS 318if (nullptr == tag ) 319return 0 ; 320auto p = tagIDs .Lookup (tag ); 321if (nullptr != p ) 322return p -> m_value ; 323const size_t newTag = tagIDs .GetCount ()+ 1 ; 324if (newTag <=0xFFFF ) 325 { 326tagIDs .SetAt (tag , (uint16_t )newTag ); 327tagNames .push_back (tag ); 328return (uint16_t )newTag ; 329 } 330throw DISP_E_OVERFLOW ; 331#else 332return 0 ; 333#endif 334}