Download kernels/satu1_avx512.cpp from deeprcurs/IKNN-Rl1-A1: direct link, hf CLI and curl.
- Browser
- Download file 5.89 kB
-
https://huggingface.co/deeprcurs/IKNN-Rl1-A1/resolve/main/kernels/satu1_avx512.cpp
- Command line
-
hf download hf://deeprcurs/IKNN-Rl1-A1/kernels/satu1_avx512.cpp
-
curl -L -o satu1_avx512.cpp https://huggingface.co/deeprcurs/IKNN-Rl1-A1/resolve/main/kernels/satu1_avx512.cpp
5.89 kB
| // satu1_avx512.cpp — IKNN-Rl1-A1 — SatU1 AVX-512 Kernel (Native VPOPCNTDQ) | |
| // Version: v1.0 | |
| // Created: 2026-09-03T16:55:00+07:00 | |
| // Last Updated: 2026-09-03T16:55:00+07:00 | |
| // Status: PUBLISHABLE — EN ONLY — M1 Kernel Validation | |
| // Repo: IKNN-Rl1-A1 — Integrated Knowledge-phase Neural Network — Recursive Language Iteration 1 — Architecture 1 | |
| // Hardware Target: Intel Xeon / Sapphire Rapids — AVX512F, BW, VL, VBMI2, VNNI, BITALG, VPOPCNTDQ (this sandbox) | |
| // — 2 vCPU, 54MB L3, DDR 50-90GB/s, 8GB swap at /home/user/.cache/swap-8gb (excluded) | |
| // Description: SatU1 1-bit XNOR+POPCOUNT, 512 connections per cycle per lane, 4 cycles per 512-bit | |
| // Canonical mapping: bit 0 = -1, bit 1 = +1, XNOR = NOT(A XOR B), S = popcount(XNOR), Y = (2S-K)*alpha | |
| // DRSS: direct-register streaming, no intermediate buffer | |
| // RoPE handling: RoPE applied on FP16 before Sign (see 5.4 step 3a) | |
| namespace iknn { | |
| namespace satu1 { | |
| namespace avx512 { | |
| // AVX-512 native kernel — 8x uint64_t = 512 bits = 512 weights per iteration | |
| // Requires: AVX512F + AVX512BW + AVX512_VPOPCNTDQ + AVX512_BITALG (for _mm512_xnor? we emulate via xor+not) | |
| inline float compute_satu1_block_avx512( | |
| const uint64_t* __restrict__ activation_bits, | |
| const uint64_t* __restrict__ weight_bits, | |
| float alpha, | |
| int block_size_words) // block_size_words = number of 64-bit words, must be multiple of 8 for 512-bit | |
| { | |
| // Accumulate popcount in 64-bit lanes | |
| __m512i total_pop = _mm512_setzero_si512(); | |
| int i = 0; | |
| // Process 8 words = 512 bits per iteration | |
| for (; i + 7 < block_size_words; i += 8) { | |
| __m512i a = _mm512_loadu_si512(reinterpret_cast<const __m512i*>(&activation_bits[i])); | |
| __m512i w = _mm512_loadu_si512(reinterpret_cast<const __m512i*>(&weight_bits[i])); | |
| // XNOR = NOT(A XOR B) | |
| __m512i x = _mm512_xor_si512(a, w); | |
| __m512i xnor = _mm512_xor_si512(x, _mm512_set1_epi64(-1)); // NOT via XOR with all 1s (BITALG: _mm512_xnor would be better if available) | |
| // Native popcount per 64-bit lane — VPOPCNTDQ — 1 cycle | |
| __m512i cnt = _mm512_popcnt_epi64(xnor); | |
| total_pop = _mm512_add_epi64(total_pop, cnt); | |
| } | |
| // Tail handling for remaining words (<8) | |
| int32_t tail_pop = 0; | |
| for (; i < block_size_words; ++i) { | |
| uint64_t xnor = ~(activation_bits[i] ^ weight_bits[i]); | |
| tail_pop += __builtin_popcountll(xnor); | |
| } | |
| // Horizontal sum of 8x 64-bit lanes | |
| // _mm512_reduce_add_epi64 requires AVX-512, use manual extract | |
| alignas(64) uint64_t pop_array[8]; | |
| _mm512_store_si512(reinterpret_cast<__m512i*>(pop_array), total_pop); | |
| int64_t total = tail_pop; | |
| for (int j = 0; j < 8; ++j) total += pop_array[j]; | |
| int64_t signed_sum = (2 * total) - (static_cast<int64_t>(block_size_words) * 64); | |
| return static_cast<float>(signed_sum) * alpha; | |
| } | |
| // Variant for 512-bit block (8 words) — most efficient, 1 ZMM = 512 weights | |
| inline float compute_satu1_zmm512( | |
| const __m512i& activation_zmm, // 512 bits = 8x64 bits packed signs | |
| const __m512i& weight_zmm, | |
| float alpha) | |
| { | |
| __m512i x = _mm512_xor_si512(activation_zmm, weight_zmm); | |
| __m512i xnor = _mm512_xor_si512(x, _mm512_set1_epi64(-1)); | |
| __m512i cnt = _mm512_popcnt_epi64(xnor); | |
| // reduce | |
| int64_t total = _mm512_reduce_add_epi64(cnt); | |
| int64_t signed_sum = (2 * total) - 512; | |
| return static_cast<float>(signed_sum) * alpha; | |
| } | |
| } // namespace avx512 | |
| } // namespace satu1 | |
| } // namespace iknn | |
| // Standalone test harness (when compiled as executable) | |
| int main() { | |
| using namespace iknn::satu1; | |
| using namespace iknn::satu1::avx512; | |
| std::cout << "[SatU1 AVX-512 Test] " << __DATE__ << " " << __TIME__ << std::endl; | |
| std::cout << "Hardware: Xeon AVX-512 VPOPCNTDQ, VBMI2" << std::endl; | |
| // Correctness test | |
| std::mt19937_64 rng(42); | |
| const int WORDS = 8; // 512 bits | |
| uint64_t act[WORDS], w[WORDS]; | |
| for (int i = 0; i < WORDS; ++i) { | |
| act[i] = rng(); | |
| w[i] = rng(); | |
| } | |
| float alpha = 0.5f; | |
| float naive = compute_satu1_block_naive(act, w, alpha, WORDS); | |
| float avx512_res = compute_satu1_block_avx512(act, w, alpha, WORDS); | |
| std::cout << "Naive: " << naive << " AVX-512: " << avx512_res << std::endl; | |
| if (std::abs(naive - avx512_res) < 1e-3f) { | |
| std::cout << "[PASS] Correctness" << std::endl; | |
| } else { | |
| std::cout << "[FAIL] Correctness mismatch!" << std::endl; | |
| return 1; | |
| } | |
| // Throughput benchmark | |
| const int ITERS = 1000000; | |
| auto start = std::chrono::high_resolution_clock::now(); | |
| float sum = 0; | |
| for (int it = 0; it < ITERS; ++it) { | |
| // Vary data to prevent optimization | |
| act[0] ^= it; | |
| sum += compute_satu1_block_avx512(act, w, alpha, WORDS); | |
| } | |
| auto end = std::chrono::high_resolution_clock::now(); | |
| auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); | |
| double giga_pop = (double)ITERS * WORDS * 64 / 1e9; | |
| double sec = ms / 1000.0; | |
| double giga_per_sec = giga_pop / sec; | |
| double tps_equiv = (double)ITERS / sec; // tokens per second if 1 block = 1 token (simplified) | |
| std::cout << "[BENCH] Iters: " << ITERS << " Time: " << ms << " ms" << std::endl; | |
| std::cout << "[BENCH] Giga-popcnt/s: " << giga_per_sec << std::endl; | |
| std::cout << "[BENCH] TPS equiv (512 weights): " << tps_equiv << std::endl; | |
| std::cout << "[BENCH] Sum (prevent opt): " << sum << std::endl; | |
| // Expected: On Xeon 2.6GHz with VPOPCNTDQ, ~4 cycles per 512 bits => ~0.65e9 popcnt per core per GHz? Rough. | |
| // Realistic target: >2 Giga-popcnt/s per core | |
| return 0; | |
| } | |