Files
wehub-resource-sync ec436095dd
Book-CI / test (macos-latest) (push) Has been cancelled
Book-CI / test (ubuntu-latest) (push) Has been cancelled
Book-CI / test (windows-latest) (push) Has been cancelled
Release Fake Tag / publish (push) Has been cancelled
Deploy / deploy (macos-latest) (push) Has been cancelled
Deploy / deploy (ubuntu-latest) (push) Has been cancelled
Deploy / deploy (windows-latest) (push) Has been cancelled
Release to PyPI / Build & publish sglang-kt (push) Has been cancelled
Release to PyPI / Build kt-kernel (Python 3.11) (push) Has been cancelled
Release to PyPI / Build kt-kernel (Python 3.12) (push) Has been cancelled
Release to PyPI / Publish kt-kernel to PyPI (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:30:03 +08:00

491 lines
13 KiB
C++

#ifndef AMX_MAT_TEST_HPP
#define AMX_MAT_TEST_HPP
#include <cassert>
#include <iostream>
#include <limits>
#include <random>
#include "../../common.hpp"
#include "../la/utils.hpp"
#include "llama.cpp/ggml-impl.h"
#include "llama.cpp/ggml-quants.h"
#include "timer.hh"
template <typename T>
struct DotProductImpl {
static_assert(sizeof(T) == -1, "No associated type defined for this type.");
using type = void;
};
template <typename T>
using DotProductType = typename DotProductImpl<T>::type;
template <>
struct DotProductImpl<uint8_t> {
using type = uint32_t;
};
template <>
struct DotProductImpl<int8_t> {
using type = int32_t;
};
template <>
struct DotProductImpl<uint32_t> {
using type = uint32_t;
};
template <>
struct DotProductImpl<int32_t> {
using type = int32_t;
};
template <>
struct DotProductImpl<float> {
using type = float;
};
enum class Layout {
RowMajor,
ColumnMajor,
VNNIColumnMajor,
};
template <typename T>
struct Mat {
int rows, cols;
size_t size() { return rows * cols; }
T* data;
size_t stride_in_bytes;
void* qdata = nullptr;
ggml_type q_type;
size_t q_stride;
Layout layout = Layout::RowMajor;
Mat() {};
Mat(int rows, int cols, Layout layout) : rows(rows), cols(cols), layout(layout) {
size_t total_size;
if (layout == Layout::RowMajor) {
stride_in_bytes = cols * sizeof(T);
stride_in_bytes = (stride_in_bytes + 63) / 64 * 64;
total_size = stride_in_bytes * rows;
} else if (layout == Layout::ColumnMajor) {
stride_in_bytes = rows * sizeof(T);
stride_in_bytes = (stride_in_bytes + 63) / 64 * 64;
total_size = stride_in_bytes * cols;
} else {
assert(0);
}
// data = new(std::align_val_t(64)) T[rows * cols];
data = reinterpret_cast<T*>(aligned_alloc(64, total_size));
memset(data, 0, total_size);
}
Mat<T> sub_mat(int r, int c) {
Mat<T> re;
re.rows = r;
re.cols = c;
re.data = data;
re.layout = layout;
re.stride_in_bytes = stride_in_bytes;
re.qdata = qdata;
re.q_stride = q_stride;
re.q_type = q_type;
}
void dealloc() {
delete[] data;
if (qdata) {
delete[] reinterpret_cast<char*>(qdata);
}
}
void row_major_increase() {
int x = 0;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
at(i, j) = x++;
}
}
}
void dis_to_00() {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
at(i, j) = i + j;
}
}
}
void random(std::mt19937& gen) {
if constexpr (std::is_integral_v<T>) {
std::uniform_int_distribution<T> dist(0, 100);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
at(i, j) = dist(gen);
}
}
} else if constexpr (std::is_floating_point_v<T>) {
std::uniform_real_distribution<T> dist(-1.0, 1.0);
for (int i = 0; i < rows; i++) {
std::mt19937 gen_row(gen());
for (int j = 0; j < cols; j++) {
at(i, j) = dist(gen_row);
}
}
} else {
throw std::runtime_error("Unsupported type");
}
}
size_t stride() { return stride_in_bytes; }
int line_element_count() {
if (layout == Layout::RowMajor) {
return cols;
} else if (layout == Layout::ColumnMajor) {
return rows;
} else {
assert(0);
}
assert(0);
return 0;
}
T& at(int r, int c) {
switch (layout) {
case Layout::RowMajor:
return *offset_pointer_row_major(data, r, c, stride());
case Layout::ColumnMajor:
return *offset_pointer_col_major(data, r, c, stride());
// case Layout::VNNIColumnMajor:
// return data[c*rows+r];
default: {
assert(0);
}
}
throw std::runtime_error("Unsupported layout");
// assert(0);
}
void print() {
int limit = 10; // 设置阈值
int print_rows = 3; // 开头和结尾打印的行数和列数
for (int i = 0; i < rows; i++) {
// 当行数过多时,跳过中间的行
if (rows > limit && (i >= print_rows && i < rows - print_rows)) {
if (i == print_rows) {
std::cout << "...\n...\n";
}
continue;
}
for (int j = 0; j < cols; j++) {
// 当列数过多时,跳过中间的列
if (cols > limit && (j >= print_rows && j < cols - print_rows)) {
if (j == print_rows) {
std::cout << "... ";
}
continue;
}
if constexpr (std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t>) {
std::cout << (int)at(i, j) << " ";
} else {
std::cout << at(i, j) << " ";
}
}
std::cout << std::endl;
}
std::cout << std::endl;
}
void print_all() {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if constexpr (std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t>) {
std::cout << (int)at(i, j) << " ";
} else if constexpr (std::is_floating_point_v<T>) {
// std::cout << std::setw(6) << std::scientific << std::setprecision(2) << at(i, j) << " ";
printf("%6.2f ", at(i, j));
} else {
std::cout << at(i, j) << " ";
}
}
std::cout << std::endl;
}
std::cout << std::endl;
}
Mat<DotProductType<T>> mul_check(Mat<T>& b) {
assert(cols == b.rows);
Mat<DotProductType<T>> c(rows, b.cols, Layout::RowMajor);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < b.cols; j++) {
c.at(i, j) = 0;
for (int k = 0; k < cols; k++) {
c.at(i, j) += static_cast<DotProductType<T>>(at(i, k)) * static_cast<DotProductType<T>>(b.at(k, j));
}
}
}
return c;
}
bool cmp(Mat<T>& b) {
if constexpr (std::is_integral_v<T>) {
assert(rows == b.rows && cols == b.cols);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (at(i, j) != b.at(i, j)) {
std::cout << "Error at " << i << " " << j << " " << at(i, j) << ", " << b.at(i, j) << std::endl;
// std::cout << "Error at " << i << " " << j << std::endl;
// std::cout << "Other: " << b.at(i, j) << std::endl;
// std::cout << "Me: " << at(i, j) << std::endl;
// assert(0);
// break;
// return false;
}
}
}
std::cout << "Check passed" << std::endl;
return true;
}
if constexpr (std::is_floating_point_v<T>) {
T rel_error_sum = 0;
T error_sum = 0;
T max_error = 0;
T max_rel_error = 0;
int max_i = 0, max_j = 0;
assert(rows == b.rows && cols == b.cols);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
T error = std::abs(at(i, j) - b.at(i, j));
error_sum += error;
rel_error_sum += error / std::abs(at(i, j));
if (error / std::abs(at(i, j)) > max_rel_error) {
max_rel_error = error / std::abs(at(i, j));
}
if (error > max_error) {
max_i = i;
max_j = j;
max_error = error;
}
}
}
if (rel_error_sum / size() > 1e-2 || max_error / at(max_i, max_j) > 1e-2) {
std::cout << "Max Error: " << std::fixed << max_error << "(" << max_error / at(max_i, max_j) << ")"
<< " at " << max_i << " " << max_j << ", Max Rel Error " << max_rel_error
<< ", Average Relative: " << rel_error_sum / size() << ", Average Error: " << error_sum / size()
<< std::endl;
} else {
std::cout << "Error Less Than 1%" << std::endl;
}
return true;
}
}
void quant(ggml_type to) {
if constexpr (std::is_same<T, float>::value == false) {
throw std::runtime_error("Quantization only supported for f32 matrices");
}
// Timer t(std::string("to ") + ggml_type_name(to));
assert(line_element_count() * sizeof(T) == stride());
assert(line_element_count() % ggml_blck_size(to) == 0);
int blck_cnt_per_row = line_element_count() / ggml_blck_size(to);
q_stride = blck_cnt_per_row * ggml_type_size(to);
size_t qdata_size = size() * ggml_type_size(to) / ggml_blck_size(to);
qdata_size += 512 - q_stride % 512;
qdata = new (std::align_val_t(512)) char[qdata_size];
q_type = to;
switch (to) {
case GGML_TYPE_F32: {
return;
}
case GGML_TYPE_F16: {
ggml_fp32_to_fp16_row(data, reinterpret_cast<ggml_fp16_t*>(qdata), size());
return;
}
case GGML_TYPE_BF16: {
ggml_fp32_to_bf16_row(data, reinterpret_cast<ggml_bf16_t*>(qdata), size());
return;
}
case GGML_TYPE_Q4_0: {
quantize_row_q4_0(data, reinterpret_cast<block_q4_0*>(qdata), size());
return;
}
case GGML_TYPE_Q4_1: {
quantize_row_q4_1(data, reinterpret_cast<block_q4_1*>(qdata), size());
return;
}
case GGML_TYPE_Q5_0: {
quantize_row_q5_0(data, reinterpret_cast<block_q5_0*>(qdata), size());
return;
}
case GGML_TYPE_Q5_1: {
quantize_row_q5_1(data, reinterpret_cast<block_q5_1*>(qdata), size());
return;
}
case GGML_TYPE_Q8_0: {
quantize_row_q8_0(data, reinterpret_cast<block_q8_0*>(qdata), size());
return;
}
case GGML_TYPE_Q8_1: {
quantize_row_q8_1(data, reinterpret_cast<block_q8_1*>(qdata), size());
return;
}
case GGML_TYPE_Q2_K: {
quantize_row_q2_K(data, reinterpret_cast<block_q2_K*>(qdata), size());
return;
}
case GGML_TYPE_Q3_K: {
quantize_row_q3_K(data, reinterpret_cast<block_q3_K*>(qdata), size());
return;
}
case GGML_TYPE_Q4_K: {
quantize_row_q4_K(data, reinterpret_cast<block_q4_K*>(qdata), size());
return;
}
case GGML_TYPE_Q5_K: {
quantize_row_q5_K(data, reinterpret_cast<block_q5_K*>(qdata), size());
return;
}
case GGML_TYPE_Q6_K: {
quantize_row_q6_K(data, reinterpret_cast<block_q6_K*>(qdata), size());
return;
}
case GGML_TYPE_Q8_K: {
quantize_row_q8_K(data, reinterpret_cast<block_q8_K*>(qdata), size());
return;
}
case GGML_TYPE_IQ2_XXS:
case GGML_TYPE_IQ2_XS:
case GGML_TYPE_IQ3_XXS:
case GGML_TYPE_IQ1_S:
case GGML_TYPE_IQ4_NL:
case GGML_TYPE_IQ3_S:
case GGML_TYPE_IQ2_S:
case GGML_TYPE_IQ4_XS:
case GGML_TYPE_I8:
case GGML_TYPE_I16:
case GGML_TYPE_I32:
case GGML_TYPE_I64:
case GGML_TYPE_F64:
case GGML_TYPE_IQ1_M:
case GGML_TYPE_COUNT:
default:
throw std::runtime_error("Unsupported quantization type");
}
throw std::runtime_error("Unsupported quantization type");
}
template <typename Block>
Block* quant_data() {
return reinterpret_cast<Block*>(qdata);
}
void dequant() {
auto x = q_type;
switch (x) {
case GGML_TYPE_F32: {
return;
}
case GGML_TYPE_F16: {
ggml_fp16_to_fp32_row(reinterpret_cast<ggml_fp16_t*>(qdata), data, size());
return;
}
case GGML_TYPE_Q4_0: {
dequantize_row_q4_0(reinterpret_cast<block_q4_0*>(qdata), data, size());
return;
}
case GGML_TYPE_Q4_1: {
dequantize_row_q4_1(reinterpret_cast<block_q4_1*>(qdata), data, size());
return;
}
case GGML_TYPE_Q5_0: {
dequantize_row_q5_0(reinterpret_cast<block_q5_0*>(qdata), data, size());
return;
}
case GGML_TYPE_Q5_1: {
dequantize_row_q5_1(reinterpret_cast<block_q5_1*>(qdata), data, size());
return;
}
case GGML_TYPE_Q8_0: {
dequantize_row_q8_0(reinterpret_cast<block_q8_0*>(qdata), data, size());
return;
}
case GGML_TYPE_Q8_1: {
throw std::runtime_error("not supported");
}
case GGML_TYPE_Q2_K: {
dequantize_row_q2_K(reinterpret_cast<block_q2_K*>(qdata), data, size());
return;
}
case GGML_TYPE_Q3_K: {
dequantize_row_q3_K(reinterpret_cast<block_q3_K*>(qdata), data, size());
return;
}
case GGML_TYPE_Q4_K: {
dequantize_row_q4_K(reinterpret_cast<block_q4_K*>(qdata), data, size());
return;
}
case GGML_TYPE_Q5_K: {
dequantize_row_q5_K(reinterpret_cast<block_q5_K*>(qdata), data, size());
return;
}
case GGML_TYPE_Q6_K: {
dequantize_row_q6_K(reinterpret_cast<block_q6_K*>(qdata), data, size());
return;
}
case GGML_TYPE_Q8_K: {
dequantize_row_q8_K(reinterpret_cast<block_q8_K*>(qdata), data, size());
return;
}
case GGML_TYPE_IQ2_XXS:
case GGML_TYPE_IQ2_XS:
case GGML_TYPE_IQ3_XXS:
case GGML_TYPE_IQ1_S:
case GGML_TYPE_IQ4_NL:
case GGML_TYPE_IQ3_S:
case GGML_TYPE_IQ2_S:
case GGML_TYPE_IQ4_XS:
case GGML_TYPE_I8:
case GGML_TYPE_I16:
case GGML_TYPE_I32:
case GGML_TYPE_I64:
case GGML_TYPE_F64:
case GGML_TYPE_IQ1_M:
case GGML_TYPE_BF16: {
ggml_bf16_to_fp32_row(reinterpret_cast<ggml_bf16_t*>(qdata), data, size());
return;
}
case GGML_TYPE_COUNT:
default:
throw std::runtime_error("Unsupported quantization type");
}
throw std::runtime_error("Unsupported quantization type");
}
};
inline void init() {
struct ggml_init_params params = {
0,
NULL,
true,
};
auto ctx_eval = ggml_init(params);
if (!ctx_eval) {
throw std::runtime_error("Failed to create ggml context");
}
}
#endif