@mytec: iter3.7.0 start, gpu calc int

This commit is contained in:
2026-02-03 22:41:08 +02:00
parent a61753c642
commit 6cd9d869cc
29 changed files with 2288 additions and 28 deletions

View File

@@ -0,0 +1,305 @@
# rfcp-server-gpu.spec — GPU-enabled build (CuPy + CUDA 13.x)
# RFCP Iteration 3.6.0
#
# Mode: ONEDIR (directory output, not single exe)
# This is better for CUDA — DLLs load directly without temp extraction
#
# Requirements:
# pip install cupy-cuda13x fastrlock pyinstaller
# CUDA Toolkit 13.x installed (winget install Nvidia.CUDA)
#
# Build:
# cd backend && pyinstaller ../installer/rfcp-server-gpu.spec --clean --noconfirm
#
# Output:
# backend/dist/rfcp-server/rfcp-server.exe (+ DLLs in same folder)
import os
import sys
import glob
from PyInstaller.utils.hooks import collect_all, collect_dynamic_libs
backend_path = os.path.abspath(os.path.join(os.path.dirname(SPEC), '..', 'backend'))
print(f"[GPU SPEC] Backend path: {backend_path}")
# ═══════════════════════════════════════════
# Collect CuPy packages
# ═══════════════════════════════════════════
cupy_datas = []
cupy_binaries = []
cupy_hiddenimports = []
cupyb_datas = []
cupyb_binaries = []
cupyb_hiddenimports = []
try:
cupy_datas, cupy_binaries, cupy_hiddenimports = collect_all('cupy')
cupyb_datas, cupyb_binaries, cupyb_hiddenimports = collect_all('cupy_backends')
print(f"[GPU SPEC] CuPy: {len(cupy_binaries)} binaries, {len(cupy_datas)} data files")
except Exception as e:
print(f"[GPU SPEC] WARNING: CuPy collection failed: {e}")
# NOTE: nvidia pip packages REMOVED - they have cuda12 DLLs that conflict with cupy-cuda13x
# We use CUDA Toolkit 13.x DLLs only
# ═══════════════════════════════════════════
# Collect CUDA Toolkit DLLs (system install)
# ═══════════════════════════════════════════
# Installed via: winget install Nvidia.CUDA
cuda_toolkit_binaries = []
cuda_path = os.environ.get('CUDA_PATH', '')
if cuda_path:
# Scan BOTH bin\ and bin\x64\ directories
cuda_bin_dirs = [
os.path.join(cuda_path, 'bin'),
os.path.join(cuda_path, 'bin', 'x64'),
]
# Only essential CUDA runtime DLLs (exclude NPP, nvjpeg, nvblas, nvfatbin)
cuda_dll_patterns = [
'cublas64_*.dll',
'cublasLt64_*.dll',
'cudart64_*.dll',
'cufft64_*.dll',
'cufftw64_*.dll',
'curand64_*.dll',
'cusolver64_*.dll',
'cusolverMg64_*.dll',
'cusparse64_*.dll',
'nvrtc64_*.dll',
'nvrtc-builtins64_*.dll',
'nvJitLink_*.dll',
'nvjitlink_*.dll',
]
collected_dlls = set() # Avoid duplicates
for cuda_bin in cuda_bin_dirs:
if os.path.isdir(cuda_bin):
for pattern in cuda_dll_patterns:
for dll in glob.glob(os.path.join(cuda_bin, pattern)):
dll_name = os.path.basename(dll)
if dll_name not in collected_dlls:
cuda_toolkit_binaries.append((dll, '.'))
collected_dlls.add(dll_name)
print(f"[GPU SPEC] Scanned: {cuda_bin}")
print(f"[GPU SPEC] CUDA Toolkit ({cuda_path}): {len(cuda_toolkit_binaries)} DLLs")
for dll, _ in cuda_toolkit_binaries:
print(f"[GPU SPEC] {os.path.basename(dll)}")
else:
print("[GPU SPEC] ERROR: CUDA_PATH not set!")
print("[GPU SPEC] Install: winget install Nvidia.CUDA")
# All GPU binaries (CUDA Toolkit only, no nvidia pip packages)
all_gpu_binaries = cuda_toolkit_binaries
if len(all_gpu_binaries) == 0:
print("[GPU SPEC] NO CUDA DLLs FOUND!")
print("[GPU SPEC] Install CUDA Toolkit: winget install Nvidia.CUDA")
else:
print(f"[GPU SPEC] Total GPU DLLs: {len(all_gpu_binaries)}")
# ═══════════════════════════════════════════
# Collect fastrlock (CuPy dependency)
# ═══════════════════════════════════════════
fl_datas = []
fl_binaries = []
fl_hiddenimports = []
try:
fl_datas, fl_binaries, fl_hiddenimports = collect_all('fastrlock')
print(f"[GPU SPEC] fastrlock: {len(fl_binaries)} binaries")
except Exception:
print("[GPU SPEC] fastrlock not found (optional)")
# ═══════════════════════════════════════════
# PyInstaller Analysis
# ═══════════════════════════════════════════
a = Analysis(
[os.path.join(backend_path, 'run_server.py')],
pathex=[backend_path],
binaries=(
cupy_binaries + cupyb_binaries +
fl_binaries + all_gpu_binaries
),
datas=[
# Include app/ source code
(os.path.join(backend_path, 'app'), 'app'),
] + cupy_datas + cupyb_datas + fl_datas,
hiddenimports=[
# ── Uvicorn internals ──
'uvicorn.logging',
'uvicorn.loops',
'uvicorn.loops.auto',
'uvicorn.loops.asyncio',
'uvicorn.protocols',
'uvicorn.protocols.http',
'uvicorn.protocols.http.auto',
'uvicorn.protocols.http.h11_impl',
'uvicorn.protocols.http.httptools_impl',
'uvicorn.protocols.websockets',
'uvicorn.protocols.websockets.auto',
'uvicorn.protocols.websockets.wsproto_impl',
'uvicorn.lifespan',
'uvicorn.lifespan.on',
'uvicorn.lifespan.off',
# ── FastAPI / Starlette ──
'fastapi',
'fastapi.middleware',
'fastapi.middleware.cors',
'fastapi.routing',
'fastapi.responses',
'fastapi.exceptions',
'starlette',
'starlette.routing',
'starlette.middleware',
'starlette.middleware.cors',
'starlette.responses',
'starlette.requests',
'starlette.concurrency',
'starlette.formparsers',
'starlette.staticfiles',
# ── Pydantic ──
'pydantic',
'pydantic.fields',
'pydantic_settings',
'pydantic_core',
# ── HTTP / networking ──
'httpx',
'httpcore',
'h11',
'httptools',
'anyio',
'anyio._backends',
'anyio._backends._asyncio',
'sniffio',
# ── MongoDB (motor/pymongo) ──
'motor',
'motor.motor_asyncio',
'pymongo',
'pymongo.errors',
'pymongo.collection',
'pymongo.database',
'pymongo.mongo_client',
# ── Async I/O ──
'aiofiles',
'aiofiles.os',
'aiofiles.ospath',
# ── Scientific ──
'numpy',
'numpy.core',
'scipy',
'scipy.special',
'scipy.interpolate',
'shapely',
'shapely.geometry',
'shapely.ops',
# ── Multipart ──
'multipart',
'python_multipart',
# ── Encoding ──
'email.mime',
'email.mime.multipart',
# ── Multiprocessing ──
'multiprocessing',
'multiprocessing.pool',
'multiprocessing.queues',
'concurrent.futures',
# ── CuPy + CUDA ──
'cupy',
'cupy.cuda',
'cupy.cuda.runtime',
'cupy.cuda.driver',
'cupy.cuda.memory',
'cupy.cuda.stream',
'cupy.cuda.device',
'cupy._core',
'cupy._core.core',
'cupy._core._routines_math',
'cupy._core._routines_logic',
'cupy._core._routines_manipulation',
'cupy._core._routines_sorting',
'cupy._core._routines_statistics',
'cupy._core._cub_reduction',
'cupy.fft',
'cupy.linalg',
'cupy.random',
'cupy_backends',
'cupy_backends.cuda',
'cupy_backends.cuda.api',
'cupy_backends.cuda.libs',
'fastrlock',
'fastrlock.rlock',
] + cupy_hiddenimports + cupyb_hiddenimports + fl_hiddenimports,
hookspath=[],
hooksconfig={},
runtime_hooks=[os.path.join(os.path.dirname(SPEC), 'rthook_cuda_dlls.py')],
# ── Exclude bloat ──
excludes=[
# GUI
'tkinter',
'matplotlib',
'PIL',
'IPython',
# Data science bloat
'pandas',
'tensorflow',
'torch',
'keras',
# Testing
'pytest',
# Jupyter
'jupyter',
'notebook',
'ipykernel',
# gRPC / telemetry (often pulled in by dependencies)
'grpc',
'grpcio',
'google.protobuf',
'opentelemetry',
'opentelemetry.sdk',
'opentelemetry.instrumentation',
# Ray (too heavy, we use multiprocessing)
'ray',
# Other
'cv2',
'sklearn',
'sympy',
],
noarchive=False,
)
pyz = PYZ(a.pure)
# ═══════════════════════════════════════════
# ONEDIR mode: EXE + COLLECT
# ═══════════════════════════════════════════
# Creates: dist/rfcp-server/rfcp-server.exe + all DLLs in same folder
# Better for CUDA — no temp extraction needed
exe = EXE(
pyz,
a.scripts,
[], # No binaries/datas in EXE — they go in COLLECT
exclude_binaries=True, # ONEDIR mode
name='rfcp-server',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=False, # Don't compress — CUDA libs need fast loading
console=True,
icon=os.path.join(os.path.dirname(SPEC), 'rfcp.ico') if os.path.exists(os.path.join(os.path.dirname(SPEC), 'rfcp.ico')) else None,
)
coll = COLLECT(
exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=False,
upx_exclude=[],
name='rfcp-server',
)