service read_only memory passed to CreateBuffer

- only when cl_mem_flags allows for read only memory
and USE_HOST_PTR is used

Change-Id: Id023f9cb551f7d81ec680de9cc546005980e6f75
This commit is contained in:
Hoppe, Mateusz 2018-03-05 15:52:35 +01:00 committed by sys_ocldev
parent 385fcdb7ca
commit 76dd4ac1f3
4 changed files with 170 additions and 1 deletions

View File

@ -132,6 +132,12 @@ Buffer *Buffer::create(Context *context,
//Host ptr was not created with clSVMAlloc - create graphic allocation
memory = memoryManager->createGraphicsAllocationWithRequiredBitness(size, hostPtr, true);
}
if (!memory && Buffer::isReadOnlyMemoryPermittedByFlags(flags)) {
memory = memoryManager->createGraphicsAllocationWithRequiredBitness(size, nullptr, true);
zeroCopy = false;
copyMemoryFromHostPtr = true;
allocateMemory = true;
}
}
if (!memory) {
@ -229,6 +235,14 @@ void Buffer::checkMemory(cl_mem_flags flags,
return;
}
bool Buffer::isReadOnlyMemoryPermittedByFlags(cl_mem_flags flags) {
// Host won't access or will only read and kernel will only read
if ((flags & (CL_MEM_HOST_NO_ACCESS | CL_MEM_HOST_READ_ONLY)) && (flags & CL_MEM_READ_ONLY)) {
return true;
}
return false;
}
Buffer *Buffer::createSubBuffer(cl_mem_flags flags,
const cl_buffer_region *region,
cl_int &errcodeRet) {

View File

@ -127,6 +127,8 @@ class Buffer : public MemObj {
bool &copyMemoryFromHostPtr,
MemoryManager *memMngr);
static bool isReadOnlyMemoryPermittedByFlags(cl_mem_flags flags);
void transferData(void *dst, void *src, size_t copySize, size_t copyOffset);
};

View File

@ -185,7 +185,7 @@ class MemoryManager {
return createGraphicsAllocationWithRequiredBitness(size, ptr, false);
}
GraphicsAllocation *createGraphicsAllocationWithRequiredBitness(size_t size, void *ptr, bool forcePin) {
MOCKABLE_VIRTUAL GraphicsAllocation *createGraphicsAllocationWithRequiredBitness(size_t size, void *ptr, bool forcePin) {
if (force32bitAllocations && is64bit) {
return allocate32BitGraphicsMemory(size, ptr, MemoryType::EXTERNAL_ALLOCATION);
} else {

View File

@ -25,6 +25,7 @@
#include "runtime/gmm_helper/gmm_helper.h"
#include "unit_tests/fixtures/device_fixture.h"
#include "unit_tests/fixtures/memory_management_fixture.h"
#include "unit_tests/gen_common/matchers.h"
#include "unit_tests/helpers/debug_manager_state_restore.h"
#include "unit_tests/helpers/memory_management.h"
#include "unit_tests/mocks/mock_context.h"
@ -66,6 +67,158 @@ TEST(Buffer, givenBufferWhenAskedForPtrLengthThenReturnCorrectValue) {
EXPECT_EQ(size[0], retOffset);
}
TEST(Buffer, givenReadOnlySetOfInputFlagsWhenPassedToisReadOnlyMemoryPermittedByFlagsThenTrueIsReturned) {
class MockBuffer : public Buffer {
public:
using Buffer::isReadOnlyMemoryPermittedByFlags;
};
cl_mem_flags flags = CL_MEM_HOST_NO_ACCESS | CL_MEM_READ_ONLY;
EXPECT_TRUE(MockBuffer::isReadOnlyMemoryPermittedByFlags(flags));
flags = CL_MEM_HOST_READ_ONLY | CL_MEM_READ_ONLY;
EXPECT_TRUE(MockBuffer::isReadOnlyMemoryPermittedByFlags(flags));
}
class BufferReadOnlyTest : public testing::TestWithParam<uint64_t> {
};
TEST_P(BufferReadOnlyTest, givenNonReadOnlySetOfInputFlagsWhenPassedToisReadOnlyMemoryPermittedByFlagsThenFalseIsReturned) {
class MockBuffer : public Buffer {
public:
using Buffer::isReadOnlyMemoryPermittedByFlags;
};
cl_mem_flags flags = GetParam() | CL_MEM_USE_HOST_PTR;
EXPECT_FALSE(MockBuffer::isReadOnlyMemoryPermittedByFlags(flags));
}
static cl_mem_flags nonReadOnlyFlags[] = {
CL_MEM_READ_WRITE | CL_MEM_HOST_READ_ONLY,
CL_MEM_WRITE_ONLY,
CL_MEM_READ_ONLY | CL_MEM_HOST_WRITE_ONLY,
CL_MEM_HOST_READ_ONLY,
CL_MEM_HOST_WRITE_ONLY,
CL_MEM_HOST_NO_ACCESS,
CL_MEM_HOST_READ_ONLY | CL_MEM_WRITE_ONLY,
CL_MEM_HOST_WRITE_ONLY | CL_MEM_WRITE_ONLY,
0};
INSTANTIATE_TEST_CASE_P(
nonReadOnlyFlags,
BufferReadOnlyTest,
testing::ValuesIn(nonReadOnlyFlags));
class GMockMemoryManagerFailFirstAllocation : public MockMemoryManager {
public:
MOCK_METHOD3(createGraphicsAllocationWithRequiredBitness, GraphicsAllocation *(size_t size, void *ptr, bool forcePin));
GraphicsAllocation *baseCreateGraphicsAllocationWithRequiredBitness(size_t size, void *ptr, bool forcePin) {
return MockMemoryManager::createGraphicsAllocationWithRequiredBitness(size, ptr, forcePin);
}
};
TEST(Buffer, givenReadOnlyHostPtrMemoryWhenBufferIsCreatedWithReadOnlyFlagsThenBufferHasAllocatedNewMemoryStorageAndBufferIsNotZeroCopy) {
void *memory = alignedMalloc(MemoryConstants::pageSize, MemoryConstants::pageSize);
ASSERT_NE(nullptr, memory);
memset(memory, 0xAA, MemoryConstants::pageSize);
std::unique_ptr<MockDevice> device(DeviceHelper<>::create(nullptr));
::testing::NiceMock<GMockMemoryManagerFailFirstAllocation> *memoryManager = new ::testing::NiceMock<GMockMemoryManagerFailFirstAllocation>;
device->injectMemoryManager(memoryManager);
MockContext ctx(device.get());
// First fail in createGraphicsAllocation simulates error for read only memory allocation
EXPECT_CALL(*memoryManager, createGraphicsAllocationWithRequiredBitness(MemoryConstants::pageSize, (void *)memory, true))
.WillOnce(::testing::Return(nullptr));
EXPECT_CALL(*memoryManager, createGraphicsAllocationWithRequiredBitness(::testing::_, nullptr, ::testing::_))
.WillRepeatedly(::testing::Invoke(memoryManager, &GMockMemoryManagerFailFirstAllocation::baseCreateGraphicsAllocationWithRequiredBitness));
cl_int retVal;
cl_mem_flags flags = CL_MEM_HOST_READ_ONLY | CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR;
std::unique_ptr<Buffer> buffer(Buffer::create(&ctx, flags, MemoryConstants::pageSize, (void *)memory, retVal));
EXPECT_FALSE(buffer->isMemObjZeroCopy());
void *memoryStorage = buffer->getCpuAddressForMemoryTransfer();
EXPECT_NE((void *)memory, memoryStorage);
EXPECT_THAT(buffer->getCpuAddressForMemoryTransfer(), MemCompare(memory, MemoryConstants::pageSize));
alignedFree(memory);
}
TEST(Buffer, givenReadOnlyHostPtrMemoryWhenBufferIsCreatedWithReadOnlyFlagsAndSecondAllocationFailsThenNullptrIsReturned) {
void *memory = alignedMalloc(MemoryConstants::pageSize, MemoryConstants::pageSize);
ASSERT_NE(nullptr, memory);
memset(memory, 0xAA, MemoryConstants::pageSize);
std::unique_ptr<MockDevice> device(DeviceHelper<>::create(nullptr));
::testing::NiceMock<GMockMemoryManagerFailFirstAllocation> *memoryManager = new ::testing::NiceMock<GMockMemoryManagerFailFirstAllocation>;
device->injectMemoryManager(memoryManager);
MockContext ctx(device.get());
// First fail in createGraphicsAllocation simulates error for read only memory allocation
EXPECT_CALL(*memoryManager, createGraphicsAllocationWithRequiredBitness(MemoryConstants::pageSize, (void *)memory, true))
.WillOnce(::testing::Return(nullptr));
EXPECT_CALL(*memoryManager, createGraphicsAllocationWithRequiredBitness(::testing::_, nullptr, ::testing::_))
.WillOnce(::testing::Return(nullptr));
cl_int retVal;
cl_mem_flags flags = CL_MEM_HOST_READ_ONLY | CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR;
std::unique_ptr<Buffer> buffer(Buffer::create(&ctx, flags, MemoryConstants::pageSize, (void *)memory, retVal));
EXPECT_EQ(nullptr, buffer.get());
alignedFree(memory);
}
TEST(Buffer, givenReadOnlyHostPtrMemoryWhenBufferIsCreatedWithKernelWriteFlagThenBufferAllocationFailsAndReturnsNullptr) {
void *memory = alignedMalloc(MemoryConstants::pageSize, MemoryConstants::pageSize);
ASSERT_NE(nullptr, memory);
memset(memory, 0xAA, MemoryConstants::pageSize);
std::unique_ptr<MockDevice> device(DeviceHelper<>::create(nullptr));
::testing::NiceMock<GMockMemoryManagerFailFirstAllocation> *memoryManager = new ::testing::NiceMock<GMockMemoryManagerFailFirstAllocation>;
device->injectMemoryManager(memoryManager);
MockContext ctx(device.get());
// First fail in createGraphicsAllocation simulates error for read only memory allocation
EXPECT_CALL(*memoryManager, createGraphicsAllocationWithRequiredBitness(MemoryConstants::pageSize, (void *)memory, true))
.WillOnce(::testing::Return(nullptr));
cl_int retVal;
cl_mem_flags flags = CL_MEM_HOST_READ_ONLY | CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR;
std::unique_ptr<Buffer> buffer(Buffer::create(&ctx, flags, MemoryConstants::pageSize, (void *)memory, retVal));
EXPECT_EQ(nullptr, buffer.get());
alignedFree(memory);
}
TEST(Buffer, givenNullPtrWhenBufferIsCreatedWithKernelReadOnlyFlagsThenBufferAllocationFailsAndReturnsNullptr) {
std::unique_ptr<MockDevice> device(DeviceHelper<>::create(nullptr));
::testing::NiceMock<GMockMemoryManagerFailFirstAllocation> *memoryManager = new ::testing::NiceMock<GMockMemoryManagerFailFirstAllocation>;
device->injectMemoryManager(memoryManager);
MockContext ctx(device.get());
// First fail in createGraphicsAllocation simulates error for read only memory allocation
EXPECT_CALL(*memoryManager, createGraphicsAllocationWithRequiredBitness(::testing::_, nullptr, ::testing::_))
.WillOnce(::testing::Return(nullptr));
cl_int retVal;
cl_mem_flags flags = CL_MEM_HOST_READ_ONLY | CL_MEM_WRITE_ONLY;
std::unique_ptr<Buffer> buffer(Buffer::create(&ctx, flags, MemoryConstants::pageSize, nullptr, retVal));
EXPECT_EQ(nullptr, buffer.get());
}
class BufferTest : public DeviceFixture,
public testing::TestWithParam<uint64_t /*cl_mem_flags*/> {
public: