Skip to content

Commit d392556

Browse files
committed
std: Fix perf of local allocations in newsched
Mostly optimizing TLS accesses to bring local heap allocation performance closer to that of oldsched. It's not completely at parity but removing the branches involved in supporting oldsched and optimizing pthread_get/setspecific to instead use our dedicated TCB slot will probably make up for it.
1 parent a931e04 commit d392556

File tree

9 files changed

+92
-68
lines changed

9 files changed

+92
-68
lines changed

src/libstd/os.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1142,9 +1142,9 @@ pub fn real_args() -> ~[~str] {
11421142
#[cfg(target_os = "freebsd")]
11431143
pub fn real_args() -> ~[~str] {
11441144
use rt;
1145-
use rt::TaskContext;
1145+
use rt::NewRtContext;
11461146

1147-
if rt::context() == TaskContext {
1147+
if rt::context() == NewRtContext {
11481148
match rt::args::clone() {
11491149
Some(args) => args,
11501150
None => fail!("process arguments not initialized")

src/libstd/rt/comm.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use cast;
1515
use ops::Drop;
1616
use rt::kill::BlockedTask;
1717
use kinds::Send;
18+
use rt;
1819
use rt::sched::Scheduler;
1920
use rt::local::Local;
2021
use rt::select::{Select, SelectPort};
@@ -24,7 +25,6 @@ use util::Void;
2425
use comm::{GenericChan, GenericSmartChan, GenericPort, Peekable};
2526
use cell::Cell;
2627
use clone::Clone;
27-
use rt::{context, SchedulerContext};
2828
use tuple::ImmutableTuple;
2929

3030
/// A combined refcount / BlockedTask-as-uint pointer.
@@ -113,7 +113,7 @@ impl<T> ChanOne<T> {
113113
// 'do_resched' configures whether the scheduler immediately switches to
114114
// the receiving task, or leaves the sending task still running.
115115
fn try_send_inner(self, val: T, do_resched: bool) -> bool {
116-
rtassert!(context() != SchedulerContext);
116+
rtassert!(!rt::in_sched_context());
117117

118118
let mut this = self;
119119
let mut recvr_active = true;

src/libstd/rt/local_heap.rs

+15-7
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use libc;
1414
use libc::{c_void, uintptr_t, size_t};
1515
use ops::Drop;
16+
use option::{Some, None};
1617
use rt;
1718
use rt::OldTaskContext;
1819
use rt::local::Local;
@@ -86,20 +87,19 @@ impl Drop for LocalHeap {
8687

8788
// A little compatibility function
8889
pub unsafe fn local_free(ptr: *libc::c_char) {
89-
match rt::context() {
90-
OldTaskContext => {
90+
// XXX: Unsafe borrow for speed. Lame.
91+
match Local::try_unsafe_borrow::<Task>() {
92+
Some(task) => {
93+
(*task).heap.free(ptr as *libc::c_void);
94+
}
95+
None => {
9196
rust_upcall_free_noswitch(ptr);
9297

9398
extern {
9499
#[fast_ffi]
95100
fn rust_upcall_free_noswitch(ptr: *libc::c_char);
96101
}
97102
}
98-
_ => {
99-
do Local::borrow::<Task,()> |task| {
100-
task.heap.free(ptr as *libc::c_void);
101-
}
102-
}
103103
}
104104
}
105105

@@ -119,20 +119,28 @@ pub fn live_allocs() -> *raw::Box<()> {
119119
}
120120

121121
extern {
122+
#[fast_ffi]
122123
fn rust_new_memory_region(synchronized: uintptr_t,
123124
detailed_leaks: uintptr_t,
124125
poison_on_free: uintptr_t) -> *MemoryRegion;
126+
#[fast_ffi]
125127
fn rust_delete_memory_region(region: *MemoryRegion);
128+
#[fast_ffi]
126129
fn rust_new_boxed_region(region: *MemoryRegion,
127130
poison_on_free: uintptr_t) -> *BoxedRegion;
131+
#[fast_ffi]
128132
fn rust_delete_boxed_region(region: *BoxedRegion);
133+
#[fast_ffi]
129134
fn rust_boxed_region_malloc(region: *BoxedRegion,
130135
td: *TypeDesc,
131136
size: size_t) -> *OpaqueBox;
137+
#[fast_ffi]
132138
fn rust_boxed_region_realloc(region: *BoxedRegion,
133139
ptr: *OpaqueBox,
134140
size: size_t) -> *OpaqueBox;
141+
#[fast_ffi]
135142
fn rust_boxed_region_free(region: *BoxedRegion, box: *OpaqueBox);
143+
#[fast_ffi]
136144
fn rust_current_boxed_region() -> *BoxedRegion;
137145
}
138146

src/libstd/rt/mod.rs

+32-19
Original file line numberDiff line numberDiff line change
@@ -407,14 +407,10 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int {
407407
/// or the old scheduler.
408408
#[deriving(Eq)]
409409
pub enum RuntimeContext {
410-
// Only the exchange heap is available
411-
GlobalContext,
412-
// The scheduler may be accessed
413-
SchedulerContext,
414-
// Full task services, e.g. local heap, unwinding
415-
TaskContext,
416410
// Running in an old-style task
417-
OldTaskContext
411+
OldTaskContext,
412+
// Not old task context
413+
NewRtContext
418414
}
419415

420416
/// Determine the current RuntimeContext
@@ -424,23 +420,40 @@ pub fn context() -> RuntimeContext {
424420

425421
if unsafe { rust_try_get_task().is_not_null() } {
426422
return OldTaskContext;
427-
} else if Local::exists::<Task>() {
428-
// In this case we know it is a new runtime context, but we
429-
// need to check which one. Going to try borrowing task to
430-
// check. Task should always be in TLS, so hopefully this
431-
// doesn't conflict with other ops that borrow.
432-
return do Local::borrow::<Task,RuntimeContext> |task| {
433-
match task.task_type {
434-
SchedTask => SchedulerContext,
435-
GreenTask(_) => TaskContext
436-
}
437-
};
438423
} else {
439-
return GlobalContext;
424+
return NewRtContext;
440425
}
441426

442427
extern {
443428
#[rust_stack]
444429
pub fn rust_try_get_task() -> *rust_task;
445430
}
446431
}
432+
433+
pub fn in_sched_context() -> bool {
434+
unsafe {
435+
match Local::try_unsafe_borrow::<Task>() {
436+
Some(task) => {
437+
match (*task).task_type {
438+
SchedTask => true,
439+
_ => false
440+
}
441+
}
442+
None => false
443+
}
444+
}
445+
}
446+
447+
pub fn in_green_task_context() -> bool {
448+
unsafe {
449+
match Local::try_unsafe_borrow::<Task>() {
450+
Some(task) => {
451+
match (*task).task_type {
452+
GreenTask(_) => true,
453+
_ => false
454+
}
455+
}
456+
None => false
457+
}
458+
}
459+
}

src/libstd/sys.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ impl FailWithCause for &'static str {
136136
pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
137137
use either::Left;
138138
use option::{Some, None};
139-
use rt::{context, OldTaskContext, TaskContext};
139+
use rt::{context, OldTaskContext, in_green_task_context};
140140
use rt::task::Task;
141141
use rt::local::Local;
142142
use rt::logging::Logger;
@@ -158,7 +158,7 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
158158

159159
// XXX: Logging doesn't work correctly in non-task context because it
160160
// invokes the local heap
161-
if context == TaskContext {
161+
if in_green_task_context() {
162162
// XXX: Logging doesn't work here - the check to call the log
163163
// function never passes - so calling the log function directly.
164164
do Local::borrow::<Task, ()> |task| {

src/libstd/task/mod.rs

+8-7
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ use cmp::Eq;
4242
use comm::{stream, Chan, GenericChan, GenericPort, Port};
4343
use result::Result;
4444
use result;
45-
use rt::{context, OldTaskContext, TaskContext};
45+
use rt::{context, OldTaskContext, in_green_task_context};
4646
use rt::local::Local;
4747
use unstable::finally::Finally;
4848
use util;
@@ -527,14 +527,15 @@ pub fn try<T:Send>(f: ~fn() -> T) -> Result<T,()> {
527527
pub fn with_task_name<U>(blk: &fn(Option<&str>) -> U) -> U {
528528
use rt::task::Task;
529529

530-
match context() {
531-
TaskContext => do Local::borrow::<Task, U> |task| {
530+
if in_green_task_context() {
531+
do Local::borrow::<Task, U> |task| {
532532
match task.name {
533533
Some(ref name) => blk(Some(name.as_slice())),
534534
None => blk(None)
535535
}
536-
},
537-
_ => fail!("no task name exists in %?", context()),
536+
}
537+
} else {
538+
fail!("no task name exists in %?", context())
538539
}
539540
}
540541

@@ -614,7 +615,7 @@ pub fn unkillable<U>(f: &fn() -> U) -> U {
614615
rt::rust_task_allow_kill(t);
615616
}
616617
}
617-
TaskContext => {
618+
_ if in_green_task_context() => {
618619
// The inhibits/allows might fail and need to borrow the task.
619620
let t = Local::unsafe_borrow::<Task>();
620621
do (|| {
@@ -645,7 +646,7 @@ pub unsafe fn rekillable<U>(f: &fn() -> U) -> U {
645646
rt::rust_task_inhibit_kill(t);
646647
}
647648
}
648-
TaskContext => {
649+
_ if in_green_task_context() => {
649650
let t = Local::unsafe_borrow::<Task>();
650651
do (|| {
651652
(*t).death.allow_kill((*t).unwinder.unwinding);

src/libstd/task/spawn.rs

+8-9
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ use to_bytes::IterBytes;
9191
use uint;
9292
use util;
9393
use unstable::sync::Exclusive;
94-
use rt::{OldTaskContext, TaskContext, SchedulerContext, GlobalContext, context};
94+
use rt::{OldTaskContext, NewRtContext, context, in_green_task_context};
9595
use rt::local::Local;
9696
use rt::task::{Task, Sched};
9797
use rt::kill::KillHandle;
@@ -526,7 +526,7 @@ impl RuntimeGlue {
526526
let me = rt::rust_get_task();
527527
blk(OldTask(me), rt::rust_task_is_unwinding(me))
528528
},
529-
TaskContext => unsafe {
529+
NewRtContext if in_green_task_context() => unsafe {
530530
// Can't use safe borrow, because the taskgroup destructor needs to
531531
// access the scheduler again to send kill signals to other tasks.
532532
let me = Local::unsafe_borrow::<Task>();
@@ -535,7 +535,7 @@ impl RuntimeGlue {
535535
blk(NewTask((*me).death.kill_handle.get_ref().clone()),
536536
(*me).unwinder.unwinding)
537537
},
538-
SchedulerContext | GlobalContext => rtabort!("task dying in bad context"),
538+
NewRtContext => rtabort!("task dying in bad context"),
539539
}
540540
}
541541

@@ -563,7 +563,7 @@ impl RuntimeGlue {
563563
}
564564
}
565565
},
566-
TaskContext => unsafe {
566+
NewRtContext if in_green_task_context() => unsafe {
567567
// Can't use safe borrow, because creating new hashmaps for the
568568
// tasksets requires an rng, which needs to borrow the sched.
569569
let me = Local::unsafe_borrow::<Task>();
@@ -588,7 +588,7 @@ impl RuntimeGlue {
588588
Some(ref group) => group,
589589
})
590590
},
591-
SchedulerContext | GlobalContext => rtabort!("spawning in bad context"),
591+
NewRtContext => rtabort!("spawning in bad context"),
592592
}
593593
}
594594
}
@@ -666,10 +666,9 @@ fn enlist_many(child: TaskHandle, child_arc: &TaskGroupArc,
666666

667667
pub fn spawn_raw(opts: TaskOpts, f: ~fn()) {
668668
match context() {
669-
OldTaskContext => spawn_raw_oldsched(opts, f),
670-
TaskContext => spawn_raw_newsched(opts, f),
671-
SchedulerContext => fail!("can't spawn from scheduler context"),
672-
GlobalContext => fail!("can't spawn from global context"),
669+
OldTaskContext => spawn_raw_oldsched(opts, f),
670+
_ if in_green_task_context() => spawn_raw_newsched(opts, f),
671+
_ => fail!("can't spawn from this context")
673672
}
674673
}
675674

src/libstd/unstable/lang.rs

+7-10
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
1313
use cast::transmute;
1414
use libc::{c_char, c_uchar, c_void, size_t, uintptr_t, c_int};
15+
use option::{Some, None};
1516
use str;
1617
use sys;
17-
use rt::{context, OldTaskContext};
1818
use rt::task::Task;
1919
use rt::local::Local;
2020
use rt::borrowck;
@@ -56,16 +56,13 @@ pub fn fail_bounds_check(file: *c_char, line: size_t,
5656

5757
#[lang="malloc"]
5858
pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char {
59-
match context() {
60-
OldTaskContext => {
61-
return rustrt::rust_upcall_malloc_noswitch(td, size);
59+
// XXX: Unsafe borrow for speed. Lame.
60+
match Local::try_unsafe_borrow::<Task>() {
61+
Some(task) => {
62+
(*task).heap.alloc(td as *c_void, size as uint) as *c_char
6263
}
63-
_ => {
64-
let mut alloc = ::ptr::null();
65-
do Local::borrow::<Task,()> |task| {
66-
alloc = task.heap.alloc(td as *c_void, size as uint) as *c_char;
67-
}
68-
return alloc;
64+
None => {
65+
rustrt::rust_upcall_malloc_noswitch(td, size)
6966
}
7067
}
7168
}

src/libstd/unstable/sync.rs

+16-10
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ pub unsafe fn atomically<U>(f: &fn() -> U) -> U {
282282
use rt::task::Task;
283283
use task::rt;
284284
use rt::local::Local;
285-
use rt::{context, OldTaskContext, TaskContext};
285+
use rt::{context, OldTaskContext};
286286

287287
match context() {
288288
OldTaskContext => {
@@ -296,17 +296,23 @@ pub unsafe fn atomically<U>(f: &fn() -> U) -> U {
296296
rt::rust_task_allow_kill(t);
297297
}
298298
}
299-
TaskContext => {
300-
let t = Local::unsafe_borrow::<Task>();
301-
do (|| {
302-
(*t).death.inhibit_yield();
303-
f()
304-
}).finally {
305-
(*t).death.allow_yield();
299+
_ => {
300+
let t = Local::try_unsafe_borrow::<Task>();
301+
match t {
302+
Some(t) => {
303+
do (|| {
304+
(*t).death.inhibit_yield();
305+
f()
306+
}).finally {
307+
(*t).death.allow_yield();
308+
}
309+
}
310+
None => {
311+
// FIXME(#3095): As in unkillable().
312+
f()
313+
}
306314
}
307315
}
308-
// FIXME(#3095): As in unkillable().
309-
_ => f()
310316
}
311317
}
312318

0 commit comments

Comments
 (0)