diff options
| author | bors <bors@rust-lang.org> | 2013-10-25 10:36:09 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-10-25 10:36:09 -0700 |
| commit | baeed886aa64943ad48121cc3b57dabec12bc835 (patch) | |
| tree | 28ba7cc4b0c36636e884dd6c45fcd612b25e2b37 /src/libstd/rt/task.rs | |
| parent | deeca5d586bfaa4aa60246f671a8d611d38f6248 (diff) | |
| parent | e8f72c38f4bf74e7291043917fdd0bae1404b407 (diff) | |
| download | rust-baeed886aa64943ad48121cc3b57dabec12bc835.tar.gz rust-baeed886aa64943ad48121cc3b57dabec12bc835.zip | |
auto merge of #10060 : alexcrichton/rust/cached-stdout, r=brson
Almost all languages provide some form of buffering of the stdout stream, and this commit adds this feature for rust. A handle to stdout is lazily initialized in the Task structure as a buffered owned Writer trait object. The buffer behavior depends on where stdout is directed to. Like C, this line-buffers the stream when the output goes to a terminal (flushes on newlines), and also like C this uses a fixed-size buffer when output is not directed at a terminal. We may decide the fixed-size buffering is overkill, but it certainly does reduce write syscall counts when piping output elsewhere. This is a *huge* benefit to any code using logging macros or the printing macros. Formatting emits calls to `write` very frequently, and to have each of them backed by a write syscall was very expensive. In a local benchmark of printing 10000 lines of "what" to stdout, I got the following timings: when | terminal | redirected ----------|---------------|-------- before | 0.575s | 0.525s after | 0.197s | 0.013s C | 0.019s | 0.004s I can also confirm that we're buffering the output appropriately in both situtations. We're still far slower than C, but I believe much of that has to do with the "homing" that all tasks due, we're still performing an order of magnitude more write syscalls than C does.
Diffstat (limited to 'src/libstd/rt/task.rs')
| -rw-r--r-- | src/libstd/rt/task.rs | 27 |
1 files changed, 22 insertions, 5 deletions
diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index 7bf124ad312..f82eb929a39 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -23,6 +23,7 @@ use option::{Option, Some, None}; use rt::borrowck; use rt::borrowck::BorrowRecord; use rt::env; +use rt::io::Writer; use rt::kill::Death; use rt::local::Local; use rt::logging::StdErrLogger; @@ -56,7 +57,8 @@ pub struct Task { sched: Option<~Scheduler>, task_type: TaskType, // Dynamic borrowck debugging info - borrow_list: Option<~[BorrowRecord]> + borrow_list: Option<~[BorrowRecord]>, + stdout_handle: Option<~Writer>, } pub enum TaskType { @@ -141,7 +143,8 @@ impl Task { name: None, sched: None, task_type: SchedTask, - borrow_list: None + borrow_list: None, + stdout_handle: None, } } @@ -175,7 +178,8 @@ impl Task { coroutine: Some(Coroutine::new(stack_pool, stack_size, start)), sched: None, task_type: GreenTask(Some(home)), - borrow_list: None + borrow_list: None, + stdout_handle: None, } } @@ -198,7 +202,8 @@ impl Task { coroutine: Some(Coroutine::new(stack_pool, stack_size, start)), sched: None, task_type: GreenTask(Some(home)), - borrow_list: None + borrow_list: None, + stdout_handle: None, } } @@ -234,6 +239,7 @@ impl Task { // Run the task main function, then do some cleanup. do f.finally { + // First, destroy task-local storage. This may run user dtors. // // FIXME #8302: Dear diary. I'm so tired and confused. @@ -257,6 +263,17 @@ impl Task { // Destroy remaining boxes. Also may run user dtors. unsafe { cleanup::annihilate(); } + + // Finally flush and destroy any output handles which the task + // owns. There are no boxes here, and no user destructors should + // run after this any more. + match self.stdout_handle.take() { + Some(handle) => { + let mut handle = handle; + handle.flush(); + } + None => {} + } } } @@ -331,7 +348,7 @@ impl Task { impl Drop for Task { fn drop(&mut self) { rtdebug!("called drop for a task: {}", borrow::to_uint(self)); - rtassert!(self.destroyed) + rtassert!(self.destroyed); } } |
