Files
dex/pkg/lx/orderbook_cuda.go
zeekay c9c79f5c96 dex/pkg/lx: AMM cross-platform + CLOB CUDA + ABI mirror asserts + parity
AMM unification (one Go entry point, per-platform impls):
- amm_gpu.go          (cgo) — BatchEvalConstantProduct dispatcher with
                                LUX_GPU_DISABLE kill switch + fallback metrics
- amm_gpu_metal.go    (cgo && darwin) — Metal driver via lux-dex-amm-metal
- amm_gpu_cuda.go     (cgo && linux)  — CUDA driver via lux-dex-amm-cuda
- amm_gpu_stub.go     (cgo && other)  — errAMMGPUUnsupported sentinel
- amm_nogpu.go        (!cgo)          — pure CPU path

CLOB CUDA wire (the LP-108 missing piece — Backend enum can come back):
- orderbook_cuda_types.go     — Go mirrors of DEXOrder (64B), DEXTrade (80B),
                                 DEXPrice; assertDEXABI() in init() panics
                                 on any size/offset drift vs the C header
- orderbook_match_cpu.go      — MatchOrderCPU canonical Go oracle
- orderbook_cuda.go           (cgo && linux) — gpuMatchOrder via
                                 lux-dex-clob-cuda → libdex_clob_cuda.a →
                                 luxcpp/cuda/kernels/gpu/dex_swap.cu
- orderbook_cuda_stub.go      (other) — errCLOBGPUUnsupported sentinel
- orderbook_gpu.go            — MatchOrderGPU dispatcher with strict fallback
                                 policy + backend.RecordFallback observability
- orderbook_cuda_parity_test.go — 8 randomized parity subtests using
                                  DEXTrade.EqualFields / DEXOrder.EqualFields
                                  (NOT struct ==) so padding bytes can't
                                  cause false negatives

Padding normalization: _ blank pads renamed to _pad (addressable);
ClearPadding() methods on DEXOrder/DEXTrade; CPU oracle + CUDA host
driver both zero pad bytes for deterministic structural comparison.

Branding: all `Lux*`/`LUX_*` types in the C ABI mirror dropped (DEXOrder,
DEXTrade, DEXPrice, AMMReservePair, DEX_SIDE_BID, etc.).

Temporary replace github.com/luxfi/crypto => ../../lux/crypto pending
publication of crypto with backend.GPUDisabled / RecordFallback /
FallbackReason. Remove the replace once crypto is tagged.
2026-05-24 14:19:56 -07:00

92 lines
2.3 KiB
Go

// Copyright (C) 2025-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
//go:build cgo && linux
package lx
// CUDA backend for the DEX CLOB match_order kernel. Linked via
// lux-dex-clob-cuda pkg-config bundle
// -> libdex_clob_cuda.a (luxcpp/dex/gpu/cuda/dex_clob_host.cu
// + luxcpp/cuda/kernels/gpu/dex_swap.cu)
/*
#cgo pkg-config: lux-dex-clob-cuda
#include <stdint.h>
#include "dex_clob_host.h"
*/
import "C"
import (
"fmt"
"runtime"
"unsafe"
)
// gpuMatchOrder is the CUDA implementation called by orderbook_gpu.go.
// Returns errCLOBGPUUnsupported when no NVIDIA device is present so the
// dispatcher falls back to MatchOrderCPU.
func gpuMatchOrder(
incoming *DEXOrder,
book []DEXOrder,
bookIndices []uint32,
tradeIDBase uint64,
timestamp uint64,
) ([]DEXTrade, uint64, error) {
if len(bookIndices) == 0 {
return nil, incoming.Quantity, nil
}
tradesOut := make([]DEXTrade, len(bookIndices))
var (
tradesWritten uint32
remaining uint64
)
var pinner runtime.Pinner
defer pinner.Unpin()
pinner.Pin(incoming)
pinner.Pin(&book[0])
pinner.Pin(&bookIndices[0])
pinner.Pin(&tradesOut[0])
pinner.Pin(&tradesWritten)
pinner.Pin(&remaining)
rc := C.dex_clob_match_order_host(
(*C.DEXOrder)(unsafe.Pointer(incoming)),
(*C.DEXOrder)(unsafe.Pointer(&book[0])),
(*C.uint32_t)(unsafe.Pointer(&bookIndices[0])),
C.uint32_t(len(bookIndices)),
(*C.DEXTrade)(unsafe.Pointer(&tradesOut[0])),
C.uint64_t(tradeIDBase),
C.uint64_t(timestamp),
(*C.uint32_t)(unsafe.Pointer(&tradesWritten)),
(*C.uint64_t)(unsafe.Pointer(&remaining)),
)
runtime.KeepAlive(incoming)
runtime.KeepAlive(book)
runtime.KeepAlive(bookIndices)
runtime.KeepAlive(tradesOut)
switch rc {
case 0:
// Padding normalization: the host driver already zeros the
// padding bytes for emitted trades and touched book rows, but
// belt-and-braces here in case a future kernel revision
// changes the contract.
trades := tradesOut[:int(tradesWritten)]
for i := range trades {
trades[i].ClearPadding()
}
for i := range book {
book[i].ClearPadding()
}
return trades, remaining, nil
case -2:
return nil, 0, errCLOBGPUUnsupported
default:
return nil, 0, fmt.Errorf("lx: dex_clob_match_order_host rc=%d", int(rc))
}
}