CPUs can make a little heat, as a treat

initial version

Stella 52241ec4

+1
.gitignore
··· 1 + /target
+331
Cargo.lock
··· 1 + # This file is automatically @generated by Cargo. 2 + # It is not intended for manual editing. 3 + version = 4 4 + 5 + [[package]] 6 + name = "anstream" 7 + version = "0.6.21" 8 + source = "registry+https://github.com/rust-lang/crates.io-index" 9 + checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" 10 + dependencies = [ 11 + "anstyle", 12 + "anstyle-parse", 13 + "anstyle-query", 14 + "anstyle-wincon", 15 + "colorchoice", 16 + "is_terminal_polyfill", 17 + "utf8parse", 18 + ] 19 + 20 + [[package]] 21 + name = "anstyle" 22 + version = "1.0.13" 23 + source = "registry+https://github.com/rust-lang/crates.io-index" 24 + checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" 25 + 26 + [[package]] 27 + name = "anstyle-parse" 28 + version = "0.2.7" 29 + source = "registry+https://github.com/rust-lang/crates.io-index" 30 + checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" 31 + dependencies = [ 32 + "utf8parse", 33 + ] 34 + 35 + [[package]] 36 + name = "anstyle-query" 37 + version = "1.1.4" 38 + source = "registry+https://github.com/rust-lang/crates.io-index" 39 + checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" 40 + dependencies = [ 41 + "windows-sys 0.60.2", 42 + ] 43 + 44 + [[package]] 45 + name = "anstyle-wincon" 46 + version = "3.0.10" 47 + source = "registry+https://github.com/rust-lang/crates.io-index" 48 + checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" 49 + dependencies = [ 50 + "anstyle", 51 + "once_cell_polyfill", 52 + "windows-sys 0.60.2", 53 + ] 54 + 55 + [[package]] 56 + name = "bitflags" 57 + version = "2.9.4" 58 + source = "registry+https://github.com/rust-lang/crates.io-index" 59 + checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" 60 + 61 + [[package]] 62 + name = "cfg-if" 63 + version = "1.0.3" 64 + source = "registry+https://github.com/rust-lang/crates.io-index" 65 + checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" 66 + 67 + [[package]] 68 + name = "cfg_aliases" 69 + version = "0.2.1" 70 + source = "registry+https://github.com/rust-lang/crates.io-index" 71 + checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 72 + 73 + [[package]] 74 + name = "clap" 75 + version = "4.5.48" 76 + source = "registry+https://github.com/rust-lang/crates.io-index" 77 + checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" 78 + dependencies = [ 79 + "clap_builder", 80 + "clap_derive", 81 + ] 82 + 83 + [[package]] 84 + name = "clap_builder" 85 + version = "4.5.48" 86 + source = "registry+https://github.com/rust-lang/crates.io-index" 87 + checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" 88 + dependencies = [ 89 + "anstream", 90 + "anstyle", 91 + "clap_lex", 92 + "strsim", 93 + ] 94 + 95 + [[package]] 96 + name = "clap_derive" 97 + version = "4.5.47" 98 + source = "registry+https://github.com/rust-lang/crates.io-index" 99 + checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" 100 + dependencies = [ 101 + "heck", 102 + "proc-macro2", 103 + "quote", 104 + "syn", 105 + ] 106 + 107 + [[package]] 108 + name = "clap_lex" 109 + version = "0.7.5" 110 + source = "registry+https://github.com/rust-lang/crates.io-index" 111 + checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" 112 + 113 + [[package]] 114 + name = "colorchoice" 115 + version = "1.0.4" 116 + source = "registry+https://github.com/rust-lang/crates.io-index" 117 + checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" 118 + 119 + [[package]] 120 + name = "ctrlc" 121 + version = "3.5.0" 122 + source = "registry+https://github.com/rust-lang/crates.io-index" 123 + checksum = "881c5d0a13b2f1498e2306e82cbada78390e152d4b1378fb28a84f4dcd0dc4f3" 124 + dependencies = [ 125 + "dispatch", 126 + "nix", 127 + "windows-sys 0.61.2", 128 + ] 129 + 130 + [[package]] 131 + name = "dispatch" 132 + version = "0.2.0" 133 + source = "registry+https://github.com/rust-lang/crates.io-index" 134 + checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" 135 + 136 + [[package]] 137 + name = "heater" 138 + version = "0.1.0" 139 + dependencies = [ 140 + "clap", 141 + "ctrlc", 142 + "num_cpus", 143 + ] 144 + 145 + [[package]] 146 + name = "heck" 147 + version = "0.5.0" 148 + source = "registry+https://github.com/rust-lang/crates.io-index" 149 + checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 150 + 151 + [[package]] 152 + name = "hermit-abi" 153 + version = "0.5.2" 154 + source = "registry+https://github.com/rust-lang/crates.io-index" 155 + checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" 156 + 157 + [[package]] 158 + name = "is_terminal_polyfill" 159 + version = "1.70.1" 160 + source = "registry+https://github.com/rust-lang/crates.io-index" 161 + checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 162 + 163 + [[package]] 164 + name = "libc" 165 + version = "0.2.177" 166 + source = "registry+https://github.com/rust-lang/crates.io-index" 167 + checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" 168 + 169 + [[package]] 170 + name = "nix" 171 + version = "0.30.1" 172 + source = "registry+https://github.com/rust-lang/crates.io-index" 173 + checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" 174 + dependencies = [ 175 + "bitflags", 176 + "cfg-if", 177 + "cfg_aliases", 178 + "libc", 179 + ] 180 + 181 + [[package]] 182 + name = "num_cpus" 183 + version = "1.17.0" 184 + source = "registry+https://github.com/rust-lang/crates.io-index" 185 + checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" 186 + dependencies = [ 187 + "hermit-abi", 188 + "libc", 189 + ] 190 + 191 + [[package]] 192 + name = "once_cell_polyfill" 193 + version = "1.70.1" 194 + source = "registry+https://github.com/rust-lang/crates.io-index" 195 + checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" 196 + 197 + [[package]] 198 + name = "proc-macro2" 199 + version = "1.0.101" 200 + source = "registry+https://github.com/rust-lang/crates.io-index" 201 + checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" 202 + dependencies = [ 203 + "unicode-ident", 204 + ] 205 + 206 + [[package]] 207 + name = "quote" 208 + version = "1.0.41" 209 + source = "registry+https://github.com/rust-lang/crates.io-index" 210 + checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" 211 + dependencies = [ 212 + "proc-macro2", 213 + ] 214 + 215 + [[package]] 216 + name = "strsim" 217 + version = "0.11.1" 218 + source = "registry+https://github.com/rust-lang/crates.io-index" 219 + checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 220 + 221 + [[package]] 222 + name = "syn" 223 + version = "2.0.106" 224 + source = "registry+https://github.com/rust-lang/crates.io-index" 225 + checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" 226 + dependencies = [ 227 + "proc-macro2", 228 + "quote", 229 + "unicode-ident", 230 + ] 231 + 232 + [[package]] 233 + name = "unicode-ident" 234 + version = "1.0.19" 235 + source = "registry+https://github.com/rust-lang/crates.io-index" 236 + checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" 237 + 238 + [[package]] 239 + name = "utf8parse" 240 + version = "0.2.2" 241 + source = "registry+https://github.com/rust-lang/crates.io-index" 242 + checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 243 + 244 + [[package]] 245 + name = "windows-link" 246 + version = "0.2.1" 247 + source = "registry+https://github.com/rust-lang/crates.io-index" 248 + checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 249 + 250 + [[package]] 251 + name = "windows-sys" 252 + version = "0.60.2" 253 + source = "registry+https://github.com/rust-lang/crates.io-index" 254 + checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" 255 + dependencies = [ 256 + "windows-targets", 257 + ] 258 + 259 + [[package]] 260 + name = "windows-sys" 261 + version = "0.61.2" 262 + source = "registry+https://github.com/rust-lang/crates.io-index" 263 + checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" 264 + dependencies = [ 265 + "windows-link", 266 + ] 267 + 268 + [[package]] 269 + name = "windows-targets" 270 + version = "0.53.5" 271 + source = "registry+https://github.com/rust-lang/crates.io-index" 272 + checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" 273 + dependencies = [ 274 + "windows-link", 275 + "windows_aarch64_gnullvm", 276 + "windows_aarch64_msvc", 277 + "windows_i686_gnu", 278 + "windows_i686_gnullvm", 279 + "windows_i686_msvc", 280 + "windows_x86_64_gnu", 281 + "windows_x86_64_gnullvm", 282 + "windows_x86_64_msvc", 283 + ] 284 + 285 + [[package]] 286 + name = "windows_aarch64_gnullvm" 287 + version = "0.53.1" 288 + source = "registry+https://github.com/rust-lang/crates.io-index" 289 + checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" 290 + 291 + [[package]] 292 + name = "windows_aarch64_msvc" 293 + version = "0.53.1" 294 + source = "registry+https://github.com/rust-lang/crates.io-index" 295 + checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" 296 + 297 + [[package]] 298 + name = "windows_i686_gnu" 299 + version = "0.53.1" 300 + source = "registry+https://github.com/rust-lang/crates.io-index" 301 + checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" 302 + 303 + [[package]] 304 + name = "windows_i686_gnullvm" 305 + version = "0.53.1" 306 + source = "registry+https://github.com/rust-lang/crates.io-index" 307 + checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" 308 + 309 + [[package]] 310 + name = "windows_i686_msvc" 311 + version = "0.53.1" 312 + source = "registry+https://github.com/rust-lang/crates.io-index" 313 + checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" 314 + 315 + [[package]] 316 + name = "windows_x86_64_gnu" 317 + version = "0.53.1" 318 + source = "registry+https://github.com/rust-lang/crates.io-index" 319 + checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" 320 + 321 + [[package]] 322 + name = "windows_x86_64_gnullvm" 323 + version = "0.53.1" 324 + source = "registry+https://github.com/rust-lang/crates.io-index" 325 + checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" 326 + 327 + [[package]] 328 + name = "windows_x86_64_msvc" 329 + version = "0.53.1" 330 + source = "registry+https://github.com/rust-lang/crates.io-index" 331 + checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
+9
Cargo.toml
··· 1 + [package] 2 + name = "heater" 3 + version = "0.1.0" 4 + edition = "2024" 5 + 6 + [dependencies] 7 + clap = { version = "4.5.48", features = ["derive"] } 8 + ctrlc = "3.5.0" 9 + num_cpus = "1.17.0"
+48
README.md
··· 1 + # Heater 2 + 3 + A Rust command-line application that churns your CPU cores at maximum capacity so your laptop isn't cold 4 + 5 + ## Build 6 + 7 + ```bash 8 + cargo build --release 9 + ``` 10 + 11 + The compiled binary will be at `target/release/heater`. 12 + 13 + ## Usage 14 + 15 + ### Run indefinitely (until Ctrl+C) 16 + ```bash 17 + cargo run --release 18 + # or 19 + ./target/release/heater 20 + ``` 21 + 22 + ### Run for a specific duration (in seconds) 23 + ```bash 24 + cargo run --release -- --duration 30 25 + # or 26 + ./target/release/heater --duration 30 27 + ``` 28 + 29 + ### Customize the number of free cores 30 + ```bash 31 + # Leave 2 cores free 32 + cargo run --release -- --free-cores 2 33 + 34 + # Use ALL cores (leave 0 free) 35 + cargo run --release -- --free-cores 0 36 + 37 + # Run for 60 seconds, leaving 2 cores free 38 + cargo run --release -- --duration 60 --free-cores 2 39 + ``` 40 + 41 + ## Options 42 + 43 + ``` 44 + -d, --duration <DURATION> Duration to run in seconds (omit for indefinite run) 45 + -f, --free-cores <FREE_CORES> Number of cores to leave free (default: 1) 46 + -h, --help Print help 47 + -V, --version Print version 48 + ```
+90
src/main.rs
··· 1 + use clap::Parser; 2 + use std::sync::atomic::{AtomicBool, Ordering}; 3 + use std::sync::Arc; 4 + use std::thread; 5 + use std::time::{Duration, Instant}; 6 + 7 + #[derive(Parser, Debug)] 8 + #[command(author, version, about = "A CPU heater that churns CPU cores", long_about = None)] 9 + struct Args { 10 + /// Duration to run in seconds (omit for indefinite run) 11 + #[arg(short, long)] 12 + duration: Option<u64>, 13 + 14 + /// Number of cores to leave free (default: 1) 15 + #[arg(short = 'f', long, default_value_t = 1)] 16 + free_cores: usize, 17 + } 18 + 19 + fn main() { 20 + let args = Args::parse(); 21 + 22 + // Get the number of logical CPU cores 23 + let total_cores = num_cpus::get(); 24 + let cores_to_use = total_cores.saturating_sub(args.free_cores).max(1); 25 + 26 + println!("Total CPU cores: {}", total_cores); 27 + println!("Cores to heat: {}", cores_to_use); 28 + println!("Cores to leave free: {}", args.free_cores); 29 + 30 + match args.duration { 31 + Some(seconds) => println!("Running for {} seconds", seconds), 32 + None => println!("Running indefinitely (press Ctrl+C to stop)"), 33 + } 34 + 35 + // Set up signal handler for graceful shutdown 36 + let running = Arc::new(AtomicBool::new(true)); 37 + let r = running.clone(); 38 + 39 + ctrlc::set_handler(move || { 40 + println!("\nReceived Ctrl+C, shutting down..."); 41 + r.store(false, Ordering::SeqCst); 42 + }) 43 + .expect("Error setting Ctrl-C handler"); 44 + 45 + let start_time = Instant::now(); 46 + let duration = args.duration.map(Duration::from_secs); 47 + 48 + // Spawn threads to churn CPU 49 + let mut handles = vec![]; 50 + for i in 0..cores_to_use { 51 + let running = running.clone(); 52 + let handle = thread::spawn(move || { 53 + println!("Thread {} started", i); 54 + let mut counter: u64 = 0; 55 + while running.load(Ordering::SeqCst) { 56 + //compute something meaningless but CPU-intensive 57 + counter = counter.wrapping_add(1); 58 + for j in 0..1000 { 59 + counter = counter 60 + .wrapping_mul(1103515245) 61 + .wrapping_add(j) 62 + .wrapping_rem(2147483648); 63 + } 64 + } 65 + println!("Thread {} stopped after {} iterations", i, counter); 66 + }); 67 + handles.push(handle); 68 + } 69 + 70 + // Monitor duration if specified 71 + if let Some(dur) = duration { 72 + while start_time.elapsed() < dur && running.load(Ordering::SeqCst) { 73 + thread::sleep(Duration::from_millis(100)); 74 + } 75 + running.store(false, Ordering::SeqCst); 76 + } else { 77 + // Wait indefinitely until Ctrl+C 78 + for handle in handles { 79 + handle.join().unwrap(); 80 + } 81 + return; 82 + } 83 + 84 + // Wait for all threads to finish 85 + for handle in handles { 86 + handle.join().unwrap(); 87 + } 88 + 89 + println!("Finished heating for {:?}", start_time.elapsed()); 90 + }