parallelchain-io / hotstuff_rs

Rust implementation of the HotStuff consensus algorithm.
34 stars 4 forks source link

high cpu usage #27

Open m00dy opened 6 months ago

m00dy commented 6 months ago

Hi,

has anyone observed high cpu usage on a network with 3 validators ? I'm testing on a dedicated machine where specs should be fine. I also attach the flame graph here. flamegraph copy 3

If you look at the flamegraph, it is easy to spot std::sync::mpsc::Receiver::try_recv doing some nasty things...I wonder is it possible to replace it something less resource hugry ?

here is my network implementation.

pub struct TestNetwork { pub my_verifying_key: VerifyingKey, pub my_hostname: String, pub all_hostnames: HashMap<VerifyingKey, String>, pub outgoing_sender_queue: Sender<(String, MessagePayload)>, pub incoming_msg_queue: Arc<Mutex<Receiver<(String, MessagePayload)>>>, }

impl Network for XoXoNetwork { fn init_validatorset(&mut self, : ValidatorSet) { }

fn update_validator_set(&mut self, _: ValidatorSetUpdates) {
}

fn send(&mut self, peer: VerifyingKey, message: Message) {
    if let Some(hostname) = self.all_hostnames.get(&peer) {
        let _ = self.outgoing_sender_queue.send((hostname.to_string(), MessagePayload{message, sender: self.my_verifying_key}));
    }
}

fn broadcast(&mut self, message: Message) {
    //get all hostnames 
    for hostname in self.all_hostnames.values() {
        let _ = self.outgoing_sender_queue.send((hostname.to_string(), MessagePayload{message: message.clone(), sender: self.my_verifying_key}));
    }
}

fn recv(&mut self) -> Option<(VerifyingKey, Message)> {
    match self.incoming_msg_queue.lock().unwrap().try_recv() {
        Ok((_, payload)) => Some((payload.sender, payload.message)),
        Err(TryRecvError::Empty) => None,
        Err(TryRecvError::Disconnected) => panic!(),
    }
}

}

lscpu output >

Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Address sizes: 39 bits physical, 48 bits virtual Byte Order: Little Endian CPU(s): 8 On-line CPU(s) list: 0-7 Vendor ID: GenuineIntel Model name: Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz CPU family: 6 Model: 94 Thread(s) per core: 2 Core(s) per socket: 4 Socket(s): 1 Stepping: 3 CPU max MHz: 4000.0000 CPU min MHz: 800.0000 BogoMIPS: 6799.81

m00dy commented 5 months ago

There are 4 threads that I put into sleep; algorithm, event_bus, networking and sync_server. 4 milliseconds enough to get around cpu exhaustion.

lyulka commented 5 months ago

Thanks for the feedback, @m00dy.

The reason you're probably seeing high CPU utilization in some of your cores is that we use busy-waiting in a few places in the codebase, including busy-waiting on Receiver::try_recv. We are aware of this behavior, and one of our ideas for how to reduce busy-waiting is to adopt Async Rust. However, this entails a major refactor and will also affect the stability and compatibility of our library (the Async Rust ecosystem is not super stable yet), which is why we don't have this as an immediate priority.