diff --git a/.gitignore b/.gitignore index c803b62..f6ea711 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,21 @@ -# compiled objects -*.o +/build/ # compiled binaries (match Makefile clean + all build targets) -qxmx_info -qxmx_load -qxmx_tok -qxmx_diff -qxmx_run -qxmx_ref_run +# compiled objects +deltanet_gpu_test +esimd_crash_repro +fused_test gemm gemv gemvprobe +ktest +*.o profgemm -profgemm_target profgemm_stream_target -deltanet_gpu_test -esimd_crash_repro -ktest -fused_test +profgemm_target +qxmx_diff +qxmx_info +qxmx_load +qxmx_ref_run +qxmx_run +qxmx_tok diff --git a/Makefile b/Makefile deleted file mode 100644 index b13329b..0000000 --- a/Makefile +++ /dev/null @@ -1,109 +0,0 @@ -# qxmx: dedicated SYCL/Xe2 inference engine for Ternary-Bonsai-27B -# (prism-ml, GGUF Q2_0_g64) on Intel Arc Pro B70. -# -# Build tiers: -# make tools -> CPU-only loader/binder/validation (no GPU needed) -# make all -> + SYCL engine (needs icpx + oneAPI, B70) - -MAKEFLAGS += -j$(shell nproc) - -CC ?= cc -NVCC ?= icpx # SYCL via DPC++ (rename later when kernels land) -CFLAGS ?= -O2 -Wall -Wextra -Wno-unused-parameter - -# SYCL/ESIMD build (needs oneAPI + the gcc-install-dir workaround: -fsycl's -# autodetect picks the i686 gcc-cross; pin to the x86_64 system gcc). -SYCC ?= icpx -SYFLAGS = -fsycl -O2 -std=c++17 \ - -Ithird_party \ - --gcc-install-dir=/usr/lib/gcc/x86_64-linux-gnu/14 - -# ---- CPU validation tools (build + run anywhere) ----------------------- -.PHONY: tools -tools: qxmx_info - -qxmx_info: qxmx_info.c qxmx_model.c gguf.c qxmx.h qxmx_model.h gguf.h - $(CC) $(CFLAGS) -lm $^ -o $@ - -# ---- SYCL GEMM probe (build on the B70) --------------------------------- -gemm: gemm.cpp qxmx.h - $(SYCC) $(SYFLAGS) $< -o $@ - -# ---- SYCL decode GEMV (batch=1) ------------------------------------------ -gemv: gemv.cpp qxmx.h - $(SYCC) $(SYFLAGS) $< -o $@ - -# ---- M1: weight residency (SYCL + model loader) --------------------------- -# C sources (gguf, qxmx_model) are compiled with cc and linked into the SYCL -# binary -- -fsycl forces the C++ frontend, which rejects several C idioms in -# the readers. The C headers carry extern "C" guards for clean interop. -qxmx_model.o: qxmx_model.c qxmx.h qxmx_model.h gguf.h - $(CC) $(CFLAGS) -c $< -o $@ -gguf.o: gguf.c gguf.h - $(CC) $(CFLAGS) -c $< -o $@ - -qxmx_load: qxmx_load.cpp qxmx_device.cpp qxmx_model.o gguf.o qxmx_device.h - $(SYCC) $(SYFLAGS) qxmx_load.cpp qxmx_device.cpp qxmx_model.o gguf.o -o $@ - -# ---- M4.5 spike: standalone DeltaNet GPU kernel vs CPU oracle -------------- -deltanet_gpu_test: deltanet_gpu_test.cpp qxmx_model.o gguf.o qxmx.h qxmx_ref.h - $(SYCC) $(SYFLAGS) $< qxmx_model.o gguf.o -o $@ - -# ---- M4 debug: ESIMD crash minimal reproduction -------------------------- -esimd_crash_repro: esimd_crash_repro.cpp qxmx_model.o gguf.o qxmx.h - $(SYCC) $(SYFLAGS) $< qxmx_model.o gguf.o -o $@ - -# ---- M4 debug: per-layer diff engine vs CPU ref --------------------------- -qxmx_diff: qxmx_diff.cpp qxmx_gpu.cpp qxmx_ref.cpp qxmx_model.o gguf.o \ - qxmx_tokenizer.cpp third_party/unicode.cpp third_party/unicode-data.cpp \ - qxmx_gpu.h qxmx_engine.h qxmx_ref.h qxmx_tokenizer.h qxmx_model.h gguf.h qxmx.h - $(SYCC) $(SYFLAGS) qxmx_diff.cpp qxmx_gpu.cpp qxmx_ref.cpp qxmx_tokenizer.cpp \ - third_party/unicode.cpp third_party/unicode-data.cpp \ - qxmx_model.o gguf.o -o $@ - -# ---- M4: B70 decode engine + CPU oracle, runtime-selectable ---------------- -qxmx_run: qxmx_run.cpp qxmx_gpu.cpp qxmx_cpu.cpp qxmx_ref.cpp qxmx_model.o gguf.o \ - qxmx_tokenizer.cpp third_party/unicode.cpp third_party/unicode-data.cpp \ - qxmx_gpu.h qxmx_cpu.h qxmx_engine.h qxmx_ref.h qxmx_tokenizer.h qxmx_model.h gguf.h qxmx.h - $(SYCC) $(SYFLAGS) qxmx_run.cpp qxmx_gpu.cpp qxmx_cpu.cpp qxmx_ref.cpp qxmx_tokenizer.cpp \ - third_party/unicode.cpp third_party/unicode-data.cpp \ - qxmx_model.o gguf.o -o $@ - -# ---- M3: CPU forward reference (the correctness oracle) ------------------- -qxmx_ref_run: qxmx_ref_run.cpp qxmx_ref.cpp qxmx_model.o gguf.o \ - qxmx_tokenizer.cpp third_party/unicode.cpp third_party/unicode-data.cpp \ - qxmx_ref.h qxmx_tokenizer.h qxmx_model.h gguf.h qxmx.h - $(SYCC) $(SYFLAGS) qxmx_ref_run.cpp qxmx_ref.cpp qxmx_tokenizer.cpp \ - third_party/unicode.cpp third_party/unicode-data.cpp \ - qxmx_model.o gguf.o -o $@ - -# ---- M2: tokenizer (links vendored llama.cpp unicode tables) ---------------- -qxmx_tok: qxmx_tok.cpp qxmx_tokenizer.cpp third_party/unicode.cpp \ - qxmx_model.o gguf.o qxmx_tokenizer.h qxmx_model.h gguf.h - $(SYCC) $(SYFLAGS) qxmx_tok.cpp qxmx_tokenizer.cpp \ - third_party/unicode.cpp third_party/unicode-data.cpp \ - qxmx_model.o gguf.o -o $@ - -# ---- GEMV limiter probe (load-only isolator) --------------------------- -gemvprobe: gemvprobe.cpp qxmx.h - $(SYCC) $(SYFLAGS) $< -o $@ - -# ---- SYCL GEMM profiling microbench ------------------------------------- -profgemm: profgemm.cpp qxmx.h - $(SYCC) $(SYFLAGS) $< -o $@ - -# ---- VTune profiling target (loops the real GEMM for ~5s) ---------------- -profgemm_target: profgemm_target.cpp qxmx.h - $(SYCC) $(SYFLAGS) $< -o $@ - -profgemm_stream_target: profgemm_stream_target.cpp qxmx.h - $(SYCC) $(SYFLAGS) $< -o $@ - -.PHONY: test -test: qxmx_info - ./qxmx_info $(MODEL) - -.PHONY: clean -clean: - rm -f qxmx_info qxmx_load qxmx_tok gemm gemv gemvprobe profgemm \ - profgemm_target profgemm_stream_target qxmx_model.o gguf.o diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..2aeb427 --- /dev/null +++ b/meson.build @@ -0,0 +1,80 @@ +# qxmx: SYCL/ESIMD inference engine for Ternary-Bonsai-27B on Intel Arc Pro B70. +# +# Setup: +# meson setup build --native-file meson/icpx.ini +# meson compile -C build +# +# Core targets: qxmx_run, qxmx_diff, gemv, qxmx_tok, qxmx_info. +# The SYCL toolchain (oneAPI icpx + -fsycl) is pinned via the native file +# meson/icpx.ini. C sources (gguf.c, qxmx_model.c) are compiled with the +# system cc because icpx's -fsycl C++ frontend rejects several C idioms in +# the readers (same split as the former Makefile). + +project('qxmx', 'c', 'cpp', + version : '0.1', + default_options : [ + 'c_std=gnu11', # gnu11 (not strict c11): gguf.c uses madvise() which needs _DEFAULT_SOURCE + 'cpp_std=c++17', + 'warning_level=2', # -Wall -Wextra + 'buildtype=release', # -O2 (matches Makefile CFLAGS/SYFLAGS) + ]) + +# oneAPI workaround: -fsycl's autodetect picks the i686 gcc-cross; pin to the +# x86_64 system gcc. The --gcc-install-dir flag lives in the native file's +# [built-in options] (it must apply to meson's sanity probe). -fsycl itself +# is per-target: only the SYCL binaries need it (qxmx_tok and the C-only tool +# do not). +sycl_args = ['-fsycl'] + +inc = include_directories('third_party') +c_compiler = meson.get_compiler('c') +libm = c_compiler.find_library('m', required : false) + +# ---- C objects (compiled with cc, linked into SYCL binaries) ------------ +# The -Wno-unused-parameter matches the Makefile (the C readers have a few). +c_warn = ['-Wno-unused-parameter'] +libgguf = static_library('gguf', 'gguf.c', c_args : c_warn) +libmodel = static_library('qxmx_model', 'qxmx_model.c', c_args : c_warn) + +# ---- qxmx_info: CPU-only loader (no SYCL, pure C) ----------------------- +executable('qxmx_info', + sources : 'qxmx_info.c', + link_with : [libgguf, libmodel], + dependencies : libm) + +# ---- qxmx_tok: tokenizer tool (C++, no SYCL, links C objects) ----------- +# Compiled with the cpp compiler (icpx via native file) for consistency with +# the SYCL targets that share the tokenizer; does not itself need -fsycl. +tok_sources = ['qxmx_tok.cpp', 'qxmx_tokenizer.cpp', + 'third_party/unicode.cpp', 'third_party/unicode-data.cpp'] +executable('qxmx_tok', + sources : tok_sources, + link_with : [libgguf, libmodel], + include_directories : inc) + +# ---- gemv: standalone SYCL/ESIMD decode-gemv harness -------------------- +executable('gemv', + sources : 'gemv.cpp', + cpp_args : sycl_args, + link_args : sycl_args, + include_directories : inc) + +# ---- Shared engine sources (SYCL via qxmx_gpu.cpp) ---------------------- +engine_sources_common = [ + 'qxmx_gpu.cpp', 'qxmx_ref.cpp', 'qxmx_tokenizer.cpp', + 'third_party/unicode.cpp', 'third_party/unicode-data.cpp', +] + +executable('qxmx_run', + sources : ['qxmx_run.cpp', 'qxmx_cpu.cpp'] + engine_sources_common, + link_with : [libgguf, libmodel], + cpp_args : sycl_args, + link_args : sycl_args, + include_directories : inc) + +executable('qxmx_diff', + sources : ['qxmx_diff.cpp'] + engine_sources_common, + link_with : [libgguf, libmodel], + cpp_args : sycl_args, + link_args : sycl_args, + include_directories : inc) diff --git a/meson/icpx.ini b/meson/icpx.ini new file mode 100644 index 0000000..0ab4382 --- /dev/null +++ b/meson/icpx.ini @@ -0,0 +1,20 @@ +# Native file pinning the C/C++ compilers and the oneAPI gcc workaround. +# +# meson setup build --native-file meson/icpx.ini +# +# C uses the system cc; C++ uses oneAPI icpx (provides -fsycl / ESIMD). +# --gcc-install-dir MUST be in [built-in options] (not just per-target) so it +# applies to meson's compiler sanity probe — without it icpx auto-detects the +# i686 gcc-cross and fails to link a trivial program. +# +# If icpx is not on PATH, set the full path here or export it. +# If your system gcc major differs from 14, update both gcc_install_dir paths +# (or pass -Dgcc_install_dir=... to meson setup and edit cpp_args/cpp_link_args). + +[binaries] +c = 'cc' +cpp = 'icpx' + +[built-in options] +cpp_args = ['--gcc-install-dir=/usr/lib/gcc/x86_64-linux-gnu/14'] +cpp_link_args = ['--gcc-install-dir=/usr/lib/gcc/x86_64-linux-gnu/14'] diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..333a0fe --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,4 @@ +option('gcc_install_dir', + type : 'string', + value : '/usr/lib/gcc/x86_64-linux-gnu/14', + description : 'Path passed to icpx --gcc-install-dir (oneAPI -fsycl workaround: pins the x86_64 system gcc instead of the i686 cross). Override if your system gcc major differs.')