char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
9f4098935
char/aliceai-t5-moe
1#include <cstdio> 2#include <type_traits> 3#include <vector> 4#include <random> 5#include <chrono> 6#include <cstdlib> 7#include <cmath> 8#include <cassert> 9#include <cstring> 10#include <array> 11#include <type_traits> 12 13#include <ggml.h> 14#include <ggml-cpu.h> 15 16constexpr int kVecSize = 1 <<16 ; 17 18// Copy-pasted from ggml.c 19#define QK4_0 32 20typedef struct { 21float d ;// delta 22uint8_t qs [QK4_0 /2 ];// nibbles / quants 23}block_q4_0 ; 24static_assert(sizeof (block_q4_0 )== sizeof (float )+ QK4_0 /2 ,"wrong q4_0 block size/padding" ); 25 26#define QK4_1 32 27typedef struct { 28float d ;// delta 29float m ;// min 30uint8_t qs [QK4_1 /2 ];// nibbles / quants 31}block_q4_1 ; 32static_assert(sizeof (block_q4_1 )== sizeof (float )* 2 + QK4_1 /2 ,"wrong q4_1 block size/padding" ); 33 34// Copy-pasted from ggml.c 35#define QK8_0 32 36typedef struct { 37float d ;// delta 38float s ;// d * sum(qs[i]) 39int8_t qs [QK8_0 ];// quants 40}block_q8_0 ; 41static_assert(sizeof (block_q8_0 )== 2 * sizeof (float )+ QK8_0 ,"wrong q8_0 block size/padding" ); 42 43static_assert(QK4_1 == QK8_0 ,"QK4_1 and QK8_0 must be the same" ); 44static_assert(QK4_0 == QK8_0 ,"QK4_0 and QK8_0 must be the same" ); 45 46template < typename T > 47static void fillQ4blocks (std::vector < T >& blocks , std::mt19937 & rndm ) { 48for (auto & b :blocks ) { 49b .d = 1 ; 50for (int i = 0 ;i < QK4_1 /2 ;++ i ) { 51uint8_t v1 = rndm () >>28 ; 52uint8_t v2 = rndm () >>28 ; 53b .qs [i ]= v1 | (v2 <<4 ); 54 } 55 } 56} 57 58static void fillQ80blocks (std::vector < block_q8_0 >& blocks , std::mt19937 & rndm ) { 59for (auto & b :blocks ) { 60b .d = 1 ; 61int sum = 0 ; 62for (int i = 0 ;i < QK8_0 ;++ i ) { 63b .qs [i ]= (rndm () >>24 )- 128 ; 64sum += b .qs [i ]; 65 } 66b .s = b .d * sum ; 67 } 68} 69 70static float simpleDot (const block_q4_0 & x ,const block_q8_0 & y ) { 71int s1 = 0 ;//, s2 = 0; 72for (int i = 0 ;i < QK4_1 /2 ;i += 2 ) { 73int v1 = x .qs [i + 0 ]& 0xf ; 74int v2 = x .qs [i + 0 ] >>4 ; 75int v3 = x .qs [i + 1 ]& 0xf ; 76int v4 = x .qs [i + 1 ] >>4 ; 77int j = 2 * i ; 78s1 += v1 * y .qs [j ]+ v2 * y .qs [j + 1 ]+ v3 * y .qs [j + 2 ]+ v4 * y .qs [j + 3 ]; 79//s2 += y.qs[j] + y.qs[j+1] + y.qs[j+2] + y.qs[j+3]; 80 } 81return y .d * x .d * s1 - 8 * x .d * y .s ; 82//return y.d * x.d * (s1 - 8 * s2); 83} 84 85static float simpleDot (const block_q4_1 & x ,const block_q8_0 & y ) { 86int s1 = 0 ;//, s2 = 0; 87for (int i = 0 ;i < QK4_1 /2 ;i += 2 ) { 88int v1 = x .qs [i + 0 ]& 0xf ; 89int v2 = x .qs [i + 0 ] >>4 ; 90int v3 = x .qs [i + 1 ]& 0xf ; 91int v4 = x .qs [i + 1 ] >>4 ; 92int j = 2 * i ; 93s1 += v1 * y .qs [j ]+ v2 * y .qs [j + 1 ]+ v3 * y .qs [j + 2 ]+ v4 * y .qs [j + 3 ]; 94//s2 += y.qs[j] + y.qs[j+1] + y.qs[j+2] + y.qs[j+3]; 95 } 96return y .d * x .d * s1 + y .s * x .m ; 97//return y.d * (x.d * s1 + x.m * s2); 98} 99 100struct Stat { 101double sum = 0 ,sumt = 0 ,sumt2 = 0 ,maxt = 0 ; 102int nloop = 0 ; 103void addResult (double s ,double t ) { 104sum += s ; 105sumt += t ;sumt2 += t * t ;maxt = std::max (maxt ,t ); 106++ nloop ; 107 } 108void reportResult (const char * title )const { 109if (nloop < 1 ) { 110printf ("%s(%s): no result\n" ,__func__ ,title ); 111return ; 112 } 113printf ("============ %s\n" ,title ); 114printf ("<dot> = %g\n" ,sum /nloop ); 115auto t = sumt /nloop ,dt = sumt2 /nloop - t * t ; 116if (dt > 0 )dt = sqrt (dt ); 117printf ("<time> = %g +/- %g us. Max. time = %g us.\n" ,t ,dt ,maxt ); 118 } 119}; 120 121 122int main (int argc ,char ** argv ) { 123 124int nloop = argc > 1 ?atoi (argv [1 ]) :10 ; 125int type = argc > 2 ?atoi (argv [2 ]) :1 ; 126 127 std::mt19937 rndm (1234 ); 128 129 std::vector < block_q4_1 > x41 ; 130 std::vector < block_q4_0 > x40 ; 131 std::vector < block_q8_0 > y (kVecSize ); 132if (type == 0 )x40 .resize (kVecSize ); 133else { 134x41 .resize (kVecSize ); 135for (auto & b :x41 )b .m = 1 ; 136 } 137 138auto ggml_type = type == 0 ?GGML_TYPE_Q4_0 :GGML_TYPE_Q4_1 ; 139 140const auto * funcs = ggml_get_type_traits_cpu (ggml_type ); 141 142Stat simple ,ggml ; 143 144for (int iloop = 0 ;iloop < nloop ;++ iloop ) { 145 146if (type == 0 )fillQ4blocks (x40 ,rndm ); 147else fillQ4blocks (x41 ,rndm ); 148fillQ80blocks (y ,rndm ); 149 150auto t1 = std::chrono::high_resolution_clock::now (); 151double s = 0 ; 152if (type == 0 )for (int i = 0 ;i < kVecSize ;++ i )s += simpleDot (x40 [i ],y [i ]); 153else for (int i = 0 ;i < kVecSize ;++ i )s += simpleDot (x41 [i ],y [i ]); 154auto t2 = std::chrono::high_resolution_clock::now (); 155auto t = 1e-3 * std::chrono::duration_cast < std::chrono::nanoseconds > (t2 - t1 ).count (); 156if (iloop > 3 )simple .addResult (s ,t ); 157 158t1 = std::chrono::high_resolution_clock::now (); 159float fs ; 160if (type == 0 )funcs -> vec_dot (kVecSize * QK4_1 ,& fs ,0 ,x40 .data (),0 ,y .data (),0 ,1 ); 161else funcs -> vec_dot (kVecSize * QK4_1 ,& fs ,0 ,x41 .data (),0 ,y .data (),0 ,1 ); 162t2 = std::chrono::high_resolution_clock::now (); 163t = 1e-3 * std::chrono::duration_cast < std::chrono::nanoseconds > (t2 - t1 ).count (); 164if (iloop > 3 )ggml .addResult (fs ,t ); 165 166 } 167 168// Report the time (and the average of the dot products so the compiler does not come up with the idea 169// of optimizing away the function calls after figuring that the result is not used). 170simple .reportResult ("Simple" ); 171ggml .reportResult ("ggml" ); 172return 0 ; 173}