-
Notifications
You must be signed in to change notification settings - Fork 51
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # 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: