big performance uplift
This commit is contained in:
+10
-31
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user