Skip to content

Commit c7d3512

Browse files
committed
runtime: Add a metric that counts currently active tasks
Adds a new metric for the number of active tasks for the Runtime. We count the elements on the OwnedTasks LinkedList, and access that through RuntimeMetrics. Closes: #5400
1 parent effead2 commit c7d3512

File tree

7 files changed

+71
-0
lines changed

7 files changed

+71
-0
lines changed

tokio/src/runtime/metrics/runtime.rs

+19
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,25 @@ impl RuntimeMetrics {
6868
self.handle.inner.num_blocking_threads()
6969
}
7070

71+
/// Returns the number of active tasks in the runtime.
72+
///
73+
/// # Examples
74+
///
75+
/// ```
76+
/// use tokio::runtime::Handle;
77+
///
78+
/// #[tokio::main]
79+
/// async fn main() {
80+
/// let metrics = Handle::current().metrics();
81+
///
82+
/// let n = metrics.active_tasks_count();
83+
/// println!("Runtime has {} active tasks", n);
84+
/// }
85+
/// ```
86+
pub fn active_tasks_count(&self) -> usize {
87+
self.handle.inner.active_tasks_count()
88+
}
89+
7190
/// Returns the number of idle threads, which have spawned by the runtime
7291
/// for `spawn_blocking` calls.
7392
///

tokio/src/runtime/scheduler/current_thread.rs

+4
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,10 @@ cfg_metrics! {
430430
pub(crate) fn blocking_queue_depth(&self) -> usize {
431431
self.blocking_spawner.queue_depth()
432432
}
433+
434+
pub(crate) fn active_tasks_count(&self) -> usize {
435+
self.shared.owned.active_tasks_count()
436+
}
433437
}
434438
}
435439

tokio/src/runtime/scheduler/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ cfg_rt! {
135135
}
136136
}
137137

138+
pub(crate) fn active_tasks_count(&self) -> usize {
139+
match self {
140+
Handle::CurrentThread(handle) => handle.active_tasks_count(),
141+
#[cfg(all(feature = "rt-multi-thread", not(tokio_wasi)))]
142+
Handle::MultiThread(handle) => handle.active_tasks_count(),
143+
}
144+
}
145+
138146
pub(crate) fn scheduler_metrics(&self) -> &SchedulerMetrics {
139147
match self {
140148
Handle::CurrentThread(handle) => handle.scheduler_metrics(),

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

+4
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ cfg_metrics! {
6969
self.blocking_spawner.num_idle_threads()
7070
}
7171

72+
pub(crate) fn active_tasks_count(&self) -> usize {
73+
self.shared.owned.active_tasks_count()
74+
}
75+
7276
pub(crate) fn scheduler_metrics(&self) -> &SchedulerMetrics {
7377
&self.shared.scheduler_metrics
7478
}

tokio/src/runtime/task/list.rs

+4
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,10 @@ impl<S: 'static> OwnedTasks<S> {
153153
}
154154
}
155155

156+
pub(crate) fn active_tasks_count(&self) -> usize {
157+
self.inner.lock().list.count()
158+
}
159+
156160
pub(crate) fn remove(&self, task: &Task<S>) -> Option<Task<S>> {
157161
let task_id = task.header().get_owner_id();
158162
if task_id == 0 {

tokio/src/util/linked_list.rs

+15
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,21 @@ impl<L: Link> LinkedList<L, L::Target> {
174174
true
175175
}
176176

177+
// Counts the elements of the LinkedList
178+
pub(crate) fn count(&self) -> usize {
179+
let mut count = 0;
180+
let mut current = self.head;
181+
182+
while let Some(node) = current {
183+
unsafe {
184+
count += 1;
185+
current = L::pointers(node).as_ref().get_next()
186+
}
187+
}
188+
189+
count
190+
}
191+
177192
/// Removes the specified node from the list
178193
///
179194
/// # Safety

tokio/tests/rt_metrics.rs

+17
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,23 @@ fn blocking_queue_depth() {
8181
assert_eq!(0, rt.metrics().blocking_queue_depth());
8282
}
8383

84+
#[test]
85+
fn active_tasks_count() {
86+
let rt = current_thread();
87+
let metrics = rt.metrics();
88+
assert_eq!(0, metrics.active_tasks_count());
89+
rt.spawn(async move {
90+
assert_eq!(1, metrics.active_tasks_count());
91+
});
92+
93+
let rt = threaded();
94+
let metrics = rt.metrics();
95+
assert_eq!(0, metrics.active_tasks_count());
96+
rt.spawn(async move {
97+
assert_eq!(1, metrics.active_tasks_count());
98+
});
99+
}
100+
84101
#[test]
85102
fn remote_schedule_count() {
86103
use std::thread;

0 commit comments

Comments
 (0)