Skip to content

Commit 0c7da6f

Browse files
committed
Add: Unified runtime hardware dispatch layer (Phase 5.6)
Replaces scattered compile-time #ifdef chains with a centralized runtime hardware detection and backend selection module. CPUID probes AVX-512 at runtime, CUDA/Metal availability checked via device queries, OpenMP thread count detected dynamically. Backend can be overridden via FLEXAIDS_BACKEND environment variable with automatic fallback to next-best available. New files: - LIB/hardware_dispatch.h — HardwareBackend enum, HardwareCapabilities struct, API - LIB/hardware_dispatch.cpp — CPUID, CUDA, Metal, OpenMP detection + selection logic Updated: - ShannonThermoStack now uses runtime dispatch for report strings and exposes active_shannon_backend() for programmatic backend queries - CMakeLists.txt wires hardware_dispatch.cpp into all targets, fixes Eigen compile definition propagation for test_hardware_dispatch, adds SIMD configuration to test target - 18 new tests covering runtime detection, backend selection, fallback logic, exclusion lists, edge cases (100k histograms, extreme ranges, single-bin) All 63 hardware dispatch tests pass. Pre-existing StatMech tolerance test (HighTemperatureFlattensWeights) unchanged. https://claude.ai/code/session_015b2LFt2aRHwau6rv6hnHoZ
1 parent af69aee commit 0c7da6f

File tree

6 files changed

+606
-27
lines changed

6 files changed

+606
-27
lines changed

CMakeLists.txt

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ target_sources(FlexAID PRIVATE
241241
LIB/statmech.cpp
242242
LIB/encom.cpp # ← NEW: ENCoM vibrational entropy
243243
# ── v1.5 thermodynamic + hardware acceleration modules ──
244+
LIB/hardware_dispatch.cpp
244245
LIB/ShannonThermoStack/ShannonThermoStack.cpp
245246
LIB/LigandRingFlex/RingConformerLibrary.cpp
246247
LIB/LigandRingFlex/SugarPucker.cpp
@@ -488,22 +489,32 @@ if(BUILD_TESTING)
488489
endif()
489490
add_test(NAME StatMechTests COMMAND test_statmech)
490491

491-
# test_hardware_dispatch — ShannonThermoStack dispatch layer tests
492+
# test_hardware_dispatch — ShannonThermoStack dispatch layer + unified runtime dispatch tests
492493
add_executable(test_hardware_dispatch
493494
tests/test_hardware_dispatch.cpp
494495
LIB/ShannonThermoStack/ShannonThermoStack.cpp
496+
LIB/hardware_dispatch.cpp
495497
LIB/statmech.cpp
496498
LIB/tencm.cpp)
497499
target_include_directories(test_hardware_dispatch PRIVATE
498500
${CMAKE_CURRENT_SOURCE_DIR}/LIB
499501
${CMAKE_CURRENT_SOURCE_DIR}/LIB/ShannonThermoStack)
500502
target_link_libraries(test_hardware_dispatch PRIVATE GTest::gtest GTest::gtest_main)
501-
target_compile_options(test_hardware_dispatch PRIVATE -O2)
503+
if(MSVC)
504+
target_compile_options(test_hardware_dispatch PRIVATE /O2)
505+
else()
506+
target_compile_options(test_hardware_dispatch PRIVATE -O2)
507+
endif()
508+
flexaids_configure_simd(test_hardware_dispatch)
502509
if(FLEXAIDS_USE_OPENMP AND OpenMP_CXX_FOUND)
503510
target_link_libraries(test_hardware_dispatch PRIVATE OpenMP::OpenMP_CXX)
504511
endif()
505-
if(FLEXAIDS_HAS_EIGEN)
512+
if(FLEXAIDS_USE_EIGEN AND Eigen3_FOUND)
506513
target_link_libraries(test_hardware_dispatch PRIVATE Eigen3::Eigen)
514+
target_compile_definitions(test_hardware_dispatch PRIVATE FLEXAIDS_HAS_EIGEN)
515+
elseif(FLEXAIDS_USE_EIGEN AND EIGEN3_FOUND)
516+
target_include_directories(test_hardware_dispatch PRIVATE ${EIGEN3_INCLUDE_DIRS})
517+
target_compile_definitions(test_hardware_dispatch PRIVATE FLEXAIDS_HAS_EIGEN)
507518
endif()
508519
add_test(NAME HardwareDispatchTests COMMAND test_hardware_dispatch)
509520

LIB/ShannonThermoStack/ShannonThermoStack.cpp

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
// ShannonThermoStack.cpp — multi-path implementation
22
//
3-
// Hardware dispatch priority (runtime):
4-
// 1. CUDA GPU (FLEXAIDS_USE_CUDA)
5-
// 2. Metal GPU (FLEXAIDS_HAS_METAL_SHANNON, Apple Silicon)
6-
// 3. AVX-512 (__AVX512F__) — 8 doubles/cycle histogram binning
7-
// 4. OpenMP (_OPENMP)
3+
// Hardware dispatch priority (runtime, via hardware_dispatch.h):
4+
// 1. CUDA GPU (FLEXAIDS_USE_CUDA + runtime device detected)
5+
// 2. Metal GPU (FLEXAIDS_HAS_METAL_SHANNON + runtime device detected)
6+
// 3. AVX-512 (__AVX512F__ + CPUID confirmation at runtime)
7+
// 4. OpenMP (_OPENMP + >1 thread available)
88
// 5. Scalar (always available)
99
//
1010
// Eigen is used for vectorised log() / probability array ops on all CPU paths.
11+
// The active backend can be queried at runtime via active_shannon_backend().
1112
#include "ShannonThermoStack.h"
13+
#include "../hardware_dispatch.h"
1214

1315
#ifdef FLEXAIDS_HAS_METAL_SHANNON
1416
# include "ShannonMetalBridge.h"
@@ -278,29 +280,51 @@ FullThermoResult run_shannon_thermo_stack(
278280
double S_contrib = -temperature_K * total_S;
279281
double final_dG = base_deltaG + S_contrib;
280282

281-
const char* hw =
282-
#if defined(FLEXAIDS_USE_CUDA)
283-
"CUDA";
284-
#elif defined(FLEXAIDS_HAS_METAL_SHANNON)
285-
"Metal";
286-
#elif defined(__AVX512F__)
287-
"AVX-512";
288-
#elif defined(_OPENMP)
289-
"OpenMP";
290-
#else
291-
"scalar";
292-
#endif
283+
const auto backend = active_shannon_backend();
284+
const char* hw = flexaids::backend_name(backend);
285+
286+
std::string eigen_tag;
287+
if (flexaids::detect_hardware().has_eigen)
288+
eigen_tag = "+Eigen";
293289

294290
std::string report =
295-
std::string("ShannonThermoStack[") + hw +
296-
#ifdef FLEXAIDS_HAS_EIGEN
297-
"+Eigen"
298-
#endif
291+
std::string("ShannonThermoStack[") + hw + eigen_tag +
299292
"]: S_conf=" + std::to_string(S_conf_bits) +
300293
" bits, S_vib=" + std::to_string(S_vib) +
301294
" kcal/mol/K, ΔG=" + std::to_string(final_dG) + " kcal/mol";
302295

303296
return { final_dG, S_conf_bits, S_vib, S_contrib, report };
304297
}
305298

299+
// ─── active_shannon_backend ─────────────────────────────────────────────────
300+
// Returns the backend that compute_shannon_entropy() actually uses for
301+
// histogram computation. This mirrors the compile-time #ifdef chain but
302+
// also consults runtime detection for AVX-512 (CPUID) and OpenMP (thread
303+
// count) to avoid reporting a backend that would silently fall through.
304+
305+
flexaids::HardwareBackend active_shannon_backend() {
306+
#if defined(FLEXAIDS_USE_CUDA)
307+
if (flexaids::is_backend_available(flexaids::HardwareBackend::CUDA))
308+
return flexaids::HardwareBackend::CUDA;
309+
#endif
310+
#if defined(FLEXAIDS_HAS_METAL_SHANNON)
311+
if (flexaids::is_backend_available(flexaids::HardwareBackend::METAL))
312+
return flexaids::HardwareBackend::METAL;
313+
#endif
314+
#if defined(__AVX512F__)
315+
if (flexaids::is_backend_available(flexaids::HardwareBackend::AVX512)) {
316+
# if defined(_OPENMP)
317+
return flexaids::HardwareBackend::AVX512; // AVX-512 + OpenMP combined path
318+
# else
319+
return flexaids::HardwareBackend::AVX512;
320+
# endif
321+
}
322+
#endif
323+
#if defined(_OPENMP)
324+
if (flexaids::is_backend_available(flexaids::HardwareBackend::OPENMP))
325+
return flexaids::HardwareBackend::OPENMP;
326+
#endif
327+
return flexaids::HardwareBackend::SCALAR;
328+
}
329+
306330
} // namespace shannon_thermo

