#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
use core::arch::x86_64::*;
#[cfg(target_arch = "x86")]
use core::arch::x86::*;
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
use core::arch::x86_64::{_mm512_add_epi32, _mm512_extracti32x4_epi32, _mm512_set1_epi32};
#[cfg(feature = "std")]
mod avx512_monitor {
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::OnceLock;
static MONITOR_INITIALIZED: AtomicBool = AtomicBool::new(false);
static AVX512_USAGE_COUNT: AtomicUsize = AtomicUsize::new(0);
static AVX512_FAILURES: AtomicUsize = AtomicUsize::new(0);
pub fn init_monitoring() {
if MONITOR_INITIALIZED.swap(true, Ordering::Relaxed) {
return; }
let avx512_available = super::is_avx512_available();
let avx2_available = super::is_avx2_available();
println!("ClockHash AVX-512 Monitoring Initialized:");
println!(" AVX2 Available: {}", avx2_available);
println!(" AVX-512 Available: {}", avx512_available);
if avx512_available {
let vendor = super::get_cpu_vendor().unwrap_or("unknown");
let (family, model, stepping) = super::get_cpu_model_info().unwrap_or((0, 0, 0));
println!(" CPU Vendor: {}", vendor);
println!(" CPU Model: Family {}, Model {}, Stepping {}", family, model, stepping);
let virtualized = super::is_likely_virtualized();
if virtualized {
println!(" ⚠️ Warning: Running in virtualized environment");
println!(" AVX-512 usage may be unreliable");
}
let model_safe = super::is_cpu_model_avx512_safe();
if !model_safe {
println!(" ⚠️ Warning: CPU model not in AVX-512 safety whitelist");
println!(" Using force override or experimental support");
}
}
println!(" Monitoring active: AVX-512 usage will be tracked");
}
pub fn record_avx512_usage() {
AVX512_USAGE_COUNT.fetch_add(1, Ordering::Relaxed);
}
pub fn record_avx512_failure() {
AVX512_FAILURES.fetch_add(1, Ordering::Relaxed);
eprintln!("⚠️ AVX-512 operation failure detected!");
}
pub fn get_stats() -> Avx512Stats {
Avx512Stats {
usage_count: AVX512_USAGE_COUNT.load(Ordering::Relaxed),
failure_count: AVX512_FAILURES.load(Ordering::Relaxed),
}
}
#[derive(Debug, Clone)]
pub struct Avx512Stats {
pub usage_count: usize,
pub failure_count: usize,
}
impl std::fmt::Display for Avx512Stats {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"AVX-512 Stats: {} successful operations, {} failures",
self.usage_count, self.failure_count
)
}
}
}
#[cfg(feature = "std")]
use avx512_monitor::*;
#[inline]
pub fn is_avx_available() -> bool {
crate::cpuid::has_avx()
}
#[inline]
pub fn is_os_avx_supported() -> bool {
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
{
true
}
#[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))]
{
false
}
}
#[cfg(feature = "simd")]
#[inline]
pub fn is_avx2_available() -> bool {
if !is_avx_available() || !is_os_avx_supported() {
return false;
}
let has_avx2 = crate::cpuid::has_avx2();
if !has_avx2 {
return false;
}
if is_likely_virtualized() {
#[cfg(feature = "std")]
{
if let Ok(val) = std::env::var("CLOCKHASH_FORCE_AVX2") {
if val == "1" || val.to_lowercase() == "true" {
return true;
}
}
}
return false;
}
has_avx2
}
#[inline]
fn get_cpu_vendor() -> Option<&'static str> {
crate::cpuid::get_vendor_string()
}
#[inline]
fn get_cpu_model_info() -> Option<(u8, u8, u8)> {
crate::cpuid::get_family_model_stepping()
}
#[inline]
fn is_cpu_model_avx512_safe() -> bool {
let vendor = match get_cpu_vendor() {
Some(v) => v,
None => return false, };
let (family, model, _stepping) = match get_cpu_model_info() {
Some(info) => info,
None => return false, };
match vendor {
"intel" => {
if family == 6 {
matches!(model, 0x55 | 0x7E | 0x8D | 0xA7 | 0x97 | 0xB7 | 0xAA)
} else {
false
}
}
"amd" => {
if matches!(family, 0x17 | 0x18 | 0x19 | 0x1A | 0x1B | 0x1C) {
#[cfg(feature = "std")]
{
if let Ok(val) = std::env::var("CLOCKHASH_ENABLE_AMD_AVX512") {
if val == "1" || val.to_lowercase() == "true" {
return true;
}
}
}
false } else {
false
}
}
_ => false, }
}
#[cfg(all(feature = "simd", feature = "std", any(target_arch = "x86_64", target_arch = "x86")))]
#[inline]
fn test_avx512_runtime_safety() -> bool {
use core::sync::atomic::{AtomicBool, Ordering};
static AVX512_TESTED: AtomicBool = AtomicBool::new(false);
static AVX512_SAFE: AtomicBool = AtomicBool::new(false);
if AVX512_TESTED.load(Ordering::Relaxed) {
return AVX512_SAFE.load(Ordering::Relaxed);
}
let features = crate::cpuid::get_avx512_features();
let is_consistent = if features.avx512f {
features.avx512vl && (features.avx512bw || features.avx512dq)
} else {
!features.avx512bw && !features.avx512vl && !features.avx512dq
};
let model_safe = is_cpu_model_avx512_safe();
let is_safe = is_consistent && model_safe;
AVX512_SAFE.store(is_safe, Ordering::Relaxed);
AVX512_TESTED.store(true, Ordering::Relaxed);
is_safe
}
#[inline]
pub fn is_avx512_available() -> bool {
if !is_avx_available() || !is_os_avx_supported() {
return false;
}
if is_likely_virtualized() {
return false;
}
if !is_cpu_model_avx512_safe() {
#[cfg(feature = "std")]
{
if let Ok(val) = std::env::var("CLOCKHASH_FORCE_AVX512") {
if !(val == "1" || val.to_lowercase() == "true") {
return false;
}
} else {
return false;
}
}
#[cfg(not(feature = "std"))]
{
return false;
}
}
#[cfg(feature = "std")]
{
if !test_avx512_runtime_safety() {
return false;
}
}
if !crate::cpuid::has_avx512_essential() {
return false;
}
true
}
#[inline]
fn is_likely_virtualized() -> bool {
crate::cpuid::is_virtualized()
}
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
#[inline]
fn test_avx512_safely() -> bool {
is_avx512_available()
}
#[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))]
#[inline]
fn test_avx512_safely() -> bool {
false
}
#[inline]
#[cfg(feature = "simd")]
pub fn clock_mix_avx2(message: &mut [u64; 16]) {
#[cfg(feature = "std")]
{
static MONITOR_INIT: std::sync::Once = std::sync::Once::new();
MONITOR_INIT.call_once(|| {
avx512_monitor::init_monitoring();
});
}
if is_avx512_available() {
#[cfg(feature = "std")]
avx512_monitor::record_avx512_usage();
#[cfg(feature = "std")]
{
let original_message = *message;
unsafe { crate::simd::avx512::clock_mix_avx512_impl(message) };
let mut scalar_message = original_message;
crate::simd::scalar::scalar_clock_mix(&mut scalar_message);
if *message != scalar_message {
avx512_monitor::record_avx512_failure();
*message = scalar_message;
}
}
#[cfg(not(feature = "std"))]
unsafe { crate::simd::avx512::clock_mix_avx512_impl(message) }
} else if is_avx2_available() {
unsafe { crate::simd::avx2::clock_mix_avx2_impl(message) }
} else {
crate::simd::scalar::scalar_clock_mix(message);
}
}
#[cfg(feature = "std")]
pub fn get_avx512_stats() -> avx512_monitor::Avx512Stats {
avx512_monitor::get_stats()
}
#[cfg(not(feature = "simd"))]
#[inline]
pub fn clock_mix_avx2(message: &mut [u64; 16]) {
crate::simd::scalar::scalar_clock_mix(message);
}
#[cfg(feature = "simd")]
#[inline]
pub fn process_block_simd(block: &[u8; 128], state: &mut [u64; 8]) {
#[cfg(target_arch = "x86_64")]
unsafe {
core::arch::x86_64::_mm_prefetch(
state.as_ptr() as *const i8,
core::arch::x86_64::_MM_HINT_T0,
);
}
let mut words = [0u64; 16];
for i in 0..16 {
let offset = i * 8;
words[i] = u64::from_le_bytes([
block[offset],
block[offset + 1],
block[offset + 2],
block[offset + 3],
block[offset + 4],
block[offset + 5],
block[offset + 6],
block[offset + 7],
]);
}
clock_mix_avx2(&mut words);
for i in 0..8 {
state[i] = state[i].wrapping_add(words[i]);
let rot_idx = (i + 4) % 8;
state[i] ^= crate::utils::rotl64(state[rot_idx], 17);
}
crate::clockpermute::clock_permute(state);
}
#[cfg(not(feature = "simd"))]
#[inline]
pub fn process_block_simd(block: &[u8; 128], state: &mut [u64; 8]) {
let mut words = [0u64; 16];
for i in 0..16 {
let offset = i * 8;
words[i] = u64::from_le_bytes([
block[offset],
block[offset + 1],
block[offset + 2],
block[offset + 3],
block[offset + 4],
block[offset + 5],
block[offset + 6],
block[offset + 7],
]);
}
crate::simd::scalar::scalar_clock_mix(&mut words);
for i in 0..8 {
state[i] = state[i].wrapping_add(words[i]);
let rot_idx = (i + 4) % 8;
state[i] ^= crate::utils::rotl64(state[rot_idx], 17);
}
crate::clockpermute::clock_permute(state);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_avx2_detection() {
let _ = is_avx2_available();
}
#[test]
fn test_avx512_detection() {
let _ = is_avx512_available();
}
#[test]
fn test_simd_dispatch_priority() {
let mut msg1 = [0u64; 16];
let mut msg2 = [0u64; 16];
for i in 0..16 {
msg1[i] = (i as u64).wrapping_mul(0x123456789ABCDEF0);
msg2[i] = msg1[i];
}
crate::simd::scalar::scalar_clock_mix(&mut msg1);
clock_mix_avx2(&mut msg2);
assert_eq!(
msg1, msg2,
"SIMD dispatch should produce identical results to scalar"
);
}
#[test]
#[cfg_attr(not(target_feature = "avx2"), ignore = "Requires AVX2 support")]
fn test_process_block_simd_consistency() {
let block = [0u8; 128];
let mut state1 = [0u64; 8];
let mut state2 = [0u64; 8];
for i in 0..8 {
state1[i] = (i as u64) * 0x1111111111111111;
state2[i] = state1[i];
}
let mut words = [0u64; 16];
for i in 0..16 {
let offset = i * 8;
words[i] = u64::from_le_bytes([
block[offset],
block[offset + 1],
block[offset + 2],
block[offset + 3],
block[offset + 4],
block[offset + 5],
block[offset + 6],
block[offset + 7],
]);
}
crate::simd::scalar::scalar_clock_mix(&mut words);
for i in 0..8 {
state1[i] = state1[i].wrapping_add(words[i]);
let rot_idx = (i + 4) % 8;
state1[i] ^= crate::utils::rotl64(state1[rot_idx], 17);
}
crate::clockpermute::clock_permute(&mut state1);
process_block_simd(&block, &mut state2);
assert_eq!(
state1, state2,
"process_block_simd should produce identical results to scalar implementation"
);
}
#[test]
fn test_cpu_feature_detection_stability() {
let avx2_1 = is_avx2_available();
let avx2_2 = is_avx2_available();
assert_eq!(avx2_1, avx2_2, "AVX2 detection should be stable");
let avx512_1 = is_avx512_available();
let avx512_2 = is_avx512_available();
assert_eq!(avx512_1, avx512_2, "AVX-512 detection should be stable");
}
#[test]
fn test_cpu_vendor_detection() {
let _vendor = get_cpu_vendor();
}
#[test]
fn test_cpu_model_info() {
let _info = get_cpu_model_info();
}
#[test]
fn test_cpu_model_avx512_safety() {
let _safe = is_cpu_model_avx512_safe();
}
#[test]
fn test_avx512_detection_conservative() {
let avx512_available = is_avx512_available();
let _ = avx512_available;
let avx512_available2 = is_avx512_available();
assert_eq!(
avx512_available, avx512_available2,
"AVX-512 detection should be consistent"
);
}
#[test]
#[cfg(feature = "std")]
fn test_runtime_avx512_safety() {
let safe = test_avx512_runtime_safety();
let _ = safe; }
#[test]
#[cfg(feature = "std")]
fn test_avx512_monitoring() {
use super::get_avx512_stats;
let initial_stats = get_avx512_stats();
let mut message = [0u64; 16];
for i in 0..16 {
message[i] = i as u64;
}
for _ in 0..5 {
clock_mix_avx2(&mut message);
}
let updated_stats = get_avx512_stats();
let _ = format!("{}", initial_stats);
let _ = format!("{}", updated_stats);
}
}