On 02/01/2013 09:23 AM, Matthieu Monrocq wrote:
On Fri, Feb 1, 2013 at 12:09 PM, Michael Neumann <mneum...@ntecs.de
<mailto:mneum...@ntecs.de>> wrote:
Am 31.01.2013 23:37, schrieb Patrick Walton:
Hi everyone,
With the revamp of the scheduler underway, I'd like to propose
a change to the way C functions work.
Currently, we generate a shim and a stack switch for every
function call from Rust to C and likewise from C to Rust,
except for functions annotated with `#[rust_stack]`. These
wrappers result in a significant performance overhead. For
some workloads this performance overhead is acceptable in
order to maintain small stacks. For some workloads the
performance overhead is undesirable.
For instance, the DOM in Servo requires lots of very small
calls from JavaScript to Rust. The overhead of stack switching
swamps most of the time here. Popular Web benchmarks will do
things like `someElement.clientX;` over and over, which
require calls from JavaScript to Rust to retrieve a cached
value. So we must carefully consider every CPU cycle spent in
the C-to-Rust transition.
To address these issues I would like to propose a somewhat
radical change: don't have the compiler generate stack
switching stubs at all. Instead, the scheduler can expose a
primitive that generates the stack switch, and it's the
programmer's responsibility to perform the stack switch to
call out to C functions. To avoid the obvious footgun here, I
propose a lint pass, on by default, that ensures that
functions not annotated with `#[rust_stack]` are called inside
a stack switching helper.
The rationale here is as follows:
1. It should be possible to group many C calls under a single
stack switching operation. For example:
do stackswitch {
c_function_1();
c_function_2();
c_function_3();
}
wouldn't it be possible for this case to just do:
extern mod lib_c {
#[rust_stack]
fn c_function_1();
#[rust_stack]
fn c_function_2();
#[rust_stack]
fn c_function_3();
}
and then calling it like above with *one* "do stackswitch"?
The default would still be to do a stack switch. If you need to
call c_function_1 sometimes with a stack switch, and sometimes
in a group of other functions (with just one stack switch for that
group), we could have something like this:
extern mod lib_c {
// This is the default
fn c_function_1();
#[rust_stack]
fn c_function_1() as rs_c_function1();
}
Then use lib_c::c_function_1() when you want a stack switch, or
rs_c_function1() without. One could go further
and auto generate for mod lib_c a sub module called "rs" (for rust
stack), where each function has a #[rust_stack]
directive in front of it, so you don't have to declare it twice.
This woudl give use: lib_c::c_function_1() and
lib_c::rs::c_function_1().
Regards,
Michael
_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org <mailto:Rust-dev@mozilla.org>
https://mail.mozilla.org/listinfo/rust-dev
I would have a stupid proposal: what if the C function declaration was
annotated not with #[rust_stack] but with #[stack 5k] instead. That
is, instead of having a single blunt tool, let the programmer declare
how much stack is necessary for the C function and let the compiler
reason about it to guarantee that enough stack is available.
extern mod lib_c {
#[stack 4k]
fn c_function_1();
#[stack unlimited]
fn c_function_2();
#[stack 16k]
fn c_function_3();
}
I do imagine we will eventually want precise control to declare how much
stack we need. I originally wanted this for optimizations in core, but
as more of core is written in Rust this probably isn't going to matter
much. There is an issue open on this subject:
https://github.com/mozilla/rust/issues/4481
Then when the compiler sees a bunch of C functions:
fn func(x: int) {
c_function_1();
c_function_1();
c_function_1();
c_function_3();
}
=> if one is marked as "unlimited", then it performs stack switching
(once); this can deferred to the branch the function is called in if
judged "better".
=> otherwise, it evaluates the maximum amount of stack needed and
prepares it at the beginning of the function, as usual
This sounds like it requires the compiler to have yet more knowledge
about stack switching, and a goal of pcwalton's proposal is to get the
stack switching logic out of the compiler (into a syntax extension).
Advantages:
+ Code is not invalidated, only the function declarations are, and
it's easy enough to do a bulk replace #[rust_stack] -> #[stack 4k]
+ The information can bubble up at "func" automatically, so that
caller of "func" can perform the switch/reservation themselves if it's
judged profitable.
Disadvantages:
- Myth of the sufficiently smart compiler spotted.
-- Matthieu
_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev
_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev