On Fri, Feb 1, 2013 at 12:09 PM, Michael Neumann <[email protected]> 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
> [email protected]
> https://mail.mozilla.org/**listinfo/rust-dev<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();
}
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
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
[email protected]
https://mail.mozilla.org/listinfo/rust-dev