big performance uplift

This commit is contained in:
2024-07-17 00:56:13 +02:00
parent 099012a60b
commit ce507071b9
6 changed files with 197 additions and 119 deletions
+10 -31
View File
@@ -1,7 +1,5 @@
pub mod prime_utils {
use num::{BigUint, One, Zero};
use crate::primality_test::primality_tests::is_probably_prime;
use num::{BigUint, One};
#[must_use]
pub fn log_2(x: &BigUint) -> u64 {
@@ -17,42 +15,27 @@ pub mod prime_utils {
return true;
}
let sqrtnum = number.sqrt();
if sqrtnum.pow(2) == *number {
if number == &BigUint::from(23u8) {
eprintln!("SQRT check failed");
}
return false;
}
let two = BigUint::from(2u8);
// number = 2^a - 1
// a = log2(number + 1)
let a = log_2(&(number + 1u8));
//if number isn't a mersenne number
if BigUint::from(2u8).pow(a as u32) - BigUint::one() != *number {
const ZERO: BigUint = BigUint::ZERO;
let mut i = BigUint::one();
let one = BigUint::one();
let zero = BigUint::zero();
let sqrtnum = sqrtnum + &one; //fake ceil function
let sqrtnum = number.sqrt() + &one; //fake ceil function
for prime in g_primes {
if prime < &sqrtnum && number % prime == zero {
if number == &BigUint::from(23u8) {
eprintln!("Prime table check failed");
}
if prime < &sqrtnum && number % prime == ZERO {
return false;
}
}
loop {
i += &one;
if number % &i == zero {
if number == &BigUint::from(23u8) {
eprintln!("manual check failed");
}
if number % &i == ZERO {
return false;
}
if i == sqrtnum {
@@ -61,19 +44,15 @@ pub mod prime_utils {
}
}
//check if it's a mersenne prime
// 4 12 194
let mut last = BigUint::from(4u8);
let two = BigUint::from(2u8);
for _i in 2..a {
last = (last.pow(2) - &two) % number;
}
let ret = last == BigUint::from(0u8);
if number == &BigUint::from(23u8) && !ret {
eprintln!("RET check failed");
}
ret
last == BigUint::from(0u8)
}
}
+83 -84
View File
@@ -9,7 +9,10 @@ use num::{BigUint, One};
use once_cell::sync::Lazy;
use std::{
io::Write,
sync::atomic::{AtomicI64, AtomicUsize},
sync::{
atomic::{AtomicU64, AtomicUsize},
Arc, RwLock,
},
thread,
time::SystemTime,
};
@@ -40,8 +43,8 @@ fn to_f64(u: usize) -> f64 {
f64::from_bits(u as u64)
}
#[cfg(target_os = "windows")]
fn try_set_thread_priority() {
#[cfg(target_os = "windows")]
if let Err(e) = set_current_thread_priority(ThreadPriority::Max) {
eprintln!("[WARN] failed to set thread priority to max");
eprintln!("{e}");
@@ -50,26 +53,78 @@ fn try_set_thread_priority() {
fn write_primes(primes: &[BigUint]) {
let mut file = std::fs::File::create("primes.json").unwrap();
file.write_all(b"[").unwrap();
let mut it = primes.iter().peekable();
while let Some(prime) = it.next() {
file.write_all(prime.to_string().as_bytes()).unwrap();
if it.peek().is_some() {
file.write_all(b",").unwrap();
file.write_all(serde_json::to_string(primes).unwrap().as_bytes())
.unwrap();
}
const N: i64 = 1_000_000;
const NF: f64 = N as f64;
const NU: usize = N as usize;
const THREADS: usize = 30;
const SPLITTER: u64 = N as u64 / THREADS as u64;
fn worker(
workloads: usize,
i: usize,
progress: &AtomicU64,
arcclone: &Arc<RwLock<Vec<BigUint>>>,
threads_done: &AtomicUsize,
) {
#[cfg(target_os = "windows")]
try_set_thread_priority();
static INC: once_cell::sync::Lazy<BigUint> = Lazy::new(BigUint::one);
let one_thousand = &BigUint::from(SPLITTER * 10);
let one_hundred = &BigUint::from(SPLITTER);
let ten = &BigUint::from(10u8);
let work_uint = BigUint::from(workloads);
let mut number = BigUint::from(i) * &work_uint;
let max = BigUint::from(i + 1) * work_uint;
let mut primecache = Vec::with_capacity(NU);
let mut primecache_outside_len = 0;
let mut global_primes = arcclone.read().unwrap();
loop {
number += &*INC;
if prime_utils::is_prime(&number, &global_primes) {
primecache.push(number.clone());
progress.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
}
if (&number * one_thousand) / &max / ten == &number / &max * one_hundred {
drop(global_primes);
let mut new_primecache = arcclone.write().unwrap();
new_primecache.extend_from_slice(&primecache[primecache_outside_len..]);
new_primecache.sort_unstable();
primecache.clone_from(&new_primecache);
primecache_outside_len = new_primecache.len();
drop(new_primecache);
global_primes = arcclone.read().unwrap();
}
if number == max {
break;
}
}
file.write_all(b"]").unwrap();
drop(global_primes);
let mut new_primecache = arcclone.write().unwrap();
new_primecache.extend_from_slice(&primecache[primecache_outside_len..]);
new_primecache.sort_unstable();
threads_done.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
}
fn main() {
const N: i64 = 1_000_000;
const NF: f64 = N as f64;
const NU: usize = N as usize;
const THREADS: usize = 30;
const SPLITTER: u64 = N as u64 / THREADS as u64;
try_set_thread_priority();
let sys_time = SystemTime::now();
let nthprime_approx: usize = to_usize(p(NF * 1.02));
@@ -77,10 +132,10 @@ fn main() {
let workloads = nthprime_approx / THREADS;
let primecache: Vec<BigUint> = Vec::with_capacity(NU);
let primemutex = std::sync::Mutex::new(primecache);
let primemutex = std::sync::RwLock::new(primecache);
let primearc = std::sync::Arc::new(primemutex);
let progress_val = AtomicI64::new(0);
let progress_val = AtomicU64::new(0);
let progress = &progress_val;
let threads_done_val = AtomicUsize::new(0);
@@ -89,56 +144,7 @@ fn main() {
thread::scope(|scope| {
for i in 0..THREADS {
let arcclone = primearc.clone();
scope.spawn(move || {
try_set_thread_priority();
let one_thousand = &BigUint::from(SPLITTER * 10);
let one_hundred = &BigUint::from(SPLITTER);
let ten = &BigUint::from(10u8);
let work_uint = BigUint::from(workloads);
let mut number = BigUint::from(i) * &work_uint;
static INC: once_cell::sync::Lazy<BigUint> = Lazy::new(BigUint::one);
let max = BigUint::from(i + 1) * work_uint;
let mut primecache = Vec::with_capacity(NU);
let mut primecache_outside_len = 0;
loop {
number += &*INC;
if prime_utils::is_prime(&number, &primecache) {
primecache.push(number.clone());
progress.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
}
if (&number * one_thousand) / &max / ten == &number / &max * one_hundred {
let tried_getting = SystemTime::now();
let mut new_primecache = arcclone.lock().unwrap();
if SystemTime::now()
.duration_since(tried_getting)
.unwrap()
.as_millis()
> 50
{
eprintln!("[WARN] Waited 0.05+ seconds for lock!");
}
new_primecache.extend_from_slice(&primecache[primecache_outside_len..]);
new_primecache.sort_unstable();
primecache.clone_from(&new_primecache);
primecache_outside_len = new_primecache.len();
}
if number == max {
break;
}
}
let mut new_primecache = arcclone.lock().unwrap();
new_primecache.extend_from_slice(&primecache[primecache_outside_len..]);
new_primecache.sort_unstable();
threads_done.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
});
scope.spawn(move || worker(workloads, i, progress, &arcclone, threads_done));
}
loop {
@@ -160,27 +166,23 @@ fn main() {
}
});
let mut primes = primearc.lock().unwrap().to_vec();
let mut primes = primearc.write().unwrap();
#[allow(clippy::cast_possible_wrap)]
let removed: i32 = if primes.len() > NU {
let mut rem = 0;
loop {
if primes.len() <= NU {
break;
}
rem += 1;
primes.pop();
}
rem
let rem = primes.len() - NU;
primes.truncate(NU);
rem as i32
} else {
0
};
let added = NU - primes.len();
if primes.len() < NU {
static INC: once_cell::sync::Lazy<BigUint> = Lazy::new(BigUint::one);
println!("[INFO] less primes than expected");
let mut number = BigUint::from(THREADS) * BigUint::from(workloads);
static INC: once_cell::sync::Lazy<BigUint> = Lazy::new(BigUint::one);
loop {
number += &*INC;
if prime_utils::is_prime(&number, &primes) {
@@ -192,10 +194,7 @@ fn main() {
}
}
let new_sys_time = SystemTime::now();
let difference = new_sys_time
.duration_since(sys_time)
.expect("Clock may have gone backwards");
let difference = sys_time.elapsed().unwrap();
assert_eq!(primes.len(), NU);
+1
View File
@@ -10,6 +10,7 @@ pub mod primality_tests {
BigUint::from_bytes_be(&buf)
}
#[must_use]
pub fn is_probably_prime(number: &BigUint, iterations: u32) -> bool {
if number <= &BigUint::one() || number == &BigUint::from(4u32) {
return false;