-
Notifications
You must be signed in to change notification settings - Fork 10.5k
concurrency: alloc an async-let task with the parent's allocator. #36993
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
Conversation
2cdcb4a
to
f61e959
Compare
@swift-ci test |
class alignas(2 * alignof(void*)) Job : | ||
// For async-let tasks, the refcount bits are initialized as "immortal" | ||
// because such a task is allocated with the parent's stack allocator. | ||
public HeapObject { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice, thanks for the comment!
@@ -165,7 +164,13 @@ static void swift_asyncLet_endImpl(AsyncLet *alet) { | |||
// TODO: we need to implicitly await either before the end or here somehow. | |||
|
|||
// and finally, release the task and free the async-let |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// and finally, release the task and free the async-let | |
// and finally deallocate the async-let |
no releasing anymore (yay!)
static void destroyTask(SWIFT_CONTEXT HeapObject *obj) { | ||
auto task = static_cast<AsyncTask*>(obj); | ||
|
||
task->~AsyncTask(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no idea if doing a destructor is nicer... am I missing something?
so far we've mostly had all destroyX things explicitly (but I'm by no means C++ or this codebase guru...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's a matter of taste
static AsyncTaskAndContext swift_task_create_group_future_commonImpl( | ||
JobFlags flags, TaskGroup *group, | ||
const Metadata *futureResultType, | ||
FutureAsyncSignature::FunctionType *function, | ||
void *closureContext, bool owningClosureContext, | ||
void *closureContext, bool isAsyncLetTask, | ||
size_t initialContextSize) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ABI wise my impression was we wanted something like [TaskCreateRecords]
to be passed in and e.g. check their .kind == .isAsyncLet
or similar to be future proof about adding more smarts to creating tasks.
But maybe we want to do that in a separate PR? (totally find by me to do later on!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, let's do that in a separate PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okey 👍
&completeTask); | ||
assert(parent); | ||
void *initialSlab = (char*)allocation + amountToAllocate; | ||
_swift_task_alloc_initialize_with_slab(task, initialSlab, initialSlabSize); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cool! so even a bunch of tiny task-local allocs inside the child have a chance to stay in the initial slab... <3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I read through in detail and looks fantastic to me :)
Build failed |
This PR needs #37010 to land first |
…ator. Also, do this for the initial slab for the task's allocator itself. This avoids memory allocations for async-lets. In case the async-task's memory demand does not exceed the initial slab size, it is now completely malloc-free. The refcount bits of an async-let task are initialized to "immortal" so that ARC operations don't have an effect on the task.
f61e959
to
075ad87
Compare
@swift-ci test |
Build failed |
@swift-ci smoke test macOS |
1 similar comment
@swift-ci smoke test macOS |
Also, do this for the initial slab for the task's allocator itself.
This avoids memory allocations for async-lets.
In case the async-task's memory demand does not exceed the initial slab size, it is now completely malloc-free.
The refcount bits of an async-let task are initialized to "immortal" so that ARC operations don't have an effect on the task.