LIB/ShannonThermoStack/ShannonThermoStack.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,18 @@
33
// Combines:
44
// – Shannon configurational entropy over GA ensemble (binned into 256 mega-clusters)
55
// – Torsional ENCoM vibrational entropy from NormalMode fluctuations (protein + nucleotide backbones)
6-
// – Hardware-accelerated histogram computation (Metal on Apple Silicon, OpenMP/Eigen on other platforms)
6+
// – Hardware-accelerated histogram computation (CUDA, Metal, AVX-512, OpenMP, scalar)
7+
//
8+
// Runtime backend selection via hardware_dispatch.h replaces compile-time #ifdef
9+
// chains. The environment variable FLEXAIDS_BACKEND can override auto-selection.
710
//
811
// Reuses StatMechEngine (statmech.h) and TorsionalENM (tencm.h) without modification.
912
// BindingPopulation is untouched; SugarPuckerGene flexibility is separate.
1013
#pragma once
1114

1215
#include "../statmech.h"
1316
#include "../tencm.h"
17+
#include "../hardware_dispatch.h"
1418
#include <vector>
1519
#include <string>
1620
#include <cmath>
@@ -87,4 +91,9 @@ FullThermoResult run_shannon_thermo_stack(
8791
double base_deltaG,
8892
double temperature_K = TEMPERATURE_K);
8993

94+
// ─── query the active backend at runtime ────────────────────────────────────
95+
// Returns the backend that compute_shannon_entropy() will use for histogram
96+
// computation, accounting for compile-time availability and runtime detection.
97+
flexaids::HardwareBackend active_shannon_backend();
98+
9099
} // namespace shannon_thermo

0 commit comments

Comments
 (0)