File size: 2,341 Bytes
45f1d0b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// Compare ggml_vec_dot_nvfp4_q8_0 (arch path) against ggml_vec_dot_nvfp4_q8_0_generic on random data.
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stddef.h>

typedef struct { uint8_t d[4]; uint8_t qs[32]; } block_nvfp4;   // 64 elems: 4 UE4M3 scales + 32 nibble bytes
typedef struct { _Float16 d; int8_t qs[32]; } block_q8_0;       // 32 elems

void ggml_vec_dot_nvfp4_q8_0(int n, float * s, size_t bs, const void * vx, size_t bx, const void * vy, size_t by, int nrc);
void ggml_vec_dot_nvfp4_q8_0_generic(int n, float * s, size_t bs, const void * vx, size_t bx, const void * vy, size_t by, int nrc);

static uint32_t rng_state = 12345;
static uint32_t rnd(void) { rng_state = rng_state * 1664525u + 1013904223u; return rng_state >> 8; }

void ggml_cpu_init(void);
int main(void) {
    ggml_cpu_init();
    int fails = 0;
    for (int trial = 0; trial < 20; ++trial) {
        const int n = 64 * (1 + (trial * 37) % 200);
        const int nb = n / 64;
        block_nvfp4 * w = aligned_alloc(64, sizeof(block_nvfp4) * nb);
        block_q8_0  * a = aligned_alloc(64, sizeof(block_q8_0) * (n / 32));
        for (int i = 0; i < nb; ++i) {
            for (int s = 0; s < 4; ++s) w[i].d[s] = (uint8_t)(rnd() % 127);  // avoid NaN code 0x7F
            for (int j = 0; j < 32; ++j) w[i].qs[j] = (uint8_t)rnd();
        }
        for (int i = 0; i < n / 32; ++i) {
            float amax = 0.f; float xs[32];
            for (int j = 0; j < 32; ++j) { xs[j] = ((int)(rnd() % 20001) - 10000) / 1000.0f; if (fabsf(xs[j]) > amax) amax = fabsf(xs[j]); }
            float d = amax / 127.0f; float id = d ? 1.0f / d : 0.0f;
            a[i].d = (_Float16) d;
            for (int j = 0; j < 32; ++j) a[i].qs[j] = (int8_t) lrintf(xs[j] * id);
        }
        float r_gen = 0.f, r_arch = 0.f;
        ggml_vec_dot_nvfp4_q8_0_generic(n, &r_gen, 0, w, 0, a, 0, 1);
        ggml_vec_dot_nvfp4_q8_0(n, &r_arch, 0, w, 0, a, 0, 1);
        double rel = fabs((double) r_arch - r_gen) / (fabs((double) r_gen) + 1e-9);
        printf("n=%6d generic=% .6f arch=% .6f rel=%.3e %s\n", n, r_gen, r_arch, rel, rel < 1e-5 ? "OK" : "FAIL");
        if (rel >= 1e-5) fails++;
        free(w); free(a);
    }
    printf("%s (%d failures)\n", fails ? "FAILED" : "PASSED", fails);
    return fails != 0;
}