Skip to content

Commit 0116da2

Browse files
committed
[Concurrency] Emit async task running/waitingOn metadata inline into CPUTrace.
This allows tracking async code execution throughout a task's lifetime. rdar://137230240
1 parent 61cb1a9 commit 0116da2

File tree

5 files changed

+36
-11
lines changed

5 files changed

+36
-11
lines changed

stdlib/public/Concurrency/TaskPrivate.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -728,10 +728,11 @@ class alignas(2 * sizeof(void*)) ActiveTaskStatus {
728728
return record_iterator::rangeBeginning(getInnermostRecord());
729729
}
730730

731-
void traceStatusChanged(AsyncTask *task, bool isStarting) {
731+
void traceStatusChanged(AsyncTask *task, bool isStarting, bool wasRunning) {
732732
concurrency::trace::task_status_changed(
733733
task, static_cast<uint8_t>(getStoredPriority()), isCancelled(),
734-
isStoredPriorityEscalated(), isStarting, isRunning(), isEnqueued());
734+
isStoredPriorityEscalated(), isStarting, isRunning(), isEnqueued(),
735+
wasRunning);
735736
}
736737
};
737738

@@ -971,7 +972,7 @@ inline void AsyncTask::flagAsRunning() {
971972
if (_private()._status().compare_exchange_weak(oldStatus, newStatus,
972973
/* success */ std::memory_order_relaxed,
973974
/* failure */ std::memory_order_relaxed)) {
974-
newStatus.traceStatusChanged(this, true);
975+
newStatus.traceStatusChanged(this, true, oldStatus.isRunning());
975976
adoptTaskVoucher(this);
976977
swift_task_enterThreadLocalContext(
977978
(char *)&_private().ExclusivityAccessSet[0]);

stdlib/public/Concurrency/TaskStatus.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,9 @@ static void withStatusRecordLock(
9494
status, newStatus,
9595
/*success*/ SWIFT_MEMORY_ORDER_CONSUME,
9696
/*failure*/ std::memory_order_relaxed)) {
97+
bool wasRunning = status.isRunning();
9798
status = newStatus;
98-
status.traceStatusChanged(task, false);
99+
status.traceStatusChanged(task, false, wasRunning);
99100
break;
100101
}
101102
}
@@ -130,7 +131,7 @@ static void withStatusRecordLock(
130131
status, newStatus,
131132
/*success*/ std::memory_order_relaxed,
132133
/*failure*/ std::memory_order_relaxed)) {
133-
newStatus.traceStatusChanged(task, false);
134+
newStatus.traceStatusChanged(task, false, status.isRunning());
134135
break;
135136
}
136137
}
@@ -196,7 +197,7 @@ bool swift::addStatusRecord(AsyncTask *task, TaskStatusRecord *newRecord,
196197
if (task->_private()._status().compare_exchange_weak(oldStatus, newStatus,
197198
/*success*/ std::memory_order_release,
198199
/*failure*/ std::memory_order_relaxed)) {
199-
newStatus.traceStatusChanged(task, false);
200+
newStatus.traceStatusChanged(task, false, oldStatus.isRunning());
200201
return true;
201202
} else {
202203
// Retry
@@ -302,7 +303,7 @@ void swift::removeStatusRecord(AsyncTask *task, TaskStatusRecord *record,
302303
oldStatus, newStatus,
303304
/*success*/ std::memory_order_relaxed,
304305
/*failure*/ std::memory_order_relaxed)) {
305-
newStatus.traceStatusChanged(task, false);
306+
newStatus.traceStatusChanged(task, false, oldStatus.isRunning());
306307
return;
307308
}
308309

@@ -904,7 +905,7 @@ static void swift_task_cancelImpl(AsyncTask *task) {
904905
}
905906
}
906907

907-
newStatus.traceStatusChanged(task, false);
908+
newStatus.traceStatusChanged(task, false, oldStatus.isRunning());
908909
if (newStatus.getInnermostRecord() == nullptr) {
909910
// No records, nothing to propagate
910911
return;

stdlib/public/Concurrency/Tracing.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ void task_create(AsyncTask *task, AsyncTask *parent, TaskGroup *group,
6363
void task_destroy(AsyncTask *task);
6464

6565
void task_status_changed(AsyncTask *task, uint8_t maxPriority, bool isCancelled,
66-
bool isEscalated, bool isStarting, bool isRunning, bool isEnqueued);
66+
bool isEscalated, bool isStarting, bool isRunning,
67+
bool isEnqueued, bool wasRunning);
6768

6869
void task_flags_changed(AsyncTask *task, uint8_t jobPriority, bool isChildTask,
6970
bool isFuture, bool isGroupChildTask,

stdlib/public/Concurrency/TracingSignpost.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
#include <os/log.h>
2929
#include <os/signpost.h>
3030

31+
#if defined(__arm64__) && __has_include(<os/apt_private.h>)
32+
#include <os/apt_private.h>
33+
#endif
34+
3135
// Compatibility notes:
3236
//
3337
// These signposts can be read by external software that isn't synced with the
@@ -210,7 +214,24 @@ inline void task_destroy(AsyncTask *task) {
210214

211215
inline void task_status_changed(AsyncTask *task, uint8_t maxPriority,
212216
bool isCancelled, bool isEscalated,
213-
bool isStarting, bool isRunning, bool isEnqueued) {
217+
bool isStarting, bool isRunning,
218+
bool isEnqueued, bool wasRunning) {
219+
#if !TARGET_OS_SIMULATOR
220+
#if OS_APT_SPI_VERSION >= 20241023
221+
uint64_t taskId = task->getTaskId();
222+
if (isRunning) {
223+
if (SWIFT_RUNTIME_WEAK_CHECK(os_apt_msg_async_task_running_4swift)) {
224+
SWIFT_RUNTIME_WEAK_USE(os_apt_msg_async_task_running_4swift(taskId));
225+
}
226+
} else if (!isRunning && wasRunning) {
227+
#if OS_APT_SPI_VERSION >= 20250710
228+
if (SWIFT_RUNTIME_WEAK_CHECK(os_apt_msg_async_task_stopped_4swift)) {
229+
SWIFT_RUNTIME_WEAK_USE(os_apt_msg_async_task_stopped_4swift(taskId));
230+
}
231+
#endif // OS_APT_SPI_VERSION >= 20250710
232+
}
233+
#endif // OS_APT_SPI_VERSION >= 20241023
234+
#endif // !TARGET_OS_SIMULATOR
214235
ENSURE_LOGS();
215236
auto id = os_signpost_id_make_with_pointer(TaskLog, task);
216237
os_signpost_event_emit(

stdlib/public/Concurrency/TracingStubs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ inline void task_resume(AsyncTask *task) {}
5656

5757
inline void task_status_changed(AsyncTask *task, uint8_t maxPriority,
5858
bool isCancelled, bool isEscalated,
59-
bool isStarting, bool isRunning, bool isEnqueued) {}
59+
bool isStarting, bool isRunning,
60+
bool isEnqueued, bool wasRunning) {}
6061

6162
inline void task_flags_changed(AsyncTask *task, uint8_t jobPriority,
6263
bool isChildTask, bool isFuture,

0 commit comments

Comments
 (0)