use starknet_ff::FieldElement as FieldElement252;
use crate::core::fields::m31::BaseField;
use crate::core::fields::qm31::SecureField;
use crate::core::vcs::blake2_hash::Blake2sHash;
use crate::prover::backend::simd::column::{BaseColumn, SecureColumn};
use crate::prover::backend::ColumnOps;
#[cfg(feature = "cuda-runtime")]
use crate::prover::backend::Column;
use super::GpuBackend;
#[cfg(feature = "cuda-runtime")]
use super::memory::GpuBuffer;
#[cfg(feature = "cuda-runtime")]
use super::cuda_executor::{CudaFftError, get_cuda_executor};
pub const GPU_THRESHOLD_ELEMENTS: usize = 1 << 14;
impl ColumnOps<BaseField> for GpuBackend {
type Column = BaseColumn;
fn bit_reverse_column(column: &mut Self::Column) {
#[cfg(feature = "cuda-runtime")]
{
let len = column.len();
if len >= GPU_THRESHOLD_ELEMENTS {
if let Ok(()) = gpu_bit_reverse_base_column(column) {
return;
}
tracing::warn!("GPU bit_reverse failed, using CPU");
}
}
use crate::prover::backend::simd::SimdBackend;
<SimdBackend as ColumnOps<BaseField>>::bit_reverse_column(column);
}
}
impl ColumnOps<SecureField> for GpuBackend {
type Column = SecureColumn;
fn bit_reverse_column(column: &mut Self::Column) {
#[cfg(feature = "cuda-runtime")]
{
let len = column.len();
if len >= GPU_THRESHOLD_ELEMENTS / 4 {
if let Ok(()) = gpu_bit_reverse_secure_column(column) {
return;
}
tracing::warn!("GPU bit_reverse (secure) failed, using CPU");
}
}
use crate::prover::backend::simd::SimdBackend;
<SimdBackend as ColumnOps<SecureField>>::bit_reverse_column(column);
}
}
impl ColumnOps<FieldElement252> for GpuBackend {
type Column = Vec<FieldElement252>;
fn bit_reverse_column(_column: &mut Self::Column) {
unimplemented!("GPU bit_reverse for FieldElement252 not needed for Merkle")
}
}
impl ColumnOps<Blake2sHash> for GpuBackend {
type Column = Vec<Blake2sHash>;
fn bit_reverse_column(_column: &mut Self::Column) {
unimplemented!("bit_reverse_column not implemented for Blake2sHash columns")
}
}
#[cfg(feature = "cuda-runtime")]
fn gpu_bit_reverse_base_column(column: &mut BaseColumn) -> Result<(), CudaFftError> {
let executor = get_cuda_executor().map_err(|e| e.clone())?;
let len = column.len();
let log_size = len.ilog2();
let raw_data: &mut [u32] = unsafe {
std::slice::from_raw_parts_mut(
column.data.as_mut_ptr() as *mut u32,
len
)
};
executor.bit_reverse(raw_data, log_size)?;
Ok(())
}
#[cfg(feature = "cuda-runtime")]
fn gpu_bit_reverse_secure_column(column: &mut SecureColumn) -> Result<(), CudaFftError> {
let executor = get_cuda_executor().map_err(|e| e.clone())?;
let len = column.length;
let log_size = len.ilog2();
let raw_data: &mut [u32] = unsafe {
std::slice::from_raw_parts_mut(
column.data.as_mut_ptr() as *mut u32,
len * 4 )
};
executor.bit_reverse(raw_data, log_size)?;
Ok(())
}
#[cfg(feature = "cuda-runtime")]
pub fn base_column_to_gpu(column: &BaseColumn) -> Result<GpuBuffer<u32>, CudaFftError> {
let raw_data: &[u32] = unsafe {
std::slice::from_raw_parts(
column.data.as_ptr() as *const u32,
column.len()
)
};
GpuBuffer::from_cpu(raw_data)
}
#[cfg(feature = "cuda-runtime")]
pub fn gpu_to_base_column(buffer: &GpuBuffer<u32>, column: &mut BaseColumn) -> Result<(), CudaFftError> {
let raw_data: &mut [u32] = unsafe {
std::slice::from_raw_parts_mut(
column.data.as_mut_ptr() as *mut u32,
column.len()
)
};
buffer.to_cpu_into(raw_data)
}
pub fn should_use_gpu(len: usize) -> bool {
#[cfg(feature = "cuda-runtime")]
{
len >= GPU_THRESHOLD_ELEMENTS && super::cuda_executor::is_cuda_available()
}
#[cfg(not(feature = "cuda-runtime"))]
{
let _ = len;
false
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::prover::backend::Column;
#[test]
fn test_base_column_zeros() {
let col = <GpuBackend as ColumnOps<BaseField>>::Column::zeros(1024);
assert_eq!(col.len(), 1024);
}
#[test]
fn test_should_use_gpu_threshold() {
#[cfg(not(feature = "cuda-runtime"))]
{
assert!(!should_use_gpu(1_000_000));
}
#[cfg(feature = "cuda-runtime")]
{
assert!(!should_use_gpu(1000));
}
}
#[test]
fn test_bit_reverse_small_column() {
let mut col = BaseColumn::zeros(256);
<GpuBackend as ColumnOps<BaseField>>::bit_reverse_column(&mut col);
}
}