Skip to content

Commit 1914e1e

Browse files
authored
time: use sharding for timer implementation (#6534)
1 parent e62c3e9 commit 1914e1e

File tree

10 files changed

+184
-70
lines changed

10 files changed

+184
-70
lines changed

tokio/src/runtime/builder.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,7 @@ impl Builder {
702702
}
703703
}
704704

705-
fn get_cfg(&self) -> driver::Cfg {
705+
fn get_cfg(&self, workers: usize) -> driver::Cfg {
706706
driver::Cfg {
707707
enable_pause_time: match self.kind {
708708
Kind::CurrentThread => true,
@@ -715,6 +715,7 @@ impl Builder {
715715
enable_time: self.enable_time,
716716
start_paused: self.start_paused,
717717
nevents: self.nevents,
718+
workers,
718719
}
719720
}
720721

@@ -1095,7 +1096,7 @@ impl Builder {
10951096
use crate::runtime::scheduler::{self, CurrentThread};
10961097
use crate::runtime::{runtime::Scheduler, Config};
10971098

1098-
let (driver, driver_handle) = driver::Driver::new(self.get_cfg())?;
1099+
let (driver, driver_handle) = driver::Driver::new(self.get_cfg(1))?;
10991100

11001101
// Blocking pool
11011102
let blocking_pool = blocking::create_blocking_pool(self, self.max_blocking_threads);
@@ -1248,7 +1249,7 @@ cfg_rt_multi_thread! {
12481249

12491250
let core_threads = self.worker_threads.unwrap_or_else(num_cpus);
12501251

1251-
let (driver, driver_handle) = driver::Driver::new(self.get_cfg())?;
1252+
let (driver, driver_handle) = driver::Driver::new(self.get_cfg(core_threads))?;
12521253

12531254
// Create the blocking pool
12541255
let blocking_pool =
@@ -1295,7 +1296,7 @@ cfg_rt_multi_thread! {
12951296
use crate::runtime::scheduler::MultiThreadAlt;
12961297

12971298
let core_threads = self.worker_threads.unwrap_or_else(num_cpus);
1298-
let (driver, driver_handle) = driver::Driver::new(self.get_cfg())?;
1299+
let (driver, driver_handle) = driver::Driver::new(self.get_cfg(core_threads))?;
12991300

13001301
// Create the blocking pool
13011302
let blocking_pool =

tokio/src/runtime/context.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::runtime::coop;
33

44
use std::cell::Cell;
55

6-
#[cfg(any(feature = "rt", feature = "macros"))]
6+
#[cfg(any(feature = "rt", feature = "macros", feature = "time"))]
77
use crate::util::rand::FastRand;
88

99
cfg_rt! {
@@ -57,7 +57,7 @@ struct Context {
5757
#[cfg(feature = "rt")]
5858
runtime: Cell<EnterRuntime>,
5959

60-
#[cfg(any(feature = "rt", feature = "macros"))]
60+
#[cfg(any(feature = "rt", feature = "macros", feature = "time"))]
6161
rng: Cell<Option<FastRand>>,
6262

6363
/// Tracks the amount of "work" a task may still do before yielding back to
@@ -100,7 +100,7 @@ tokio_thread_local! {
100100
#[cfg(feature = "rt")]
101101
runtime: Cell::new(EnterRuntime::NotEntered),
102102

103-
#[cfg(any(feature = "rt", feature = "macros"))]
103+
#[cfg(any(feature = "rt", feature = "macros", feature = "time"))]
104104
rng: Cell::new(None),
105105

106106
budget: Cell::new(coop::Budget::unconstrained()),
@@ -121,7 +121,11 @@ tokio_thread_local! {
121121
}
122122
}
123123

124-
#[cfg(any(feature = "macros", all(feature = "sync", feature = "rt")))]
124+
#[cfg(any(
125+
feature = "time",
126+
feature = "macros",
127+
all(feature = "sync", feature = "rt")
128+
))]
125129
pub(crate) fn thread_rng_n(n: u32) -> u32 {
126130
CONTEXT.with(|ctx| {
127131
let mut rng = ctx.rng.get().unwrap_or_else(FastRand::new);

tokio/src/runtime/driver.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub(crate) struct Cfg {
4040
pub(crate) enable_pause_time: bool,
4141
pub(crate) start_paused: bool,
4242
pub(crate) nevents: usize,
43+
pub(crate) workers: usize,
4344
}
4445

4546
impl Driver {
@@ -48,7 +49,8 @@ impl Driver {
4849

4950
let clock = create_clock(cfg.enable_pause_time, cfg.start_paused);
5051

51-
let (time_driver, time_handle) = create_time_driver(cfg.enable_time, io_stack, &clock);
52+
let (time_driver, time_handle) =
53+
create_time_driver(cfg.enable_time, io_stack, &clock, cfg.workers);
5254

5355
Ok((
5456
Self { inner: time_driver },
@@ -306,9 +308,10 @@ cfg_time! {
306308
enable: bool,
307309
io_stack: IoStack,
308310
clock: &Clock,
311+
workers: usize,
309312
) -> (TimeDriver, TimeHandle) {
310313
if enable {
311-
let (driver, handle) = crate::runtime::time::Driver::new(io_stack, clock);
314+
let (driver, handle) = crate::runtime::time::Driver::new(io_stack, clock, workers as u32);
312315

313316
(TimeDriver::Enabled { driver }, Some(handle))
314317
} else {
@@ -361,6 +364,7 @@ cfg_not_time! {
361364
_enable: bool,
362365
io_stack: IoStack,
363366
_clock: &Clock,
367+
_workers: usize,
364368
) -> (TimeDriver, TimeHandle) {
365369
(io_stack, ())
366370
}

tokio/src/runtime/scheduler/multi_thread/worker.rs

+5
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,11 @@ impl Context {
742742
pub(crate) fn defer(&self, waker: &Waker) {
743743
self.defer.defer(waker);
744744
}
745+
746+
#[allow(dead_code)]
747+
pub(crate) fn get_worker_index(&self) -> usize {
748+
self.worker.index
749+
}
745750
}
746751

747752
impl Core {

tokio/src/runtime/scheduler/multi_thread_alt/worker.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1311,6 +1311,11 @@ impl Context {
13111311
fn shared(&self) -> &Shared {
13121312
&self.handle.shared
13131313
}
1314+
1315+
#[cfg_attr(not(feature = "time"), allow(dead_code))]
1316+
pub(crate) fn get_worker_index(&self) -> usize {
1317+
self.index
1318+
}
13141319
}
13151320

13161321
impl Core {

tokio/src/runtime/time/entry.rs

+35-2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ use crate::loom::cell::UnsafeCell;
5858
use crate::loom::sync::atomic::AtomicU64;
5959
use crate::loom::sync::atomic::Ordering;
6060

61+
use crate::runtime::context;
6162
use crate::runtime::scheduler;
6263
use crate::sync::AtomicWaker;
6364
use crate::time::Instant;
@@ -328,6 +329,8 @@ pub(super) type EntryList = crate::util::linked_list::LinkedList<TimerShared, Ti
328329
///
329330
/// Note that this structure is located inside the `TimerEntry` structure.
330331
pub(crate) struct TimerShared {
332+
/// The shard id. We should never change it.
333+
shard_id: u32,
331334
/// A link within the doubly-linked list of timers on a particular level and
332335
/// slot. Valid only if state is equal to Registered.
333336
///
@@ -368,8 +371,9 @@ generate_addr_of_methods! {
368371
}
369372

370373
impl TimerShared {
371-
pub(super) fn new() -> Self {
374+
pub(super) fn new(shard_id: u32) -> Self {
372375
Self {
376+
shard_id,
373377
cached_when: AtomicU64::new(0),
374378
pointers: linked_list::Pointers::new(),
375379
state: StateCell::default(),
@@ -438,6 +442,11 @@ impl TimerShared {
438442
pub(super) fn might_be_registered(&self) -> bool {
439443
self.state.might_be_registered()
440444
}
445+
446+
/// Gets the shard id.
447+
pub(super) fn shard_id(&self) -> u32 {
448+
self.shard_id
449+
}
441450
}
442451

443452
unsafe impl linked_list::Link for TimerShared {
@@ -485,8 +494,10 @@ impl TimerEntry {
485494
fn inner(&self) -> &TimerShared {
486495
let inner = unsafe { &*self.inner.get() };
487496
if inner.is_none() {
497+
let shard_size = self.driver.driver().time().inner.get_shard_size();
498+
let shard_id = generate_shard_id(shard_size);
488499
unsafe {
489-
*self.inner.get() = Some(TimerShared::new());
500+
*self.inner.get() = Some(TimerShared::new(shard_id));
490501
}
491502
}
492503
return inner.as_ref().unwrap();
@@ -643,3 +654,25 @@ impl Drop for TimerEntry {
643654
unsafe { Pin::new_unchecked(self) }.as_mut().cancel();
644655
}
645656
}
657+
658+
// Generates a shard id. If current thread is a worker thread, we use its worker index as a shard id.
659+
// Otherwise, we use a random number generator to obtain the shard id.
660+
cfg_rt! {
661+
fn generate_shard_id(shard_size: u32) -> u32 {
662+
let id = context::with_scheduler(|ctx| match ctx {
663+
Some(scheduler::Context::CurrentThread(_ctx)) => 0,
664+
#[cfg(feature = "rt-multi-thread")]
665+
Some(scheduler::Context::MultiThread(ctx)) => ctx.get_worker_index() as u32,
666+
#[cfg(all(tokio_unstable, feature = "rt-multi-thread"))]
667+
Some(scheduler::Context::MultiThreadAlt(ctx)) => ctx.get_worker_index() as u32,
668+
None => context::thread_rng_n(shard_size),
669+
});
670+
id % shard_size
671+
}
672+
}
673+
674+
cfg_not_rt! {
675+
fn generate_shard_id(shard_size: u32) -> u32 {
676+
context::thread_rng_n(shard_size)
677+
}
678+
}

0 commit comments

Comments
 (0)