diff options
| author | Brian Anderson <banderson@mozilla.com> | 2013-05-29 22:38:15 -0700 |
|---|---|---|
| committer | Brian Anderson <banderson@mozilla.com> | 2013-05-30 00:18:07 -0700 |
| commit | 8eb358bb00f161f9e289de6cad8cfecc4c6eb681 (patch) | |
| tree | 9c884ef810bc30c2b70b319669a7f450bb98e5ef /src/libstd/rt | |
| parent | ca2eebd5dd8ceea1da77b6a6f4fb8c68462a400b (diff) | |
| download | rust-8eb358bb00f161f9e289de6cad8cfecc4c6eb681.tar.gz rust-8eb358bb00f161f9e289de6cad8cfecc4c6eb681.zip | |
core::rt: Begin recording scheduler metrics
Diffstat (limited to 'src/libstd/rt')
| -rw-r--r-- | src/libstd/rt/comm.rs | 23 | ||||
| -rw-r--r-- | src/libstd/rt/metrics.rs | 88 | ||||
| -rw-r--r-- | src/libstd/rt/mod.rs | 2 | ||||
| -rw-r--r-- | src/libstd/rt/sched.rs | 18 |
4 files changed, 123 insertions, 8 deletions
diff --git a/src/libstd/rt/comm.rs b/src/libstd/rt/comm.rs index ebfa9e263ef..19fb809d437 100644 --- a/src/libstd/rt/comm.rs +++ b/src/libstd/rt/comm.rs @@ -119,8 +119,16 @@ impl<T> ChanOne<T> { match oldstate { STATE_BOTH => { // Port is not waiting yet. Nothing to do + do Local::borrow::<Scheduler> |sched| { + rtdebug!("non-rendezvous send"); + sched.metrics.non_rendezvous_sends += 1; + } } STATE_ONE => { + do Local::borrow::<Scheduler> |sched| { + rtdebug!("rendezvous send"); + sched.metrics.rendezvous_sends += 1; + } // Port has closed. Need to clean up. let _packet: ~Packet<T> = cast::transmute(this.inner.void_packet); recvr_active = false; @@ -128,7 +136,9 @@ impl<T> ChanOne<T> { task_as_state => { // Port is blocked. Wake it up. let recvr: ~Coroutine = cast::transmute(task_as_state); - let sched = Local::take::<Scheduler>(); + let mut sched = Local::take::<Scheduler>(); + rtdebug!("rendezvous send"); + sched.metrics.rendezvous_sends += 1; sched.schedule_task(recvr); } } @@ -170,18 +180,19 @@ impl<T> PortOne<T> { match oldstate { STATE_BOTH => { // Data has not been sent. Now we're blocked. + rtdebug!("non-rendezvous recv"); + sched.metrics.non_rendezvous_recvs += 1; } STATE_ONE => { + rtdebug!("rendezvous recv"); + sched.metrics.rendezvous_recvs += 1; + // Channel is closed. Switch back and check the data. // NB: We have to drop back into the scheduler event loop here // instead of switching immediately back or we could end up // triggering infinite recursion on the scheduler's stack. let task: ~Coroutine = cast::transmute(task_as_state); - let task = Cell(task); - do sched.event_loop.callback { - let sched = Local::take::<Scheduler>(); - sched.resume_task_immediately(task.take()); - } + sched.enqueue_task(task); } _ => util::unreachable() } diff --git a/src/libstd/rt/metrics.rs b/src/libstd/rt/metrics.rs new file mode 100644 index 00000000000..70e347fdfb6 --- /dev/null +++ b/src/libstd/rt/metrics.rs @@ -0,0 +1,88 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <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. + +use to_str::ToStr; + +pub struct SchedMetrics { + // The number of times executing `run_sched_once`. + turns: uint, + // The number of turns that received a message. + messages_received: uint, + // The number of turns that ran a task from the queue. + tasks_resumed_from_queue: uint, + // The number of turns that found no work to perform. + wasted_turns: uint, + // The number of times the scheduler went to sleep. + sleepy_times: uint, + // Context switches from the scheduler into a task. + context_switches_sched_to_task: uint, + // Context switches from a task into the scheduler. + context_switches_task_to_sched: uint, + // Context switches from a task to a task. + context_switches_task_to_task: uint, + // Message sends that unblock the receiver + rendezvous_sends: uint, + // Message sends that do not unblock the receiver + non_rendezvous_sends: uint, + // Message receives that do not block the receiver + rendezvous_recvs: uint, + // Message receives that block the receiver + non_rendezvous_recvs: uint +} + +impl SchedMetrics { + pub fn new() -> SchedMetrics { + SchedMetrics { + turns: 0, + messages_received: 0, + tasks_resumed_from_queue: 0, + wasted_turns: 0, + sleepy_times: 0, + context_switches_sched_to_task: 0, + context_switches_task_to_sched: 0, + context_switches_task_to_task: 0, + rendezvous_sends: 0, + non_rendezvous_sends: 0, + rendezvous_recvs: 0, + non_rendezvous_recvs: 0 + } + } +} + +impl ToStr for SchedMetrics { + fn to_str(&self) -> ~str { + fmt!("turns: %u\n\ + messages_received: %u\n\ + tasks_resumed_from_queue: %u\n\ + wasted_turns: %u\n\ + sleepy_times: %u\n\ + context_switches_sched_to_task: %u\n\ + context_switches_task_to_sched: %u\n\ + context_switches_task_to_task: %u\n\ + rendezvous_sends: %u\n\ + non_rendezvous_sends: %u\n\ + rendezvous_recvs: %u\n\ + non_rendezvous_recvs: %u\n\ + ", + self.turns, + self.messages_received, + self.tasks_resumed_from_queue, + self.wasted_turns, + self.sleepy_times, + self.context_switches_sched_to_task, + self.context_switches_task_to_sched, + self.context_switches_task_to_task, + self.rendezvous_sends, + self.non_rendezvous_sends, + self.rendezvous_recvs, + self.non_rendezvous_recvs + ) + } +} \ No newline at end of file diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 1113d7abe7d..23dc7578002 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -130,6 +130,8 @@ pub mod local_ptr; /// Bindings to pthread/windows thread-local storage. pub mod thread_local_storage; +pub mod metrics; + /// Set up a default runtime configuration, given compiler-supplied arguments. /// diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index 75b53066441..b5b8bb732e7 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -13,6 +13,7 @@ use sys; use cast::transmute; use cell::Cell; use clone::Clone; +use to_str::ToStr; use super::sleeper_list::SleeperList; use super::work_queue::WorkQueue; @@ -24,6 +25,7 @@ use super::message_queue::MessageQueue; use rt::local_ptr; use rt::local::Local; use rt::rtio::{IoFactoryObject, RemoteCallback}; +use rt::metrics::SchedMetrics; /// The Scheduler is responsible for coordinating execution of Coroutines /// on a single thread. When the scheduler is running it is owned by @@ -63,7 +65,8 @@ pub struct Scheduler { current_task: Option<~Coroutine>, /// An action performed after a context switch on behalf of the /// code running before the context switch - priv cleanup_job: Option<CleanupJob> + priv cleanup_job: Option<CleanupJob>, + metrics: SchedMetrics } pub struct SchedHandle { @@ -115,6 +118,7 @@ pub impl Scheduler { saved_context: Context::empty(), current_task: None, cleanup_job: None, + metrics: SchedMetrics::new() } } @@ -141,20 +145,24 @@ pub impl Scheduler { let sched = Local::take::<Scheduler>(); assert!(sched.work_queue.is_empty()); + rtdebug!("scheduler metrics: %s\n", sched.metrics.to_str()); return sched; } fn run_sched_once() { + let mut sched = Local::take::<Scheduler>(); + sched.metrics.turns += 1; + // First, check the message queue for instructions. // XXX: perf. Check for messages without atomics. // It's ok if we miss messages occasionally, as long as // we sync and check again before sleeping. - let sched = Local::take::<Scheduler>(); if sched.interpret_message_queue() { // We performed a scheduling action. There may be other work // to do yet, so let's try again later. let mut sched = Local::take::<Scheduler>(); + sched.metrics.messages_received += 1; sched.event_loop.callback(Scheduler::run_sched_once); Local::put(sched); return; @@ -166,6 +174,7 @@ pub impl Scheduler { // We performed a scheduling action. There may be other work // to do yet, so let's try again later. let mut sched = Local::take::<Scheduler>(); + sched.metrics.tasks_resumed_from_queue += 1; sched.event_loop.callback(Scheduler::run_sched_once); Local::put(sched); return; @@ -176,8 +185,10 @@ pub impl Scheduler { // somebody can wake us up later. rtdebug!("no work to do"); let mut sched = Local::take::<Scheduler>(); + sched.metrics.wasted_turns += 1; if !sched.sleepy && !sched.no_sleep { rtdebug!("sleeping"); + sched.metrics.sleepy_times += 1; sched.sleepy = true; let handle = sched.make_handle(); sched.sleeper_list.push(handle); @@ -327,6 +338,7 @@ pub impl Scheduler { assert!(!this.in_task_context()); rtdebug!("scheduling a task"); + this.metrics.context_switches_sched_to_task += 1; // Store the task in the scheduler so it can be grabbed later this.current_task = Some(task); @@ -369,6 +381,7 @@ pub impl Scheduler { assert!(this.in_task_context()); rtdebug!("blocking task"); + this.metrics.context_switches_task_to_sched += 1; unsafe { let blocked_task = this.current_task.swap_unwrap(); @@ -401,6 +414,7 @@ pub impl Scheduler { assert!(this.in_task_context()); rtdebug!("switching tasks"); + this.metrics.context_switches_task_to_task += 1; let old_running_task = this.current_task.swap_unwrap(); let f_fake_region = unsafe { |
