1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
//! Contents for GPU support
use error::Result;
use faiss_sys::*;
use std::ptr;
/// Common interface for GPU resources used by Faiss.
pub trait GpuResources {
/// Obtain a raw pointer to the native GPU resources object.
fn inner_ptr(&self) -> *mut FaissGpuResources;
/// Disable allocation of temporary memory; all temporary memory
/// requests will call `cudaMalloc` / `cudaFree` at the point of use
fn no_temp_memory(&mut self) -> Result<()>;
/// Specify that we wish to use a certain fixed size of memory on
/// all devices as temporary memory
fn set_temp_memory(&mut self, size: usize) -> Result<()>;
/// Specify that we wish to use a certain fraction of memory on
/// all devices as temporary memory
fn set_temp_memory_fraction(&mut self, fraction: f32) -> Result<()>;
/// Set amount of pinned memory to allocate, for async GPU <-> CPU
/// transfers
fn set_pinned_memory(&mut self, size: usize) -> Result<()>;
}
/// Standard GPU resources descriptor.
///
/// # Examples
///
/// GPU resources are meant to be passed to an index implementation's
/// [`into_gpu`] or [`to_gpu`] methods.
///
/// [`to_gpu`]: ../index/struct.IndexImpl.html#method.to_gpu
/// [`into_gpu`]: ../index/struct.IndexImpl.html#method.into_gpu
///
/// ```
/// # fn run() -> Result<(), Box<::std::error::Error>> {
/// use faiss::{StandardGpuResources, MetricType};
/// use faiss::index::flat::FlatIndex;
///
/// let gpu = StandardGpuResources::new()?;
/// let index = FlatIndex::new(64, MetricType::L2)?;
/// let gpu_index = index.into_gpu(&gpu, 0)?;
/// # Ok(())
/// # }
/// # run().unwrap();
/// ```
///
/// Since GPU implementations are not thread-safe, attempting to use the GPU
/// resources from another thread is not allowed.
///
/// ```compile_fail
/// use faiss::{GpuResources, StandardGpuResources};
/// use faiss::index::flat::FlatIndex;
/// use std::sync::Arc;
/// use std::thread;
///
/// # fn run() -> Result<(), Box<::std::error::Error>> {
/// let gpu = Arc::new(StandardGpuResources::new()?);
/// let gpu_rc = gpu.clone();
/// thread::spawn(move || {
/// let index = FlatIndex::new_l2(64)?;
/// let gpu_index = index.into_gpu(&*gpu_rc, 0)?; // will not compile
/// Ok(())
/// });
/// # Ok(())
/// # }
/// # run().unwrap();
/// ```
///
/// Other than that, indexes can share the same GPU resources, so long as
/// neither of them cross any thread boundaries.
///
/// ```
/// use faiss::{GpuResources, StandardGpuResources, MetricType, index_factory};
///
/// # fn run() -> Result<(), Box<::std::error::Error>> {
/// let mut gpu = StandardGpuResources::new()?;
/// let index1 = index_factory(64, "Flat", MetricType::L2)?
/// .into_gpu(&gpu, 0)?;
/// let index2 = index_factory(32, "Flat", MetricType::InnerProduct)?
/// .into_gpu(&gpu, 0)?;
/// # Ok(())
/// # }
/// # run().unwrap();
/// ```
///
#[derive(Debug)]
pub struct StandardGpuResources {
inner: *mut FaissGpuResources,
}
// Deliberately _not_ Sync!
unsafe impl Send for StandardGpuResources {}
impl StandardGpuResources {
/// Create a standard GPU resources object.
pub fn new() -> Result<Self> {
unsafe {
let mut ptr = ptr::null_mut();
faiss_try!(faiss_StandardGpuResources_new(&mut ptr));
Ok(StandardGpuResources { inner: ptr })
}
}
}
impl GpuResources for StandardGpuResources {
fn inner_ptr(&self) -> *mut FaissGpuResources {
self.inner
}
fn no_temp_memory(&mut self) -> Result<()> {
unsafe {
faiss_try!(faiss_StandardGpuResources_noTempMemory(self.inner));
Ok(())
}
}
fn set_temp_memory(&mut self, size: usize) -> Result<()> {
unsafe {
faiss_try!(faiss_StandardGpuResources_setTempMemory(self.inner, size));
Ok(())
}
}
fn set_temp_memory_fraction(&mut self, fraction: f32) -> Result<()> {
unsafe {
faiss_try!(faiss_StandardGpuResources_setTempMemoryFraction(
self.inner, fraction
));
Ok(())
}
}
fn set_pinned_memory(&mut self, size: usize) -> Result<()> {
unsafe {
faiss_try!(faiss_StandardGpuResources_setPinnedMemory(self.inner, size));
Ok(())
}
}
}
impl<'g> GpuResources for &'g mut StandardGpuResources {
fn inner_ptr(&self) -> *mut FaissGpuResources {
self.inner
}
fn no_temp_memory(&mut self) -> Result<()> {
(**self).no_temp_memory()
}
fn set_temp_memory(&mut self, size: usize) -> Result<()> {
(**self).set_temp_memory(size)
}
fn set_temp_memory_fraction(&mut self, fraction: f32) -> Result<()> {
(**self).set_temp_memory_fraction(fraction)
}
fn set_pinned_memory(&mut self, size: usize) -> Result<()> {
(**self).set_pinned_memory(size)
}
}
#[cfg(test)]
mod tests {
use super::StandardGpuResources;
#[test]
fn smoke_detector() {
StandardGpuResources::new().unwrap();
}
}