Skip to content

Commit 2b4082e

Browse files
committed
[Concurrency] Fix task switch performance issue.
When using the new custom default executors, sometimes we end up taking a long time to do a task switch. This is happening because the path the new code takes sometimes results in a concrete pointer to the default global executor being in the executor tracking information in `swift_task_switch()`, and if we try to switch to a `nil` task executor (which _also_ means the default global executor), we aren’t spotting that and we’re taking the slow path. Essentially, we want to take the fast path in cases where we switch from `nil` to the concrete default global executor and vice-versa. rdar://156701386
1 parent d0cf535 commit 2b4082e

File tree

3 files changed

+17
-6
lines changed

3 files changed

+17
-6
lines changed

stdlib/public/Concurrency/Actor.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2391,13 +2391,15 @@ static bool mustSwitchToRun(SerialExecutorRef currentSerialExecutor,
23912391
}
23922392

23932393
// else, we may have to switch if the preferred task executor is different
2394-
auto differentTaskExecutor =
2395-
currentTaskExecutor.getIdentity() != newTaskExecutor.getIdentity();
2396-
if (differentTaskExecutor) {
2397-
return true;
2398-
}
2394+
if (currentTaskExecutor.getIdentity() == newTaskExecutor.getIdentity())
2395+
return false;
23992396

2400-
return false;
2397+
if (currentTaskExecutor.isUndefined())
2398+
currentTaskExecutor = swift_getDefaultExecutor();
2399+
if (newTaskExecutor.isUndefined())
2400+
newTaskExecutor = swift_getDefaultExecutor();
2401+
2402+
return currentTaskExecutor.getIdentity() != newTaskExecutor.getIdentity();
24012403
}
24022404

24032405
/// Given that we've assumed control of an executor on this thread,

stdlib/public/Concurrency/ExecutorBridge.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ namespace swift {
2323
extern "C" SWIFT_CC(swift)
2424
SerialExecutorRef swift_getMainExecutor();
2525

26+
extern "C" SWIFT_CC(swift)
27+
TaskExecutorRef swift_getDefaultExecutor();
28+
2629
#if !SWIFT_CONCURRENCY_EMBEDDED
2730
extern "C" SWIFT_CC(swift)
2831
void *swift_createDispatchEventC(void (*handler)(void *), void *context);

stdlib/public/Concurrency/ExecutorBridge.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@ internal func _getMainExecutorAsSerialExecutor() -> (any SerialExecutor)?
106106
#endif // SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
107107
#endif // os(WASI) || !$Embedded
108108

109+
@available(StdlibDeploymentTarget 6.2, *)
110+
@_silgen_name("swift_getDefaultExecutor")
111+
internal func _getDefaultExecutorAsTaskExecutor() -> (any TaskExecutor)? {
112+
return Task.defaultExecutor
113+
}
114+
109115
@available(StdlibDeploymentTarget 6.2, *)
110116
@_silgen_name("swift_dispatchMain")
111117
internal func _dispatchMain()

0 commit comments

Comments
 (0)