Validate all eleven native gfx1201 K layers with Windows replay

This commit is contained in:
Codex committed 2026-09-30 16:55:41 +03:00
1 parent 3c28a82e34
commit a0c36a6d6f
7 files changed
+381 -8

No files matched your search

+2
View File
@@ -116,6 +116,7 @@ struct Args {
std::string ngx_mode = "init";
unsigned preset = 11;
std::string fixture_dir;
std::string output_dir;
std::string kernel_name = "enc1";
unsigned iterations = 32;
int device = -1;
@@ -142,6 +143,7 @@ struct Args {
throw std::runtime_error("preset must be 5 (E), 11 (K) or 13 (M)");
}
else if (key == "--fixture-dir") fixture_dir = value;
else if (key == "--output-dir") output_dir = value;
else if (key == "--kernel-name") kernel_name = value;
else if (key == "--iterations") {
size_t end = 0;
+1
View File
@@ -25,6 +25,7 @@ struct HipApi {
D4R_HIP_FUNCTION(hipModuleLoad);
D4R_HIP_FUNCTION(hipModuleUnload);
D4R_HIP_FUNCTION(hipModuleGetFunction);
D4R_HIP_FUNCTION(hipModuleGetGlobal);
D4R_HIP_FUNCTION(hipModuleLaunchKernel);
D4R_HIP_FUNCTION(hipDeviceSynchronize);
D4R_HIP_FUNCTION(hipStreamCreateWithFlags);
+152
View File
@@ -0,0 +1,152 @@
#!/usr/bin/env python3
"""Generate public synthetic K replay fixtures and validate native outputs.
Uses the upstream replay format and NumPy model for all eleven K layers.
No NVIDIA weights, PTX or DLLs are used by this fixture generator.
"""
import argparse
import math
import pathlib
import struct
import sys
import numpy as np
ROOT = pathlib.Path(__file__).resolve().parents[2]
REFERENCE = pathlib.Path(__file__).resolve().parent / 'reference'
if not (REFERENCE / 'pwin_check.py').exists():
REFERENCE = ROOT / 'kernels/tools'
sys.path.insert(0, str(REFERENCE))
import pwin_model as pm
from pwin_check import LAYERS, model_window, Outputs, stored
def generate(layer, directory):
kind, heads, channels, other, extra = LAYERS[layer]
cin = 16 if kind == 'enc0' else channels
low = kind in ('dec', 'dec0')
cout = other if kind in ('enc', 'enc0') else channels
layout = pm.Layout(heads, channels, cout)
core_base = 2 * channels + 2 * 16 * channels if kind == 'enc0' else 0
if low:
core_base = 2 * other * 4 * channels + 8 * channels
weight_bytes = core_base + layout.PMB + 2 * layout.NPA * heads
weights = np.zeros(weight_bytes, np.uint8)
def half(offset, value):
weights[offset:offset + 2] = np.array([value], np.float16).view(np.uint8)
def matrix(base, k, n, stride, value=1.0):
half(base + 512 * (k // 16) + stride * (n // 16) + pm.frag_offset(k % 16, n % 16), value)
if kind == 'enc0':
for k in range(16):
matrix(2 * channels, k, k, 512)
matrix(2 * channels, k, k + 16, 512, .5)
if low:
for q in range(4):
for k in range(min(other, channels)):
matrix(0, k, q * channels + k, 512 * (other // 16), .25)
for c in range(channels):
half(core_base + layout.G1 + 2 * c, 1)
half(core_base + layout.G2 + 2 * c, 1)
half(core_base + layout.BO + 2 * c, 1 / 64)
half(core_base + layout.B2 + 2 * c, 1 / 64)
position_only = kind in ('enc0', 'dec0') or bool(extra)
for head in range(heads):
source_group = head % (channels // 32)
for j in range(3):
for k in range(32):
matrix(core_base + layout.QKV + layout.HEAD * head + 2048 * (3 * source_group + j),
k, k, 1024, .5 if j == 2 else .25)
for k in range(32):
matrix(core_base + layout.WO + 64 * channels * head, k,
32 * source_group + k, 1024, .5)
if position_only:
for row in range(64):
for col in range(64):
r, c = row % 16, col % 16
offset = core_base + layout.BIAS + head * 8192 + 512 * (4 * (col // 16) + row // 16)
offset += 64 * (r & 7) + 16 * ((c & 7) >> 1) + 2 * (c & 1) + 4 * (r >> 3) + 8 * (c >> 3)
half(offset, 1 / 64)
for group in range(channels // 32):
for k in range(32):
matrix(core_base + layout.W1 + 64 * channels * group, 32 * group + k, k, 32 * channels, .5)
matrix(core_base + layout.W2 + 64 * channels * group, k, 32 * group + k, 1024, .5)
if kind in ('enc', 'enc0'):
for n in range(cout):
matrix(core_base + layout.PM, n % channels + channels * ((n // channels) % 4),
n, 128 * channels, .5)
if kind == 'dec0':
for n in range(40):
matrix(core_base + layout.PM + 2 * 48, n % channels, n, 1024, .5)
half(core_base + layout.PM + 2 * n, 1 / 64)
input_elements = 16 * other if low else 64 * cin
x = ((np.arange(input_elements) % 9 - 4) / 4).astype(np.float16)
skip = ((np.arange(64 * channels) % 7 - 3) / 8).astype(np.float16)
output_channels = 40 if kind == 'dec0' else channels
allocations = {0: x.view(np.uint8), 1: skip.view(np.uint8), 2: weights}
if kind in ('enc0', 'enc'):
allocations[3] = np.full(16 * cout, np.nan, np.float16).view(np.uint8)
allocations[4] = np.full(64 * channels, np.nan, np.float16).view(np.uint8)
else:
allocations[3] = np.full(64 * output_channels, np.nan, np.float16).view(np.uint8)
parameters = bytearray(176)
struct.pack_into('<ii', parameters, 0, 8, 8)
pointers = {8: 0, 64: 2, 24: 3}
if low:
pointers[16] = 1
if kind in ('enc0', 'enc'):
pointers[32] = 4
bases = {i: 0x100000000 + i * 0x1000000 for i in allocations}
for offset, identifier in pointers.items():
struct.pack_into('<Q', parameters, offset, bases[identifier])
directory.mkdir(parents=True, exist_ok=True)
for identifier, data in allocations.items():
data.tofile(directory / f'alloc-{identifier}.bin')
(directory / 'args.bin').write_bytes(parameters)
lines = [f'kernel dltss_pwin_{layer}_layer', 'launch 1 1 1 32 1 4 0']
lines += [f'alloc {i} {bases[i]:016x} {data.size}' for i, data in allocations.items()]
lines += [f'pointer {offset} {i} 0' for offset, i in pointers.items()]
(directory / 'manifest.txt').write_text('\n'.join(lines) + '\n', encoding='utf-8')
print(f'PASS K_FIXTURE kernel={layer} weights={weight_bytes} public_synthetic=1')
def validate(layer, directory, output):
dump = pm.Dump(str(directory))
model, extra = model_window(dump, layer, 0, 0)
expected, actual = stored(dump, Outputs(dump, str(output)), layer, 0, 0, model, extra)
if not np.isfinite(expected).all() or not np.isfinite(actual).all():
raise RuntimeError('K replay contains NaN/Inf or unwritten output')
difference = np.abs(actual.astype(np.float64) - expected.astype(np.float64))
maximum = float(difference.max())
relative = float((difference / np.maximum(np.abs(expected.astype(np.float64)), 1e-3)).max())
rms = float(np.sqrt(np.mean(difference ** 2)))
peak = max(1., float(np.abs(expected.astype(np.float64)).max()))
psnr = math.inf if not rms else 20 * math.log10(peak / rms)
print(f'K_REPLAY_REFERENCE kernel={layer} elements={actual.size} max_abs={maximum:.9g} '
f'max_rel={relative:.9g} rms={rms:.9g} psnr_db={psnr:.6g}')
if maximum > .001 or psnr < 60:
worst = int(difference.argmax())
raise RuntimeError(f'K mismatch at {worst}: reference={expected[worst]}, gpu={actual[worst]}')
print(f'PASS K_REPLAY_REFERENCE kernel={layer} architecture=gfx1201 nan_inf=0')
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('mode', choices=['generate', 'validate'])
parser.add_argument('--layer', choices=list(LAYERS), required=True)
parser.add_argument('--fixture-dir', type=pathlib.Path, required=True)
parser.add_argument('--output-dir', type=pathlib.Path)
args = parser.parse_args()
try:
if args.mode == 'generate':
generate(args.layer, args.fixture_dir)
else:
if not args.output_dir:
parser.error('validate requires --output-dir')
validate(args.layer, args.fixture_dir, args.output_dir)
except Exception as error:
print(f'FAIL K_REPLAY {error}', file=sys.stderr)
raise SystemExit(5)
+123
View File
@@ -0,0 +1,123 @@
#include "hip_api.h"
#include <fstream>
#include <sstream>
#include <memory>
namespace {
std::vector<uint8_t> read_file(const std::filesystem::path& path) {
std::ifstream file(path, std::ios::binary);
if (!file) throw std::runtime_error("Cannot read replay file " + d4r::diag::utf8(path.c_str()));
return {std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()};
}
struct Allocation {
d4r::diag::HipApi& hip;
int id;
size_t size;
void* device = nullptr;
Allocation(d4r::diag::HipApi& api, int identifier, const std::vector<uint8_t>& bytes)
: hip(api), id(identifier), size(bytes.size()) {
hip.check(hip.hipMalloc(&device, size), "hipMalloc(replay)");
try { hip.check(hip.hipMemcpy(device, bytes.data(), size, hipMemcpyHostToDevice), "hipMemcpy(replay upload)"); }
catch (...) { (void)hip.hipFree(device); device = nullptr; throw; }
}
~Allocation() { if (device) (void)hip.hipFree(device); }
};
}
int main(int argc, char** argv) {
using namespace d4r::diag;
start();
try {
Args args(argc, argv);
if (args.module.empty() || args.fixture_dir.empty() || args.output_dir.empty())
throw std::runtime_error("--module, --fixture-dir and --output-dir are required");
HipApi hip(args.hip_root);
hipDeviceProp_t props{};
hip.select_gfx1201(args.device, props);
const std::filesystem::path input(wide(args.fixture_dir)), output(wide(args.output_dir));
auto parameters = read_file(input / L"args.bin");
if (parameters.empty() || parameters.size() > 4096) throw std::runtime_error("Invalid replay parameter size");
std::ifstream manifest(input / L"manifest.txt");
if (!manifest) throw std::runtime_error("Replay manifest is missing");
std::vector<std::string> lines;
std::string line, kernel;
unsigned grid[3] = {1, 1, 1}, block[3] = {32, 1, 4}, shared = 0;
std::vector<std::unique_ptr<Allocation>> allocations;
while (std::getline(manifest, line)) {
lines.push_back(line);
std::istringstream stream(line);
std::string kind;
stream >> kind;
if (kind == "kernel") stream >> kernel;
else if (kind == "launch") stream >> grid[0] >> grid[1] >> grid[2] >> block[0] >> block[1] >> block[2] >> shared;
else if (kind == "texture" || kind == "surface") throw std::runtime_error("This replay requires a texture/surface recreation backend");
else if (kind == "alloc") {
int id = -1; std::string base; size_t size = 0;
stream >> id >> base >> size;
if (!stream || id < 0 || size == 0 || size > props.totalGlobalMem / 2)
throw std::runtime_error("Invalid replay allocation record");
for (const auto& allocation : allocations)
if (allocation->id == id) throw std::runtime_error("Duplicate replay allocation ID");
auto bytes = read_file(input / ("alloc-" + std::to_string(id) + ".bin"));
if (bytes.size() != size) throw std::runtime_error("Replay allocation size mismatch");
allocations.push_back(std::make_unique<Allocation>(hip, id, bytes));
}
}
if (kernel.empty() || allocations.empty() || !grid[0] || !grid[1] || !grid[2])
throw std::runtime_error("Incomplete replay manifest");
for (const auto& record : lines) {
std::istringstream stream(record); std::string kind;
stream >> kind;
if (kind != "pointer") continue;
size_t offset = 0, delta = 0; int id = -1;
stream >> offset >> id >> delta;
if (!stream || offset > parameters.size() || parameters.size() - offset < 8)
throw std::runtime_error("Invalid replay pointer offset");
auto allocation = std::find_if(allocations.begin(), allocations.end(), [&](const auto& a) { return a->id == id; });
if (allocation == allocations.end() || delta >= (*allocation)->size)
throw std::runtime_error("Invalid replay pointer relocation");
const uint64_t pointer = reinterpret_cast<uintptr_t>((*allocation)->device) + delta;
std::memcpy(parameters.data() + offset, &pointer, 8);
}
hipModule_t module = nullptr;
hip.check(hip.hipModuleLoad(&module, args.module.c_str()), "hipModuleLoad(replay gfx1201)");
struct Cleanup { HipApi& hip; hipModule_t module; ~Cleanup() { (void)hip.hipModuleUnload(module); } } cleanup{hip, module};
auto scalar = [&](const char* name, unsigned fallback) {
hipDeviceptr_t address = nullptr; size_t size = 0;
if (hip.hipModuleGetGlobal(&address, &size, module, name) != hipSuccess) return fallback;
if (size != 4) throw std::runtime_error(std::string("Invalid native metadata ") + name);
unsigned value = 0;
hip.check(hip.hipMemcpy(&value, address, 4, hipMemcpyDeviceToHost), name);
return value ? value : fallback;
};
block[2] = scalar("d4r_block_z", block[2]);
const unsigned persistentGrid = scalar("d4r_grid_x", 0);
if (persistentGrid) { grid[0] = persistentGrid; grid[1] = grid[2] = 1; }
hipFunction_t function = nullptr, prep = nullptr;
hip.check(hip.hipModuleGetFunction(&function, module, kernel.c_str()), "hipModuleGetFunction(replay)");
void* launchArguments[] = {parameters.data()};
if (hip.hipModuleGetFunction(&prep, module, (kernel + "_prep").c_str()) == hipSuccess) {
const unsigned prepBlocks = scalar("d4r_prep_blocks", 0);
if (!prepBlocks) throw std::runtime_error("Native prep has no valid d4r_prep_blocks");
hip.check(hip.hipModuleLaunchKernel(prep, prepBlocks, 1, 1, 128, 1, 1, 0, nullptr, launchArguments, nullptr), "hipModuleLaunchKernel(replay prep)");
}
std::printf("REPLAY kernel=%s grid=%u,%u,%u block=%u,%u,%u allocations=%zu arguments=%zu\n",
kernel.c_str(), grid[0], grid[1], grid[2], block[0], block[1], block[2], allocations.size(), parameters.size());
for (unsigned iteration = 0; iteration < args.iterations; ++iteration)
hip.check(hip.hipModuleLaunchKernel(function, grid[0], grid[1], grid[2], block[0], block[1], block[2], shared,
nullptr, launchArguments, nullptr), "hipModuleLaunchKernel(replay)");
hip.check(hip.hipDeviceSynchronize(), "hipDeviceSynchronize(replay)");
std::filesystem::create_directories(output);
for (const auto& allocation : allocations) {
std::vector<uint8_t> bytes(allocation->size);
hip.check(hip.hipMemcpy(bytes.data(), allocation->device, bytes.size(), hipMemcpyDeviceToHost), "hipMemcpy(replay result)");
std::ofstream file(output / ("alloc-" + std::to_string(allocation->id) + ".bin"), std::ios::binary);
file.write(reinterpret_cast<const char*>(bytes.data()), std::streamsize(bytes.size()));
if (!file) throw std::runtime_error("Cannot save replay allocation");
}
std::printf("PASS NATIVE_REPLAY architecture=gfx1201 kernel=%s iterations=%u numerical_reference=pending\n", kernel.c_str(), args.iterations);
return 0;
} catch (const std::exception& error) {
std::fprintf(stderr, "FAIL NATIVE_REPLAY %s\n", error.what()); loaded_modules(); return 4;
}
}