From ab85674f8a061b4f29c1cd8bfc200c06b080d568 Mon Sep 17 00:00:00 2001 From: German Andryeyev Date: Thu, 12 Mar 2020 12:26:00 -0400 Subject: [PATCH] SWDEV-224471 - [19H1][Polaris10][Acer] Test window will quit or show error message when run OpenCL API. Add a workaround for the race condition with the first page during pinning. Change-Id: I9a27b4e173cf94c84aefcb94e255f11169453d94 --- rocclr/device/gpu/gpuvirtual.cpp | 47 ++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/rocclr/device/gpu/gpuvirtual.cpp b/rocclr/device/gpu/gpuvirtual.cpp index a7d4fa5bfc..f84cfadaf7 100644 --- a/rocclr/device/gpu/gpuvirtual.cpp +++ b/rocclr/device/gpu/gpuvirtual.cpp @@ -680,8 +680,28 @@ void VirtualGPU::submitReadMemory(amd::ReadMemoryCommand& vcmd) { result = blitMgr().copyBuffer(*memory, *hostMemory, origin, dstOrigin, size, vcmd.isEntireMemory()); } else { - result = - blitMgr().readBuffer(*memory, vcmd.destination(), origin, size, vcmd.isEntireMemory()); + // The logic below will perform 2 step copy to make sure memory pinning doesn't + // occur on the first unaligned page, because in Windows memory manager can + // have CPU access to the allocation header in another thread + // and a race condition is possible. + char* tmpHost = + amd::alignUp(reinterpret_cast(vcmd.destination()), PinnedMemoryAlignment); + + // Find the partial size for unaligned copy + size_t partial = tmpHost - reinterpret_cast(vcmd.destination()); + result = true; + // Check if it's staging copy, then ignore unaligned address + if (size[0] <= dev().settings().pinnedMinXferSize_) { + partial = size[0]; + } + // Make first step transfer + if (partial > 0) { + result = blitMgr().readBuffer(*memory, vcmd.destination(), origin, partial); + } + // Second step transfer if something left to copy + if (partial < size[0]) { + result &= blitMgr().readBuffer(*memory, tmpHost, origin[0] + partial, size[0] - partial); + } } if (NULL != bufferFromImage) { bufferFromImage->release(); @@ -777,7 +797,28 @@ void VirtualGPU::submitWriteMemory(amd::WriteMemoryCommand& vcmd) { result = blitMgr().copyBuffer(*hostMemory, *memory, srcOrigin, origin, size, vcmd.isEntireMemory()); } else { - result = blitMgr().writeBuffer(vcmd.source(), *memory, origin, size, vcmd.isEntireMemory()); + // The logic below will perform 2 step copy to make sure memory pinning doesn't + // occur on the first unaligned page, because in Windows memory manager can + // have CPU access to the allocation header in another thread + // and a race condition is possible. + const char* tmpHost = + amd::alignUp(reinterpret_cast(vcmd.source()), PinnedMemoryAlignment); + + // Find the partial size for unaligned copy + size_t partial = tmpHost - reinterpret_cast(vcmd.source()); + result = true; + // Check if it's staging copy, then ignore unaligned address + if (size[0] <= dev().settings().pinnedMinXferSize_) { + partial = size[0]; + } + // Make first step transfer + if (partial > 0) { + result = blitMgr().writeBuffer(vcmd.source(), *memory, origin, partial); + } + // Second step transfer if something left to copy + if (partial < size[0]) { + result &= blitMgr().writeBuffer(tmpHost, *memory, origin[0] + partial, size[0] - partial); + } } if (NULL != bufferFromImage) { bufferFromImage->release();