@@ -444,6 +444,8 @@ struct Taskgroup final : DataPoolEntry<Taskgroup> {
444
444
Taskgroup (DataPool<Taskgroup> *dp) : DataPoolEntry<Taskgroup>(dp) {}
445
445
};
446
446
447
+ enum ArcherTaskFlag { ArcherTaskFulfilled = 0x00010000 };
448
+
447
449
struct TaskData ;
448
450
typedef DataPool<TaskData> TaskDataPool;
449
451
template <> __thread TaskDataPool *TaskDataPool::ThreadDataPool = nullptr ;
@@ -460,6 +462,9 @@ struct TaskData final : DataPoolEntry<TaskData> {
460
462
// / Child tasks use its address to model omp_all_memory dependencies
461
463
ompt_tsan_clockid AllMemory[2 ]{0 };
462
464
465
+ // / Index of which barrier to use next.
466
+ char BarrierIndex{0 };
467
+
463
468
// / Whether this task is currently executing a barrier.
464
469
bool InBarrier{false };
465
470
@@ -469,18 +474,12 @@ struct TaskData final : DataPoolEntry<TaskData> {
469
474
// / count execution phase
470
475
int execution{0 };
471
476
472
- // / Index of which barrier to use next.
473
- char BarrierIndex{0 };
474
-
475
477
// / Count how often this structure has been put into child tasks + 1.
476
478
std::atomic_int RefCount{1 };
477
479
478
480
// / Reference to the parent that created this task.
479
481
TaskData *Parent{nullptr };
480
482
481
- // / Reference to the implicit task in the stack above this task.
482
- TaskData *ImplicitTask{nullptr };
483
-
484
483
// / Reference to the team of this task.
485
484
ParallelData *Team{nullptr };
486
485
@@ -515,6 +514,9 @@ struct TaskData final : DataPoolEntry<TaskData> {
515
514
bool isInitial () { return TaskType & ompt_task_initial; }
516
515
bool isTarget () { return TaskType & ompt_task_target; }
517
516
517
+ bool isFulfilled () { return TaskType & ArcherTaskFulfilled; }
518
+ void setFulfilled () { TaskType |= ArcherTaskFulfilled; }
519
+
518
520
void setAllMemoryDep () { AllMemory[0 ] = 1 ; }
519
521
bool hasAllMemoryDep () { return AllMemory[0 ]; }
520
522
@@ -529,6 +531,7 @@ struct TaskData final : DataPoolEntry<TaskData> {
529
531
TaskType = taskType;
530
532
Parent = parent;
531
533
Team = Parent->Team ;
534
+ BarrierIndex = Parent->BarrierIndex ;
532
535
if (Parent != nullptr ) {
533
536
Parent->RefCount ++;
534
537
// Copy over pointer to taskgroup. This task may set up its own stack
@@ -541,7 +544,6 @@ struct TaskData final : DataPoolEntry<TaskData> {
541
544
TaskData *Init (ParallelData *team, int taskType) {
542
545
TaskType = taskType;
543
546
execution = 1 ;
544
- ImplicitTask = this ;
545
547
Team = team;
546
548
return this ;
547
549
}
@@ -553,7 +555,6 @@ struct TaskData final : DataPoolEntry<TaskData> {
553
555
BarrierIndex = 0 ;
554
556
RefCount = 1 ;
555
557
Parent = nullptr ;
556
- ImplicitTask = nullptr ;
557
558
Team = nullptr ;
558
559
TaskGroup = nullptr ;
559
560
if (DependencyMap) {
@@ -584,7 +585,9 @@ struct TaskData final : DataPoolEntry<TaskData> {
584
585
} // namespace
585
586
586
587
static inline TaskData *ToTaskData (ompt_data_t *task_data) {
587
- return reinterpret_cast <TaskData *>(task_data->ptr );
588
+ if (task_data)
589
+ return reinterpret_cast <TaskData *>(task_data->ptr );
590
+ return nullptr ;
588
591
}
589
592
590
593
// / Store a mutex for each wait_id to resolve race condition with callbacks.
@@ -899,6 +902,79 @@ static void acquireDependencies(TaskData *task) {
899
902
}
900
903
}
901
904
905
+ static void completeTask (TaskData *FromTask) {
906
+ if (!FromTask)
907
+ return ;
908
+ // Task-end happens after a possible omp_fulfill_event call
909
+ if (FromTask->isFulfilled ())
910
+ TsanHappensAfter (FromTask->GetTaskPtr ());
911
+ // Included tasks are executed sequentially, no need to track
912
+ // synchronization
913
+ if (!FromTask->isIncluded ()) {
914
+ // Task will finish before a barrier in the surrounding parallel region
915
+ // ...
916
+ ParallelData *PData = FromTask->Team ;
917
+ TsanHappensBefore (PData->GetBarrierPtr (FromTask->BarrierIndex ));
918
+
919
+ // ... and before an eventual taskwait by the parent thread.
920
+ TsanHappensBefore (FromTask->Parent ->GetTaskwaitPtr ());
921
+
922
+ if (FromTask->TaskGroup != nullptr ) {
923
+ // This task is part of a taskgroup, so it will finish before the
924
+ // corresponding taskgroup_end.
925
+ TsanHappensBefore (FromTask->TaskGroup ->GetPtr ());
926
+ }
927
+ }
928
+ // release dependencies
929
+ releaseDependencies (FromTask);
930
+ }
931
+
932
+ static void suspendTask (TaskData *FromTask) {
933
+ if (!FromTask)
934
+ return ;
935
+ // Task may be resumed at a later point in time.
936
+ TsanHappensBefore (FromTask->GetTaskPtr ());
937
+ }
938
+
939
+ static void switchTasks (TaskData *FromTask, TaskData *ToTask) {
940
+ // Legacy handling for missing reduction callback
941
+ if (hasReductionCallback < ompt_set_always) {
942
+ if (FromTask && FromTask->InBarrier ) {
943
+ // We want to ignore writes in the runtime code during barriers,
944
+ // but not when executing tasks with user code!
945
+ TsanIgnoreWritesEnd ();
946
+ }
947
+ if (ToTask && ToTask->InBarrier ) {
948
+ // We want to ignore writes in the runtime code during barriers,
949
+ // but not when executing tasks with user code!
950
+ TsanIgnoreWritesBegin ();
951
+ }
952
+ }
953
+ // // Not yet used
954
+ // if (FromTask)
955
+ // FromTask->deactivate();
956
+ // if (ToTask)
957
+ // ToTask->activate();
958
+ }
959
+
960
+ static void endTask (TaskData *FromTask) {
961
+ if (!FromTask)
962
+ return ;
963
+ }
964
+
965
+ static void startTask (TaskData *ToTask) {
966
+ if (!ToTask)
967
+ return ;
968
+ // Handle dependencies on first execution of the task
969
+ if (ToTask->execution == 0 ) {
970
+ ToTask->execution ++;
971
+ acquireDependencies (ToTask);
972
+ }
973
+ // 1. Task will begin execution after it has been created.
974
+ // 2. Task will resume after it has been switched away.
975
+ TsanHappensAfter (ToTask->GetTaskPtr ());
976
+ }
977
+
902
978
static void ompt_tsan_task_schedule (ompt_data_t *first_task_data,
903
979
ompt_task_status_t prior_task_status,
904
980
ompt_data_t *second_task_data) {
@@ -916,88 +992,62 @@ static void ompt_tsan_task_schedule(ompt_data_t *first_task_data,
916
992
// ompt_task_cancel = 3,
917
993
// -> first completed, first freed, second starts
918
994
//
995
+ // ompt_taskwait_complete = 8,
996
+ // -> first starts, first completes, first freed, second ignored
997
+ //
919
998
// ompt_task_detach = 4,
920
999
// ompt_task_yield = 2,
921
1000
// ompt_task_switch = 7
922
1001
// -> first suspended, second starts
923
1002
//
924
1003
925
- if (prior_task_status == ompt_task_early_fulfill)
926
- return ;
927
-
928
1004
TaskData *FromTask = ToTaskData (first_task_data);
1005
+ TaskData *ToTask = ToTaskData (second_task_data);
929
1006
930
- // Legacy handling for missing reduction callback
931
- if (hasReductionCallback < ompt_set_always && FromTask->InBarrier ) {
932
- // We want to ignore writes in the runtime code during barriers,
933
- // but not when executing tasks with user code!
934
- TsanIgnoreWritesEnd ();
935
- }
936
-
937
- // The late fulfill happens after the detached task finished execution
938
- if (prior_task_status == ompt_task_late_fulfill)
1007
+ switch (prior_task_status) {
1008
+ case ompt_task_early_fulfill:
1009
+ TsanHappensBefore (FromTask->GetTaskPtr ());
1010
+ FromTask->setFulfilled ();
1011
+ return ;
1012
+ case ompt_task_late_fulfill:
939
1013
TsanHappensAfter (FromTask->GetTaskPtr ());
940
-
941
- // task completed execution
942
- if (prior_task_status == ompt_task_complete ||
943
- prior_task_status == ompt_task_cancel ||
944
- prior_task_status == ompt_task_late_fulfill) {
945
- // Included tasks are executed sequentially, no need to track
946
- // synchronization
947
- if (!FromTask->isIncluded ()) {
948
- // Task will finish before a barrier in the surrounding parallel region
949
- // ...
950
- ParallelData *PData = FromTask->Team ;
951
- TsanHappensBefore (
952
- PData->GetBarrierPtr (FromTask->ImplicitTask ->BarrierIndex ));
953
-
954
- // ... and before an eventual taskwait by the parent thread.
955
- TsanHappensBefore (FromTask->Parent ->GetTaskwaitPtr ());
956
-
957
- if (FromTask->TaskGroup != nullptr ) {
958
- // This task is part of a taskgroup, so it will finish before the
959
- // corresponding taskgroup_end.
960
- TsanHappensBefore (FromTask->TaskGroup ->GetPtr ());
961
- }
962
- }
963
-
964
- // release dependencies
965
- releaseDependencies (FromTask);
966
- // free the previously running task
1014
+ completeTask (FromTask);
967
1015
freeTask (FromTask);
968
- }
969
-
970
- // For late fulfill of detached task, there is no task to schedule to
971
- if (prior_task_status == ompt_task_late_fulfill) {
1016
+ return ;
1017
+ case ompt_taskwait_complete:
1018
+ acquireDependencies (FromTask);
1019
+ freeTask (FromTask);
1020
+ return ;
1021
+ case ompt_task_complete:
1022
+ completeTask (FromTask);
1023
+ endTask (FromTask);
1024
+ switchTasks (FromTask, ToTask);
1025
+ freeTask (FromTask);
1026
+ return ;
1027
+ case ompt_task_cancel:
1028
+ completeTask (FromTask);
1029
+ endTask (FromTask);
1030
+ switchTasks (FromTask, ToTask);
1031
+ freeTask (FromTask);
1032
+ startTask (ToTask);
1033
+ return ;
1034
+ case ompt_task_detach:
1035
+ endTask (FromTask);
1036
+ suspendTask (FromTask);
1037
+ switchTasks (FromTask, ToTask);
1038
+ startTask (ToTask);
1039
+ return ;
1040
+ case ompt_task_yield:
1041
+ suspendTask (FromTask);
1042
+ switchTasks (FromTask, ToTask);
1043
+ startTask (ToTask);
1044
+ return ;
1045
+ case ompt_task_switch:
1046
+ suspendTask (FromTask);
1047
+ switchTasks (FromTask, ToTask);
1048
+ startTask (ToTask);
972
1049
return ;
973
1050
}
974
-
975
- TaskData *ToTask = ToTaskData (second_task_data);
976
- // Legacy handling for missing reduction callback
977
- if (hasReductionCallback < ompt_set_always && ToTask->InBarrier ) {
978
- // We re-enter runtime code which currently performs a barrier.
979
- TsanIgnoreWritesBegin ();
980
- }
981
-
982
- // task suspended
983
- if (prior_task_status == ompt_task_switch ||
984
- prior_task_status == ompt_task_yield ||
985
- prior_task_status == ompt_task_detach) {
986
- // Task may be resumed at a later point in time.
987
- TsanHappensBefore (FromTask->GetTaskPtr ());
988
- ToTask->ImplicitTask = FromTask->ImplicitTask ;
989
- assert (ToTask->ImplicitTask != NULL &&
990
- " A task belongs to a team and has an implicit task on the stack" );
991
- }
992
-
993
- // Handle dependencies on first execution of the task
994
- if (ToTask->execution == 0 ) {
995
- ToTask->execution ++;
996
- acquireDependencies (ToTask);
997
- }
998
- // 1. Task will begin execution after it has been created.
999
- // 2. Task will resume after it has been switched away.
1000
- TsanHappensAfter (ToTask->GetTaskPtr ());
1001
1051
}
1002
1052
1003
1053
static void ompt_tsan_dependences (ompt_data_t *task_data,
0 commit comments