a deliberately stupid space heater that wastes electricity on fire shaders and prime numbers
1use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
2use std::sync::Arc;
3
4/// Test whether `n` is prime using trial division up to √n.
5/// Deliberately not optimized — we *want* to burn CPU.
6fn is_prime(n: u64) -> bool {
7 if n < 2 {
8 return false;
9 }
10 if n < 4 {
11 return true;
12 }
13 if n % 2 == 0 || n % 3 == 0 {
14 return false;
15 }
16 let mut i = 5u64;
17 while i.saturating_mul(i) <= n {
18 if n % i == 0 || n % (i + 2) == 0 {
19 return false;
20 }
21 i += 6;
22 }
23 true
24}
25
26/// CPU-burning worker that counts primes by brute-force trial division.
27///
28/// Each thread tests a disjoint slice of odd numbers (interleaved by stride)
29/// and atomically increments shared counters for primes found and numbers tested.
30/// Uses constant memory regardless of how long it runs.
31pub fn prime_worker(
32 running: Arc<AtomicBool>,
33 primes_found: Arc<AtomicU64>,
34 numbers_tested: Arc<AtomicU64>,
35 thread_id: u64,
36 num_threads: u64,
37) {
38 // Each thread works on odd numbers: 3 + 2*thread_id, stepping by 2*num_threads.
39 // Thread 0 also accounts for the prime 2 by adding 1 to its first batch.
40 let stride = 2 * num_threads;
41 let mut n = 3 + 2 * thread_id;
42 let batch_size = 500u64;
43
44 if thread_id == 0 {
45 // Count prime 2 once
46 primes_found.fetch_add(1, Ordering::Relaxed);
47 }
48
49 while running.load(Ordering::Relaxed) {
50 let mut local_primes = 0u64;
51
52 for _ in 0..batch_size {
53 if is_prime(n) {
54 local_primes += 1;
55 }
56 n += stride;
57 }
58
59 primes_found.fetch_add(local_primes, Ordering::Relaxed);
60 numbers_tested.fetch_add(batch_size, Ordering::Relaxed);
61 }
62}