pub struct GpuBatch<Args, R> {
pub program: GpuProgram,
/* private fields */
}Expand description
A #[handwired] function’s circuit on the GPU, run on typed arguments.
Fields§
§program: GpuProgramImplementations§
Source§impl<Args: Params, R: HwType> GpuBatch<Args, R>
impl<Args: Params, R: HwType> GpuBatch<Args, R>
Sourcepub fn new(
gpu: &Gpu,
compiled: &Compiled<Args, R>,
) -> Result<GpuBatch<Args, R>, GpuError>
pub fn new( gpu: &Gpu, compiled: &Compiled<Args, R>, ) -> Result<GpuBatch<Args, R>, GpuError>
Examples found in repository?
examples/search.rs (line 76)
25fn main() {
26 let records = 100_000;
27 let words: [&[u8]; 8] = [b"cat ", b"dog ", b"the ", b"cart ", b"scatter ", b"a ", b"category ", b"doge "];
28 let mut seed = 0x2545_F491_4F6C_DD1Du64;
29 let mut next = move || {
30 seed ^= seed << 13;
31 seed ^= seed >> 7;
32 seed ^= seed << 17;
33 seed
34 };
35 let inputs: Vec<([u8; TEXT], [u8; 3])> = (0..records)
36 .map(|_| {
37 let mut text = Vec::new();
38 while text.len() < TEXT {
39 text.extend_from_slice(words[(next() % 8) as usize]);
40 }
41 let text: [u8; TEXT] = text[..TEXT].try_into().unwrap();
42 let pattern = if next() % 2 == 0 { *b"cat" } else { *b"dog" };
43 (text, pattern)
44 })
45 .collect();
46
47 let start = Instant::now();
48 let compiled = find_pattern_circuit();
49 println!(
50 "circuit: {} live operations in {} layers, built in {:.1?}",
51 compiled.program.live_operation_count(),
52 compiled.program.layers.len(),
53 start.elapsed()
54 );
55
56 let start = Instant::now();
57 let native: Vec<(bool, u8)> = inputs.iter().map(|&(text, pattern)| find_pattern(text, pattern)).collect();
58 let native_time = start.elapsed();
59
60 let start = Instant::now();
61 let mut executor = TensorExecutor::new(&compiled.program);
62 let mut source = Vec::with_capacity(TEXT + 3);
63 let cpu: Vec<(bool, u8)> = inputs
64 .iter()
65 .map(|record| {
66 source.clear();
67 handwired_rs::dsl::Params::encode(&(record.0, record.1), &mut source);
68 let outputs = executor.run(&source);
69 (outputs[0] == 1.0, outputs[1] as u8)
70 })
71 .collect();
72 let cpu_time = start.elapsed();
73
74 let gpu = Gpu::new().expect("a GPU adapter");
75 let start = Instant::now();
76 let batch = GpuBatch::new(&gpu, &compiled).unwrap();
77 let shader_time = start.elapsed();
78 let _ = batch.run(&gpu, &inputs[..1024]).unwrap();
79 let start = Instant::now();
80 let on_gpu = batch.run(&gpu, &inputs).unwrap();
81 let gpu_time = start.elapsed();
82
83 assert_eq!(cpu, native, "the CPU tensor executor disagrees with the function");
84 assert_eq!(on_gpu, native, "the GPU disagrees with the function");
85 let found = native.iter().filter(|result| result.0).count();
86 println!("{records} records, {found} contain their pattern; every result matches the function");
87 println!("plain Rust: {native_time:>10.1?}");
88 println!("CPU tensor executor: {cpu_time:>10.1?} (one thread)");
89 println!(
90 "GPU ({}, {:?}): {gpu_time:>10.1?} (upload, run, read back; shader built once in {shader_time:.1?})",
91 gpu.info.name, gpu.info.device_type
92 );
93}More examples
examples/kv_store.rs (line 131)
84fn main() {
85 let start = Instant::now();
86 let compiled = kv_step_circuit();
87 println!(
88 "kv_step: {} live operations in {} layers, built in {:.1?}",
89 compiled.program.live_operation_count(),
90 compiled.program.layers.len(),
91 start.elapsed()
92 );
93 let report = compiled.verify(20_000).unwrap();
94 println!("verified against the function on {} sampled inputs", report.checked);
95
96 // A session: the circuit holds the store's state from one operation to the next, like a database.
97 let mut executor = TensorExecutor::new(&compiled.program);
98 let mut circuit_state: State = ([0; SLOTS], [0; SLOTS]);
99 let mut native_state: State = ([0; SLOTS], [0; SLOTS]);
100 let script = [(PUT, 3, 300), (PUT, 7, 700), (GET, 3, 0), (PUT, 3, 333), (GET, 3, 0), (DELETE, 7, 0), (GET, 7, 0)];
101 let mut source = Vec::new();
102 for (op, key, value) in script {
103 source.clear();
104 (circuit_state.0, circuit_state.1, op, key, value).encode(&mut source);
105 let outputs = executor.run(&source);
106 let keys: [u16; SLOTS] = std::array::from_fn(|slot| outputs[slot] as u16);
107 let values: [u16; SLOTS] = std::array::from_fn(|slot| outputs[SLOTS + slot] as u16);
108 let (found, previous) = (outputs[2 * SLOTS] == 1.0, outputs[2 * SLOTS + 1] as u16);
109 circuit_state = (keys, values);
110 let native = kv_step(native_state.0, native_state.1, op, key, value);
111 native_state = (native.0, native.1);
112 assert_eq!((circuit_state, found, previous), (native_state, native.2, native.3));
113 let name = ["get", "put", "delete"][op as usize];
114 println!(" {name:6} {key:>2} {value:>4} -> found {found:5}, previous {previous}");
115 }
116
117 // 100,000 independent operations on 100,000 different stores, in one GPU dispatch.
118 let mut rng = Rng(0x9E37_79B9_7F4A_7C15);
119 let records: Vec<([u16; SLOTS], [u16; SLOTS], u8, u16, u16)> = (0..100_000)
120 .map(|_| {
121 let keys: [u16; SLOTS] = std::array::from_fn(|_| rng.below(16) as u16);
122 let values: [u16; SLOTS] = std::array::from_fn(|_| rng.below(65_536) as u16);
123 (keys, values, rng.below(3) as u8, 1 + rng.below(15) as u16, rng.below(65_536) as u16)
124 })
125 .collect();
126 let start = Instant::now();
127 let native: Vec<_> =
128 records.iter().map(|&(keys, values, op, key, value)| kv_step(keys, values, op, key, value)).collect();
129 let native_time = start.elapsed();
130 let gpu = Gpu::new().expect("a GPU adapter");
131 let batch = GpuBatch::new(&gpu, &compiled).unwrap();
132 let _ = batch.run(&gpu, &records[..1024]).unwrap();
133 let start = Instant::now();
134 let on_gpu = batch.run(&gpu, &records).unwrap();
135 let gpu_time = start.elapsed();
136 assert_eq!(on_gpu, native, "the GPU disagrees with the function");
137 println!("100,000 operations on separate stores; every result matches the function");
138 println!("plain Rust: {native_time:>9.1?}");
139 println!("GPU ({}, {:?}): {gpu_time:>9.1?} (upload, run, read back)", gpu.info.name, gpu.info.device_type);
140}Sourcepub fn encode(&self, records: &[Args]) -> Vec<f32>
pub fn encode(&self, records: &[Args]) -> Vec<f32>
The source tables for records, checked against the declared ranges.
Sourcepub fn run(&self, gpu: &Gpu, records: &[Args]) -> Result<Vec<R>, GpuError>
pub fn run(&self, gpu: &Gpu, records: &[Args]) -> Result<Vec<R>, GpuError>
Examples found in repository?
examples/search.rs (line 78)
25fn main() {
26 let records = 100_000;
27 let words: [&[u8]; 8] = [b"cat ", b"dog ", b"the ", b"cart ", b"scatter ", b"a ", b"category ", b"doge "];
28 let mut seed = 0x2545_F491_4F6C_DD1Du64;
29 let mut next = move || {
30 seed ^= seed << 13;
31 seed ^= seed >> 7;
32 seed ^= seed << 17;
33 seed
34 };
35 let inputs: Vec<([u8; TEXT], [u8; 3])> = (0..records)
36 .map(|_| {
37 let mut text = Vec::new();
38 while text.len() < TEXT {
39 text.extend_from_slice(words[(next() % 8) as usize]);
40 }
41 let text: [u8; TEXT] = text[..TEXT].try_into().unwrap();
42 let pattern = if next() % 2 == 0 { *b"cat" } else { *b"dog" };
43 (text, pattern)
44 })
45 .collect();
46
47 let start = Instant::now();
48 let compiled = find_pattern_circuit();
49 println!(
50 "circuit: {} live operations in {} layers, built in {:.1?}",
51 compiled.program.live_operation_count(),
52 compiled.program.layers.len(),
53 start.elapsed()
54 );
55
56 let start = Instant::now();
57 let native: Vec<(bool, u8)> = inputs.iter().map(|&(text, pattern)| find_pattern(text, pattern)).collect();
58 let native_time = start.elapsed();
59
60 let start = Instant::now();
61 let mut executor = TensorExecutor::new(&compiled.program);
62 let mut source = Vec::with_capacity(TEXT + 3);
63 let cpu: Vec<(bool, u8)> = inputs
64 .iter()
65 .map(|record| {
66 source.clear();
67 handwired_rs::dsl::Params::encode(&(record.0, record.1), &mut source);
68 let outputs = executor.run(&source);
69 (outputs[0] == 1.0, outputs[1] as u8)
70 })
71 .collect();
72 let cpu_time = start.elapsed();
73
74 let gpu = Gpu::new().expect("a GPU adapter");
75 let start = Instant::now();
76 let batch = GpuBatch::new(&gpu, &compiled).unwrap();
77 let shader_time = start.elapsed();
78 let _ = batch.run(&gpu, &inputs[..1024]).unwrap();
79 let start = Instant::now();
80 let on_gpu = batch.run(&gpu, &inputs).unwrap();
81 let gpu_time = start.elapsed();
82
83 assert_eq!(cpu, native, "the CPU tensor executor disagrees with the function");
84 assert_eq!(on_gpu, native, "the GPU disagrees with the function");
85 let found = native.iter().filter(|result| result.0).count();
86 println!("{records} records, {found} contain their pattern; every result matches the function");
87 println!("plain Rust: {native_time:>10.1?}");
88 println!("CPU tensor executor: {cpu_time:>10.1?} (one thread)");
89 println!(
90 "GPU ({}, {:?}): {gpu_time:>10.1?} (upload, run, read back; shader built once in {shader_time:.1?})",
91 gpu.info.name, gpu.info.device_type
92 );
93}More examples
examples/kv_store.rs (line 132)
84fn main() {
85 let start = Instant::now();
86 let compiled = kv_step_circuit();
87 println!(
88 "kv_step: {} live operations in {} layers, built in {:.1?}",
89 compiled.program.live_operation_count(),
90 compiled.program.layers.len(),
91 start.elapsed()
92 );
93 let report = compiled.verify(20_000).unwrap();
94 println!("verified against the function on {} sampled inputs", report.checked);
95
96 // A session: the circuit holds the store's state from one operation to the next, like a database.
97 let mut executor = TensorExecutor::new(&compiled.program);
98 let mut circuit_state: State = ([0; SLOTS], [0; SLOTS]);
99 let mut native_state: State = ([0; SLOTS], [0; SLOTS]);
100 let script = [(PUT, 3, 300), (PUT, 7, 700), (GET, 3, 0), (PUT, 3, 333), (GET, 3, 0), (DELETE, 7, 0), (GET, 7, 0)];
101 let mut source = Vec::new();
102 for (op, key, value) in script {
103 source.clear();
104 (circuit_state.0, circuit_state.1, op, key, value).encode(&mut source);
105 let outputs = executor.run(&source);
106 let keys: [u16; SLOTS] = std::array::from_fn(|slot| outputs[slot] as u16);
107 let values: [u16; SLOTS] = std::array::from_fn(|slot| outputs[SLOTS + slot] as u16);
108 let (found, previous) = (outputs[2 * SLOTS] == 1.0, outputs[2 * SLOTS + 1] as u16);
109 circuit_state = (keys, values);
110 let native = kv_step(native_state.0, native_state.1, op, key, value);
111 native_state = (native.0, native.1);
112 assert_eq!((circuit_state, found, previous), (native_state, native.2, native.3));
113 let name = ["get", "put", "delete"][op as usize];
114 println!(" {name:6} {key:>2} {value:>4} -> found {found:5}, previous {previous}");
115 }
116
117 // 100,000 independent operations on 100,000 different stores, in one GPU dispatch.
118 let mut rng = Rng(0x9E37_79B9_7F4A_7C15);
119 let records: Vec<([u16; SLOTS], [u16; SLOTS], u8, u16, u16)> = (0..100_000)
120 .map(|_| {
121 let keys: [u16; SLOTS] = std::array::from_fn(|_| rng.below(16) as u16);
122 let values: [u16; SLOTS] = std::array::from_fn(|_| rng.below(65_536) as u16);
123 (keys, values, rng.below(3) as u8, 1 + rng.below(15) as u16, rng.below(65_536) as u16)
124 })
125 .collect();
126 let start = Instant::now();
127 let native: Vec<_> =
128 records.iter().map(|&(keys, values, op, key, value)| kv_step(keys, values, op, key, value)).collect();
129 let native_time = start.elapsed();
130 let gpu = Gpu::new().expect("a GPU adapter");
131 let batch = GpuBatch::new(&gpu, &compiled).unwrap();
132 let _ = batch.run(&gpu, &records[..1024]).unwrap();
133 let start = Instant::now();
134 let on_gpu = batch.run(&gpu, &records).unwrap();
135 let gpu_time = start.elapsed();
136 assert_eq!(on_gpu, native, "the GPU disagrees with the function");
137 println!("100,000 operations on separate stores; every result matches the function");
138 println!("plain Rust: {native_time:>9.1?}");
139 println!("GPU ({}, {:?}): {gpu_time:>9.1?} (upload, run, read back)", gpu.info.name, gpu.info.device_type);
140}Auto Trait Implementations§
impl<Args, R> !RefUnwindSafe for GpuBatch<Args, R>
impl<Args, R> !UnwindSafe for GpuBatch<Args, R>
impl<Args, R> Freeze for GpuBatch<Args, R>
impl<Args, R> Send for GpuBatch<Args, R>
impl<Args, R> Sync for GpuBatch<Args, R>
impl<Args, R> Unpin for GpuBatch<Args, R>
impl<Args, R> UnsafeUnpin for GpuBatch<Args, R>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more