big performance uplift
This commit is contained in:
parent
099012a60b
commit
ce507071b9
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,6 +1,6 @@
|
||||
/target
|
||||
report.json
|
||||
primes.json
|
||||
primes1.json
|
||||
primes1.txt
|
||||
primes1.zip
|
||||
primes*.json
|
||||
primes*.txt
|
||||
primes*.zip
|
||||
|
80
Cargo.lock
generated
80
Cargo.lock
generated
@ -39,9 +39,16 @@ dependencies = [
|
||||
"num-bigint",
|
||||
"once_cell",
|
||||
"rand",
|
||||
"serde_json",
|
||||
"thread-priority",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.155"
|
||||
@ -76,6 +83,7 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -139,6 +147,24 @@ version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
@ -175,6 +201,54 @@ version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.204"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.204"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.120"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread-priority"
|
||||
version = "1.1.0"
|
||||
@ -189,6 +263,12 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
|
21
Cargo.toml
21
Cargo.toml
@ -9,8 +9,9 @@ edition = "2021"
|
||||
num = "0.4"
|
||||
thread-priority = "1.1"
|
||||
rand = "0.8"
|
||||
num-bigint = { default-features = false, version = "0.4" }
|
||||
num-bigint = { default-features = false, version = "0.4", features = ["serde"] }
|
||||
once_cell = "1.19"
|
||||
serde_json = "1.0"
|
||||
|
||||
[profile.release]
|
||||
lto = true # Enable link-time optimization
|
||||
@ -21,3 +22,21 @@ overflow-checks = false
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 3
|
||||
|
||||
[lints.clippy]
|
||||
pedantic = { level = "deny", priority = -1 }
|
||||
perf = { level = "deny", priority = 1 }
|
||||
complexity = { level = "deny", priority = -1 }
|
||||
style = { level = "deny", priority = -1 }
|
||||
correctness = { level = "deny", priority = -1 }
|
||||
format_collect = "deny"
|
||||
format_in_format_args = "deny"
|
||||
format_push_string = "deny"
|
||||
mut_mut = "deny"
|
||||
let_underscore_untyped = "deny"
|
||||
str_to_string = "deny"
|
||||
|
||||
cast_possible_truncation = "allow"
|
||||
cast_precision_loss = "allow"
|
||||
cast_sign_loss = "allow"
|
||||
missing_errors_doc = "allow"
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
157
src/main.rs
157
src/main.rs
@ -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)
|
||||
}
|
||||
|
||||
fn try_set_thread_priority() {
|
||||
#[cfg(target_os = "windows")]
|
||||
fn try_set_thread_priority() {
|
||||
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(b"]").unwrap();
|
||||
file.write_all(serde_json::to_string(primes).unwrap().as_bytes())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user