flattiverse_connector 36.1.1

Connector library for the flattiverse.com game server.
Documentation


use rand;
use rand::Rng;

use std::thread;

use std::sync::Arc;
use std::sync::RwLock;

use crate::Error;
use crate::TimeSpan;
use crate::StopWatch;
use crate::ManualResetEvent;
use crate::net::BinaryWriter;

pub struct PerformanceTest {
    result:  RwLock<i64>,
    memory:  bool,
    ready:   ManualResetEvent,
    control: Arc<ManualResetEvent>,
}

impl PerformanceTest {
    pub fn new(control: Arc<ManualResetEvent>, time: TimeSpan, memory: bool) -> Arc<PerformanceTest> {
        let test = Arc::new(PerformanceTest {
            result: RwLock::new(0_i64),
            control,
            memory,
            ready: ManualResetEvent::new(false),
        });
        let clone = test.clone();
        thread::spawn(move || {
            let time = time;
            clone.test_sequence(&time).unwrap();
        });
        test
    }

    pub fn test_sequence(&self, time: &TimeSpan) -> Result<(), Error> {
        let mut stop_watch = StopWatch::default();
        let mut last_view  = TimeSpan::new(0);

        let mut last_result = 0_i64;
        let mut planned_phase = 1_000_000_i64;
        let mut result = 0_i64;

        self.ready.set()?;
        self.control.wait_one()?;
        self.ready.reset()?;
        stop_watch.start();

        loop {
            #[allow(clippy::mut_range_bound)]
            for _ in result..planned_phase {
                result += 1;
            }

            let current_measurement = stop_watch.elapsed();

            if current_measurement.ticks() > time.ticks() || (current_measurement.ticks() - last_view.ticks()) <= 10 {
                break;
            }

            planned_phase = (time.ticks() - current_measurement.ticks())
                          * 15_i64
                          * (result - last_result)
                          / (current_measurement.ticks() - last_view.ticks())
                          / 16_i64
                          + result;
            last_view     = current_measurement;
            last_result   = result;
        }

        stop_watch.stop();
        result      = result * 10_000_000_i64 / stop_watch.ticks();
        *self.result.write()? = result;

        if !self.memory {
            self.ready().set()?;
            return Ok(());
        }

        stop_watch.reset();
        last_view     = TimeSpan::new(0);
        planned_phase = 100_i64;
        last_result   = 0_i64;
        result        = 0_i64;

        let mut rand = rand::thread_rng();
        let mut ram_data = Vec::with_capacity(128);

        for _ in 0..128 {
            let mut vec = Vec::with_capacity(1_048_576);
            {
                let writer = &mut vec as &mut BinaryWriter;
                for _ in 0..(1_048_576/8) {
                    writer.write_i64(rand.gen::<i64>())?
                }
            }
            ram_data.push(vec);
        }

        let mut tmp_data = Box::new([0u8; 262_144]);


        self.ready.set()?;
        self.control.wait_one()?;
        self.ready.reset()?;
        stop_watch.start();


        loop {
            #[allow(clippy::mut_range_bound)]
            for _ in result..planned_phase {
                result += 1;
            }

            let array = (rand.gen::<u8>() / 2_u8) as usize;
            let from  = (rand.gen::<f32>() * 786_432_f32) as usize;
            let to           = from + 262_144;
            tmp_data.clone_from_slice(&ram_data[array][from..to]);

            let current_measurement = stop_watch.elapsed();

            if current_measurement.ticks() > time.ticks() || current_measurement.ticks() - last_view.ticks() <= 10 {
                break;
            }

            planned_phase = (time.ticks() - current_measurement.ticks())
                          * 15_i64
                          * (result - last_result)
                          / (current_measurement.ticks() - last_view.ticks())
                          / 16_i64
                          + result;
            last_view     = current_measurement;
            last_result   = result;
        }

        stop_watch.stop();
        result = result * 10_000_000_i64 / stop_watch.ticks();
        *self.result.write()? = result;
        self.ready.set()?;
        Ok(())
    }

    pub fn try_result(&self) -> Result<i64, Error> {
        Ok(*self.result.read()?)
    }

    pub fn ready(&self) -> &ManualResetEvent {
        &self.ready
    }

    pub fn control(&self) -> &ManualResetEvent {
        &self.control
    }

    pub fn close(self) -> Result<(), Error> {
        self.ready.close()
    }
}