Team Ai
Datasetpublic

echodict/llama.cpp

version https://git-lfs.github.com/spec/v1 oid sha256:cfc44b7ba25614df70e6b65e3341cae0310163bd32fd31a6b928a542df433faf size 30786

sourceHugging Faceupdated 6mo agoView on Hugging Face
0likes479downloads
test-backend-ops.cpp9403 linesDownload Raw Back to tests
1// This file defines tests for various GGML ops and backends.2// For the forward pass it asserts that the results of multiple backends computing the same GGML ops are consistent.3// For the backward pass it asserts that the gradients from backpropagation are consistent4// with the gradients obtained via the method of finite differences ("grad" mode, this is optional).5// It is also possible to check the performance ("perf" mode).6//7// this file has three sections: Section 1 does general setup, section 2 defines the GGML ops to be tested,8// and section 3 defines which tests to run.9// Quick start for adding a new GGML op: Go to section 2 and create a struct that inherits from test_case,10// then go to section 3 and add an instantiation of your struct.11 12 13// ##############################14// ## Section 1: General Setup ##15// ##############################16 17 18#include <ggml.h>19#include <ggml-alloc.h>20#include <ggml-backend.h>21#include <ggml-cpp.h>22 23#include <algorithm>24#include <array>25#include <cfloat>26#include <cinttypes>27#include <cstdarg>28#include <cstdint>29#include <cstdio>30#include <cstdlib>31#include <cstring>32#include <ctime>33#include <future>34#include <fstream>35#include <memory>36#include <random>37#include <regex>38#include <set>39#include <sstream>40#include <string>41#include <string_view>42#include <thread>43#include <vector>44#include <unordered_map>45 46#ifdef __EMSCRIPTEN__47#   define N_THREADS 148#else49#   define N_THREADS std::thread::hardware_concurrency()50#endif51 52static void init_tensor_uniform(ggml_tensor * tensor, float min = -1.0f, float max = 1.0f) {53    size_t nels = ggml_nelements(tensor);54    std::vector<float> data(nels);55    {56        // parallel initialization57        static const size_t n_threads = N_THREADS;58        // static RNG initialization (revisit if n_threads stops being constant)59        static std::vector<std::default_random_engine> generators = []() {60            std::random_device rd;61            std::vector<std::default_random_engine> vec;62            vec.reserve(n_threads);63            //for (size_t i = 0; i < n_threads; i++) { vec.emplace_back(1234 + i); } // fixed seed64            for (size_t i = 0; i < n_threads; i++) { vec.emplace_back(rd()); }65            return vec;66        }();67 68        auto init_thread = [&](size_t ith, size_t start, size_t end) {69            std::uniform_real_distribution<float> distribution(min, max);70            auto & gen = generators[ith];71            for (size_t i = start; i < end; i++) {72                data[i] = distribution(gen);73            }74        };75 76        if (n_threads == 1) {77            init_thread(0, 0, nels);78        } else {79            std::vector<std::future<void>> tasks;80            tasks.reserve(n_threads);81            for (size_t i = 0; i < n_threads; i++) {82                size_t start =     i*nels/n_threads;83                size_t end   = (i+1)*nels/n_threads;84                tasks.push_back(std::async(std::launch::async, init_thread, i, start, end));85            }86            for (auto & t : tasks) {87                t.get();88            }89        }90    }91 92    if (tensor->type == GGML_TYPE_F32 || tensor->type == GGML_TYPE_I32) {93        ggml_backend_tensor_set(tensor, data.data(), 0, nels * sizeof(float));94    } else if (ggml_is_quantized(tensor->type) || tensor->type == GGML_TYPE_F16 || tensor->type == GGML_TYPE_BF16) {95        GGML_ASSERT(nels % ggml_blck_size(tensor->type) == 0);96 97         // dummy importance matrix98        std::vector<float> imatrix(tensor->ne[0], 1.0f);99        const float * im = imatrix.data();100        if (!ggml_quantize_requires_imatrix(tensor->type)) {101            // when the imatrix is optional, we want to test both quantization with and without imatrix102            // use one of the random numbers to decide103            if (data[0] > 0.5f*(min + max)) {104                im = nullptr;105            }106        }107 108        std::vector<uint8_t> dataq(ggml_row_size(tensor->type, nels));109        {110            // parallel quantization by block111            size_t blck_size = ggml_blck_size(tensor->type);112            size_t n_blocks = nels / blck_size;113 114            auto quantize_thread = [&](size_t start, size_t end) {115                ggml_quantize_chunk(tensor->type, data.data(), dataq.data(),116                    start * blck_size, end - start, blck_size, im);117            };118 119            const size_t min_blocks_per_thread = 1;120            const size_t n_quant_threads = std::min<size_t>(std::max<size_t>(N_THREADS/2, 1),121                                                            std::max<size_t>(1, n_blocks / min_blocks_per_thread));122 123            if (n_quant_threads == 1) {124                // single-threaded quantization: do all blocks in the current thread125                quantize_thread(0, n_blocks);126            } else {127                std::vector<std::future<void>> tasks;128                tasks.reserve(n_quant_threads);129                for (size_t i = 0; i < n_quant_threads; i++) {130                    size_t start =     i*n_blocks/n_quant_threads;131                    size_t end   = (i+1)*n_blocks/n_quant_threads;132                    tasks.push_back(std::async(std::launch::async, quantize_thread, start, end));133                }134                for (auto & t : tasks) {135                    t.get();136                }137            }138        }139        ggml_backend_tensor_set(tensor, dataq.data(), 0, dataq.size());140    } else if (tensor->type == GGML_TYPE_I8 || tensor->type == GGML_TYPE_I16 || tensor->type == GGML_TYPE_I32) {141        // This is going to create some weird integers though.142        ggml_backend_tensor_set(tensor, data.data(), 0, ggml_nbytes(tensor));143    } else if (tensor->type == GGML_TYPE_I64) {144        // Integers with a size of 8 bytes can be set by mirroring the float data, the specific values are again not really meaningful.145        const size_t nbytes_half = ggml_nbytes(tensor)/2;146        ggml_backend_tensor_set(tensor, data.data(), 0*nbytes_half, nbytes_half);147        ggml_backend_tensor_set(tensor, data.data(), 1*nbytes_half, nbytes_half);148    } else {149        GGML_ABORT("fatal error");150    }151}152 153// generate an F16 mask where certain blocks are randomly masked with -INF value154static void init_tensor_kq_mask(ggml_tensor * tensor, float min = -1.0f, float max = 1.0f) {155    GGML_ASSERT(tensor->type == GGML_TYPE_F16);156 157    GGML_TENSOR_LOCALS( int32_t, ne, tensor, ne);158 159    std::vector<float>       data_f32(ne0*ne1*ne2*ne3);160    std::vector<ggml_fp16_t> data_f16(ne0*ne1*ne2*ne3);161 162    std::random_device rd;163    std::mt19937 gen(rd());164    std::uniform_real_distribution<float> dis(min, max);165 166    for (size_t i = 0; i < data_f32.size(); i++) {167        data_f32[i] = dis(gen);168    }169 170    // block size171    const int blck0 = 128;172    const int blck1 = 64;173 174    // number of INF/zero blocks175    const int n_inf_zero_blocks = 0.2*(ne0*ne1*ne2*ne3)/(blck0*blck1);176 177    for (int b = 0; b < n_inf_zero_blocks; b++) {178        const int p3 = (rd() % ne3);179        const int p2 = (rd() % ne2);180        const int p1 = (rd() % ne1);181        const int p0 = (rd() % ne0);182 183        bool inf = rd() & 1;184 185        for (int i1 = 0; i1 < blck1 && p1 + i1 < ne1; i1++) {186            const int idx = p3*ne2*ne1*ne0 + p2*ne1*ne0 + (p1 + i1)*ne0 + p0;187 188            for (int i0 = 0; i0 < blck0 && p0 + i0 < ne0; i0++) {189                data_f32[idx + i0] = inf ? -INFINITY : 0.0f;190            }191        }192    }193 194    ggml_fp32_to_fp16_row(data_f32.data(), data_f16.data(), ne0*ne1*ne2*ne3);195 196    ggml_backend_tensor_set(tensor, data_f16.data(), 0, data_f16.size()*sizeof(ggml_fp16_t));197}198 199// generate a lower triangular matrix200static void init_tensor_tril(ggml_tensor * tensor, float min = -1.0f, float max = 1.0f) {201    GGML_ASSERT(tensor->type == GGML_TYPE_F32);202    GGML_ASSERT(tensor->ne[0] == tensor->ne[1]);203 204    GGML_TENSOR_LOCALS(int32_t, ne, tensor, ne);205    GGML_TENSOR_LOCALS(size_t, nb, tensor, nb);206 207    std::vector<float> data_f32(ne0*ne1*ne2*ne3);208 209    std::random_device rd;210    std::mt19937 gen(rd());211    std::uniform_real_distribution<float> dis(min, max);212 213    for (int64_t i3 = 0; i3 < ne3; i3++) {214        for (int64_t i2 = 0; i2 < ne2; i2++) {215            for (int64_t i1 = 0; i1 < ne1; i1++) {216                for (int64_t i0 = 0; i0 < ne0; i0++) {217                    int64_t idx = (i0 * nb0 + i1 * nb1 + i2 * nb2 + i3 * nb3) / sizeof(float);218                    if (i0 <= i1) {219                        data_f32[idx] = dis(gen);220                    } else {221                        data_f32[idx] = 0.0f;222                    }223                }224            }225        }226    }227 228    ggml_backend_tensor_set(tensor, data_f32.data(), 0, ggml_nbytes(tensor));229}230 231static std::vector<float> tensor_to_float(const ggml_tensor * t) {232    std::vector<float> tv;233    tv.reserve(ggml_nelements(t));234 235    std::vector<uint8_t> buf(ggml_nbytes(t));236    ggml_backend_tensor_get(t, buf.data(), 0, ggml_nbytes(t));237 238    const auto * tt = ggml_get_type_traits(t->type);239    size_t bs = ggml_blck_size(t->type);240    std::vector<float> vq(ggml_blck_size(t->type));241    bool quantized = ggml_is_quantized(t->type);242 243    // access elements by index to avoid gaps in views244    for (int64_t i3 = 0; i3 < t->ne[3]; i3++) {245        for (int64_t i2 = 0; i2 < t->ne[2]; i2++) {246            for (int64_t i1 = 0; i1 < t->ne[1]; i1++) {247                for (int64_t i0 = 0; i0 < t->ne[0]; i0 += bs) {248                    size_t i = i3*t->nb[3] + i2*t->nb[2] + i1*t->nb[1] + i0/bs*t->nb[0];249                    if (t->type == GGML_TYPE_F16) {250                        tv.push_back(ggml_fp16_to_fp32(*(ggml_fp16_t*)&buf[i]));251                    } else if (t->type == GGML_TYPE_BF16) {252                        tv.push_back(ggml_bf16_to_fp32(*(ggml_bf16_t*)&buf[i]));253                    } else if (t->type == GGML_TYPE_F32) {254                        tv.push_back(*(float *) &buf[i]);255                    } else if (t->type == GGML_TYPE_I64) {256                        tv.push_back((float)*(int64_t *) &buf[i]);257                    } else if (t->type == GGML_TYPE_I32) {258                        tv.push_back((float)*(int32_t *) &buf[i]);259                    } else if (t->type == GGML_TYPE_I16) {260                        tv.push_back((float)*(int16_t *) &buf[i]);261                    } else if (t->type == GGML_TYPE_I8) {262                        tv.push_back((float)*(int8_t *) &buf[i]);263                    } else if (quantized) {264                        tt->to_float(&buf[i], vq.data(), bs);265                        tv.insert(tv.end(), vq.begin(), vq.end());266                    } else {267                        GGML_ABORT("fatal error");268                    }269                }270            }271        }272    }273 274    return tv;275}276 277// normalized mean squared error = mse(a, b) / mse(a, 0)278static double nmse(const float * a, const float * b, size_t n) {279    double mse_a_b = 0.0;280    double mse_a_0 = 0.0;281 282    for (size_t i = 0; i < n; i++) {283        float a_i = a[i];284        float b_i = b[i];285 286        mse_a_b += (a_i - b_i) * (a_i - b_i);287        mse_a_0 += a_i * a_i;288    }289 290    return mse_a_b / mse_a_0;291}292 293// difference between 2 sets (Jaccard distance, 0 - no difference, 1 - no overlap)294template <typename T>295static double jdst(const T * a, const T * b, size_t n) {296    std::unordered_map<T, size_t> set_a;297    std::unordered_map<T, size_t> set_b;298 299    for (size_t i = 0; i < n; ++i) {300        set_a[a[i]]++;301        set_b[b[i]]++;302    }303 304    size_t diff = 0;305 306    for (const auto & p : set_a) {307        const int64_t na = p.second;308        const int64_t nb = set_b.find(p.first) != set_b.end() ? set_b.at(p.first) : 0;309 310        diff += std::abs(na - nb);311    }312 313    for (const auto & p : set_b) {314        if (set_a.find(p.first) == set_a.end()) {315            diff += p.second;316        }317    }318 319    return (double) diff / (2*n);320}321 322// maximum absolute asymmetry between a and b323// asymmetry: (a - b) / (a + b)324// This is more stable than relative error if one of the values fluctuates towards zero.325// n: number of values to compare.326// expected_vals: optional vector of expected values for a. If expected_vals is not empty, filter out all comparisons where327//     a does not match any of the expected values. Needed for noncontinuous gradients where the numerical calculation can fail.328static double mean_abs_asymm(const float * a, const float * b, const size_t n, const std::vector<float> & expected_vals) {329    double sum = 0.0f;330 331    size_t nvalid = 0;332    for (size_t i = 0; i < n; i++) {333        if (!expected_vals.empty()) {334            bool matches_any = false;335            for (const float & ev : expected_vals) {336                if (fabsf(a[i] - ev) < 1e-3f) {337                    matches_any = true;338                    break;339                }340            }341            if (!matches_any) {342                continue;343            }344        }345 346        const float asymm = (a[i] - b[i]) / (a[i] + b[i]);347 348        sum += fabsf(asymm);349        nvalid++;350    }351 352    return sum/nvalid;353}354 355// utils for printing the variables of the test cases356 357static std::string var_to_str(const std::string & x) {358    return x;359}360 361template<typename T>362static std::string var_to_str(const T & x) {363    return std::to_string(x);364}365 366template<typename T, size_t N>367static std::string var_to_str(const T (&x)[N]) {368    std::string s = "[";369    for (size_t i = 0; i < N; i++) {370        if (i > 0) {371            s += ",";372        }373        s += var_to_str(x[i]);374    }375    s += "]";376    return s;377}378 379template<typename T, size_t N>380static std::string var_to_str(const std::array<T, N> & x) {381    std::string s = "[";382    for (size_t i = 0; i < N; i++) {383        if (i > 0) {384            s += ",";385        }386        s += var_to_str(x[i]);387    }388    s += "]";389    return s;390}391 392static std::string var_to_str(ggml_type type) {393    return ggml_type_name(type);394}395 396static std::string var_to_str(ggml_prec prec) {397    return prec == GGML_PREC_F32 ? "f32" : "def";398}399 400static std::string var_to_str(ggml_op_pool pool) {401    switch (pool) {402        case GGML_OP_POOL_AVG:  return "avg";403        case GGML_OP_POOL_MAX:  return "max";404        default:                return std::to_string(pool);405    }406}407 408static std::string var_to_str(ggml_scale_mode mode) {409    std::string str;410    switch (mode & 0xFF) {411        case GGML_SCALE_MODE_NEAREST:  str = "nearest"; break;412        case GGML_SCALE_MODE_BILINEAR: str = "bilinear"; break;413        case GGML_SCALE_MODE_BICUBIC:  str = "bicubic"; break;414        default:                       str = std::to_string(mode); break;415    }416    if (mode & GGML_SCALE_FLAG_ALIGN_CORNERS) {417        str += "|align_corners";418    }419    if (mode & GGML_SCALE_FLAG_ANTIALIAS) {420        str += "|antialias";421    }422    return str;423}424 425#define VAR_TO_STR(x) (#x "=" + var_to_str(x))426 427#define VARS_TO_STR1(a) VAR_TO_STR(a)428#define VARS_TO_STR2(a, b) VAR_TO_STR(a) + "," + VAR_TO_STR(b)429#define VARS_TO_STR3(a, b, c) VAR_TO_STR(a) + "," + VARS_TO_STR2(b, c)430#define VARS_TO_STR4(a, b, c, d) VAR_TO_STR(a) + "," + VARS_TO_STR3(b, c, d)431#define VARS_TO_STR5(a, b, c, d, e) VAR_TO_STR(a) + "," + VARS_TO_STR4(b, c, d, e)432#define VARS_TO_STR6(a, b, c, d, e, f) VAR_TO_STR(a) + "," + VARS_TO_STR5(b, c, d, e, f)433#define VARS_TO_STR7(a, b, c, d, e, f, g) VAR_TO_STR(a) + "," + VARS_TO_STR6(b, c, d, e, f, g)434#define VARS_TO_STR8(a, b, c, d, e, f, g, h) VAR_TO_STR(a) + "," + VARS_TO_STR7(b, c, d, e, f, g, h)435#define VARS_TO_STR9(a, b, c, d, e, f, g, h, i) VAR_TO_STR(a) + "," + VARS_TO_STR8(b, c, d, e, f, g, h, i)436#define VARS_TO_STR10(a, b, c, d, e, f, g, h, i, j) VAR_TO_STR(a) + "," + VARS_TO_STR9(b, c, d, e, f, g, h, i, j)437#define VARS_TO_STR11(a, b, c, d, e, f, g, h, i, j, k) VAR_TO_STR(a) + "," + VARS_TO_STR10(b, c, d, e, f, g, h, i, j, k)438#define VARS_TO_STR12(a, b, c, d, e, f, g, h, i, j, k, l) VAR_TO_STR(a) + "," + VARS_TO_STR11(b, c, d, e, f, g, h, i, j, k, l)439#define VARS_TO_STR13(a, b, c, d, e, f, g, h, i, j, k, l, m) VAR_TO_STR(a) + "," + VARS_TO_STR12(b, c, d, e, f, g, h, i, j, k, l, m)440#define VARS_TO_STR14(a, b, c, d, e, f, g, h, i, j, k, l, m, n) VAR_TO_STR(a) + "," + VARS_TO_STR13(b, c, d, e, f, g, h, i, j, k, l, m, n)441#define VARS_TO_STR15(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) VAR_TO_STR(a) + "," + VARS_TO_STR14(b, c, d, e, f, g, h, i, j, k, l, m, n, o)442#define VARS_TO_STR16(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) VAR_TO_STR(a) + "," + VARS_TO_STR15(b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)443 444#ifdef GGML_USE_SYCL445static bool inline _isinf(float f) {446    return (*(uint32_t *)&f & 0x7fffffff) == 0x7f800000;447}448#else449static bool inline _isinf(float f) { return std::isinf(f); }450#endif451 452// accept FLT_MAX as infinity453static bool isinf_or_max(float f) {454    return _isinf(f) || f == FLT_MAX || f == -FLT_MAX;455}456 457static bool ggml_is_view_op(enum ggml_op op) {458    return op == GGML_OP_VIEW || op == GGML_OP_RESHAPE || op == GGML_OP_PERMUTE || op == GGML_OP_TRANSPOSE;459}460 461static bool backend_has_feature(ggml_backend_t backend, const char * feature_name) {462    ggml_backend_dev_t dev = ggml_backend_get_device(backend);463    ggml_backend_reg_t reg = ggml_backend_dev_backend_reg(dev);464 465    auto get_features = (ggml_backend_get_features_t) ggml_backend_reg_get_proc_address(reg, "ggml_backend_get_features");466    if (!get_features) {467        return false;468    }469 470    const ggml_backend_feature * features = get_features(reg);471    if (!features) {472        return false;473    }474 475    for (const ggml_backend_feature * f = features; f->name; ++f) {476        if (strcmp(f->name, feature_name) == 0 && strcmp(f->value, "1") == 0) {477            return true;478        }479    }480    return false;481}482 483enum test_mode {484    MODE_TEST,485    MODE_PERF,486    MODE_GRAD,487    MODE_SUPPORT,488};489 490// Output format support similar to llama-bench491enum output_formats { CONSOLE, SQL, CSV };492 493static const char * output_format_str(output_formats format) {494    switch (format) {495        case CONSOLE:496            return "console";497        case SQL:498            return "sql";499        case CSV:500            return "csv";501        default:502            GGML_ABORT("invalid output format");503    }504}505 506static bool output_format_from_str(const std::string & s, output_formats & format) {507    if (s == "console") {508        format = CONSOLE;509    } else if (s == "sql") {510        format = SQL;511    } else if (s == "csv") {512        format = CSV;513    } else {514        return false;515    }516    return true;517}518 519// Test result structure for SQL output520struct test_result {521    std::string test_time;522    std::string build_commit;523    std::string backend_name;524    std::string op_name;525    std::string op_params;526    std::string test_mode;527    bool        supported;528    bool        passed;529    std::string error_message;530    double      time_us;531    double      flops;532    double      bandwidth_gb_s;533    size_t      memory_kb;534    int         n_runs;535    std::string device_description;536    std::string backend_reg_name;537 538    test_result() {539        // Initialize with default values540        time_us        = 0.0;541        flops          = 0.0;542        bandwidth_gb_s = 0.0;543        memory_kb      = 0;544        n_runs         = 0;545        supported      = false;546        passed         = false;547 548        // Set test time549        time_t t = time(NULL);550        char   buf[32];551        std::strftime(buf, sizeof(buf), "%FT%TZ", gmtime(&t));552        test_time = buf;553 554        // Set build info555        build_commit = ggml_commit();556    }557 558    test_result(const std::string & backend_name, const std::string & op_name, const std::string & op_params,559                const std::string & test_mode, bool supported, bool passed, const std::string & error_message = "",560                double time_us = 0.0, double flops = 0.0, double bandwidth_gb_s = 0.0, size_t memory_kb = 0,561                int n_runs = 0, const std::string & device_description = "", const std::string & backend_reg_name = "") :562        backend_name(backend_name),563        op_name(op_name),564        op_params(op_params),565        test_mode(test_mode),566        supported(supported),567        passed(passed),568        error_message(error_message),569        time_us(time_us),570        flops(flops),571        bandwidth_gb_s(bandwidth_gb_s),572        memory_kb(memory_kb),573        n_runs(n_runs),574        device_description(device_description),575        backend_reg_name(backend_reg_name) {576        // Set test time577        time_t t = time(NULL);578        char   buf[32];579        std::strftime(buf, sizeof(buf), "%FT%TZ", gmtime(&t));580        test_time = buf;581 582        // Set build info583        build_commit = ggml_commit();584    }585 586    static const std::vector<std::string> & get_fields() {587        static const std::vector<std::string> fields = {588            "test_time", "build_commit",  "backend_name", "op_name", "op_params",      "test_mode", "supported",589            "passed",    "error_message", "time_us",      "flops",   "bandwidth_gb_s", "memory_kb", "n_runs",590            "device_description", "backend_reg_name"591        };592        return fields;593    }594 595    enum field_type { STRING, BOOL, INT, FLOAT };596 597    static field_type get_field_type(const std::string & field) {598        if (field == "supported" || field == "passed") {599            return BOOL;600        }601        if (field == "memory_kb" || field == "n_runs") {602            return INT;603        }604        if (field == "time_us" || field == "flops" || field == "bandwidth_gb_s") {605            return FLOAT;606        }607        return STRING;608    }609 610    std::vector<std::string> get_values() const {611        return { test_time,612                 build_commit,613                 backend_name,614                 op_name,615                 op_params,616                 test_mode,617                 std::to_string(supported),618                 std::to_string(passed),619                 error_message,620                 std::to_string(time_us),621                 std::to_string(flops),622                 std::to_string(bandwidth_gb_s),623                 std::to_string(memory_kb),624                 std::to_string(n_runs),625                 device_description,626                 backend_reg_name };627    }628};629 630// Printer classes for different output formats631enum class test_status_t { NOT_SUPPORTED, OK, FAIL, SKIPPED };632 633struct test_operation_info {634    std::string   op_name;635    std::string   op_params;636    std::string   backend_name;637    test_status_t status = test_status_t::OK;638    std::string   failure_reason;639 640    // Additional information fields that were previously in separate structs641    std::string error_component;642    std::string error_details;643 644    // Gradient info645    int64_t     gradient_index = -1;646    std::string gradient_param_name;647    float       gradient_value = 0.0f;648 649    // MAA error info650    double maa_error     = 0.0;651    double maa_threshold = 0.0;652 653    // Flags for different types of information654    bool has_error            = false;655    bool has_gradient_info    = false;656    bool has_maa_error        = false;657    bool is_compare_failure   = false;658    bool is_large_tensor_skip = false;659 660    test_operation_info() = default;661 662    test_operation_info(const std::string & op_name, const std::string & op_params, const std::string & backend_name,663                        test_status_t status = test_status_t::OK, const std::string & failure_reason = "") :664        op_name(op_name),665        op_params(op_params),666        backend_name(backend_name),667        status(status),668        failure_reason(failure_reason) {}669 670    // Set error information671    void set_error(const std::string & component, const std::string & details) {672        has_error       = true;673        error_component = component;674        error_details   = details;675        if (status == test_status_t::OK) {676            status = test_status_t::FAIL;677        }678    }679 680    // Set gradient information681    void set_gradient_info(int64_t index, const std::string & param_name, float value) {682        has_gradient_info   = true;683        gradient_index      = index;684        gradient_param_name = param_name;685        gradient_value      = value;686        if (status == test_status_t::OK) {687            status = test_status_t::FAIL;688        }689    }690 691    // Set MAA error information692    void set_maa_error(double error, double threshold) {693        has_maa_error = true;694        maa_error     = error;695        maa_threshold = threshold;696        if (status == test_status_t::OK) {697            status = test_status_t::FAIL;698        }699    }700 701    // Set compare failure702    void set_compare_failure() {703        is_compare_failure = true;704        if (status == test_status_t::OK) {705            status = test_status_t::FAIL;706        }707    }708 709    // Set large tensor skip710    void set_large_tensor_skip() { is_large_tensor_skip = true; }711};712 713struct test_summary_info {714    size_t tests_passed;715    size_t tests_total;716    bool   is_backend_summary = false;  // true for backend summary, false for test summary717 718    test_summary_info() = default;719 720    test_summary_info(size_t tests_passed, size_t tests_total, bool is_backend_summary = false) :721        tests_passed(tests_passed),722        tests_total(tests_total),723        is_backend_summary(is_backend_summary) {}724};725 726struct testing_start_info {727    size_t device_count;728 729    testing_start_info() = default;730 731    testing_start_info(size_t device_count) : device_count(device_count) {}732};733 734struct backend_init_info {735    size_t      device_index;736    size_t      total_devices;737    std::string device_name;738    bool        skipped = false;739    std::string skip_reason;740    std::string description;741    size_t      memory_total_mb = 0;742    size_t      memory_free_mb  = 0;743    bool        has_memory_info = false;744 745    backend_init_info() = default;746 747    backend_init_info(size_t device_index, size_t total_devices, const std::string & device_name, bool skipped = false,748                      const std::string & skip_reason = "", const std::string & description = "",749                      size_t memory_total_mb = 0, size_t memory_free_mb = 0, bool has_memory_info = false) :750        device_index(device_index),751        total_devices(total_devices),752        device_name(device_name),753        skipped(skipped),754        skip_reason(skip_reason),755        description(description),756        memory_total_mb(memory_total_mb),757        memory_free_mb(memory_free_mb),758        has_memory_info(has_memory_info) {}759};760 761struct backend_status_info {762    std::string   backend_name;763    test_status_t status;764 765    backend_status_info() = default;766 767    backend_status_info(const std::string & backend_name, test_status_t status) :768        backend_name(backend_name),769        status(status) {}770};771 772struct overall_summary_info {773    size_t backends_passed;774    size_t backends_total;775    bool   all_passed;776 777    overall_summary_info() = default;778 779    overall_summary_info(size_t backends_passed, size_t backends_total, bool all_passed) :780        backends_passed(backends_passed),781        backends_total(backends_total),782        all_passed(all_passed) {}783};784 785struct printer {786    virtual ~printer() {}787 788    FILE * fout = stdout;789 790    virtual void print_header() {}791 792    virtual void print_test_result(const test_result & result) = 0;793 794    virtual void print_footer() {}795 796    virtual void print_operation(const test_operation_info & info) { (void) info; }797 798    virtual void print_summary(const test_summary_info & info) { (void) info; }799 800    virtual void print_testing_start(const testing_start_info & info) { (void) info; }801 802    virtual void print_backend_init(const backend_init_info & info) { (void) info; }803 804    virtual void print_backend_status(const backend_status_info & info) { (void) info; }805 806    virtual void print_overall_summary(const overall_summary_info & info) { (void) info; }807 808    virtual void print_failed_tests(const std::vector<std::string> & failed_tests) { (void) failed_tests; }809};810 811struct console_printer : public printer {812    void print_test_result(const test_result & result) override {813        if (result.test_mode == "test") {814            print_test_console(result);815        } else if (result.test_mode == "perf") {816            print_perf_console(result);817        } else if (result.test_mode == "support") {818            print_support_console(result);819        }820    }821 822    void print_operation(const test_operation_info & info) override {823        printf("  %s(%s): ", info.op_name.c_str(), info.op_params.c_str());824        fflush(stdout);825 826        // Handle large tensor skip first827        if (info.is_large_tensor_skip) {828            printf("skipping large tensors for speed \n");829            return;830        }831 832        // Handle not supported status833        if (info.status == test_status_t::NOT_SUPPORTED) {834            if (!info.failure_reason.empty()) {835                printf("not supported [%s]\n", info.failure_reason.c_str());836            } else {837                printf("not supported [%s]\n", info.backend_name.c_str());838            }839            return;840        }841 842        // Handle errors and additional information843        if (info.has_error) {844            if (info.error_component == "allocation") {845                fprintf(stderr, "failed to allocate tensors [%s] ", info.backend_name.c_str());846            } else if (info.error_component == "backend") {847                fprintf(stderr, "  Failed to initialize %s backend\n", info.backend_name.c_str());848            } else {849                fprintf(stderr, "Error in %s: %s\n", info.error_component.c_str(), info.error_details.c_str());850            }851        }852 853        // Handle gradient info854        if (info.has_gradient_info) {855            printf("[%s] nonfinite gradient at index %" PRId64 " (%s=%f) ", info.op_name.c_str(), info.gradient_index,856                   info.gradient_param_name.c_str(), info.gradient_value);857        }858 859        // Handle MAA error860        if (info.has_maa_error) {861            printf("[%s] MAA = %.9f > %.9f ", info.op_name.c_str(), info.maa_error, info.maa_threshold);862        }863 864        // Handle compare failure865        if (info.is_compare_failure) {866            printf("compare failed ");867        }868 869        // Print final status870        if (info.status == test_status_t::OK) {871            printf("\033[1;32mOK\033[0m\n");872        } else {873            printf("\033[1;31mFAIL\033[0m\n");874        }875    }876 877    void print_summary(const test_summary_info & info) override {878        if (info.is_backend_summary) {879            printf("%zu/%zu backends passed\n", info.tests_passed, info.tests_total);880        } else {881            printf("  %zu/%zu tests passed\n", info.tests_passed, info.tests_total);882        }883    }884 885    void print_backend_status(const backend_status_info & info) override {886        printf("  Backend %s: ", info.backend_name.c_str());887        if (info.status == test_status_t::OK) {888            printf("\033[1;32mOK\033[0m\n");889        } else {890            printf("\033[1;31mFAIL\033[0m\n");891        }892    }893 894    void print_testing_start(const testing_start_info & info) override {895        printf("Testing %zu devices\n\n", info.device_count);896    }897 898    void print_backend_init(const backend_init_info & info) override {899        printf("Backend %zu/%zu: %s\n", info.device_index + 1, info.total_devices, info.device_name.c_str());900 901        if (info.skipped) {902            printf("  %s\n", info.skip_reason.c_str());903            return;904        }905 906        if (!info.description.empty()) {907            printf("  Device description: %s\n", info.description.c_str());908        }909 910        if (info.has_memory_info) {911            printf("  Device memory: %zu MB (%zu MB free)\n", info.memory_total_mb, info.memory_free_mb);912        }913 914        printf("\n");915    }916 917    void print_overall_summary(const overall_summary_info & info) override {918        printf("%zu/%zu backends passed\n", info.backends_passed, info.backends_total);919        if (info.all_passed) {920            printf("\033[1;32mOK\033[0m\n");921        } else {922            printf("\033[1;31mFAIL\033[0m\n");923        }924    }925 926    void print_failed_tests(const std::vector<std::string> & failed_tests) override {927        if (failed_tests.empty()) {928            return;929        }930 931        printf("\nFailing tests:\n");932        for (const auto & test_name : failed_tests) {933            printf("  %s\n", test_name.c_str());934        }935    }936 937  private:938    void print_test_console(const test_result & result) {939        printf("  %s(%s): ", result.op_name.c_str(), result.op_params.c_str());940        fflush(stdout);941 942        if (!result.supported) {943            printf("not supported [%s] ", result.backend_name.c_str());944            printf("\n");945            return;946        }947 948        if (result.passed) {949            printf("\033[1;32mOK\033[0m\n");950        } else {951            printf("\033[1;31mFAIL\033[0m\n");952        }953    }954 955    void print_perf_console(const test_result & result) {956        int len = printf("  %s(%s): ", result.op_name.c_str(), result.op_params.c_str());957        fflush(stdout);958 959        if (!result.supported) {960            printf("not supported\n");961            return;962        }963 964        // align while also leaving some margin for variations in parameters965        int align = 8;966        int last  = (len + align - 1) / align * align;967        if (last - len < 5) {968            last += align;969        }970        printf("%*s", last - len, "");971 972        printf("    %8d runs - %8.2f us/run - ", result.n_runs, result.time_us);973 974        if (result.flops > 0) {975            auto format_flops = [](double flops) -> std::string {976                char buf[256];977                if (flops >= 1e12) {978                    snprintf(buf, sizeof(buf), "%6.2f TFLOP", flops / 1e12);979                } else if (flops >= 1e9) {980                    snprintf(buf, sizeof(buf), "%6.2f GFLOP", flops / 1e9);981                } else if (flops >= 1e6) {982                    snprintf(buf, sizeof(buf), "%6.2f MFLOP", flops / 1e6);983                } else {984                    snprintf(buf, sizeof(buf), "%6.2f kFLOP", flops / 1e3);985                }986                return buf;987            };988            uint64_t op_flops_per_run = result.flops * result.time_us / 1e6;989            printf("%s/run - \033[1;34m%sS\033[0m", format_flops(op_flops_per_run).c_str(),990                   format_flops(result.flops).c_str());991        } else {992            printf("%8zu kB/run - \033[1;34m%7.2f GB/s\033[0m", result.memory_kb, result.bandwidth_gb_s);993        }994        printf("\n");995    }996 997    void print_support_console(const test_result & result) {998        printf("  %s(%s): ", result.op_name.c_str(), result.op_params.c_str());999        fflush(stdout);1000 1001        if (result.supported) {1002            printf("\033[1;32mSUPPORTED\033[0m\n");1003        } else {1004            printf("\033[1;31mNOT SUPPORTED\033[0m\n");1005        }1006    }1007};1008 1009struct sql_printer : public printer {1010    static std::string get_sql_field_type(const std::string & field) {1011        switch (test_result::get_field_type(field)) {1012            case test_result::STRING:1013                return "TEXT";1014            case test_result::BOOL:1015            case test_result::INT:1016                return "INTEGER";1017            case test_result::FLOAT:1018                return "REAL";1019            default:1020                GGML_ABORT("invalid field type");1021        }1022    }1023 1024    void print_header() override {1025        std::vector<std::string> fields = test_result::get_fields();1026        fprintf(fout, "CREATE TABLE IF NOT EXISTS test_backend_ops (\n");1027        for (size_t i = 0; i < fields.size(); i++) {1028            fprintf(fout, "  %s %s%s\n", fields[i].c_str(), get_sql_field_type(fields[i]).c_str(),1029                    i < fields.size() - 1 ? "," : "");1030        }1031        fprintf(fout, ");\n\n");1032    }1033 1034    void print_test_result(const test_result & result) override {1035        fprintf(fout, "INSERT INTO test_backend_ops (");1036        std::vector<std::string> fields = test_result::get_fields();1037        for (size_t i = 0; i < fields.size(); i++) {1038            fprintf(fout, "%s%s", fields[i].c_str(), i < fields.size() - 1 ? ", " : "");1039        }1040        fprintf(fout, ") VALUES (");1041        std::vector<std::string> values = result.get_values();1042        for (size_t i = 0; i < values.size(); i++) {1043            fprintf(fout, "'%s'%s", values[i].c_str(), i < values.size() - 1 ? ", " : "");1044        }1045        fprintf(fout, ");\n");1046    }1047};1048 1049struct csv_printer : public printer {1050    void print_header() override {1051 1052        std::vector<std::string> fields     = test_result::get_fields();1053        std::vector<std::string> fields_csv = get_fields_csv();1054        for (size_t i = 0; i < fields.size(); i++) {1055            if (std::find(std::begin(fields_csv), std::end(fields_csv), fields[i]) == std::end(fields_csv)) {1056                continue;1057            }1058            printf("\"%s\"%s", fields[i].c_str(), i < fields.size() - 1 ? "," : "");1059        }1060        printf("\n");1061    }1062 1063    void print_test_result(const test_result & result) override {1064 1065        std::vector<std::string> values     = result.get_values();1066        std::vector<std::string> fields     = test_result::get_fields();1067        std::vector<std::string> fields_csv = get_fields_csv();1068 1069        for (size_t i = 0; i < values.size(); i++) {1070 1071            if (std::find(std::begin(fields_csv), std::end(fields_csv), fields[i]) == std::end(fields_csv)) {1072                continue;1073            }1074 1075            // Escape quotes and wrap in quotes for CSV1076            std::string escaped_value = values[i];1077            size_t pos = 0;1078            while ((pos = escaped_value.find("\"", pos)) != std::string::npos) {1079                escaped_value.replace(pos, 1, "\"\"");1080                pos += 2;1081            }1082            printf("\"%s\"%s", escaped_value.c_str(), i < values.size() - 1 ? "," : "");1083        }1084        printf("\n");1085    }1086 1087    static std::vector<std::string> get_fields_csv() {1088        return {1089            "op_name",1090            "op_params",1091            "supported",1092            "error_message",1093            "test_mode",1094            "backend_reg_name",1095            "backend_name",1096        };1097    }1098 1099};1100 1101static std::unique_ptr<printer> create_printer(output_formats format) {1102    switch (format) {1103        case CONSOLE:1104            return std::make_unique<console_printer>();1105        case SQL:1106            return std::make_unique<sql_printer>();1107        case CSV:1108            return std::make_unique<csv_printer>();1109    }1110    GGML_ABORT("invalid output format");1111}1112 1113struct test_case {1114    virtual ~test_case() {}1115 1116    virtual std::string op_desc(ggml_tensor * t) {1117        return ggml_op_desc(t);1118    }1119 1120    virtual std::string vars() {1121        return "";1122    }1123 1124    virtual ggml_tensor * build_graph(ggml_context * ctx) = 0;1125 1126    virtual double max_nmse_err() {1127        return 1e-7;1128    }1129 1130    virtual double max_nmse_err(ggml_backend_t backend) {1131        GGML_UNUSED(backend);1132        return max_nmse_err();1133    }1134 1135    virtual double max_maa_err() {1136        return 1e-4;1137    }1138 1139    virtual double max_err() {1140        return max_nmse_err();1141    }1142 1143    virtual double max_err(ggml_backend_t backend) {1144        return max_nmse_err(backend);1145    }1146 1147    virtual double err(const float * a, const float * b, size_t n) {1148        return nmse(a, b, n);1149    }1150 1151    virtual float grad_eps() {1152        return 1e-1f;1153    }1154 1155    // If false, estimate gradient with 2 points, neglects 3rd order derivative and higher.1156    // If true,  estimate gradient with 4 points, neglects 5th order derivative and higher.1157    virtual bool grad_precise() {1158        return false;1159    }1160 1161    // Skip gradient checks if total number of gradients to be checked is larger than this (to speed up the tests).1162    virtual int64_t grad_nmax() {1163        return 10000;1164    }1165 1166    // No effect if empty.1167    // If not empty, skip all gradient checks where the numerical result does not match any of the values.1168    // Needed for dealing with noncontinuous gradients (e.g. ReLU) where estimation using finite differences is unreliable.1169    virtual std::vector<float> grad_expect() {1170        return {};1171    }1172 1173    virtual void initialize_tensors(ggml_context * ctx) {1174        for (ggml_tensor * t = ggml_get_first_tensor(ctx); t != nullptr; t = ggml_get_next_tensor(ctx, t)) {1175            init_tensor_uniform(t);1176        }1177    }1178 1179    virtual size_t op_size(ggml_tensor * t) {1180        size_t size = ggml_nbytes(t);1181        // add source tensors1182        for (int i = 0; i < GGML_MAX_SRC; i++) {1183            if (t->src[i] != NULL) {1184                size += ggml_nbytes(t->src[i]);1185            }1186        }1187        return size;1188    }1189 1190    virtual uint64_t op_flops(ggml_tensor * t) {1191        GGML_UNUSED(t);1192        return 0;1193    }1194 1195    virtual bool run_whole_graph() { return false; }1196    virtual std::vector<ggml_tensor *> fusion_test_nodes() { return {}; }1197 1198    ggml_cgraph * gf = nullptr;1199    ggml_cgraph * gb = nullptr;1200 

Showing the first 1,200 of 9403 lines. Download the file for the rest.