| 1 | //===-- OpenMP/Mapping.cpp - OpenMP/OpenACC pointer mapping impl. ---------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | //===----------------------------------------------------------------------===// |
| 10 | |
| 11 | #include "OpenMP/Mapping.h" |
| 12 | |
| 13 | #include "PluginManager.h" |
| 14 | #include "Shared/Debug.h" |
| 15 | #include "Shared/Requirements.h" |
| 16 | #include "device.h" |
| 17 | |
| 18 | /// Dump a table of all the host-target pointer pairs on failure |
| 19 | void dumpTargetPointerMappings(const ident_t *Loc, DeviceTy &Device, |
| 20 | bool toStdOut) { |
| 21 | MappingInfoTy::HDTTMapAccessorTy HDTTMap = |
| 22 | Device.getMappingInfo().HostDataToTargetMap.getExclusiveAccessor(); |
| 23 | if (HDTTMap->empty()) { |
| 24 | DUMP_INFO(toStdOut, OMP_INFOTYPE_ALL, Device.DeviceID, |
| 25 | "OpenMP Host-Device pointer mappings table empty\n" ); |
| 26 | return; |
| 27 | } |
| 28 | |
| 29 | SourceInfo Kernel(Loc); |
| 30 | DUMP_INFO(toStdOut, OMP_INFOTYPE_ALL, Device.DeviceID, |
| 31 | "OpenMP Host-Device pointer mappings after block at %s:%d:%d:\n" , |
| 32 | Kernel.getFilename(), Kernel.getLine(), Kernel.getColumn()); |
| 33 | DUMP_INFO(toStdOut, OMP_INFOTYPE_ALL, Device.DeviceID, |
| 34 | "%-18s %-18s %s %s %s %s\n" , "Host Ptr" , "Target Ptr" , "Size (B)" , |
| 35 | "DynRefCount" , "HoldRefCount" , "Declaration" ); |
| 36 | for (const auto &It : *HDTTMap) { |
| 37 | HostDataToTargetTy &HDTT = *It.HDTT; |
| 38 | SourceInfo Info(HDTT.HstPtrName); |
| 39 | DUMP_INFO(toStdOut, OMP_INFOTYPE_ALL, Device.DeviceID, |
| 40 | DPxMOD " " DPxMOD " %-8" PRIuPTR " %-11s %-12s %s at %s:%d:%d\n" , |
| 41 | DPxPTR(HDTT.HstPtrBegin), DPxPTR(HDTT.TgtPtrBegin), |
| 42 | HDTT.HstPtrEnd - HDTT.HstPtrBegin, |
| 43 | HDTT.dynRefCountToStr().c_str(), HDTT.holdRefCountToStr().c_str(), |
| 44 | Info.getName(), Info.getFilename(), Info.getLine(), |
| 45 | Info.getColumn()); |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | int MappingInfoTy::associatePtr(void *HstPtrBegin, void *TgtPtrBegin, |
| 50 | int64_t Size) { |
| 51 | HDTTMapAccessorTy HDTTMap = HostDataToTargetMap.getExclusiveAccessor(); |
| 52 | |
| 53 | // Check if entry exists |
| 54 | auto It = HDTTMap->find(HstPtrBegin); |
| 55 | if (It != HDTTMap->end()) { |
| 56 | HostDataToTargetTy &HDTT = *It->HDTT; |
| 57 | std::lock_guard<HostDataToTargetTy> LG(HDTT); |
| 58 | // Mapping already exists |
| 59 | bool IsValid = HDTT.HstPtrEnd == (uintptr_t)HstPtrBegin + Size && |
| 60 | HDTT.TgtPtrBegin == (uintptr_t)TgtPtrBegin; |
| 61 | if (IsValid) { |
| 62 | DP("Attempt to re-associate the same device ptr+offset with the same " |
| 63 | "host ptr, nothing to do\n" ); |
| 64 | return OFFLOAD_SUCCESS; |
| 65 | } |
| 66 | REPORT("Not allowed to re-associate a different device ptr+offset with " |
| 67 | "the same host ptr\n" ); |
| 68 | return OFFLOAD_FAIL; |
| 69 | } |
| 70 | |
| 71 | // Mapping does not exist, allocate it with refCount=INF |
| 72 | const HostDataToTargetTy &NewEntry = |
| 73 | *HDTTMap |
| 74 | ->emplace(new HostDataToTargetTy( |
| 75 | /*HstPtrBase=*/(uintptr_t)HstPtrBegin, |
| 76 | /*HstPtrBegin=*/(uintptr_t)HstPtrBegin, |
| 77 | /*HstPtrEnd=*/(uintptr_t)HstPtrBegin + Size, |
| 78 | /*TgtAllocBegin=*/(uintptr_t)TgtPtrBegin, |
| 79 | /*TgtPtrBegin=*/(uintptr_t)TgtPtrBegin, |
| 80 | /*UseHoldRefCount=*/false, /*Name=*/nullptr, |
| 81 | /*IsRefCountINF=*/true)) |
| 82 | .first->HDTT; |
| 83 | DP("Creating new map entry: HstBase=" DPxMOD ", HstBegin=" DPxMOD |
| 84 | ", HstEnd=" DPxMOD ", TgtBegin=" DPxMOD ", DynRefCount=%s, " |
| 85 | "HoldRefCount=%s\n" , |
| 86 | DPxPTR(NewEntry.HstPtrBase), DPxPTR(NewEntry.HstPtrBegin), |
| 87 | DPxPTR(NewEntry.HstPtrEnd), DPxPTR(NewEntry.TgtPtrBegin), |
| 88 | NewEntry.dynRefCountToStr().c_str(), NewEntry.holdRefCountToStr().c_str()); |
| 89 | (void)NewEntry; |
| 90 | |
| 91 | // Notify the plugin about the new mapping. |
| 92 | return Device.notifyDataMapped(HstPtrBegin, Size); |
| 93 | } |
| 94 | |
| 95 | int MappingInfoTy::disassociatePtr(void *HstPtrBegin) { |
| 96 | HDTTMapAccessorTy HDTTMap = HostDataToTargetMap.getExclusiveAccessor(); |
| 97 | |
| 98 | auto It = HDTTMap->find(HstPtrBegin); |
| 99 | if (It == HDTTMap->end()) { |
| 100 | REPORT("Association not found\n" ); |
| 101 | return OFFLOAD_FAIL; |
| 102 | } |
| 103 | // Mapping exists |
| 104 | HostDataToTargetTy &HDTT = *It->HDTT; |
| 105 | std::lock_guard<HostDataToTargetTy> LG(HDTT); |
| 106 | |
| 107 | if (HDTT.getHoldRefCount()) { |
| 108 | // This is based on OpenACC 3.1, sec 3.2.33 "acc_unmap_data", L3656-3657: |
| 109 | // "It is an error to call acc_unmap_data if the structured reference |
| 110 | // count for the pointer is not zero." |
| 111 | REPORT("Trying to disassociate a pointer with a non-zero hold reference " |
| 112 | "count\n" ); |
| 113 | return OFFLOAD_FAIL; |
| 114 | } |
| 115 | |
| 116 | if (HDTT.isDynRefCountInf()) { |
| 117 | DP("Association found, removing it\n" ); |
| 118 | void *Event = HDTT.getEvent(); |
| 119 | delete &HDTT; |
| 120 | if (Event) |
| 121 | Device.destroyEvent(Event); |
| 122 | HDTTMap->erase(It); |
| 123 | return Device.notifyDataUnmapped(HstPtrBegin); |
| 124 | } |
| 125 | |
| 126 | REPORT("Trying to disassociate a pointer which was not mapped via " |
| 127 | "omp_target_associate_ptr\n" ); |
| 128 | return OFFLOAD_FAIL; |
| 129 | } |
| 130 | |
| 131 | LookupResult MappingInfoTy::lookupMapping(HDTTMapAccessorTy &HDTTMap, |
| 132 | void *HstPtrBegin, int64_t Size, |
| 133 | HostDataToTargetTy *OwnedTPR) { |
| 134 | |
| 135 | uintptr_t HP = (uintptr_t)HstPtrBegin; |
| 136 | LookupResult LR; |
| 137 | |
| 138 | DP("Looking up mapping(HstPtrBegin=" DPxMOD ", Size=%" PRId64 ")...\n" , |
| 139 | DPxPTR(HP), Size); |
| 140 | |
| 141 | if (HDTTMap->empty()) |
| 142 | return LR; |
| 143 | |
| 144 | // HDTTMap is std::set, ordered by HstPtrBegin. |
| 145 | // Upper is the first element whose HstPtrBegin > HP. |
| 146 | auto Upper = HDTTMap->upper_bound(HP); |
| 147 | |
| 148 | if (Size == 0) { |
| 149 | // HP satisfies |
| 150 | // std::prev(Upper)->HDTT.HstPtrBegin <= HP < Upper->HDTT.HstPtrBegin |
| 151 | if (Upper != HDTTMap->begin()) { |
| 152 | LR.TPR.setEntry(std::prev(Upper)->HDTT, OwnedTPR); |
| 153 | // We know that HP >= LR.TPR.getEntry()->HstPtrBegin |
| 154 | LR.Flags.IsContained = HP < LR.TPR.getEntry()->HstPtrEnd; |
| 155 | } |
| 156 | |
| 157 | if (!LR.Flags.IsContained && Upper != HDTTMap->end()) { |
| 158 | LR.TPR.setEntry(Upper->HDTT, OwnedTPR); |
| 159 | // This is a special case: HP is not really contained in the mapped |
| 160 | // address range, but it's contained in the extended address range, |
| 161 | // which suffices to get the mapping of the base pointer. |
| 162 | // We know that HP < LR.TPR.getEntry()->HstPtrBegin |
| 163 | LR.Flags.IsContained = HP >= LR.TPR.getEntry()->HstPtrBase; |
| 164 | } |
| 165 | } else { |
| 166 | if (Upper != HDTTMap->begin()) { |
| 167 | LR.TPR.setEntry(std::prev(Upper)->HDTT, OwnedTPR); |
| 168 | // We know that HP >= LR.TPR.getEntry()->HstPtrBegin |
| 169 | LR.Flags.IsContained = HP < LR.TPR.getEntry()->HstPtrEnd && |
| 170 | (HP + Size) <= LR.TPR.getEntry()->HstPtrEnd; |
| 171 | // Does it extend beyond the mapped address range? |
| 172 | LR.Flags.ExtendsAfter = HP < LR.TPR.getEntry()->HstPtrEnd && |
| 173 | (HP + Size) > LR.TPR.getEntry()->HstPtrEnd; |
| 174 | } |
| 175 | |
| 176 | if (!(LR.Flags.IsContained || LR.Flags.ExtendsAfter) && |
| 177 | Upper != HDTTMap->end()) { |
| 178 | LR.TPR.setEntry(Upper->HDTT, OwnedTPR); |
| 179 | // Does it extend into an already mapped address range? |
| 180 | // We know that HP < LR.TPR.getEntry()->HstPtrBegin |
| 181 | LR.Flags.ExtendsBefore = (HP + Size) > LR.TPR.getEntry()->HstPtrBegin; |
| 182 | // Does it extend beyond the mapped address range? |
| 183 | LR.Flags.ExtendsAfter = HP < LR.TPR.getEntry()->HstPtrEnd && |
| 184 | (HP + Size) > LR.TPR.getEntry()->HstPtrEnd; |
| 185 | } |
| 186 | |
| 187 | if (LR.Flags.ExtendsBefore) { |
| 188 | DP("WARNING: Pointer is not mapped but section extends into already " |
| 189 | "mapped data\n" ); |
| 190 | } |
| 191 | if (LR.Flags.ExtendsAfter) { |
| 192 | DP("WARNING: Pointer is already mapped but section extends beyond mapped " |
| 193 | "region\n" ); |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | return LR; |
| 198 | } |
| 199 | |
| 200 | TargetPointerResultTy MappingInfoTy::getTargetPointer( |
| 201 | HDTTMapAccessorTy &HDTTMap, void *HstPtrBegin, void *HstPtrBase, |
| 202 | int64_t TgtPadding, int64_t Size, map_var_info_t HstPtrName, bool HasFlagTo, |
| 203 | bool HasFlagAlways, bool IsImplicit, bool UpdateRefCount, |
| 204 | bool HasCloseModifier, bool HasPresentModifier, bool HasHoldModifier, |
| 205 | AsyncInfoTy &AsyncInfo, HostDataToTargetTy *OwnedTPR, bool ReleaseHDTTMap) { |
| 206 | |
| 207 | LookupResult LR = lookupMapping(HDTTMap, HstPtrBegin, Size, OwnedTPR); |
| 208 | LR.TPR.Flags.IsPresent = true; |
| 209 | |
| 210 | // Release the mapping table lock only after the entry is locked by |
| 211 | // attaching it to TPR. Once TPR is destroyed it will release the lock |
| 212 | // on entry. If it is returned the lock will move to the returned object. |
| 213 | // If LR.Entry is already owned/locked we avoid trying to lock it again. |
| 214 | |
| 215 | // Check if the pointer is contained. |
| 216 | // If a variable is mapped to the device manually by the user - which would |
| 217 | // lead to the IsContained flag to be true - then we must ensure that the |
| 218 | // device address is returned even under unified memory conditions. |
| 219 | if (LR.Flags.IsContained || |
| 220 | ((LR.Flags.ExtendsBefore || LR.Flags.ExtendsAfter) && IsImplicit)) { |
| 221 | const char *RefCountAction; |
| 222 | if (UpdateRefCount) { |
| 223 | // After this, reference count >= 1. If the reference count was 0 but the |
| 224 | // entry was still there we can reuse the data on the device and avoid a |
| 225 | // new submission. |
| 226 | LR.TPR.getEntry()->incRefCount(HasHoldModifier); |
| 227 | RefCountAction = " (incremented)" ; |
| 228 | } else { |
| 229 | // It might have been allocated with the parent, but it's still new. |
| 230 | LR.TPR.Flags.IsNewEntry = LR.TPR.getEntry()->getTotalRefCount() == 1; |
| 231 | RefCountAction = " (update suppressed)" ; |
| 232 | } |
| 233 | const char *DynRefCountAction = HasHoldModifier ? "" : RefCountAction; |
| 234 | const char *HoldRefCountAction = HasHoldModifier ? RefCountAction : "" ; |
| 235 | uintptr_t Ptr = LR.TPR.getEntry()->TgtPtrBegin + |
| 236 | ((uintptr_t)HstPtrBegin - LR.TPR.getEntry()->HstPtrBegin); |
| 237 | INFO(OMP_INFOTYPE_MAPPING_EXISTS, Device.DeviceID, |
| 238 | "Mapping exists%s with HstPtrBegin=" DPxMOD ", TgtPtrBegin=" DPxMOD |
| 239 | ", Size=%" PRId64 ", DynRefCount=%s%s, HoldRefCount=%s%s, Name=%s\n" , |
| 240 | (IsImplicit ? " (implicit)" : "" ), DPxPTR(HstPtrBegin), DPxPTR(Ptr), |
| 241 | Size, LR.TPR.getEntry()->dynRefCountToStr().c_str(), DynRefCountAction, |
| 242 | LR.TPR.getEntry()->holdRefCountToStr().c_str(), HoldRefCountAction, |
| 243 | (HstPtrName) ? getNameFromMapping(HstPtrName).c_str() : "unknown" ); |
| 244 | LR.TPR.TargetPointer = (void *)Ptr; |
| 245 | } else if ((LR.Flags.ExtendsBefore || LR.Flags.ExtendsAfter) && !IsImplicit) { |
| 246 | // Explicit extension of mapped data - not allowed. |
| 247 | MESSAGE("explicit extension not allowed: host address specified is " DPxMOD |
| 248 | " (%" PRId64 |
| 249 | " bytes), but device allocation maps to host at " DPxMOD |
| 250 | " (%" PRId64 " bytes)" , |
| 251 | DPxPTR(HstPtrBegin), Size, DPxPTR(LR.TPR.getEntry()->HstPtrBegin), |
| 252 | LR.TPR.getEntry()->HstPtrEnd - LR.TPR.getEntry()->HstPtrBegin); |
| 253 | if (HasPresentModifier) |
| 254 | MESSAGE("device mapping required by 'present' map type modifier does not " |
| 255 | "exist for host address " DPxMOD " (%" PRId64 " bytes)" , |
| 256 | DPxPTR(HstPtrBegin), Size); |
| 257 | } else if ((PM->getRequirements() & OMP_REQ_UNIFIED_SHARED_MEMORY && |
| 258 | !HasCloseModifier) || |
| 259 | (PM->getRequirements() & OMPX_REQ_AUTO_ZERO_COPY)) { |
| 260 | |
| 261 | // If unified shared memory is active, implicitly mapped variables that are |
| 262 | // not privatized use host address. Any explicitly mapped variables also use |
| 263 | // host address where correctness is not impeded. In all other cases maps |
| 264 | // are respected. |
| 265 | // In addition to the mapping rules above, the close map modifier forces the |
| 266 | // mapping of the variable to the device. |
| 267 | if (Size) { |
| 268 | INFO(OMP_INFOTYPE_MAPPING_CHANGED, Device.DeviceID, |
| 269 | "Return HstPtrBegin " DPxMOD " Size=%" PRId64 " for unified shared " |
| 270 | "memory\n" , |
| 271 | DPxPTR((uintptr_t)HstPtrBegin), Size); |
| 272 | DP("Return HstPtrBegin " DPxMOD " Size=%" PRId64 " for unified shared " |
| 273 | "memory\n" , |
| 274 | DPxPTR((uintptr_t)HstPtrBegin), Size); |
| 275 | LR.TPR.Flags.IsPresent = false; |
| 276 | LR.TPR.Flags.IsHostPointer = true; |
| 277 | LR.TPR.TargetPointer = HstPtrBegin; |
| 278 | } |
| 279 | } else if (HasPresentModifier) { |
| 280 | DP("Mapping required by 'present' map type modifier does not exist for " |
| 281 | "HstPtrBegin=" DPxMOD ", Size=%" PRId64 "\n" , |
| 282 | DPxPTR(HstPtrBegin), Size); |
| 283 | MESSAGE("device mapping required by 'present' map type modifier does not " |
| 284 | "exist for host address " DPxMOD " (%" PRId64 " bytes)" , |
| 285 | DPxPTR(HstPtrBegin), Size); |
| 286 | } else if (Size) { |
| 287 | // If it is not contained and Size > 0, we should create a new entry for it. |
| 288 | LR.TPR.Flags.IsNewEntry = true; |
| 289 | uintptr_t TgtAllocBegin = |
| 290 | (uintptr_t)Device.allocData(TgtPadding + Size, HstPtrBegin); |
| 291 | uintptr_t TgtPtrBegin = TgtAllocBegin + TgtPadding; |
| 292 | // Release the mapping table lock only after the entry is locked by |
| 293 | // attaching it to TPR. |
| 294 | LR.TPR.setEntry(HDTTMap |
| 295 | ->emplace(new HostDataToTargetTy( |
| 296 | (uintptr_t)HstPtrBase, (uintptr_t)HstPtrBegin, |
| 297 | (uintptr_t)HstPtrBegin + Size, TgtAllocBegin, |
| 298 | TgtPtrBegin, HasHoldModifier, HstPtrName)) |
| 299 | .first->HDTT); |
| 300 | INFO(OMP_INFOTYPE_MAPPING_CHANGED, Device.DeviceID, |
| 301 | "Creating new map entry with HstPtrBase=" DPxMOD |
| 302 | ", HstPtrBegin=" DPxMOD ", TgtAllocBegin=" DPxMOD |
| 303 | ", TgtPtrBegin=" DPxMOD |
| 304 | ", Size=%ld, DynRefCount=%s, HoldRefCount=%s, Name=%s\n" , |
| 305 | DPxPTR(HstPtrBase), DPxPTR(HstPtrBegin), DPxPTR(TgtAllocBegin), |
| 306 | DPxPTR(TgtPtrBegin), Size, |
| 307 | LR.TPR.getEntry()->dynRefCountToStr().c_str(), |
| 308 | LR.TPR.getEntry()->holdRefCountToStr().c_str(), |
| 309 | (HstPtrName) ? getNameFromMapping(HstPtrName).c_str() : "unknown" ); |
| 310 | LR.TPR.TargetPointer = (void *)TgtPtrBegin; |
| 311 | |
| 312 | // Notify the plugin about the new mapping. |
| 313 | if (Device.notifyDataMapped(HstPtrBegin, Size)) |
| 314 | return TargetPointerResultTy{}; |
| 315 | } else { |
| 316 | // This entry is not present and we did not create a new entry for it. |
| 317 | LR.TPR.Flags.IsPresent = false; |
| 318 | } |
| 319 | |
| 320 | // All mapping table modifications have been made. If the user requested it we |
| 321 | // give up the lock. |
| 322 | if (ReleaseHDTTMap) |
| 323 | HDTTMap.destroy(); |
| 324 | |
| 325 | // If the target pointer is valid, and we need to transfer data, issue the |
| 326 | // data transfer. |
| 327 | if (LR.TPR.TargetPointer && !LR.TPR.Flags.IsHostPointer && HasFlagTo && |
| 328 | (LR.TPR.Flags.IsNewEntry || HasFlagAlways) && Size != 0) { |
| 329 | DP("Moving %" PRId64 " bytes (hst:" DPxMOD ") -> (tgt:" DPxMOD ")\n" , Size, |
| 330 | DPxPTR(HstPtrBegin), DPxPTR(LR.TPR.TargetPointer)); |
| 331 | |
| 332 | int Ret = Device.submitData(LR.TPR.TargetPointer, HstPtrBegin, Size, |
| 333 | AsyncInfo, LR.TPR.getEntry()); |
| 334 | if (Ret != OFFLOAD_SUCCESS) { |
| 335 | REPORT("Copying data to device failed.\n" ); |
| 336 | // We will also return nullptr if the data movement fails because that |
| 337 | // pointer points to a corrupted memory region so it doesn't make any |
| 338 | // sense to continue to use it. |
| 339 | LR.TPR.TargetPointer = nullptr; |
| 340 | } else if (LR.TPR.getEntry()->addEventIfNecessary(Device, AsyncInfo) != |
| 341 | OFFLOAD_SUCCESS) |
| 342 | return TargetPointerResultTy{}; |
| 343 | } else { |
| 344 | // If not a host pointer and no present modifier, we need to wait for the |
| 345 | // event if it exists. |
| 346 | // Note: Entry might be nullptr because of zero length array section. |
| 347 | if (LR.TPR.getEntry() && !LR.TPR.Flags.IsHostPointer && |
| 348 | !HasPresentModifier) { |
| 349 | void *Event = LR.TPR.getEntry()->getEvent(); |
| 350 | if (Event) { |
| 351 | int Ret = Device.waitEvent(Event, AsyncInfo); |
| 352 | if (Ret != OFFLOAD_SUCCESS) { |
| 353 | // If it fails to wait for the event, we need to return nullptr in |
| 354 | // case of any data race. |
| 355 | REPORT("Failed to wait for event " DPxMOD ".\n" , DPxPTR(Event)); |
| 356 | return TargetPointerResultTy{}; |
| 357 | } |
| 358 | } |
| 359 | } |
| 360 | } |
| 361 | |
| 362 | return std::move(LR.TPR); |
| 363 | } |
| 364 | |
| 365 | TargetPointerResultTy MappingInfoTy::getTgtPtrBegin( |
| 366 | void *HstPtrBegin, int64_t Size, bool UpdateRefCount, bool UseHoldRefCount, |
| 367 | bool MustContain, bool ForceDelete, bool FromDataEnd) { |
| 368 | HDTTMapAccessorTy HDTTMap = HostDataToTargetMap.getExclusiveAccessor(); |
| 369 | |
| 370 | LookupResult LR = lookupMapping(HDTTMap, HstPtrBegin, Size); |
| 371 | |
| 372 | LR.TPR.Flags.IsPresent = true; |
| 373 | |
| 374 | if (LR.Flags.IsContained || |
| 375 | (!MustContain && (LR.Flags.ExtendsBefore || LR.Flags.ExtendsAfter))) { |
| 376 | LR.TPR.Flags.IsLast = |
| 377 | LR.TPR.getEntry()->decShouldRemove(UseHoldRefCount, ForceDelete); |
| 378 | |
| 379 | if (ForceDelete) { |
| 380 | LR.TPR.getEntry()->resetRefCount(UseHoldRefCount); |
| 381 | assert(LR.TPR.Flags.IsLast == |
| 382 | LR.TPR.getEntry()->decShouldRemove(UseHoldRefCount) && |
| 383 | "expected correct IsLast prediction for reset" ); |
| 384 | } |
| 385 | |
| 386 | // Increment the number of threads that is using the entry on a |
| 387 | // targetDataEnd, tracking the number of possible "deleters". A thread may |
| 388 | // come to own the entry deletion even if it was not the last one querying |
| 389 | // for it. Thus, we must track every query on targetDataEnds to ensure only |
| 390 | // the last thread that holds a reference to an entry actually deletes it. |
| 391 | if (FromDataEnd) |
| 392 | LR.TPR.getEntry()->incDataEndThreadCount(); |
| 393 | |
| 394 | const char *RefCountAction; |
| 395 | if (!UpdateRefCount) { |
| 396 | RefCountAction = " (update suppressed)" ; |
| 397 | } else if (LR.TPR.Flags.IsLast) { |
| 398 | LR.TPR.getEntry()->decRefCount(UseHoldRefCount); |
| 399 | assert(LR.TPR.getEntry()->getTotalRefCount() == 0 && |
| 400 | "Expected zero reference count when deletion is scheduled" ); |
| 401 | if (ForceDelete) |
| 402 | RefCountAction = " (reset, delayed deletion)" ; |
| 403 | else |
| 404 | RefCountAction = " (decremented, delayed deletion)" ; |
| 405 | } else { |
| 406 | LR.TPR.getEntry()->decRefCount(UseHoldRefCount); |
| 407 | RefCountAction = " (decremented)" ; |
| 408 | } |
| 409 | const char *DynRefCountAction = UseHoldRefCount ? "" : RefCountAction; |
| 410 | const char *HoldRefCountAction = UseHoldRefCount ? RefCountAction : "" ; |
| 411 | uintptr_t TP = LR.TPR.getEntry()->TgtPtrBegin + |
| 412 | ((uintptr_t)HstPtrBegin - LR.TPR.getEntry()->HstPtrBegin); |
| 413 | INFO(OMP_INFOTYPE_MAPPING_EXISTS, Device.DeviceID, |
| 414 | "Mapping exists with HstPtrBegin=" DPxMOD ", TgtPtrBegin=" DPxMOD ", " |
| 415 | "Size=%" PRId64 ", DynRefCount=%s%s, HoldRefCount=%s%s\n" , |
| 416 | DPxPTR(HstPtrBegin), DPxPTR(TP), Size, |
| 417 | LR.TPR.getEntry()->dynRefCountToStr().c_str(), DynRefCountAction, |
| 418 | LR.TPR.getEntry()->holdRefCountToStr().c_str(), HoldRefCountAction); |
| 419 | LR.TPR.TargetPointer = (void *)TP; |
| 420 | } else if (PM->getRequirements() & OMP_REQ_UNIFIED_SHARED_MEMORY || |
| 421 | PM->getRequirements() & OMPX_REQ_AUTO_ZERO_COPY) { |
| 422 | // If the value isn't found in the mapping and unified shared memory |
| 423 | // is on then it means we have stumbled upon a value which we need to |
| 424 | // use directly from the host. |
| 425 | DP("Get HstPtrBegin " DPxMOD " Size=%" PRId64 " for unified shared " |
| 426 | "memory\n" , |
| 427 | DPxPTR((uintptr_t)HstPtrBegin), Size); |
| 428 | LR.TPR.Flags.IsPresent = false; |
| 429 | LR.TPR.Flags.IsHostPointer = true; |
| 430 | LR.TPR.TargetPointer = HstPtrBegin; |
| 431 | } else { |
| 432 | // OpenMP Specification v5.2: if a matching list item is not found, the |
| 433 | // pointer retains its original value as per firstprivate semantics. |
| 434 | LR.TPR.Flags.IsPresent = false; |
| 435 | LR.TPR.Flags.IsHostPointer = false; |
| 436 | LR.TPR.TargetPointer = HstPtrBegin; |
| 437 | } |
| 438 | |
| 439 | return std::move(LR.TPR); |
| 440 | } |
| 441 | |
| 442 | // Return the target pointer begin (where the data will be moved). |
| 443 | void *MappingInfoTy::getTgtPtrBegin(HDTTMapAccessorTy &HDTTMap, |
| 444 | void *HstPtrBegin, int64_t Size) { |
| 445 | uintptr_t HP = (uintptr_t)HstPtrBegin; |
| 446 | LookupResult LR = lookupMapping(HDTTMap, HstPtrBegin, Size); |
| 447 | if (LR.Flags.IsContained || LR.Flags.ExtendsBefore || LR.Flags.ExtendsAfter) { |
| 448 | uintptr_t TP = |
| 449 | LR.TPR.getEntry()->TgtPtrBegin + (HP - LR.TPR.getEntry()->HstPtrBegin); |
| 450 | return (void *)TP; |
| 451 | } |
| 452 | |
| 453 | return NULL; |
| 454 | } |
| 455 | |
| 456 | int MappingInfoTy::eraseMapEntry(HDTTMapAccessorTy &HDTTMap, |
| 457 | HostDataToTargetTy *Entry, int64_t Size) { |
| 458 | assert(Entry && "Trying to delete a null entry from the HDTT map." ); |
| 459 | assert(Entry->getTotalRefCount() == 0 && |
| 460 | Entry->getDataEndThreadCount() == 0 && |
| 461 | "Trying to delete entry that is in use or owned by another thread." ); |
| 462 | |
| 463 | INFO(OMP_INFOTYPE_MAPPING_CHANGED, Device.DeviceID, |
| 464 | "Removing map entry with HstPtrBegin=" DPxMOD ", TgtPtrBegin=" DPxMOD |
| 465 | ", Size=%" PRId64 ", Name=%s\n" , |
| 466 | DPxPTR(Entry->HstPtrBegin), DPxPTR(Entry->TgtPtrBegin), Size, |
| 467 | (Entry->HstPtrName) ? getNameFromMapping(Entry->HstPtrName).c_str() |
| 468 | : "unknown" ); |
| 469 | |
| 470 | if (HDTTMap->erase(Entry) == 0) { |
| 471 | REPORT("Trying to remove a non-existent map entry\n" ); |
| 472 | return OFFLOAD_FAIL; |
| 473 | } |
| 474 | |
| 475 | return OFFLOAD_SUCCESS; |
| 476 | } |
| 477 | |
| 478 | int MappingInfoTy::deallocTgtPtrAndEntry(HostDataToTargetTy *Entry, |
| 479 | int64_t Size) { |
| 480 | assert(Entry && "Trying to deallocate a null entry." ); |
| 481 | |
| 482 | DP("Deleting tgt data " DPxMOD " of size %" PRId64 " by freeing allocation " |
| 483 | "starting at " DPxMOD "\n" , |
| 484 | DPxPTR(Entry->TgtPtrBegin), Size, DPxPTR(Entry->TgtAllocBegin)); |
| 485 | |
| 486 | void *Event = Entry->getEvent(); |
| 487 | if (Event && Device.destroyEvent(Event) != OFFLOAD_SUCCESS) { |
| 488 | REPORT("Failed to destroy event " DPxMOD "\n" , DPxPTR(Event)); |
| 489 | return OFFLOAD_FAIL; |
| 490 | } |
| 491 | |
| 492 | int Ret = Device.deleteData((void *)Entry->TgtAllocBegin); |
| 493 | |
| 494 | // Notify the plugin about the unmapped memory. |
| 495 | Ret |= Device.notifyDataUnmapped((void *)Entry->HstPtrBegin); |
| 496 | |
| 497 | delete Entry; |
| 498 | |
| 499 | return Ret; |
| 500 | } |
| 501 | |
| 502 | static void printCopyInfoImpl(int DeviceId, bool H2D, void *SrcPtrBegin, |
| 503 | void *DstPtrBegin, int64_t Size, |
| 504 | HostDataToTargetTy *HT) { |
| 505 | |
| 506 | INFO(OMP_INFOTYPE_DATA_TRANSFER, DeviceId, |
| 507 | "Copying data from %s to %s, %sPtr=" DPxMOD ", %sPtr=" DPxMOD |
| 508 | ", Size=%" PRId64 ", Name=%s\n" , |
| 509 | H2D ? "host" : "device" , H2D ? "device" : "host" , H2D ? "Hst" : "Tgt" , |
| 510 | DPxPTR(H2D ? SrcPtrBegin : DstPtrBegin), H2D ? "Tgt" : "Hst" , |
| 511 | DPxPTR(H2D ? DstPtrBegin : SrcPtrBegin), Size, |
| 512 | (HT && HT->HstPtrName) ? getNameFromMapping(HT->HstPtrName).c_str() |
| 513 | : "unknown" ); |
| 514 | } |
| 515 | |
| 516 | void MappingInfoTy::printCopyInfo( |
| 517 | void *TgtPtrBegin, void *HstPtrBegin, int64_t Size, bool H2D, |
| 518 | HostDataToTargetTy *Entry, MappingInfoTy::HDTTMapAccessorTy *HDTTMapPtr) { |
| 519 | auto HDTTMap = |
| 520 | HostDataToTargetMap.getExclusiveAccessor(!!Entry || !!HDTTMapPtr); |
| 521 | LookupResult LR; |
| 522 | if (!Entry) { |
| 523 | LR = lookupMapping(HDTTMapPtr ? *HDTTMapPtr : HDTTMap, HstPtrBegin, Size); |
| 524 | Entry = LR.TPR.getEntry(); |
| 525 | } |
| 526 | printCopyInfoImpl(Device.DeviceID, H2D, HstPtrBegin, TgtPtrBegin, Size, |
| 527 | Entry); |
| 528 | } |
| 529 | |