From 315745b8ef5bf56c000efb350b3c2e8f307f436e Mon Sep 17 00:00:00 2001 From: parazyd Date: Wed, 21 May 2025 20:19:30 +0200 Subject: [PATCH] system: Implement thread priority setting --- Cargo.toml | 1 + src/system/mod.rs | 3 + src/system/thread_priority.rs | 127 +++++++++++++++++++++++++++++++ src/validator/pow.rs | 11 ++- src/validator/randomx_factory.rs | 17 ++--- 5 files changed, 146 insertions(+), 13 deletions(-) create mode 100644 src/system/thread_priority.rs diff --git a/Cargo.toml b/Cargo.toml index 2dcf71529..6d11703d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -175,6 +175,7 @@ validator = [ "randomx", "smol", + "blockchain", "system", "wasm-runtime", ] diff --git a/src/system/mod.rs b/src/system/mod.rs index 27517f82c..aeb167c15 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -37,6 +37,9 @@ pub use publisher::{Publisher, PublisherPtr, Subscription}; pub mod timeout; pub use timeout::io_timeout; +/// Thread priority setting +pub mod thread_priority; + pub type ExecutorPtr = Arc>; /// Sleep for any number of seconds. diff --git a/src/system/thread_priority.rs b/src/system/thread_priority.rs new file mode 100644 index 000000000..51e97a781 --- /dev/null +++ b/src/system/thread_priority.rs @@ -0,0 +1,127 @@ +/* This file is part of DarkFi (https://dark.fi) + * + * Copyright (C) 2020-2025 Dyne.org foundation + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/// Levels of thread priority +pub enum ThreadPriority { + Min, + Low, + Normal, + High, + Max, +} + +/// Set current thread priority to given `priority`. +/// This usually requires root privileges. +pub fn set_thread_priority(priority: ThreadPriority) { + #[cfg(windows)] + { + type HANDLE = *mut std::ffi::c_void; + + const THREAD_PRIORITY_IDLE: i32 = -15; + const THREAD_PRIORITY_BELOW_NORMAL: i32 = -1; + const THREAD_PRIORITY_NORMAL: i32 = 0; + const THREAD_PRIORITY_ABOVE_NORMAL: i32 = 1; + const THREAD_PRIORITY_TIME_CRITICAL: i32 = 15; + + extern "system" { + fn GetCurrentThread() -> HANDLE; + fn SetThreadPriority(hThread: HANDLE, nPriority: i32) -> i32; + } + + let priority_value = match priority { + ThreadPriority::Min => THREAD_PRIORITY_IDLE, + ThreadPriority::Low => THREAD_PRIORITY_BELOW_NORMAL, + ThreadPriority::Normal => THREAD_PRIORITY_NORMAL, + ThreadPriority::High => THREAD_PRIORITY_ABOVE_NORMAL, + ThreadPriority::Max => THREAD_PRIORITY_TIME_CRITICAL, + }; + + unsafe { + SetThreadPriority(GetCurrentThread(), priority_value); + } + } + + #[cfg(target_os = "linux")] + { + extern "C" { + fn setpriority(which: i32, who: u32, prio: i32) -> i32; + } + + const PRIO_PROCESS: i32 = 0; + + let nice_value = match priority { + ThreadPriority::Min => 19, + ThreadPriority::Low => 10, + ThreadPriority::Normal => 0, + ThreadPriority::High => -10, + ThreadPriority::Max => -20, + }; + + unsafe { + setpriority(PRIO_PROCESS, std::process::id(), nice_value); + } + } + + #[cfg(any(target_os = "macos", target_os = "ios"))] + { + type mach_port_t = u32; + type thread_t = mach_port_t; + type thread_policy_flavor_t = i32; + type thread_policy_t = *mut i32; + type mach_msg_type_number_t = u32; + + const THREAD_PRECEDENCE_POLICY: thread_policy_flavor_t = 3; + + #[repr(C)] + struct thread_precedence_policy_data { + importance: i32, + } + + extern "C" { + fn mach_thread_self() -> thread_t; + fn thread_policy_set( + thread: thread_t, + flavor: thread_policy_flavor_t, + policy_info: thread_policy_t, + count: mach_msg_type_number_t, + ) -> i32; + } + + let importance = match priority { + ThreadPriority::Min => -30, + ThreadPriority::Low => -15, + ThreadPriority::Normal => 0, + ThreadPriority::High => 15, + ThreadPriority::Max => 30, + }; + + unsafe { + let thread = mach_thread_self(); + let mut policy = thread_precedence_policy_data { importance }; + let count = + std::mem::size_of::() as mach_msg_type_number_t / 4; + + thread_policy_set( + thread, + THREAD_PRECEDENCE_POLICY, + &mut policy as *mut _ as thread_policy_t, + count, + ); + } + } +} diff --git a/src/validator/pow.rs b/src/validator/pow.rs index 47414a250..1a1b243b1 100644 --- a/src/validator/pow.rs +++ b/src/validator/pow.rs @@ -36,6 +36,7 @@ use crate::{ block_store::{BlockDifficulty, BlockInfo}, Blockchain, BlockchainOverlayPtr, }, + system::thread_priority::ThreadPriority, util::{ringbuffer::RingBuffer, time::Timestamp}, validator::{randomx_factory::init_dataset_wrapper, utils::median}, Error, Result, @@ -380,9 +381,15 @@ pub fn mine_block( let dataset = if threads > 1 { let a = (dataset_item_count * (t as u32)) / (threads as u32); let b = (dataset_item_count * (t as u32 + 1)) / (threads as u32); - init_dataset_wrapper(flags, cache.clone(), a, b - a)? + init_dataset_wrapper(flags, cache.clone(), a, b - a, ThreadPriority::Normal)? } else { - init_dataset_wrapper(flags, cache.clone(), 0, dataset_item_count)? + init_dataset_wrapper( + flags, + cache.clone(), + 0, + dataset_item_count, + ThreadPriority::Normal, + )? }; let stop_signal = stop_signal.clone(); diff --git a/src/validator/randomx_factory.rs b/src/validator/randomx_factory.rs index d0b02fac7..a1a718c8b 100644 --- a/src/validator/randomx_factory.rs +++ b/src/validator/randomx_factory.rs @@ -27,7 +27,10 @@ use std::{ use log::{debug, warn}; use randomx::{RandomXCache, RandomXDataset, RandomXFlags, RandomXVM}; -use crate::Result; +use crate::{ + system::thread_priority::{set_thread_priority, ThreadPriority}, + Result, +}; /// Wrapper for creating a [`RandomXDataset`] pub fn init_dataset_wrapper( @@ -35,17 +38,9 @@ pub fn init_dataset_wrapper( cache: RandomXCache, start_item: u32, item_count: u32, - /* priority: i32, */ + priority: ThreadPriority, ) -> Result { - /* set_thread_priority(priority); */ - - /* - if (is_x86_feature_detected!("avx2") && item_count % 5) { - let dataset = RandomXDataset::new(flags, cache, start_item, item_count - (item_count % 5))?; - let dataset = RandomXDataset::new(flags, cache, start_item + item_count - 5, 5)?; - } - */ - + set_thread_priority(priority); Ok(RandomXDataset::new(flags, cache, start_item, item_count)?) }