On Fri, Feb 1, 2013 at 12:09 PM, Michael Neumann <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
> 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
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to