@@ -344,6 +344,64 @@ template <typename T> struct DataPoolEntry {
344
344
DataPoolEntry (DataPool<T> *dp) : owner(dp) {}
345
345
};
346
346
347
+ struct DependencyData ;
348
+ typedef DataPool<DependencyData> DependencyDataPool;
349
+ template <>
350
+ __thread DependencyDataPool *DependencyDataPool::ThreadDataPool = nullptr ;
351
+
352
+ // / Data structure to store additional information for task dependency.
353
+ struct DependencyData final : DataPoolEntry<DependencyData> {
354
+ ompt_tsan_clockid in;
355
+ ompt_tsan_clockid out;
356
+ ompt_tsan_clockid inoutset;
357
+ void *GetInPtr () { return ∈ }
358
+ void *GetOutPtr () { return &out; }
359
+ void *GetInoutsetPtr () { return &inoutset; }
360
+
361
+ void Reset () {}
362
+
363
+ static DependencyData *New () { return DataPoolEntry<DependencyData>::New (); }
364
+
365
+ DependencyData (DataPool<DependencyData> *dp)
366
+ : DataPoolEntry<DependencyData>(dp) {}
367
+ };
368
+
369
+ struct TaskDependency {
370
+ void *inPtr;
371
+ void *outPtr;
372
+ void *inoutsetPtr;
373
+ ompt_dependence_type_t type;
374
+ TaskDependency (DependencyData *depData, ompt_dependence_type_t type)
375
+ : inPtr(depData->GetInPtr ()), outPtr(depData->GetOutPtr ()),
376
+ inoutsetPtr(depData->GetInoutsetPtr ()), type(type) {}
377
+ void AnnotateBegin () {
378
+ if (type == ompt_dependence_type_out ||
379
+ type == ompt_dependence_type_inout ||
380
+ type == ompt_dependence_type_mutexinoutset) {
381
+ TsanHappensAfter (inPtr);
382
+ TsanHappensAfter (outPtr);
383
+ TsanHappensAfter (inoutsetPtr);
384
+ } else if (type == ompt_dependence_type_in) {
385
+ TsanHappensAfter (outPtr);
386
+ TsanHappensAfter (inoutsetPtr);
387
+ } else if (type == ompt_dependence_type_inoutset) {
388
+ TsanHappensAfter (inPtr);
389
+ TsanHappensAfter (outPtr);
390
+ }
391
+ }
392
+ void AnnotateEnd () {
393
+ if (type == ompt_dependence_type_out ||
394
+ type == ompt_dependence_type_inout ||
395
+ type == ompt_dependence_type_mutexinoutset) {
396
+ TsanHappensBefore (outPtr);
397
+ } else if (type == ompt_dependence_type_in) {
398
+ TsanHappensBefore (inPtr);
399
+ } else if (type == ompt_dependence_type_inoutset) {
400
+ TsanHappensBefore (inoutsetPtr);
401
+ }
402
+ }
403
+ };
404
+
347
405
struct ParallelData ;
348
406
typedef DataPool<ParallelData> ParallelDataPool;
349
407
template <>
@@ -451,11 +509,17 @@ struct TaskData final : DataPoolEntry<TaskData> {
451
509
Taskgroup *TaskGroup{nullptr };
452
510
453
511
// / Dependency information for this task.
454
- ompt_dependence_t *Dependencies{nullptr };
512
+ TaskDependency *Dependencies{nullptr };
455
513
456
514
// / Number of dependency entries.
457
515
unsigned DependencyCount{0 };
458
516
517
+ // The dependency-map stores DependencyData objects representing
518
+ // the dependency variables used on the sibling tasks created from
519
+ // this task
520
+ // We expect a rare need for the dependency-map, so alloc on demand
521
+ std::unordered_map<void *, DependencyData *> *DependencyMap{nullptr };
522
+
459
523
#ifdef DEBUG
460
524
int freed{0 };
461
525
#endif
@@ -506,6 +570,14 @@ struct TaskData final : DataPoolEntry<TaskData> {
506
570
ImplicitTask = nullptr ;
507
571
Team = nullptr ;
508
572
TaskGroup = nullptr ;
573
+ if (DependencyMap) {
574
+ for (auto i : *DependencyMap)
575
+ i.second ->Delete ();
576
+ delete DependencyMap;
577
+ }
578
+ DependencyMap = nullptr ;
579
+ if (Dependencies)
580
+ free (Dependencies);
509
581
Dependencies = nullptr ;
510
582
DependencyCount = 0 ;
511
583
#ifdef DEBUG
@@ -528,14 +600,6 @@ static inline TaskData *ToTaskData(ompt_data_t *task_data) {
528
600
return reinterpret_cast <TaskData *>(task_data->ptr );
529
601
}
530
602
531
- static inline void *ToInAddr (void *OutAddr) {
532
- // FIXME: This will give false negatives when a second variable lays directly
533
- // behind a variable that only has a width of 1 byte.
534
- // Another approach would be to "negate" the address or to flip the
535
- // first bit...
536
- return reinterpret_cast <char *>(OutAddr) + 1 ;
537
- }
538
-
539
603
// / Store a mutex for each wait_id to resolve race condition with callbacks.
540
604
std::unordered_map<ompt_wait_id_t , std::mutex> Locks;
541
605
std::mutex LocksMutex;
@@ -551,13 +615,19 @@ static void ompt_tsan_thread_begin(ompt_thread_t thread_type,
551
615
TaskDataPool::ThreadDataPool = new TaskDataPool;
552
616
TsanNewMemory (TaskDataPool::ThreadDataPool,
553
617
sizeof (TaskDataPool::ThreadDataPool));
618
+ DependencyDataPool::ThreadDataPool = new DependencyDataPool;
619
+ TsanNewMemory (DependencyDataPool::ThreadDataPool,
620
+ sizeof (DependencyDataPool::ThreadDataPool));
554
621
thread_data->value = my_next_id ();
555
622
}
556
623
557
624
static void ompt_tsan_thread_end (ompt_data_t *thread_data) {
625
+ TsanIgnoreWritesBegin ();
558
626
delete ParallelDataPool::ThreadDataPool;
559
627
delete TaskgroupPool::ThreadDataPool;
560
628
delete TaskDataPool::ThreadDataPool;
629
+ delete DependencyDataPool::ThreadDataPool;
630
+ TsanIgnoreWritesEnd ();
561
631
}
562
632
563
633
// / OMPT event callbacks for handling parallel regions.
@@ -805,17 +875,26 @@ static void ompt_tsan_task_create(
805
875
}
806
876
}
807
877
808
- static void __ompt_tsan_release_task (TaskData *task) {
878
+ static void freeTask (TaskData *task) {
809
879
while (task != nullptr && --task->RefCount == 0 ) {
810
880
TaskData *Parent = task->Parent ;
811
- if (task->DependencyCount > 0 ) {
812
- delete[] task->Dependencies ;
813
- }
814
881
task->Delete ();
815
882
task = Parent;
816
883
}
817
884
}
818
885
886
+ static void releaseDependencies (TaskData *task) {
887
+ for (unsigned i = 0 ; i < task->DependencyCount ; i++) {
888
+ task->Dependencies [i].AnnotateEnd ();
889
+ }
890
+ }
891
+
892
+ static void acquireDependencies (TaskData *task) {
893
+ for (unsigned i = 0 ; i < task->DependencyCount ; i++) {
894
+ task->Dependencies [i].AnnotateBegin ();
895
+ }
896
+ }
897
+
819
898
static void ompt_tsan_task_schedule (ompt_data_t *first_task_data,
820
899
ompt_task_status_t prior_task_status,
821
900
ompt_data_t *second_task_data) {
@@ -879,18 +958,9 @@ static void ompt_tsan_task_schedule(ompt_data_t *first_task_data,
879
958
}
880
959
881
960
// release dependencies
882
- for (unsigned i = 0 ; i < FromTask->DependencyCount ; i++) {
883
- ompt_dependence_t *Dependency = &FromTask->Dependencies [i];
884
-
885
- // in dependencies block following inout and out dependencies!
886
- TsanHappensBefore (ToInAddr (Dependency->variable .ptr ));
887
- if (Dependency->dependence_type == ompt_dependence_type_out ||
888
- Dependency->dependence_type == ompt_dependence_type_inout) {
889
- TsanHappensBefore (Dependency->variable .ptr );
890
- }
891
- }
961
+ releaseDependencies (FromTask);
892
962
// free the previously running task
893
- __ompt_tsan_release_task (FromTask);
963
+ freeTask (FromTask);
894
964
}
895
965
896
966
// For late fulfill of detached task, there is no task to schedule to
@@ -919,16 +989,7 @@ static void ompt_tsan_task_schedule(ompt_data_t *first_task_data,
919
989
// Handle dependencies on first execution of the task
920
990
if (ToTask->execution == 0 ) {
921
991
ToTask->execution ++;
922
- for (unsigned i = 0 ; i < ToTask->DependencyCount ; i++) {
923
- ompt_dependence_t *Dependency = &ToTask->Dependencies [i];
924
-
925
- TsanHappensAfter (Dependency->variable .ptr );
926
- // in and inout dependencies are also blocked by prior in dependencies!
927
- if (Dependency->dependence_type == ompt_dependence_type_out ||
928
- Dependency->dependence_type == ompt_dependence_type_inout) {
929
- TsanHappensAfter (ToInAddr (Dependency->variable .ptr ));
930
- }
931
- }
992
+ acquireDependencies (ToTask);
932
993
}
933
994
// 1. Task will begin execution after it has been created.
934
995
// 2. Task will resume after it has been switched away.
@@ -940,9 +1001,21 @@ static void ompt_tsan_dependences(ompt_data_t *task_data,
940
1001
if (ndeps > 0 ) {
941
1002
// Copy the data to use it in task_switch and task_end.
942
1003
TaskData *Data = ToTaskData (task_data);
943
- Data->Dependencies = new ompt_dependence_t [ndeps];
944
- std::memcpy (Data->Dependencies , deps, sizeof (ompt_dependence_t ) * ndeps);
1004
+ if (!Data->Parent ->DependencyMap )
1005
+ Data->Parent ->DependencyMap =
1006
+ new std::unordered_map<void *, DependencyData *>();
1007
+ Data->Dependencies =
1008
+ (TaskDependency *)malloc (sizeof (TaskDependency) * ndeps);
945
1009
Data->DependencyCount = ndeps;
1010
+ for (int i = 0 ; i < ndeps; i++) {
1011
+ auto ret = Data->Parent ->DependencyMap ->insert (
1012
+ std::make_pair (deps[i].variable .ptr , nullptr ));
1013
+ if (ret.second ) {
1014
+ ret.first ->second = DependencyData::New ();
1015
+ }
1016
+ new ((void *)(Data->Dependencies + i))
1017
+ TaskDependency (ret.first ->second , deps[i].dependence_type );
1018
+ }
946
1019
947
1020
// This callback is executed before this task is first started.
948
1021
TsanHappensBefore (Data->GetTaskPtr ());
0 commit comments