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 "../../Whisper/ML/testUtils.h" 3#include <immintrin.h> 4using namespace DirectCompute ; 5 6namespace 7{ 8using DirectCompute ::sTensorDiff ; 9 10 __forceinline__m256 load (const float * rsi ) 11 { 12return _mm256_loadu_ps (rsi ); 13 } 14 15 __forceinline__m256 load (const uint16_t * rsi ) 16 { 17const __m128i iv = _mm_load_si128 ( (const __m128i * )rsi ); 18return _mm256_cvtph_ps (iv ); 19 } 20 21 __forceinlinevoid loadPartial (const uint16_t * x ,const uint16_t * y ,size_t count ,__m256 & fx ,__m256 & fy ) 22 { 23__m128i ix ,iy ; 24switch (count ) 25 { 26case 1 :// load 2 bytes 27ix = _mm_cvtsi32_si128 (* x ); 28iy = _mm_cvtsi32_si128 (* y ); 29break ; 30case 2 :// load 4 bytes 31ix = _mm_cvtsi32_si128 (* (const int * )x ); 32iy = _mm_cvtsi32_si128 (* (const int * )y ); 33break ; 34case 3 :// load 6 bytes 35ix = _mm_cvtsi32_si128 (* (const int * )x ); 36iy = _mm_cvtsi32_si128 (* (const int * )y ); 37ix = _mm_insert_epi16 (ix ,x [2 ],2 ); 38iy = _mm_insert_epi16 (iy ,y [2 ],2 ); 39break ; 40case 4 :// load 8 bytes 41ix = _mm_cvtsi64_si128 (* (const int64_t * )x ); 42iy = _mm_cvtsi64_si128 (* (const int64_t * )y ); 43break ; 44case 5 :// load 10 bytes 45ix = _mm_cvtsi64_si128 (* (const int64_t * )x ); 46iy = _mm_cvtsi64_si128 (* (const int64_t * )y ); 47ix = _mm_insert_epi16 (ix ,x [4 ],4 ); 48iy = _mm_insert_epi16 (iy ,y [4 ],4 ); 49break ; 50case 6 :// load 12 bytes 51ix = _mm_cvtsi64_si128 (* (const int64_t * )x ); 52iy = _mm_cvtsi64_si128 (* (const int64_t * )y ); 53ix = _mm_insert_epi32 (ix ,* (const int * )(x + 4 ),2 ); 54iy = _mm_insert_epi32 (iy ,* (const int * )(y + 4 ),2 ); 55break ; 56case 7 :// load 14 bytes 57ix = _mm_cvtsi64_si128 (* (const int64_t * )x ); 58iy = _mm_cvtsi64_si128 (* (const int64_t * )y ); 59ix = _mm_insert_epi32 (ix ,* (const int * )(x + 4 ),2 ); 60iy = _mm_insert_epi32 (iy ,* (const int * )(y + 4 ),2 ); 61ix = _mm_insert_epi16 (ix ,x [6 ],6 ); 62iy = _mm_insert_epi16 (iy ,y [6 ],6 ); 63break ; 64default : 65fx = fy = _mm256_setzero_ps (); 66return ; 67 } 68 69fx = _mm256_cvtph_ps (ix ); 70fy = _mm256_cvtph_ps (iy ); 71 } 72 73inline __m128 loadFloat2 (const float * rsi ) 74 { 75return _mm_castpd_ps (_mm_load_sd ( (const double * )rsi ) ); 76 } 77inline __m128 loadFloat3 (const float * rsi ) 78 { 79__m128 f = loadFloat2 (rsi ); 80f = _mm_insert_ps (f ,_mm_load_ss (rsi + 2 ),0x20 ); 81return f ; 82 } 83 __forceinlinevoid loadPartial (const float * x ,const float * y ,size_t count ,__m256 & fx ,__m256 & fy ) 84 { 85__m128 low1 ,high1 ; 86__m128 low2 ,high2 ; 87high1 = high2 = _mm_setzero_ps (); 88switch (count ) 89 { 90case 1 : 91low1 = _mm_load_ss (x ); 92low2 = _mm_load_ss (y ); 93break ; 94case 2 : 95low1 = loadFloat2 (x ); 96low2 = loadFloat2 (y ); 97break ; 98case 3 : 99low1 = loadFloat3 (x ); 100low2 = loadFloat3 (y ); 101break ; 102case 4 : 103low1 = _mm_loadu_ps (x ); 104low2 = _mm_loadu_ps (y ); 105break ; 106case 5 : 107low1 = _mm_loadu_ps (x ); 108low2 = _mm_loadu_ps (y ); 109high1 = _mm_load_ss (x + 4 ); 110high2 = _mm_load_ss (y + 4 ); 111break ; 112case 6 : 113low1 = _mm_loadu_ps (x ); 114low2 = _mm_loadu_ps (y ); 115high1 = loadFloat2 (x + 4 ); 116high2 = loadFloat2 (y + 4 ); 117break ; 118case 7 :// load 14 bytes 119low1 = _mm_loadu_ps (x ); 120low2 = _mm_loadu_ps (y ); 121high1 = loadFloat3 (x + 4 ); 122high2 = loadFloat3 (y + 4 ); 123break ; 124default : 125fx = fy = _mm256_setzero_ps (); 126return ; 127 } 128 129fx = _mm256_setr_m128 (low1 ,high1 ); 130fy = _mm256_setr_m128 (low2 ,high2 ); 131 } 132 133 __forceinlinefloat horizontalMaximum (__m256 v ) 134 { 135__m128 s = _mm256_extractf128_ps (v ,1 ); 136s = _mm_max_ps (s ,_mm256_castps256_ps128 (v ) ); 137s = _mm_max_ps (s ,_mm_movehl_ps (s ,s ) ); 138s = _mm_max_ss (s ,_mm_movehdup_ps (s ) ); 139return _mm_cvtss_f32 (s ); 140 } 141 142 __forceinlinedouble horizontalSum (__m256 v ) 143 { 144__m256d d = _mm256_cvtps_pd (_mm256_extractf128_ps (v ,1 ) ); 145d = _mm256_add_pd (d ,_mm256_cvtps_pd (_mm256_castps256_ps128 (v ) ) ); 146 147__m128d s = _mm256_extractf128_pd (d ,1 ); 148s = _mm_add_pd (s ,_mm256_castpd256_pd128 (d ) ); 149s = _mm_add_sd (s ,_mm_unpackhi_pd (s ,s ) ); 150return _mm_cvtsd_f64 (s ); 151 } 152 153__m256 maskInfNan (__m256 diff ,__m256 a ,__m256 b ) 154 { 155__m256i ai = _mm256_castps_si256 (a ); 156__m256i bi = _mm256_castps_si256 (b ); 157__m256i eqi = _mm256_cmpeq_epi32 (ai ,bi ); 158__m256 eq = _mm256_castsi256_ps (eqi ); 159return _mm256_andnot_ps (eq ,diff ); 160 } 161 162class DiffAcc 163 { 164__m256 maxAbs = _mm256_setzero_ps (); 165__m256 sumSquares = _mm256_setzero_ps (); 166 167public : 168 169 __forceinlinevoid add (__m256 a ,__m256 b ) 170 { 171const __m256 neg0 = _mm256_set1_ps (-0.0f ); 172__m256 diff = _mm256_sub_ps (b ,a ); 173diff = maskInfNan (diff ,a ,b ); 174sumSquares = _mm256_fmadd_ps (diff ,diff ,sumSquares ); 175const __m256 absDiff = _mm256_andnot_ps (neg0 ,diff ); 176maxAbs = _mm256_max_ps (maxAbs ,absDiff ); 177 } 178 179 __forceinlinesTensorDiff reduce (size_t count ) 180 { 181sTensorDiff res ; 182res .maxAbsDiff = horizontalMaximum (maxAbs ); 183res .avgDiffSquared = (float )(horizontalSum (sumSquares ) / (double )(int64_t )count ); 184res .length = count ; 185return res ; 186 } 187 }; 188 189template < class E > 190static sTensorDiff __declspec(noinline )diffVectors (const E * a ,const E * b ,size_t length ) 191 { 192// const E* const aEnd = a + length; 193const E * const aEndAligned = a + (length /8 )* 8 ; 194const size_t remainder = length %8 ; 195 196DiffAcc acc ; 197for ( ;a < aEndAligned ;a += 8 ,b += 8 ) 198acc .add (load (a ),load (b ) ); 199 200if (remainder != 0 ) 201 { 202__m256 va ,vb ; 203loadPartial (a ,b ,remainder ,va ,vb ); 204acc .add (va ,vb ); 205 } 206 207return acc .reduce (length ); 208 } 209} 210 211sTensorDiff DirectCompute ::computeDiff (const float * a ,const float * b ,size_t length ) 212{ 213return diffVectors (a ,b ,length ); 214} 215 216sTensorDiff DirectCompute ::computeDiff (const uint16_t * a ,const uint16_t * b ,size_t length ) 217{ 218return diffVectors (a ,b ,length ); 219} 220 221void DirectCompute ::sTensorDiff::const 222{ 223printf ("%zu elements, maxAbsDiff = %g, avgDiffSquared = %g\n" ,length ,maxAbsDiff ,avgDiffSquared ); 224}