From 4302adad55813846a37202a72d337fe560d77359 Mon Sep 17 00:00:00 2001 From: Oliver Atkinson Date: Mon, 28 Oct 2024 10:30:22 -0600 Subject: [PATCH] cleaning...\ncleaning out my work computer --- src/main.rs | 103 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 38 deletions(-) diff --git a/src/main.rs b/src/main.rs index f8ae6e1..75eca5f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,17 @@ +use std::hint::black_box; use std::io::{stderr, Write}; +use std::sync::{Arc, RwLock}; use std::thread::{self, sleep}; use std::time::{Duration, Instant}; use num_format::{Locale, ToFormattedString}; -const ALL_CHARS: &'static str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.<>/?;':\"[]{}\\|-=_+`~!@#$%^&*()"; -const LEN: usize = 4; +const ALL_CHARS_95: &'static str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.<>/?;':\"[]{}\\|-=_+`~!@#$%^&*() "; +// const ALL_ALPHA: &'static str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +// const ALL_ALPHA_NUM: &'static str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + +const LEN: usize = 8; -static mut SOFAR: u128 = 0; static mut TOTAL: usize = 0; /// Pseudo main @@ -19,8 +23,29 @@ fn start(char_list: &str, output_len: usize) { /// Flag to communicate between main (combination crunching) and /// timer threads. static mut IS_DONE: bool = false; + /// Seconds between the calculating p/s and percentage done. + const CHECK_IN_DELAY: u64 = 1; let start = Instant::now(); + // Try multithreading... + let mut tasks = Vec::new(); + let mut counters = Vec::new(); + let mut buffers = Vec::new(); + + // Start threads + for i in char_list.chars() { + let counter = Arc::new(RwLock::new(0u128)); + let buffer = Arc::new(RwLock::new(Vec::new())); + + counters.push(counter.clone()); + buffers.push(buffer.clone()); + + let copy = char_list.to_owned(); + let worker = thread::spawn(move || { + calc(©, &i.to_string(), output_len, counter, buffer); + }); + tasks.push(worker); + } // Just to report stats let timer = thread::spawn(move || { @@ -31,40 +56,36 @@ fn start(char_list: &str, output_len: usize) { // prevent div by zero err if elapsed == 0 { elapsed = 1; } - let sofar = unsafe {SOFAR}; + let mut sofar =0; + for ele in &counters { + sofar += *ele.read().unwrap(); + }; + + // This doesn't free the memory fast enough! // FIXME + for i in &buffers { + for j in &*i.read().unwrap() { + let x = j; + black_box(x); + } + // prevent memory footprint from getting too big + i.write().unwrap().clear(); + println!("clear") + } + // output P/s let _ = out.write( - format!("\rCalculated {} possibilities thus far, at {} p/s", + format!("\rCalculated {}, at {}p/s, {:.5}%", sofar.to_formatted_string(&Locale::en_NA), (sofar / elapsed).to_formatted_string(&Locale::en_NA), + sofar as f64 / unsafe { TOTAL as f64 } * 100f64, ).as_bytes()); let _ = out.flush(); - sleep(Duration::from_secs(1)); - - /* - // output remaining time - // I haven't tested to see if this timer is somewhat accurate... - // This is code I stole of reddit... what am I doing? - let remaining = unsafe { TOTAL as u128 / (sofar / elapsed) }; - let sec = remaining % 60; - let min = (remaining / 60) % 60; - let hrs = (remaining / 60) / 60; - - let _ = out.write( - // TODO clear the whole line, don't just put cursor to the begining... - format!("\r{}%, {}h:{}m:{}s remaining ", - unsafe { sofar / TOTAL as u128 }, - hrs, min, sec - ).as_bytes()); - let _ = out.flush(); - sleep(Duration::from_secs(1)); - */ - } + sleep(Duration::from_secs(CHECK_IN_DELAY)); + }; }); - // starting with the blank string is important - calc(char_list, &"", output_len); - + // Block waiting for all the tasks to finish + for i in tasks {i.join().unwrap();} unsafe { IS_DONE = true; } timer.join().unwrap(); @@ -75,17 +96,17 @@ fn main() { // All the status messages are printed on stderr // This way you can pipe the actual permutations into // a file whilst still getting debug messages. - let t = (ALL_CHARS.len() as u128).pow(LEN.try_into().unwrap()); + let t = (ALL_CHARS_95.len() as u128).pow(LEN.try_into().unwrap()); unsafe { TOTAL = t as usize }; eprintln!( - "Calculating {} combinations...\n(Number may be trunkated if too large)\n", + "Calculating {} combinations...\n(Number may be truncated if too large)\n", unsafe { TOTAL }.to_formatted_string(&Locale::en_NA) ); - start(ALL_CHARS, LEN); + start(ALL_CHARS_95, LEN); } -/// Recurseively create and print every combination of +/// Recursively create and print every combination of /// `choices` chars inside a string of `len` length. /// /// @@ -94,23 +115,29 @@ fn main() { /// /// * `prefix` should be a blank string `""` unless you /// actually want a prefix on every output. This variable is -/// mainly used within the recursive nature of the funciton. +/// mainly used within the recursive nature of the function. /// /// * `len` the size that all the output strings wil be. -fn calc(choices: &str, prefix: &str, len: usize) { +/// +/// * `counter` what to count into +fn calc(choices: &str, prefix: &str, len: usize, counter: Arc>, buffer: Arc>>) { let need_to_fill = len - prefix.len(); match need_to_fill { // the last char in the sequence, time to print 1 => { for i in choices.chars() { - println!("{}{}", prefix, i); - unsafe { SOFAR = SOFAR + 1 }; + // This line causes a 10x slowdown + buffer.write().unwrap().push(format!("{}{}", prefix, i)); + + // Needs to be in two lines like this, otherwise the write blocks on the read. + let temp = *counter.read().unwrap(); + *counter.write().unwrap() = temp+1; } } // need to recurse farther into the sequence _ => { for i in choices.chars() { - calc(choices, &(prefix.to_string() + &i.to_string()), len); + calc(choices, &(prefix.to_string() + &i.to_string()), len, counter.clone(), buffer.clone()); } } }