-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Better autorelease ergonomics #86
Comments
Ideas for making use-case 2 possible without
Ideas for use-case 3:
|
Not sure how |
See Contexts and capabilities (internals thread), this might be very useful for functions that require a reference to the innermost autoreleasepool: mod rc {
struct AutoreleasePool { ... }
capability autoreleasepool<'p> = &'p AutoreleasePool;
}
fn get_data<'p>(bytes: &[u8]) -> &p NSData
with
rc::autoreleasepool: &'p rc::AutoreleasePool,
{
let bytes_ptr = bytes.as_ptr() as *const c_void;
let obj: *const NSData = msg_send![
cls!(NSData),
dataWithBytes: bytes_ptr,
length: bytes.len(),
]
rc::autoreleasepool.ptr_as_ref(obj)
}
fn main() {
let bytes = &[1, 2, 3];
with rc::autoreleasepool = &rc::AutoreleasePool::new() {
let data = get_data(bytes);
println!("data: {:?}", data);
}
} |
Another idea: what if fn get_thing() -> Autoreleased<Object, Shared>;
autoreleasepool(|| {
let x: &Object = get_thing().as_ref(pool);
}); Though writing this I realize that would be unsound, since you could move the The reason that would have been cool is it would allow bypassing autoreleasepools entirely (assuming something like #81): fn get_thing() -> Autoreleased<Object, Shared>;
let x: Id<Object, Shared> = Id::from_autoreleased(get_thing()) |
I tried benchmarking Number of instructions on macOS (using a Callgrind fork and injecting a deterministic allocator):
Number of instructions on GNUStep, measured with Callgrind (numbers are not comparable to macOS):
ConclusionThe general trend I found (also verified using other methods) is that using (This is the first time I've really done any kind of performance analysis, so bear that in mind). |
So the direction we want to go in is probably: fewer lifetimes bound to autorelease pools (though they will still be required in edge cases like So this is both better for ergonomics and for performance, yay! Here #81 would solve use-case 1 and 2, #120 makes it even easier to use. Ideas for use-case 3: maybe something like #112, or by adding an |
I somewhat redid the benchmark using my new M2 Pro, though I had to do it in non-ARC Objective-C using Xcode's profiling tools, as Callgrind doesn't work on M1/M2 yet. Using
These results are consistent with the conclusion before: The fast autorelease scheme is preferred to putting the object in the autorelease pool, assuming you can get by with calling |
The ergonomics of using autoreleased references are not great, especially when you are creating your own class. We should try to do better!
I see mainly three use-cases (for library / binding creators; end users probably won't touch this part of the library):
See related: gfx-rs/metal-rs#222
The text was updated successfully, but these errors were encountered: