Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,15 @@ build-vision.bat
/dist/
*.done
/third_party/*.zip

# Local test artifacts, scratch, and binaries
Test/
tools/aria2c*
tools/*.exe
tools/*.reg
tools/bench_contexts.py
download_shards.py
run_kv_q4_test.bat
*.png
.vscode/
.idea/
9 changes: 8 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Strata Engine - top-level build (P1.S1).
# Strata Engine - top-level build (P1.S1).
#
# Targets (phase-1 §P1.S1): `strata_artifact` (no CUDA dependency), `tests`. `strata_plan` and the C++
# `strata-pack` are added when their sources exist - a target with no sources would make the build graph
Expand Down Expand Up @@ -178,6 +178,7 @@ if(STRATA_ENABLE_CUDA)
src/kernels/cuda/ple.cu
src/kernels/cuda/kv_q8.cu
src/kernels/cuda/kv_stream.cu
src/kernels/cuda/kv_q4.cu
src/kernels/cuda/fused_gr.cu
src/kernels/cuda/qsa_decode_attn.cu
src/kernels/cuda/fused_gdn.cu
Expand Down Expand Up @@ -363,6 +364,12 @@ if(STRATA_ENABLE_CUDA)
target_link_libraries(kv_stream_parity PRIVATE strata_kernels CUDA::cudart)
add_test(NAME kv_stream_parity COMMAND kv_stream_parity)

# Q4_0 KV storage with Walsh-Hadamard rotation vs host reference (GPU, synthetic, no model).
add_executable(kv_q4_parity src/kernels/kv_q4_parity.cpp)
target_include_directories(kv_q4_parity PRIVATE ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES})
target_link_libraries(kv_q4_parity PRIVATE strata_kernels CUDA::cudart)
add_test(NAME kv_q4_parity COMMAND kv_q4_parity)

# Plan v0.3 P3: native MMVQ for 1..8 tokens (bitwise selftest + --bench timing); synthetic data, no model.
if(STRATA_BUILD_TESTS)
add_executable(native_mmvq_multi bench/micro/native_mmvq_multi.cpp)
Expand Down
6 changes: 6 additions & 0 deletions include/strata/core/layer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ struct QsaState {
uint16_t* v_pool = nullptr;
/// Plan v0.3 P7: INT8 KV (qsa_set_kv_int8). Codes [page][kv_head][page_size][head_dim], one FP16 scale per 64.
bool kv_int8 = false;
/// Q4_0 KV with Walsh-Hadamard rotation (qsa_set_kv_q4).
bool kv_q4 = false;
uint8_t* k_q4 = nullptr;
uint8_t* v_q4 = nullptr;
int8_t* k_q = nullptr;
int8_t* v_q = nullptr;
uint16_t* k_scale = nullptr;
Expand Down Expand Up @@ -269,6 +273,8 @@ uint64_t qsa_kv_host_bytes();
/// initializing the session; default off until gate G-C accepts it.
void qsa_set_kv_int8(bool enabled);
bool qsa_kv_int8();
void qsa_set_kv_q4(bool enabled);
bool qsa_kv_q4();
uint64_t qsa_state_init(const ModelGeometry& g, int64_t max_cells, void* base, QsaState& st,
const QsaState* share_rope = nullptr, int64_t ring_cells = 0);
/// KV streaming: the pools a reader sees (the VRAM slots) and, when streamed, make the selection's blocks resident.
Expand Down
53 changes: 53 additions & 0 deletions include/strata/kernels/kv_q4.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// include/strata/kernels/kv_q4.hpp - Q4_0 KV storage with Walsh-Hadamard rotation for QSA layers.
#pragma once

#include "strata/kernels/qsa.hpp"
#include <cuda_fp16.h>
#include <cstdint>

namespace strata::kernels {

inline constexpr int QK4_0 = 32;

#pragma pack(push, 1)
struct block_q4_0 {
uint16_t d; // delta (half fp16 scale)
uint8_t qs[QK4_0 / 2]; // 16 bytes = 32 4-bit nibbles
};
#pragma pack(pop)

static_assert(sizeof(block_q4_0) == 18, "block_q4_0 must be 18 bytes");

/// Bytes per cell (one token, one KV head): 8 blocks of 32 for head_dim=256 -> 144 bytes per head.
inline uint64_t kv_q4_bytes_per_head(int head_dim) {
return (uint64_t) (head_dim / QK4_0) * sizeof(block_q4_0);
}

inline uint64_t kv_q4_bytes_per_cell(const QsaShapes& s) {
return (uint64_t) s.n_head_kv * kv_q4_bytes_per_head((int) s.head_dim) * 2; // K and V
}

/// Orthonormal Fast Walsh-Hadamard Transform (FWHT) for dimension 256.
/// Self-inverse: H * H * x = x. Scale is 1 / sqrt(256) = 1/16.
void fwht256_cuda(const float* src, float* dst, int64_t n_rows, void* stream);

/// In-place FWHT256
inline void fwht256_inplace_cuda(float* data, int64_t n_rows, void* stream) {
fwht256_cuda(data, data, n_rows, stream);
}

/// Append the cell at step[kStepPos] into Q4_0 pool with Hadamard rotation.
void kv_append_q4_step(uint8_t* k_q4, uint8_t* v_q4, const int32_t* page_table,
const int32_t* step, const float* kcur, const float* vcur,
const QsaShapes& s, void* stream);

/// Batched append of T cells into Q4_0 pool.
void kv_append_q4(uint8_t* k_q4, uint8_t* v_q4, const int32_t* page_table, int64_t pos0, int64_t T,
const float* K, const float* V, const QsaShapes& s, void* stream);

/// Gather step[kStepWidth] cells named by `ids` from Q4_0 pool into FP16 scratch [id][kv_head][head_dim].
void kv_gather_q4_step(const uint8_t* k_q4, const uint8_t* v_q4,
const int32_t* page_table, const int32_t* ids, const int32_t* step, int64_t max_ids,
const QsaShapes& s, uint16_t* k_scratch, uint16_t* v_scratch, void* stream);

} // namespace strata::kernels
2 changes: 2 additions & 0 deletions include/strata/kernels/qsa_decode_attn.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ struct QsaAttnPools {
const int8_t* v_q = nullptr;
const uint16_t* k_scale = nullptr; ///< fp16 [page][kv_head][page_size][head_dim / 64]
const uint16_t* v_scale = nullptr;
const uint8_t* k_q4 = nullptr; ///< q4_0 block_q4_0 [page][kv_head][page_size][head_dim / 32 * 18]
const uint8_t* v_q4 = nullptr;
const int32_t* page_table = nullptr;
};

Expand Down
Loading