mcap/tools/gpu_bench/sha256.jai
Musa Mahmood 41d3543141 [0.1.26] GPU benchmark (gpu-bench branch, not for master)
bin/gpu-bench times every GPU model (OCR mobile and server, the label
image encoder, segmentation; optionally the CPU and the label text
encoder) over a fixed 30-image corpus in tools/gpu_bench/corpus. Every
corpus file is checked against corpus.txt's SHA-256 before anything
runs; each model's files and models.config entry are fingerprinted;
the GPU, driver, power limit, CUDA runtime, cuDNN and onnxruntime are
recorded, and NVML samples memory, load, power and clocks during the
timed passes. Results go to bin/gpu-bench-results as text files.

The GPU Bench button opens a window that runs gpu-bench in its own
process (no console) and lays results files from several machines side
by side against a baseline, marking a different corpus or model.
2026-10-17 21:31:31 -04:00

119 lines
4.5 KiB
Plaintext

// SHA-256 (FIPS 180-4), for gpu-bench's corpus and model fingerprints: the same hashes as the
// fetch scripts check (certutil, sha256sum), so they can be read against each other.
Sha256 :: struct {
state: [8] u32 = .[0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19];
block: [64] u8;
used: s64; // bytes in block
total: u64; // bytes hashed
}
sha256_update :: (h: *Sha256, data: [] u8) {
bytes := data;
h.total += cast(u64) bytes.count;
if h.used {
take := min(64 - h.used, bytes.count);
memcpy(h.block.data + h.used, bytes.data, take);
h.used += take;
bytes = array_view(bytes, take, bytes.count - take);
if h.used < 64 return;
sha256_blocks(h, h.block.data, 1);
h.used = 0;
}
whole := bytes.count / 64;
if whole sha256_blocks(h, bytes.data, whole);
rest := bytes.count - whole * 64;
if rest { memcpy(h.block.data, bytes.data + whole * 64, rest); h.used = rest; }
}
sha256_update :: (h: *Sha256, text: string) { sha256_update(h, cast([] u8) text); }
// Lowercase hex, 64 characters; from allocator.
sha256_finish :: (h: *Sha256, allocator := context.allocator) -> string {
bits := h.total * 8;
pad: [72] u8;
pad[0] = 0x80;
pad_count := ifx h.used < 56 then 56 - h.used else 120 - h.used;
for 0..7 pad[pad_count + it] = cast,trunc(u8) (bits >> cast(u64) (56 - 8 * it));
total := h.total;
sha256_update(h, array_view(pad, 0, pad_count + 8));
h.total = total;
HEX :: "0123456789abcdef";
result := alloc_string(64,, allocator);
for word, w: h.state for b: 0..3 {
byte := (word >> cast(u32) (24 - 8 * b)) & 0xff;
result[w * 8 + b * 2] = HEX[byte >> 4];
result[w * 8 + b * 2 + 1] = HEX[byte & 0xf];
}
return result;
}
sha256_of_string :: (text: string, allocator := context.allocator) -> string {
h: Sha256;
sha256_update(*h, text);
return sha256_finish(*h, allocator);
}
// The file's hash, read a few MB at a time; "" when it cannot be read.
sha256_of_file :: (path: string, allocator := context.allocator) -> string {
file, ok := file_open(path, log_errors = false);
if !ok return "";
defer file_close(*file);
CHUNK :: 4 * 1024 * 1024;
buffer := NewArray(CHUNK, u8,, context.default_allocator);
defer array_free(buffer,, context.default_allocator);
h: Sha256;
size := file_length(file);
done: s64;
while done < size {
count := min(CHUNK, size - done);
if !file_read(file, buffer.data, count) return "";
sha256_update(*h, array_view(buffer, 0, count));
done += count;
}
return sha256_finish(*h, allocator);
}
#scope_file
K :: u32.[
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
];
rotr :: inline (x: u32, n: u32) -> u32 #no_aoc { return (x >> n) | (x << (32 - n)); }
sha256_blocks :: (h: *Sha256, data: *u8, count: s64) #no_aoc {
w: [64] u32 = ---;
for block: 0..count - 1 {
p := data + block * 64;
for i: 0..15 {
q := p + i * 4;
w[i] = ((cast(u32) q[0]) << 24) | ((cast(u32) q[1]) << 16) | ((cast(u32) q[2]) << 8) | (cast(u32) q[3]);
}
for i: 16..63 {
s0 := rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ (w[i - 15] >> 3);
s1 := rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ (w[i - 2] >> 10);
w[i] = w[i - 16] + s0 + w[i - 7] + s1;
}
a, b, c, d, e, f, g, hh := h.state[0], h.state[1], h.state[2], h.state[3], h.state[4], h.state[5], h.state[6], h.state[7];
for i: 0..63 {
S1 := rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
ch := (e & f) ^ (~e & g);
t1 := hh + S1 + ch + K[i] + w[i];
S0 := rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
maj := (a & b) ^ (a & c) ^ (b & c);
t2 := S0 + maj;
hh = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;
}
h.state[0] += a; h.state[1] += b; h.state[2] += c; h.state[3] += d;
h.state[4] += e; h.state[5] += f; h.state[6] += g; h.state[7] += hh;
}
}