-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[TaskLocals] Remove fragment, cleanup code organization, use task-local allocator #36210
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
0a5e544
to
11d9785
Compare
@swift-ci please smoke test |
@@ -173,12 +172,16 @@ class AsyncTask : public HeapObject, public Job { | |||
/// Reserved for the use of the task-local stack allocator. | |||
void *AllocatorPrivate[4]; | |||
|
|||
/// Task local values storage container. | |||
TaskLocal::Storage Local; |
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.
Should we future proof it a bit more just in case?
Instruments folks asked for a limited size "carry it always, but only the last 3 most recent values" which I'll be implementing next. but I wonder if it might be necessary to add resilience on this level, or we're ok because task is?
#include "swift/ABI/Task.h" | ||
#include "swift/ABI/MetadataValues.h" |
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.
made includes more consistent; was battling include hell for quite a bit when adding new header files today here
@@ -122,10 +122,6 @@ void swift_task_cancel(AsyncTask *task); | |||
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) | |||
void swift_task_cancel_group_child_tasks(AsyncTask *task, TaskGroup *group); | |||
|
|||
/// Get 'active' AsyncTask, depending on platform this may use thread local storage. | |||
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) | |||
AsyncTask* swift_task_get_active(); |
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.
not used; we're using the getCurrent which does the same
// Initialize task locals fragment. | ||
auto taskLocalsFragment = task->localValuesFragment(); | ||
new (taskLocalsFragment) AsyncTask::TaskLocalValuesFragment(); | ||
taskLocalsFragment->initializeLinkParent(task, parent); |
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.
fragment is gone, every task needs the pointer because we store locals in this task so it always has to be ready to accept someone pushing a value onto it
func hash(into hasher: inout Hasher) { | ||
hasher.combine(ObjectIdentifier(self.keyType)) | ||
} | ||
} |
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.
not necessary, we use the types as identity in C by raw pointers, so no need for erasure in Swift
await x3 | ||
} | ||
|
||
_ = await x1 | ||
try! await printTaskLocal(\.number) // CHECK: NumberKey: 0 {{.*}} | ||
printTaskLocal(\.number) // CHECK: NumberKey: 0 {{.*}} |
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.
now we were able to remove a lot of await
which is awesome -- thanks to getCurrent task from sync functions
@@ -255,9 +260,6 @@ AsyncTaskAndContext swift::swift_task_create_group_future_f( | |||
// Figure out the size of the header. | |||
size_t headerSize = sizeof(AsyncTask); | |||
|
|||
/// Every task is able to store task local values. | |||
headerSize += sizeof(AsyncTask::TaskLocalValuesFragment); |
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 need for this, since locals are part of the Task now
assert(task); | ||
size_t amountToAllocate = Item::itemSize(valueType); | ||
// assert(amountToAllocate % MaximumAlignment == 0); // TODO: do we need this? | ||
void *allocation = swift_task_alloc(task, amountToAllocate); |
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.
hooray, we're now using swift_task_alloc/swift_task_dealloc, and it all works excellently thanks to the only way to bind a value being withLocal
👍
d6b8834
to
b0df9b0
Compare
b0df9b0
to
fcb1c01
Compare
@swift-ci please smoke test |
@swift-ci please smoke test macOS |
Task locals must have a pointer inside every task to implement their functionality after all, so as such, we don't need to make them a fragment.
Also proceed towards more cleanly separated out ABI and remove implementation details from Task.h entirely.
rdar://74218679