blob: 9c74521091aa41d613c22018908af6fbb365feba [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <gtest/gtest.h>
#include "../src/runtime/hexagon/hexagon_device_api.h"
using namespace tvm;
using namespace tvm::runtime;
using namespace tvm::runtime::hexagon;
using namespace tvm::ffi;
class HexagonDeviceAPITest : public ::testing::Test {
protected:
void SetUp() override {
hexapi = HexagonDeviceAPI::Global();
cpu_dev.device_type = DLDeviceType(kDLCPU);
hex_dev.device_type = DLDeviceType(kDLHexagon);
invalid_dev.device_type = DLDeviceType(kDLExtDev);
int8.bits = 8;
int8.code = 0;
int8.lanes = 1;
}
DLDevice cpu_dev;
DLDevice hex_dev;
DLDevice invalid_dev;
DLDataType int8;
HexagonDeviceAPI* hexapi;
size_t nbytes{256};
size_t alignment{64};
int64_t shape1d[1]{256};
int64_t shape2d[2]{256, 256};
int64_t shape3d[3]{256, 256, 256};
ffi::Optional<ffi::String> default_scope;
ffi::Optional<ffi::String> invalid_scope = ffi::String("invalid");
ffi::Optional<ffi::String> global_scope = ffi::String("global");
ffi::Optional<ffi::String> global_vtcm_scope = ffi::String("global.vtcm");
};
TEST_F(HexagonDeviceAPITest, global) { CHECK(hexapi != nullptr); }
TEST_F(HexagonDeviceAPITest, alloc_free_cpu) {
void* buf = hexapi->AllocDataSpace(cpu_dev, nbytes, alignment, int8);
CHECK(buf != nullptr);
hexapi->FreeDataSpace(cpu_dev, buf);
}
TEST_F(HexagonDeviceAPITest, alloc_free_hex) {
void* buf = hexapi->AllocDataSpace(hex_dev, nbytes, alignment, int8);
CHECK(buf != nullptr);
hexapi->FreeDataSpace(hex_dev, buf);
}
TEST_F(HexagonDeviceAPITest, alloc_errors) {
// invalid device
EXPECT_THROW(hexapi->AllocDataSpace(invalid_dev, nbytes, alignment, int8), InternalError);
// 0 size
EXPECT_THROW(hexapi->AllocDataSpace(hex_dev, 0, alignment, int8), InternalError);
// 0 alignment
EXPECT_THROW(hexapi->AllocDataSpace(hex_dev, nbytes, 0, int8), InternalError);
}
TEST_F(HexagonDeviceAPITest, free_errors) {
void* buf = hexapi->AllocDataSpace(hex_dev, nbytes, alignment, int8);
// invalid device
EXPECT_THROW(hexapi->FreeDataSpace(invalid_dev, buf), InternalError);
// invalid pointer
EXPECT_THROW(hexapi->FreeDataSpace(hex_dev, &buf), InternalError);
// nullptr
EXPECT_THROW(hexapi->FreeDataSpace(hex_dev, nullptr), InternalError);
// double free
hexapi->FreeDataSpace(hex_dev, buf);
EXPECT_THROW(hexapi->FreeDataSpace(hex_dev, buf), InternalError);
}
TEST_F(HexagonDeviceAPITest, allocnd_free_cpu) {
void* buf = hexapi->AllocDataSpace(cpu_dev, 3, shape3d, int8, global_scope);
CHECK(buf != nullptr);
hexapi->FreeDataSpace(cpu_dev, buf);
}
TEST_F(HexagonDeviceAPITest, allocnd_free_hex) {
void* buf = hexapi->AllocDataSpace(hex_dev, 3, shape3d, int8, global_scope);
CHECK(buf != nullptr);
hexapi->FreeDataSpace(hex_dev, buf);
}
TEST_F(HexagonDeviceAPITest, allocnd_free_hex_vtcm) {
void* buf1d = hexapi->AllocDataSpace(hex_dev, 1, shape1d, int8, global_vtcm_scope);
CHECK(buf1d != nullptr);
hexapi->FreeDataSpace(hex_dev, buf1d);
void* buf2d = hexapi->AllocDataSpace(hex_dev, 2, shape2d, int8, global_vtcm_scope);
CHECK(buf2d != nullptr);
hexapi->FreeDataSpace(hex_dev, buf2d);
}
TEST_F(HexagonDeviceAPITest, allocnd_erros) {
// invalid device
EXPECT_THROW(hexapi->AllocDataSpace(invalid_dev, 2, shape2d, int8, global_vtcm_scope),
InternalError);
// Hexagon VTCM allocations must have 0 (scalar) 1 or 2 dimensions
EXPECT_THROW(hexapi->AllocDataSpace(hex_dev, 3, shape3d, int8, global_vtcm_scope), InternalError);
// null shape
EXPECT_THROW(hexapi->AllocDataSpace(hex_dev, 2, nullptr, int8, global_vtcm_scope), InternalError);
// null shape
EXPECT_THROW(hexapi->AllocDataSpace(hex_dev, 2, shape2d, int8, invalid_scope), InternalError);
// cpu & global.vtcm scope
EXPECT_THROW(hexapi->AllocDataSpace(cpu_dev, 2, shape2d, int8, global_vtcm_scope), InternalError);
}
TEST_F(HexagonDeviceAPITest, alloc_scalar) {
void* cpuscalar = hexapi->AllocDataSpace(cpu_dev, 0, new int64_t, int8, global_scope);
CHECK(cpuscalar != nullptr);
void* hexscalar = hexapi->AllocDataSpace(hex_dev, 0, new int64_t, int8, global_vtcm_scope);
CHECK(hexscalar != nullptr);
hexscalar = hexapi->AllocDataSpace(hex_dev, 0, nullptr, int8, global_vtcm_scope);
CHECK(hexscalar != nullptr);
}
// alloc and free of the same buffer on different devices should throw
// but it currently works with no error
// hexagon and cpu device types may merge long term which would make this test case moot
// disabling this test case, for now
// TODO(HWE): Re-enable or delete this test case once we land on device type strategy
TEST_F(HexagonDeviceAPITest, DISABLED_alloc_free_diff_dev) {
void* buf = hexapi->AllocDataSpace(hex_dev, nbytes, alignment, int8);
CHECK(buf != nullptr);
EXPECT_THROW(hexapi->FreeDataSpace(cpu_dev, buf), InternalError);
}
// Ensure runtime buffer manager is properly configured and destroyed
// in Acquire/Release
TEST_F(HexagonDeviceAPITest, runtime_buffer_manager) {
hexapi->ReleaseResources();
EXPECT_THROW(hexapi->AllocDataSpace(hex_dev, nbytes, alignment, int8), InternalError);
hexapi->AcquireResources();
void* runtime_buf = hexapi->AllocDataSpace(hex_dev, nbytes, alignment, int8);
CHECK(runtime_buf != nullptr);
hexapi->ReleaseResources();
hexapi->FreeDataSpace(hex_dev, runtime_buf);
hexapi->AcquireResources();
EXPECT_THROW(hexapi->FreeDataSpace(hex_dev, runtime_buf), InternalError);
}
// Ensure thread manager is properly configured and destroyed
// in Acquire/Release
TEST_F(HexagonDeviceAPITest, thread_manager) {
HexagonThreadManager* threads = hexapi->ThreadManager();
CHECK(threads != nullptr);
hexapi->ReleaseResources();
EXPECT_THROW(hexapi->ThreadManager(), InternalError);
hexapi->AcquireResources();
}
// Ensure user DMA manager is properly configured and destroyed
// in Acquire/Release
TEST_F(HexagonDeviceAPITest, user_dma) {
HexagonUserDMA* user_dma = hexapi->UserDMA();
CHECK(user_dma != nullptr);
hexapi->ReleaseResources();
EXPECT_THROW(hexapi->UserDMA(), InternalError);
hexapi->AcquireResources();
}
// Ensure VTCM pool is properly configured and destroyed
// in Acquire/Release
TEST_F(HexagonDeviceAPITest, vtcm_pool) {
HexagonVtcmPool* vtcm_pool = hexapi->VtcmPool();
CHECK(vtcm_pool != nullptr);
hexapi->ReleaseResources();
EXPECT_THROW(hexapi->VtcmPool(), InternalError);
hexapi->AcquireResources();
}