Skip to content

Commit 8eb358b

Browse files
committed
core::rt: Begin recording scheduler metrics
1 parent ca2eebd commit 8eb358b

File tree

4 files changed

+123
-8
lines changed

4 files changed

+123
-8
lines changed

src/libstd/rt/comm.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,16 +119,26 @@ impl<T> ChanOne<T> {
119119
match oldstate {
120120
STATE_BOTH => {
121121
// Port is not waiting yet. Nothing to do
122+
do Local::borrow::<Scheduler> |sched| {
123+
rtdebug!("non-rendezvous send");
124+
sched.metrics.non_rendezvous_sends += 1;
125+
}
122126
}
123127
STATE_ONE => {
128+
do Local::borrow::<Scheduler> |sched| {
129+
rtdebug!("rendezvous send");
130+
sched.metrics.rendezvous_sends += 1;
131+
}
124132
// Port has closed. Need to clean up.
125133
let _packet: ~Packet<T> = cast::transmute(this.inner.void_packet);
126134
recvr_active = false;
127135
}
128136
task_as_state => {
129137
// Port is blocked. Wake it up.
130138
let recvr: ~Coroutine = cast::transmute(task_as_state);
131-
let sched = Local::take::<Scheduler>();
139+
let mut sched = Local::take::<Scheduler>();
140+
rtdebug!("rendezvous send");
141+
sched.metrics.rendezvous_sends += 1;
132142
sched.schedule_task(recvr);
133143
}
134144
}
@@ -170,18 +180,19 @@ impl<T> PortOne<T> {
170180
match oldstate {
171181
STATE_BOTH => {
172182
// Data has not been sent. Now we're blocked.
183+
rtdebug!("non-rendezvous recv");
184+
sched.metrics.non_rendezvous_recvs += 1;
173185
}
174186
STATE_ONE => {
187+
rtdebug!("rendezvous recv");
188+
sched.metrics.rendezvous_recvs += 1;
189+
175190
// Channel is closed. Switch back and check the data.
176191
// NB: We have to drop back into the scheduler event loop here
177192
// instead of switching immediately back or we could end up
178193
// triggering infinite recursion on the scheduler's stack.
179194
let task: ~Coroutine = cast::transmute(task_as_state);
180-
let task = Cell(task);
181-
do sched.event_loop.callback {
182-
let sched = Local::take::<Scheduler>();
183-
sched.resume_task_immediately(task.take());
184-
}
195+
sched.enqueue_task(task);
185196
}
186197
_ => util::unreachable()
187198
}

src/libstd/rt/metrics.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use to_str::ToStr;
12+
13+
pub struct SchedMetrics {
14+
// The number of times executing `run_sched_once`.
15+
turns: uint,
16+
// The number of turns that received a message.
17+
messages_received: uint,
18+
// The number of turns that ran a task from the queue.
19+
tasks_resumed_from_queue: uint,
20+
// The number of turns that found no work to perform.
21+
wasted_turns: uint,
22+
// The number of times the scheduler went to sleep.
23+
sleepy_times: uint,
24+
// Context switches from the scheduler into a task.
25+
context_switches_sched_to_task: uint,
26+
// Context switches from a task into the scheduler.
27+
context_switches_task_to_sched: uint,
28+
// Context switches from a task to a task.
29+
context_switches_task_to_task: uint,
30+
// Message sends that unblock the receiver
31+
rendezvous_sends: uint,
32+
// Message sends that do not unblock the receiver
33+
non_rendezvous_sends: uint,
34+
// Message receives that do not block the receiver
35+
rendezvous_recvs: uint,
36+
// Message receives that block the receiver
37+
non_rendezvous_recvs: uint
38+
}
39+
40+
impl SchedMetrics {
41+
pub fn new() -> SchedMetrics {
42+
SchedMetrics {
43+
turns: 0,
44+
messages_received: 0,
45+
tasks_resumed_from_queue: 0,
46+
wasted_turns: 0,
47+
sleepy_times: 0,
48+
context_switches_sched_to_task: 0,
49+
context_switches_task_to_sched: 0,
50+
context_switches_task_to_task: 0,
51+
rendezvous_sends: 0,
52+
non_rendezvous_sends: 0,
53+
rendezvous_recvs: 0,
54+
non_rendezvous_recvs: 0
55+
}
56+
}
57+
}
58+
59+
impl ToStr for SchedMetrics {
60+
fn to_str(&self) -> ~str {
61+
fmt!("turns: %u\n\
62+
messages_received: %u\n\
63+
tasks_resumed_from_queue: %u\n\
64+
wasted_turns: %u\n\
65+
sleepy_times: %u\n\
66+
context_switches_sched_to_task: %u\n\
67+
context_switches_task_to_sched: %u\n\
68+
context_switches_task_to_task: %u\n\
69+
rendezvous_sends: %u\n\
70+
non_rendezvous_sends: %u\n\
71+
rendezvous_recvs: %u\n\
72+
non_rendezvous_recvs: %u\n\
73+
",
74+
self.turns,
75+
self.messages_received,
76+
self.tasks_resumed_from_queue,
77+
self.wasted_turns,
78+
self.sleepy_times,
79+
self.context_switches_sched_to_task,
80+
self.context_switches_task_to_sched,
81+
self.context_switches_task_to_task,
82+
self.rendezvous_sends,
83+
self.non_rendezvous_sends,
84+
self.rendezvous_recvs,
85+
self.non_rendezvous_recvs
86+
)
87+
}
88+
}

src/libstd/rt/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ pub mod local_ptr;
130130
/// Bindings to pthread/windows thread-local storage.
131131
pub mod thread_local_storage;
132132

133+
pub mod metrics;
134+
133135

134136
/// Set up a default runtime configuration, given compiler-supplied arguments.
135137
///

src/libstd/rt/sched.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use sys;
1313
use cast::transmute;
1414
use cell::Cell;
1515
use clone::Clone;
16+
use to_str::ToStr;
1617

1718
use super::sleeper_list::SleeperList;
1819
use super::work_queue::WorkQueue;
@@ -24,6 +25,7 @@ use super::message_queue::MessageQueue;
2425
use rt::local_ptr;
2526
use rt::local::Local;
2627
use rt::rtio::{IoFactoryObject, RemoteCallback};
28+
use rt::metrics::SchedMetrics;
2729

2830
/// The Scheduler is responsible for coordinating execution of Coroutines
2931
/// on a single thread. When the scheduler is running it is owned by
@@ -63,7 +65,8 @@ pub struct Scheduler {
6365
current_task: Option<~Coroutine>,
6466
/// An action performed after a context switch on behalf of the
6567
/// code running before the context switch
66-
priv cleanup_job: Option<CleanupJob>
68+
priv cleanup_job: Option<CleanupJob>,
69+
metrics: SchedMetrics
6770
}
6871

6972
pub struct SchedHandle {
@@ -115,6 +118,7 @@ pub impl Scheduler {
115118
saved_context: Context::empty(),
116119
current_task: None,
117120
cleanup_job: None,
121+
metrics: SchedMetrics::new()
118122
}
119123
}
120124

@@ -141,20 +145,24 @@ pub impl Scheduler {
141145

142146
let sched = Local::take::<Scheduler>();
143147
assert!(sched.work_queue.is_empty());
148+
rtdebug!("scheduler metrics: %s\n", sched.metrics.to_str());
144149
return sched;
145150
}
146151

147152
fn run_sched_once() {
148153

154+
let mut sched = Local::take::<Scheduler>();
155+
sched.metrics.turns += 1;
156+
149157
// First, check the message queue for instructions.
150158
// XXX: perf. Check for messages without atomics.
151159
// It's ok if we miss messages occasionally, as long as
152160
// we sync and check again before sleeping.
153-
let sched = Local::take::<Scheduler>();
154161
if sched.interpret_message_queue() {
155162
// We performed a scheduling action. There may be other work
156163
// to do yet, so let's try again later.
157164
let mut sched = Local::take::<Scheduler>();
165+
sched.metrics.messages_received += 1;
158166
sched.event_loop.callback(Scheduler::run_sched_once);
159167
Local::put(sched);
160168
return;
@@ -166,6 +174,7 @@ pub impl Scheduler {
166174
// We performed a scheduling action. There may be other work
167175
// to do yet, so let's try again later.
168176
let mut sched = Local::take::<Scheduler>();
177+
sched.metrics.tasks_resumed_from_queue += 1;
169178
sched.event_loop.callback(Scheduler::run_sched_once);
170179
Local::put(sched);
171180
return;
@@ -176,8 +185,10 @@ pub impl Scheduler {
176185
// somebody can wake us up later.
177186
rtdebug!("no work to do");
178187
let mut sched = Local::take::<Scheduler>();
188+
sched.metrics.wasted_turns += 1;
179189
if !sched.sleepy && !sched.no_sleep {
180190
rtdebug!("sleeping");
191+
sched.metrics.sleepy_times += 1;
181192
sched.sleepy = true;
182193
let handle = sched.make_handle();
183194
sched.sleeper_list.push(handle);
@@ -327,6 +338,7 @@ pub impl Scheduler {
327338
assert!(!this.in_task_context());
328339

329340
rtdebug!("scheduling a task");
341+
this.metrics.context_switches_sched_to_task += 1;
330342

331343
// Store the task in the scheduler so it can be grabbed later
332344
this.current_task = Some(task);
@@ -369,6 +381,7 @@ pub impl Scheduler {
369381
assert!(this.in_task_context());
370382

371383
rtdebug!("blocking task");
384+
this.metrics.context_switches_task_to_sched += 1;
372385

373386
unsafe {
374387
let blocked_task = this.current_task.swap_unwrap();
@@ -401,6 +414,7 @@ pub impl Scheduler {
401414
assert!(this.in_task_context());
402415

403416
rtdebug!("switching tasks");
417+
this.metrics.context_switches_task_to_task += 1;
404418

405419
let old_running_task = this.current_task.swap_unwrap();
406420
let f_fake_region = unsafe {

0 commit comments

Comments
 (0)