Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace clock_ticks with std::time #3

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ keywords = [ "virtual", "udp", "connection", "message", "queue"]
license="MIT/Apache-2.0"

[dependencies]
clock_ticks = "0.1.0"
rand = "0.3.14"
clippy = { version = "*", optional = true }

Expand Down
4 changes: 2 additions & 2 deletions src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ impl Server {
while !self.closed {

let tick_start = tick::start();
let tick_delay = 1000000000 / self.config.send_rate;
let tick_delay = 1000_000_000 / self.config.send_rate;

// Receive all incoming UDP packets to our local address
let mut bytes_received = 0;
Expand Down Expand Up @@ -150,7 +150,7 @@ impl Server {
// Then feed the packet into the connection object for
// parsing
connection.receive_packet(
packet, tick_delay / 1000000, self, handler
packet, tick_delay / 1000_000, self, handler
);

}
Expand Down
47 changes: 21 additions & 26 deletions src/shared/binary_rate_limiter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern crate clock_ticks;

use std::cmp;
use std::time::{Duration, Instant};
use super::super::{Config, RateLimiter};

/// Minimum time before switching back into good mode in milliseconds.
Expand All @@ -32,9 +32,9 @@ pub struct BinaryRateLimiter {
max_tick: u32,
mode: Mode,
rtt_threshold: u32,
last_bad_time: u32,
last_good_time: u32,
good_time_duration: u32,
last_bad_time: Instant,
last_good_time: Instant,
good_time_duration: Duration,
delay_until_good_mode: u32
}

Expand All @@ -44,16 +44,17 @@ impl BinaryRateLimiter {
pub fn new(config: &Config) -> Box<BinaryRateLimiter> {

let rate = config.send_rate as f32;
let now = Instant::now();

Box::new(BinaryRateLimiter {
tick: 0,
// Calculate about a third of normal send rate
max_tick: (rate / (33.0 / (100.0 / rate))) as u32,
mode: Mode::Good,
rtt_threshold: 250,
last_bad_time: 0,
last_good_time: precise_time_ms(),
good_time_duration: 0,
last_bad_time: now,
last_good_time: now,
good_time_duration: Duration::new(0, 0),
delay_until_good_mode: MIN_GOOD_MODE_TIME_DELAY
})

Expand All @@ -68,14 +69,15 @@ impl RateLimiter for BinaryRateLimiter {
// Check current network conditions
let conditions = if rtt <= self.rtt_threshold {
// Keep track of the time we are in good mode
self.good_time_duration += precise_time_ms() - self.last_good_time;
self.last_good_time = precise_time_ms();
let now = Instant::now();
self.good_time_duration += now - self.last_good_time;
self.last_good_time = now;
Mode::Good

} else {
// Remember the last time we were in bad mode
self.last_bad_time = precise_time_ms();
self.good_time_duration = 0;
self.last_bad_time = Instant::now();
self.good_time_duration = Duration::new(0, 0);
Mode::Bad
};

Expand All @@ -91,7 +93,7 @@ impl RateLimiter for BinaryRateLimiter {

// To avoid rapid toggling between good and bad mode, if we
// drop from good mode to bad in under 10 seconds
if time_since(self.last_bad_time) < 10000 {
if self.last_bad_time.elapsed() < Duration::from_millis(10000) {

// We double the amount of time before bad mode goes
// back to good.
Expand All @@ -113,8 +115,8 @@ impl RateLimiter for BinaryRateLimiter {
// periods of bad behavior, for each 10 seconds the
// connection is in good mode, we halve the time before bad
// mode goes back to good.
if self.good_time_duration >= 10000 {
self.good_time_duration -= 10000;
if self.good_time_duration >= Duration::from_millis(10000) {
self.good_time_duration -= Duration::from_millis(10000);

// We also clamp this at a minimum
self.delay_until_good_mode = cmp::max(
Expand All @@ -132,7 +134,7 @@ impl RateLimiter for BinaryRateLimiter {

// If you are in bad mode, and conditions have been good for a
// specific length of time return to good mode
if time_since(self.last_bad_time) > self.delay_until_good_mode {
if self.last_bad_time.elapsed() > Duration::from_millis(self.delay_until_good_mode as u64) {
self.mode = Mode::Good;
}

Expand All @@ -159,21 +161,14 @@ impl RateLimiter for BinaryRateLimiter {
}

fn reset(&mut self) {
let now = Instant::now();
self.tick = 0;
self.mode = Mode::Good;
self.last_bad_time = 0;
self.last_good_time = precise_time_ms();
self.good_time_duration = 0;
self.last_bad_time = now;
self.last_good_time = now;
self.good_time_duration = Duration::new(0, 0);
self.delay_until_good_mode = MIN_GOOD_MODE_TIME_DELAY;
}

}

fn precise_time_ms() -> u32 {
(clock_ticks::precise_time_ns() / 1000000) as u32
}

fn time_since(t: u32) -> u32 {
precise_time_ms() - t
}

29 changes: 17 additions & 12 deletions src/shared/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern crate rand;
extern crate clock_ticks;

use std::cmp;
use std::net::SocketAddr;
use std::collections::HashMap;
use std::collections::VecDeque;
use std::time::{Duration, Instant};
use super::message_queue::{MessageQueue, MessageIterator};
use super::super::traits::socket::Socket;
use super::super::{Config, MessageKind, Handler, RateLimiter};
Expand Down Expand Up @@ -43,7 +43,7 @@ enum PacketState {
#[derive(Debug)]
struct SentPacketAck {
seq: u32,
time: u32,
time: Instant,
state: PacketState,
packet: Option<Vec<u8>>
}
Expand Down Expand Up @@ -124,7 +124,7 @@ pub struct Connection {
smoothed_rtt: f32,

/// Last time a packet was received
last_receive_time: u32,
last_receive_time: Instant,

/// Queue of recently received packets used for ack bitfield construction
recv_ack_queue: VecDeque<u32>,
Expand Down Expand Up @@ -187,7 +187,7 @@ impl Connection {
local_seq_number: 0,
remote_seq_number: 0,
smoothed_rtt: 0.0,
last_receive_time: precise_time_ms(),
last_receive_time: Instant::now(),
recv_ack_queue: VecDeque::new(),
sent_ack_queue: Vec::new(),
sent_packets: 0,
Expand Down Expand Up @@ -333,7 +333,7 @@ impl Connection {
}

// Update time used for disconnect detection
self.last_receive_time = precise_time_ms();
self.last_receive_time = Instant::now();

// Read remote sequence number
self.remote_seq_number = packet[8] as u32;
Expand All @@ -353,19 +353,24 @@ impl Connection {
if let Some(lost_packet) = {

let ack = self.sent_ack_queue.get_mut(i).unwrap();
let last_receive_since_ack = if self.last_receive_time > ack.time {
dur_as_ms(self.last_receive_time - ack.time)
} else {
0
};

// Calculate the roundtrip time from acknowledged packets
if seq_was_acked(ack.seq, ack_seq_number, bitfield) {
self.acked_packets = self.acked_packets.wrapping_add(1);
self.smoothed_rtt = moving_average(
self.smoothed_rtt,
(cmp::max(self.last_receive_time - ack.time, tick_delay) - tick_delay) as f32
(cmp::max(last_receive_since_ack, tick_delay) - tick_delay) as f32
);
ack.state = PacketState::Acked;
None

// Extract data from lost packets
} else if self.last_receive_time - ack.time
} else if last_receive_since_ack
> self.config.packet_drop_threshold {

self.lost_packets = self.lost_packets.wrapping_add(1);
Expand Down Expand Up @@ -546,7 +551,7 @@ impl Connection {
if self.send_ack_required(self.local_seq_number) {
self.sent_ack_queue.push(SentPacketAck {
seq: self.local_seq_number,
time: precise_time_ms(),
time: Instant::now(),
state: PacketState::Unknown,
packet: Some(packet)
});
Expand Down Expand Up @@ -576,7 +581,7 @@ impl Connection {
self.local_seq_number = 0;
self.remote_seq_number = 0;
self.smoothed_rtt = 0.0;
self.last_receive_time = precise_time_ms();
self.last_receive_time = Instant::now();
self.recv_ack_queue.clear();
self.sent_ack_queue.clear();
self.sent_packets = 0;
Expand Down Expand Up @@ -653,7 +658,7 @@ impl Connection {
) -> bool {

// Calculate time since last received packet
let inactive_time = precise_time_ms() - self.last_receive_time;
let inactive_time = dur_as_ms(self.last_receive_time.elapsed());

match self.state {

Expand Down Expand Up @@ -743,7 +748,7 @@ fn seq_was_acked(seq: u32, ack: u32, bitfield: u32) -> bool {
}
}

fn precise_time_ms() -> u32 {
(clock_ticks::precise_time_ns() / 1000000) as u32
fn dur_as_ms(dur: Duration) -> u32 {
(dur.as_secs() as u32 * 1000) + (dur.subsec_nanos() / 1000_000)
}

24 changes: 11 additions & 13 deletions src/tests/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern crate clock_ticks;

use std::cmp;
use std::net;
use std::thread;
use std::io::Error;
use std::time::Duration;
use std::time::{Duration, Instant};
use std::net::ToSocketAddrs;
use std::collections::HashMap;

Expand Down Expand Up @@ -270,7 +269,7 @@ pub struct MockTickRecorder {
load_ticks: u32,
tick_delay: u32,
tick_count: u32,
last_tick_time: u32,
last_tick_time: Instant,
expected_time: u32,
last_sleep_duration: u32,
accumulated: i32
Expand All @@ -284,25 +283,27 @@ impl MockTickRecorder {
load_ticks: load_ticks,
tick_delay: 1000 / send_rate,
tick_count: 0,
last_tick_time: 0,
last_tick_time: Instant::now(),
expected_time: expected_time,
last_sleep_duration: 0,
accumulated: 0
}
}

fn init(&mut self) {
self.last_tick_time = precise_time_ms();
self.last_tick_time = Instant::now();
}

fn tick(&mut self) -> bool {

if self.tick_count > 1 {
let delay = (precise_time_ms() - self.last_tick_time) as i32 - (self.last_sleep_duration as i32 - self.tick_delay as i32 * 2);
let elapsed = self.last_tick_time.elapsed();
let delay = elapsed.as_secs() as i32 * 1000 + elapsed.subsec_nanos() as i32 / 1000_000 -
(self.last_sleep_duration as i32 - self.tick_delay as i32 * 2);
self.accumulated += delay;
}

self.last_tick_time = precise_time_ms();
self.last_tick_time = Instant::now();
self.tick_count += 1;

if self.tick_count == self.max_ticks + 2 {
Expand All @@ -315,9 +316,10 @@ impl MockTickRecorder {

// Fake load by waiting sleeping twice the normal tick delay
} else if self.tick_count > 1 && self.tick_count <= self.load_ticks + 1 {
let before = precise_time_ms();
let before = Instant::now();
thread::sleep(Duration::from_millis((self.tick_delay * 2) as u64));
self.last_sleep_duration = precise_time_ms() - before;
let elapsed = before.elapsed();
self.last_sleep_duration = elapsed.as_secs() as u32 * 1000 + elapsed.subsec_nanos() / 1000_000;
false

} else {
Expand Down Expand Up @@ -566,10 +568,6 @@ fn to_socket_addr<T: ToSocketAddrs>(address: T) -> net::SocketAddr {
address.to_socket_addrs().unwrap().nth(0).unwrap()
}

fn precise_time_ms() -> u32 {
(clock_ticks::precise_time_ns() / 1000000) as u32
}

pub fn create_connection(config: Option<Config>) -> (Connection, MockOwner, MockOwnerHandler) {
let config = config.unwrap_or_else(||Config::default());
let local_address: net::SocketAddr = "127.0.0.1:1234".parse().unwrap();
Expand Down
14 changes: 7 additions & 7 deletions src/tick.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,27 @@
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern crate clock_ticks;

use std::cmp;
use std::thread;
use std::time::Duration;
use std::time::{Duration, Instant};

use super::Config;

pub fn start() -> u64 {
clock_ticks::precise_time_ns()
pub fn start() -> Instant {
Instant::now()
}

pub fn end(
tick_delay: u32,
tick_start: u64,
tick_start: Instant,
overflow: &mut u32,
config: &Config
) {

// Actual time taken by the tick
let time_taken = (clock_ticks::precise_time_ns() - tick_start) as u32;
let elapsed = tick_start.elapsed();
assert!(elapsed.as_secs() == 0, "tick exceeded 1 second");
let time_taken = elapsed.subsec_nanos();

// Required delay reduction to keep tick rate
let mut reduction = cmp::min(time_taken, tick_delay);
Expand Down