From b76622f04e99c3b4f7c89ea4527f63167221b1c8 Mon Sep 17 00:00:00 2001 From: Janet Schneider Date: Wed, 28 Sep 2022 18:35:44 -0700 Subject: [PATCH 01/14] First pass at VTCM allocator --- src/runtime/hexagon/hexagon_vtcm.cc | 152 ++++++++++++++++++++++++++++ src/runtime/hexagon/hexagon_vtcm.h | 93 +++++++++++++++++ 2 files changed, 245 insertions(+) create mode 100644 src/runtime/hexagon/hexagon_vtcm.cc create mode 100644 src/runtime/hexagon/hexagon_vtcm.h diff --git a/src/runtime/hexagon/hexagon_vtcm.cc b/src/runtime/hexagon/hexagon_vtcm.cc new file mode 100644 index 000000000000..b3e624d58da1 --- /dev/null +++ b/src/runtime/hexagon/hexagon_vtcm.cc @@ -0,0 +1,152 @@ +/* + * 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 "hexagon_vtcm.h" + +#include "HAP_compute_res.h" +#include "hexagon_common.h" + +namespace tvm { +namespace runtime { +namespace hexagon { + +VtcmMemoryManager::VtcmMemoryManager() { + compute_res_attr_t res_info; + HEXAGON_SAFE_CALL(HAP_compute_res_attr_init(&res_info)); + + // allocate nbytes of vtcm on a single page + HEXAGON_SAFE_CALL(HAP_compute_res_attr_set_vtcm_param(&res_info, /*vtcm_size = */ vtcm_size_, + /*b_single_page = */ 0)); + + // TODO(HWE): Investigate why a non-zero timeout results in + // hanging, both in the simulator and on hardware. + context_id_ = HAP_compute_res_acquire(&res_info, /*timeout = */ 0); + + if (context_id_) { + vtcm_data_ = HAP_compute_res_attr_get_vtcm_ptr(&res_info); + if (!vtcm_data_) { + LOG(ERROR) << "ERROR: HAP_compute_res_acquire returned nullptr when allocating VTCM."; + HEXAGON_SAFE_CALL(HAP_compute_res_release(context_id_)); + return; + } + } else { + LOG(FATAL) << "FATAL: HAP_compute_res_acquire failed to acquire requested VTCM resource."; + throw std::runtime_error( + "HAP_compute_res_acquire failed to acquire requested VTCM resource."); + } + + free_.emplace_back(std::pair((char*)vtcm_data_, vtcm_size_)); +} + +VtcmMemoryManager::~VtcmMemoryManager() { + HEXAGON_SAFE_CALL(HAP_compute_res_release(context_id_)); +} + +void* VtcmMemoryManager::Allocate(size_t nbytes) { + std::lock_guard lock(mutex_); + + LOG(INFO) << "nbytes requested: " << nbytes; + + if (nbytes & size_t(0x7FF)) { + nbytes = nbytes & ~(size_t(0x7FF)) + 0x800; + LOG(INFO) << "nbytes requested (UPDATED): " << nbytes; // jlsfix - is this right? + } + + CHECK(!free_.empty()) << "No free VTCM"; + + std::pair& entry_to_allocate = free_.front(); + for(auto entry : free_) { + if ((entry.second < entry_to_allocate.second) && (entry.second >= nbytes)) + { + entry_to_allocate = entry; + if (entry_to_allocate.second == nbytes) { + break; + } + } + } + CHECK(entry_to_allocate.second >= nbytes) << "Not enough contiguous VTCM space to allocate"; + char* ptr = entry_to_allocate.first; + allocations_.emplace(allocations_.end(), std::pair(ptr, nbytes)); + + for (auto it = free_.begin(); it != free_.end(); it++) { + if (ptr == it->first) { + if (it->second == nbytes) { + free_.erase(it); + } else { + it->first = it->first + nbytes; + it->second = it->second - nbytes; + } + break; + } + } + + return (void*)ptr; +} + +void VtcmMemoryManager::Free(void* ptr, size_t nbytes) { + char* ptr_to_free = (char*)ptr; + std::lock_guard lock(mutex_); + bool found_allocation_entry = false; + for (auto it = allocations_.begin(); it != allocations_.end(); it++) + { + if (ptr_to_free == it->first) { + // jlsfix CHECK(it->second == nbytes) << "Attempted to free a different size than was allocated"; + nbytes = it->second; // jlsfix + allocations_.erase(it); + found_allocation_entry = true; + break; + } + } + CHECK(found_allocation_entry) << "Attempted to free a pointer that had not been allocated"; + + auto it = free_.begin(); + for ( ; it != free_.end(); it++) { + CHECK(ptr_to_free != it->first) << "Attempting to free a pointer that was already free"; + if (ptr_to_free < it->first) { + CHECK(ptr_to_free + nbytes <= it->first) << "free_ is in an inconsistent state, freed block overlaps with next"; + if (ptr_to_free + nbytes == it->first) { + // Make this entry bigger + it->first = ptr_to_free; + it->second += nbytes; + } else { + // Insert an entry before this + free_.insert(it, std::pair(ptr_to_free, nbytes)); + it--; + } + break; + } + } + + if (it == free_.end()) { + // Insert an entry before this + free_.insert(it, std::pair(ptr_to_free, nbytes)); + it--; + } + + // Check for overlap with the previous entry + auto it_prev = it; it_prev--; + CHECK(it_prev->first + it_prev->second > ptr_to_free) << "free_ is in an inconsistent state, freed block overlaps with previous"; + if (it_prev->first + it_prev->second == ptr_to_free) { + it_prev->second += nbytes; + free_.erase(it); + } +} + +} // namespace hexagon +} // namespace runtime +} // namespace tvm diff --git a/src/runtime/hexagon/hexagon_vtcm.h b/src/runtime/hexagon/hexagon_vtcm.h new file mode 100644 index 000000000000..274d69f6c30b --- /dev/null +++ b/src/runtime/hexagon/hexagon_vtcm.h @@ -0,0 +1,93 @@ +/* + * 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. + */ + +#ifndef TVM_RUNTIME_HEXAGON_HEXAGON_BUFFER_H_ +#define TVM_RUNTIME_HEXAGON_HEXAGON_BUFFER_H_ + +#include +#include +#include +#include +#include + +#include +#include + +namespace tvm { +namespace runtime { +namespace hexagon { + +class VtcmMemoryManager { + public: + //! \brief Allocates all of VTCM memory, and manages allocations from the runtime + VtcmMemoryManager(); + + //! \brief Destruction deallocates the underlying VTCM allocation. + ~VtcmMemoryManager(); + + //! \brief Prevent copy construction of VtcmMemoryManager. + VtcmMemoryManager(const VtcmMemoryManager&) = delete; + + //! \brief Prevent copy assignment with VtcmMemoryManager. + VtcmMemoryManager& operator=(const VtcmMemoryManager&) = delete; + + //! \brief Prevent move construction. + VtcmMemoryManager(VtcmMemoryManager&&) = delete; + + //! \brief Prevent move assignment. + VtcmMemoryManager& operator=(VtcmMemoryManager&&) = delete; + + /* \brief Allocate memory from the VTCM manager + * + * \param nbytes The number of bytes to allocate. + */ + void* Allocate(size_t nbytes); + + /* \brief Copy data from a Hexagon Buffer an external buffer. + * + * \param ptr The pointer to the buffer to be freed. + * + * \param nbytes The number of bytes to be freed. + */ + void Free(void* ptr, size_t nbytes); + + private: + //! \brief Context for HAP_compute_res_* + const size_t vtcm_size_ = 4*1024*1024; // jlsfix - is there a better place to get this? + + //! \brief Context for HAP_compute_res_* + void* vtcm_data_; + + //! \brief Context for HAP_compute_res_* + unsigned int context_id_{0}; + + //! \brief List of allocations + std::list> allocations_; + + //! \brief List of free segments + std::list> free_; + + std::mutex mutex_; +}; + +} // namespace hexagon +} // namespace runtime +} // namespace tvm + +#endif // TVM_RUNTIME_HEXAGON_HEXAGON_BUFFER_H_ From ed43e54ec98afd7725be7a6a487d4f3c58c60999 Mon Sep 17 00:00:00 2001 From: Janet Schneider Date: Thu, 29 Sep 2022 08:39:17 -0700 Subject: [PATCH 02/14] Add to device api --- src/runtime/hexagon/hexagon_device_api.cc | 1 - src/runtime/hexagon/hexagon_device_api.h | 23 ++++++++++++------ src/runtime/hexagon/hexagon_vtcm.cc | 8 +++---- src/runtime/hexagon/hexagon_vtcm.h | 24 +++++++++---------- .../hexagon/hexagon_device_api_tests.cc | 12 +++++++++- 5 files changed, 43 insertions(+), 25 deletions(-) diff --git a/src/runtime/hexagon/hexagon_device_api.cc b/src/runtime/hexagon/hexagon_device_api.cc index 06254fba4585..db3c847a55e8 100644 --- a/src/runtime/hexagon/hexagon_device_api.cc +++ b/src/runtime/hexagon/hexagon_device_api.cc @@ -33,7 +33,6 @@ #include "../workspace_pool.h" #include "hexagon_common.h" -#include "hexagon_user_dma.h" namespace tvm { namespace runtime { diff --git a/src/runtime/hexagon/hexagon_device_api.h b/src/runtime/hexagon/hexagon_device_api.h index 555ca0fa51a8..0086ce62a6bb 100644 --- a/src/runtime/hexagon/hexagon_device_api.h +++ b/src/runtime/hexagon/hexagon_device_api.h @@ -33,6 +33,7 @@ #include "hexagon_buffer_manager.h" #include "hexagon_thread_manager.h" #include "hexagon_user_dma.h" +#include "hexagon_vtcm.h" namespace tvm { namespace runtime { @@ -56,34 +57,34 @@ class HexagonDeviceAPI final : public DeviceAPI { void AcquireResources() { CHECK_EQ(runtime_hexbuffs, nullptr); runtime_hexbuffs = std::make_unique(); - DLOG(INFO) << "runtime_hexbuffs created"; mgr = runtime_hexbuffs.get(); + CHECK_EQ(runtime_vtcm, nullptr); + runtime_vtcm = std::make_unique(); + CHECK_EQ(runtime_threads, nullptr); runtime_threads = std::make_unique(threads, stack_size, pipe_size); - DLOG(INFO) << "runtime_threads created"; CHECK_EQ(runtime_dma, nullptr); runtime_dma = std::make_unique(); - DLOG(INFO) << "runtime_dma created"; } //! \brief Ensures all runtime resources are freed void ReleaseResources() { CHECK(runtime_dma) << "runtime_dma was not created in AcquireResources"; runtime_dma.reset(); - DLOG(INFO) << "runtime_dma reset"; CHECK(runtime_threads) << "runtime_threads was not created in AcquireResources"; runtime_threads.reset(); - DLOG(INFO) << "runtime_threads reset"; + + CHECK(runtime_vtcm) << "runtime_vtcm was not created in AcquireResources"; + runtime_vtcm.reset(); CHECK(runtime_hexbuffs) << "runtime_hexbuffs was not created in AcquireResources"; if (runtime_hexbuffs && !runtime_hexbuffs->empty()) { - DLOG(INFO) << "runtime_hexbuffs was not empty in ReleaseResources"; + LOG(INFO) << "runtime_hexbuffs was not empty in ReleaseResources"; } mgr = &hexbuffs; - DLOG(INFO) << "runtime_hexbuffs reset"; runtime_hexbuffs.reset(); } @@ -168,6 +169,11 @@ class HexagonDeviceAPI final : public DeviceAPI { return runtime_dma.get(); } + HexagonVtcmPool* VtcmPool() { + CHECK(runtime_vtcm) << "runtime_vtcm has not been created"; + return runtime_vtcm.get(); + } + protected: //! Standard Device API interface to copy data from one storage to another. void CopyDataFromTo(const void* from, size_t from_offset, void* to, size_t to_offset, size_t size, @@ -202,6 +208,9 @@ class HexagonDeviceAPI final : public DeviceAPI { //! \brief User DMA manager std::unique_ptr runtime_dma; + + //! \brief VTCM memory manager + std::unique_ptr runtime_vtcm; }; } // namespace hexagon } // namespace runtime diff --git a/src/runtime/hexagon/hexagon_vtcm.cc b/src/runtime/hexagon/hexagon_vtcm.cc index b3e624d58da1..7e7e63ea7717 100644 --- a/src/runtime/hexagon/hexagon_vtcm.cc +++ b/src/runtime/hexagon/hexagon_vtcm.cc @@ -25,7 +25,7 @@ namespace tvm { namespace runtime { namespace hexagon { -VtcmMemoryManager::VtcmMemoryManager() { +HexagonVtcmPool::HexagonVtcmPool() { compute_res_attr_t res_info; HEXAGON_SAFE_CALL(HAP_compute_res_attr_init(&res_info)); @@ -53,11 +53,11 @@ VtcmMemoryManager::VtcmMemoryManager() { free_.emplace_back(std::pair((char*)vtcm_data_, vtcm_size_)); } -VtcmMemoryManager::~VtcmMemoryManager() { +HexagonVtcmPool::~HexagonVtcmPool() { HEXAGON_SAFE_CALL(HAP_compute_res_release(context_id_)); } -void* VtcmMemoryManager::Allocate(size_t nbytes) { +void* HexagonVtcmPool::Allocate(size_t nbytes) { std::lock_guard lock(mutex_); LOG(INFO) << "nbytes requested: " << nbytes; @@ -98,7 +98,7 @@ void* VtcmMemoryManager::Allocate(size_t nbytes) { return (void*)ptr; } -void VtcmMemoryManager::Free(void* ptr, size_t nbytes) { +void HexagonVtcmPool::Free(void* ptr, size_t nbytes) { char* ptr_to_free = (char*)ptr; std::lock_guard lock(mutex_); bool found_allocation_entry = false; diff --git a/src/runtime/hexagon/hexagon_vtcm.h b/src/runtime/hexagon/hexagon_vtcm.h index 274d69f6c30b..bc83396e70a4 100644 --- a/src/runtime/hexagon/hexagon_vtcm.h +++ b/src/runtime/hexagon/hexagon_vtcm.h @@ -17,8 +17,8 @@ * under the License. */ -#ifndef TVM_RUNTIME_HEXAGON_HEXAGON_BUFFER_H_ -#define TVM_RUNTIME_HEXAGON_HEXAGON_BUFFER_H_ +#ifndef TVM_RUNTIME_HEXAGON_HEXAGON_VTCM_POOL_H_ +#define TVM_RUNTIME_HEXAGON_HEXAGON_VTCM_POOL_H_ #include #include @@ -33,25 +33,25 @@ namespace tvm { namespace runtime { namespace hexagon { -class VtcmMemoryManager { +class HexagonVtcmPool { public: //! \brief Allocates all of VTCM memory, and manages allocations from the runtime - VtcmMemoryManager(); + HexagonVtcmPool(); //! \brief Destruction deallocates the underlying VTCM allocation. - ~VtcmMemoryManager(); + ~HexagonVtcmPool(); - //! \brief Prevent copy construction of VtcmMemoryManager. - VtcmMemoryManager(const VtcmMemoryManager&) = delete; + //! \brief Prevent copy construction of HexagonVtcmPool. + HexagonVtcmPool(const HexagonVtcmPool&) = delete; - //! \brief Prevent copy assignment with VtcmMemoryManager. - VtcmMemoryManager& operator=(const VtcmMemoryManager&) = delete; + //! \brief Prevent copy assignment with HexagonVtcmPool. + HexagonVtcmPool& operator=(const HexagonVtcmPool&) = delete; //! \brief Prevent move construction. - VtcmMemoryManager(VtcmMemoryManager&&) = delete; + HexagonVtcmPool(HexagonVtcmPool&&) = delete; //! \brief Prevent move assignment. - VtcmMemoryManager& operator=(VtcmMemoryManager&&) = delete; + HexagonVtcmPool& operator=(HexagonVtcmPool&&) = delete; /* \brief Allocate memory from the VTCM manager * @@ -90,4 +90,4 @@ class VtcmMemoryManager { } // namespace runtime } // namespace tvm -#endif // TVM_RUNTIME_HEXAGON_HEXAGON_BUFFER_H_ +#endif // TVM_RUNTIME_HEXAGON_HEXAGON_VTCM_POOL_H_ diff --git a/tests/cpp-runtime/hexagon/hexagon_device_api_tests.cc b/tests/cpp-runtime/hexagon/hexagon_device_api_tests.cc index d0f962cfcee5..2139aa78f7ae 100644 --- a/tests/cpp-runtime/hexagon/hexagon_device_api_tests.cc +++ b/tests/cpp-runtime/hexagon/hexagon_device_api_tests.cc @@ -175,7 +175,7 @@ TEST_F(HexagonDeviceAPITest, thread_manager) { hexapi->AcquireResources(); } -// Ensure thread manager is properly configured and destroyed +// Ensure user DMA manager is properly configured and destroyed // in Acquire/Release TEST_F(HexagonDeviceAPITest, user_dma) { HexagonUserDMA* user_dma = hexapi->UserDMA(); @@ -184,3 +184,13 @@ TEST_F(HexagonDeviceAPITest, user_dma) { 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(); +} From 9b20f05890caf36d7e93aacfcf84e0441e5d808b Mon Sep 17 00:00:00 2001 From: Janet Schneider Date: Thu, 29 Sep 2022 08:41:14 -0700 Subject: [PATCH 03/14] Rename hexagon_vtcm* to hexagon_vtcm_pool* --- src/runtime/hexagon/hexagon_device_api.h | 2 +- src/runtime/hexagon/{hexagon_vtcm.cc => hexagon_vtcm_pool.cc} | 2 +- src/runtime/hexagon/{hexagon_vtcm.h => hexagon_vtcm_pool.h} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/runtime/hexagon/{hexagon_vtcm.cc => hexagon_vtcm_pool.cc} (99%) rename src/runtime/hexagon/{hexagon_vtcm.h => hexagon_vtcm_pool.h} (100%) diff --git a/src/runtime/hexagon/hexagon_device_api.h b/src/runtime/hexagon/hexagon_device_api.h index 0086ce62a6bb..66b96e2c85ef 100644 --- a/src/runtime/hexagon/hexagon_device_api.h +++ b/src/runtime/hexagon/hexagon_device_api.h @@ -33,7 +33,7 @@ #include "hexagon_buffer_manager.h" #include "hexagon_thread_manager.h" #include "hexagon_user_dma.h" -#include "hexagon_vtcm.h" +#include "hexagon_vtcm_pool.h" namespace tvm { namespace runtime { diff --git a/src/runtime/hexagon/hexagon_vtcm.cc b/src/runtime/hexagon/hexagon_vtcm_pool.cc similarity index 99% rename from src/runtime/hexagon/hexagon_vtcm.cc rename to src/runtime/hexagon/hexagon_vtcm_pool.cc index 7e7e63ea7717..1f2636d7db53 100644 --- a/src/runtime/hexagon/hexagon_vtcm.cc +++ b/src/runtime/hexagon/hexagon_vtcm_pool.cc @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -#include "hexagon_vtcm.h" +#include "hexagon_vtcm_pool.h" #include "HAP_compute_res.h" #include "hexagon_common.h" diff --git a/src/runtime/hexagon/hexagon_vtcm.h b/src/runtime/hexagon/hexagon_vtcm_pool.h similarity index 100% rename from src/runtime/hexagon/hexagon_vtcm.h rename to src/runtime/hexagon/hexagon_vtcm_pool.h From 94726c71b41b07df9f72081025138957fc63306a Mon Sep 17 00:00:00 2001 From: Janet Schneider Date: Thu, 29 Sep 2022 10:46:31 -0700 Subject: [PATCH 04/14] basic unit test passes --- src/runtime/hexagon/hexagon_device_api.h | 8 +-- src/runtime/hexagon/hexagon_vtcm_pool.cc | 54 ++++++++++++---- src/runtime/hexagon/hexagon_vtcm_pool.h | 16 +++-- .../hexagon/hexagon_device_api_tests.cc | 14 ++--- .../hexagon/hexagon_vtcm_pool_tests.cc | 63 +++++++++++++++++++ 5 files changed, 127 insertions(+), 28 deletions(-) create mode 100644 tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc diff --git a/src/runtime/hexagon/hexagon_device_api.h b/src/runtime/hexagon/hexagon_device_api.h index 66b96e2c85ef..d7c1d1b6c9eb 100644 --- a/src/runtime/hexagon/hexagon_device_api.h +++ b/src/runtime/hexagon/hexagon_device_api.h @@ -59,8 +59,8 @@ class HexagonDeviceAPI final : public DeviceAPI { runtime_hexbuffs = std::make_unique(); mgr = runtime_hexbuffs.get(); - CHECK_EQ(runtime_vtcm, nullptr); - runtime_vtcm = std::make_unique(); + // CHECK_EQ(runtime_vtcm, nullptr); + // runtime_vtcm = std::make_unique(); CHECK_EQ(runtime_threads, nullptr); runtime_threads = std::make_unique(threads, stack_size, pipe_size); @@ -77,8 +77,8 @@ class HexagonDeviceAPI final : public DeviceAPI { CHECK(runtime_threads) << "runtime_threads was not created in AcquireResources"; runtime_threads.reset(); - CHECK(runtime_vtcm) << "runtime_vtcm was not created in AcquireResources"; - runtime_vtcm.reset(); + // CHECK(runtime_vtcm) << "runtime_vtcm was not created in AcquireResources"; + // runtime_vtcm.reset(); CHECK(runtime_hexbuffs) << "runtime_hexbuffs was not created in AcquireResources"; if (runtime_hexbuffs && !runtime_hexbuffs->empty()) { diff --git a/src/runtime/hexagon/hexagon_vtcm_pool.cc b/src/runtime/hexagon/hexagon_vtcm_pool.cc index 1f2636d7db53..1707851a50ba 100644 --- a/src/runtime/hexagon/hexagon_vtcm_pool.cc +++ b/src/runtime/hexagon/hexagon_vtcm_pool.cc @@ -51,6 +51,8 @@ HexagonVtcmPool::HexagonVtcmPool() { } free_.emplace_back(std::pair((char*)vtcm_data_, vtcm_size_)); + + DebugDump(); } HexagonVtcmPool::~HexagonVtcmPool() { @@ -60,11 +62,12 @@ HexagonVtcmPool::~HexagonVtcmPool() { void* HexagonVtcmPool::Allocate(size_t nbytes) { std::lock_guard lock(mutex_); - LOG(INFO) << "nbytes requested: " << nbytes; - if (nbytes & size_t(0x7FF)) { - nbytes = nbytes & ~(size_t(0x7FF)) + 0x800; - LOG(INFO) << "nbytes requested (UPDATED): " << nbytes; // jlsfix - is this right? + size_t nbytes_requested = nbytes; + nbytes = nbytes >> 11; + nbytes = nbytes << 11; + nbytes += 0x800; + LOG(INFO) << "nbytes requested: " << nbytes_requested << " nbytes (UPDATED): " << nbytes; } CHECK(!free_.empty()) << "No free VTCM"; @@ -95,18 +98,28 @@ void* HexagonVtcmPool::Allocate(size_t nbytes) { } } + DebugDump(); + return (void*)ptr; } void HexagonVtcmPool::Free(void* ptr, size_t nbytes) { char* ptr_to_free = (char*)ptr; std::lock_guard lock(mutex_); + + if (nbytes & size_t(0x7FF)) { + size_t nbytes_requested = nbytes; + nbytes = nbytes >> 11; + nbytes = nbytes << 11; + nbytes += 0x800; + LOG(INFO) << "nbytes requested: " << nbytes_requested << " nbytes (UPDATED): " << nbytes; + } + bool found_allocation_entry = false; for (auto it = allocations_.begin(); it != allocations_.end(); it++) { if (ptr_to_free == it->first) { - // jlsfix CHECK(it->second == nbytes) << "Attempted to free a different size than was allocated"; - nbytes = it->second; // jlsfix + CHECK(it->second == nbytes) << "Attempted to free a different size than was allocated"; allocations_.erase(it); found_allocation_entry = true; break; @@ -125,7 +138,7 @@ void HexagonVtcmPool::Free(void* ptr, size_t nbytes) { it->second += nbytes; } else { // Insert an entry before this - free_.insert(it, std::pair(ptr_to_free, nbytes)); + free_.emplace(it, std::pair(ptr_to_free, nbytes)); it--; } break; @@ -134,16 +147,31 @@ void HexagonVtcmPool::Free(void* ptr, size_t nbytes) { if (it == free_.end()) { // Insert an entry before this - free_.insert(it, std::pair(ptr_to_free, nbytes)); + free_.emplace(it, std::pair(ptr_to_free, nbytes)); it--; } // Check for overlap with the previous entry - auto it_prev = it; it_prev--; - CHECK(it_prev->first + it_prev->second > ptr_to_free) << "free_ is in an inconsistent state, freed block overlaps with previous"; - if (it_prev->first + it_prev->second == ptr_to_free) { - it_prev->second += nbytes; - free_.erase(it); + if (it != free_.begin()) { + auto it_prev = it; it_prev--; + CHECK(it_prev->first + it_prev->second >= ptr_to_free) << "free_ is in an inconsistent state, freed block overlaps with previous"; + if (it_prev->first + it_prev->second == ptr_to_free) { + it_prev->second += nbytes; + free_.erase(it); + } + } + + DebugDump(); +} + +void HexagonVtcmPool::DebugDump() +{ + for (auto it = allocations_.begin(); it != allocations_.end(); it++) { + LOG(INFO) << "jlsfix vtcm alloc ptr: " << (void*)it->first << " size: " << it->second; + } + + for (auto it = free_.begin(); it != free_.end(); it++) { + LOG(INFO) << "jlsfix vtcm free ptr: " << (void*)it->first << " size: " << it->second; } } diff --git a/src/runtime/hexagon/hexagon_vtcm_pool.h b/src/runtime/hexagon/hexagon_vtcm_pool.h index bc83396e70a4..799d1bc9d338 100644 --- a/src/runtime/hexagon/hexagon_vtcm_pool.h +++ b/src/runtime/hexagon/hexagon_vtcm_pool.h @@ -67,14 +67,18 @@ class HexagonVtcmPool { */ void Free(void* ptr, size_t nbytes); + //! \brief Returns the total number of bytes in this pool + size_t TotalBytes() {return vtcm_size_; } + private: - //! \brief Context for HAP_compute_res_* - const size_t vtcm_size_ = 4*1024*1024; // jlsfix - is there a better place to get this? + //! \brief Context for HAP_compute_res_* + // TODO(janetsc) get the size programmatically + const size_t vtcm_size_ = 1024*1024; - //! \brief Context for HAP_compute_res_* + //! \brief Context for HAP_compute_res_* void* vtcm_data_; - //! \brief Context for HAP_compute_res_* + //! \brief Context for HAP_compute_res_* unsigned int context_id_{0}; //! \brief List of allocations @@ -83,7 +87,11 @@ class HexagonVtcmPool { //! \brief List of free segments std::list> free_; + //! \brief Mutext to protect access to the lists std::mutex mutex_; + + //! \brief Debug only dump of the state of the lists + void DebugDump(); }; } // namespace hexagon diff --git a/tests/cpp-runtime/hexagon/hexagon_device_api_tests.cc b/tests/cpp-runtime/hexagon/hexagon_device_api_tests.cc index 2139aa78f7ae..df597d48a0bf 100644 --- a/tests/cpp-runtime/hexagon/hexagon_device_api_tests.cc +++ b/tests/cpp-runtime/hexagon/hexagon_device_api_tests.cc @@ -187,10 +187,10 @@ TEST_F(HexagonDeviceAPITest, user_dma) { // 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(); -} +// TEST_F(HexagonDeviceAPITest, vtcm_pool) { +// HexagonVtcmPool* vtcm_pool = hexapi->VtcmPool(); +// CHECK(vtcm_pool != nullptr); +// hexapi->ReleaseResources(); +// EXPECT_THROW(hexapi->VtcmPool(), InternalError); +// hexapi->AcquireResources(); +// } diff --git a/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc b/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc new file mode 100644 index 000000000000..2d985dd5892c --- /dev/null +++ b/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc @@ -0,0 +1,63 @@ +/* + * 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 + +#include "../src/runtime/hexagon/hexagon_device_api.h" + +using namespace tvm::runtime; +using namespace tvm::runtime::hexagon; + +class HexagonVtcmPoolTest : public ::testing::Test { + void SetUp() override { + vtcm_pool = std::make_unique(); + } + void TearDown() override { + vtcm_pool.reset(); + } + + public: + std::unique_ptr vtcm_pool; +}; + +TEST_F(HexagonVtcmPoolTest, basic) { + void* ptr; + size_t max_bytes = vtcm_pool->TotalBytes(); + size_t two_k_block = 2048; + size_t one_k_block = 1024; + ptr = vtcm_pool->Allocate(max_bytes); + vtcm_pool->Free(ptr, max_bytes); + ptr = vtcm_pool->Allocate(two_k_block); + vtcm_pool->Free(ptr, two_k_block); + ptr = vtcm_pool->Allocate(one_k_block); + vtcm_pool->Free(ptr, one_k_block); +} + +// TEST_F(HexagonVtcmPoolTest, basic) { +// void* ptr; +// size_t max_bytes = 1024*1024; +// size_t two_k_block = 2048; +// size_t one_k_block = 1024; +// ptr = vtcm_pool->Allocate(max_bytes); +// vtcm_pool->Free(ptr, max_bytes); +// ptr = vtcm_pool->Allocate(two_k_block); +// vtcm_pool->Free(ptr, two_k_block); +// ptr = vtcm_pool->Allocate(one_k_block); +// vtcm_pool->Free(ptr, one_k_block); +// } From bf284d1b66d0b4501b004675c6b395968abb8b9e Mon Sep 17 00:00:00 2001 From: Janet Schneider Date: Thu, 29 Sep 2022 11:49:29 -0700 Subject: [PATCH 05/14] additional tests --- .../hexagon/hexagon_vtcm_pool_tests.cc | 77 ++++++++++++++++--- 1 file changed, 65 insertions(+), 12 deletions(-) diff --git a/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc b/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc index 2d985dd5892c..f043e917d17f 100644 --- a/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc +++ b/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc @@ -41,23 +41,76 @@ TEST_F(HexagonVtcmPoolTest, basic) { size_t max_bytes = vtcm_pool->TotalBytes(); size_t two_k_block = 2048; size_t one_k_block = 1024; + size_t one_byte_block = 1; ptr = vtcm_pool->Allocate(max_bytes); vtcm_pool->Free(ptr, max_bytes); ptr = vtcm_pool->Allocate(two_k_block); vtcm_pool->Free(ptr, two_k_block); ptr = vtcm_pool->Allocate(one_k_block); vtcm_pool->Free(ptr, one_k_block); + ptr = vtcm_pool->Allocate(one_byte_block); + vtcm_pool->Free(ptr, one_byte_block); } -// TEST_F(HexagonVtcmPoolTest, basic) { -// void* ptr; -// size_t max_bytes = 1024*1024; -// size_t two_k_block = 2048; -// size_t one_k_block = 1024; -// ptr = vtcm_pool->Allocate(max_bytes); -// vtcm_pool->Free(ptr, max_bytes); -// ptr = vtcm_pool->Allocate(two_k_block); -// vtcm_pool->Free(ptr, two_k_block); -// ptr = vtcm_pool->Allocate(one_k_block); -// vtcm_pool->Free(ptr, one_k_block); -// } +TEST_F(HexagonVtcmPoolTest, no_free_vtcm) { + void* ptr; + size_t max_bytes = vtcm_pool->TotalBytes(); + ptr = vtcm_pool->Allocate(max_bytes); + EXPECT_THROW(vtcm_pool->Allocate(1), InternalError); + vtcm_pool->Free(ptr, max_bytes); +} + +TEST_F(HexagonVtcmPoolTest, not_enough_free_vtcm) { + void* ptr; + size_t max_bytes = vtcm_pool->TotalBytes(); + size_t two_k_block = 2048; + ptr = vtcm_pool->Allocate(max_bytes-two_k_block); + EXPECT_THROW(vtcm_pool->Allocate(two_k_block*2), InternalError); + vtcm_pool->Free(ptr, max_bytes-two_k_block); +} + +TEST_F(HexagonVtcmPoolTest, free_with_wrong_size) { + void* ptr; + size_t two_k_block = 2048; + ptr = vtcm_pool->Allocate(two_k_block*2); + EXPECT_THROW(vtcm_pool->Free(ptr, two_k_block), InternalError); + vtcm_pool->Free(ptr, two_k_block*2); +} + +TEST_F(HexagonVtcmPoolTest, free_alloc_in_middle) { + void* ptr1; + void* ptr2; + void* ptr3; + void* ptr4; + void* new_ptr; + size_t two_k_block = 2048; + size_t max_less_3_blocks = vtcm_pool->TotalBytes()-(3*two_k_block); + ptr1 = vtcm_pool->Allocate(two_k_block); + ptr2 = vtcm_pool->Allocate(two_k_block); + ptr3 = vtcm_pool->Allocate(two_k_block); + ptr4 = vtcm_pool->Allocate(max_less_3_blocks); + + // Make sure pointers are 2k apart from each other + CHECK((char*)ptr1+two_k_block == (char*)ptr2); + CHECK((char*)ptr2+two_k_block == (char*)ptr3); + CHECK((char*)ptr3+two_k_block == (char*)ptr4); + + // Free 2, realloc it, make sure it is the same as before + vtcm_pool->Free(ptr2, two_k_block); + new_ptr = vtcm_pool->Allocate(two_k_block); + CHECK(new_ptr==ptr2); + + // Free 1 and 2, re-alloc and make sure they are the same + vtcm_pool->Free(ptr1, two_k_block); + vtcm_pool->Free(ptr2, two_k_block); + new_ptr = vtcm_pool->Allocate(two_k_block); + CHECK(new_ptr==ptr1); + new_ptr = vtcm_pool->Allocate(two_k_block); + CHECK(new_ptr==ptr2); + + // Free in order to exercise different deletion scenarios + vtcm_pool->Free(ptr2, two_k_block); + vtcm_pool->Free(ptr3, two_k_block); + vtcm_pool->Free(ptr4, max_less_3_blocks); + vtcm_pool->Free(ptr1, two_k_block); +} From 17d800e061f6bd81ee3a77156d03b1812392a02d Mon Sep 17 00:00:00 2001 From: Janet Schneider Date: Thu, 29 Sep 2022 12:54:06 -0700 Subject: [PATCH 06/14] more tests, variable size pool --- src/runtime/hexagon/hexagon_vtcm_pool.cc | 64 +++++++++---------- src/runtime/hexagon/hexagon_vtcm_pool.h | 5 +- .../hexagon/hexagon_vtcm_pool_tests.cc | 11 +++- 3 files changed, 41 insertions(+), 39 deletions(-) diff --git a/src/runtime/hexagon/hexagon_vtcm_pool.cc b/src/runtime/hexagon/hexagon_vtcm_pool.cc index 1707851a50ba..23bb61a1aca5 100644 --- a/src/runtime/hexagon/hexagon_vtcm_pool.cc +++ b/src/runtime/hexagon/hexagon_vtcm_pool.cc @@ -26,37 +26,34 @@ namespace runtime { namespace hexagon { HexagonVtcmPool::HexagonVtcmPool() { - compute_res_attr_t res_info; - HEXAGON_SAFE_CALL(HAP_compute_res_attr_init(&res_info)); - - // allocate nbytes of vtcm on a single page - HEXAGON_SAFE_CALL(HAP_compute_res_attr_set_vtcm_param(&res_info, /*vtcm_size = */ vtcm_size_, - /*b_single_page = */ 0)); - - // TODO(HWE): Investigate why a non-zero timeout results in - // hanging, both in the simulator and on hardware. - context_id_ = HAP_compute_res_acquire(&res_info, /*timeout = */ 0); - - if (context_id_) { - vtcm_data_ = HAP_compute_res_attr_get_vtcm_ptr(&res_info); - if (!vtcm_data_) { - LOG(ERROR) << "ERROR: HAP_compute_res_acquire returned nullptr when allocating VTCM."; - HEXAGON_SAFE_CALL(HAP_compute_res_release(context_id_)); - return; - } - } else { - LOG(FATAL) << "FATAL: HAP_compute_res_acquire failed to acquire requested VTCM resource."; - throw std::runtime_error( - "HAP_compute_res_acquire failed to acquire requested VTCM resource."); - } + compute_res_attr_t res_info; + HEXAGON_SAFE_CALL(HAP_compute_res_attr_init(&res_info)); + + // TODO(HWE): get the max and min size programmatically + const unsigned int max_size = 4*1024*1024; + const unsigned int min_size = 1024*1024; + + // allocate nbytes of vtcm on a single page + HEXAGON_SAFE_CALL(HAP_compute_res_attr_set_vtcm_param_v2(&res_info, + /*vtcm_size = */ max_size, + /*min_page_size = */ 0, + /*min_vtcm_size = */ min_size)); + + // TODO(HWE): Investigate why a non-zero timeout results in + // hanging, both in the simulator and on hardware. + context_id_ = HAP_compute_res_acquire(&res_info, /*timeout = */ 0); + CHECK(context_id_) << "HAP_compute_res_acquire failed to acquire requested VTCM resource."; + HEXAGON_SAFE_CALL(HAP_compute_res_attr_get_vtcm_ptr_v2(&res_info, &vtcm_data_, &vtcm_size_)); + CHECK(vtcm_data_ != nullptr) << "HAP_compute_res_acquire returned nullptr when allocating VTCM."; + CHECK(vtcm_size_ >= min_size) + << "HAP_compute_res_acquire failed to allocate minimum amount of VTCM"; + free_.emplace_back(std::pair((char*)vtcm_data_, vtcm_size_)); - free_.emplace_back(std::pair((char*)vtcm_data_, vtcm_size_)); - - DebugDump(); + DebugDump(); } HexagonVtcmPool::~HexagonVtcmPool() { - HEXAGON_SAFE_CALL(HAP_compute_res_release(context_id_)); + HEXAGON_SAFE_CALL(HAP_compute_res_release(context_id_)); } void* HexagonVtcmPool::Allocate(size_t nbytes) { @@ -138,8 +135,7 @@ void HexagonVtcmPool::Free(void* ptr, size_t nbytes) { it->second += nbytes; } else { // Insert an entry before this - free_.emplace(it, std::pair(ptr_to_free, nbytes)); - it--; + it = free_.emplace(it, std::pair(ptr_to_free, nbytes)); } break; } @@ -147,14 +143,13 @@ void HexagonVtcmPool::Free(void* ptr, size_t nbytes) { if (it == free_.end()) { // Insert an entry before this - free_.emplace(it, std::pair(ptr_to_free, nbytes)); - it--; + it = free_.emplace(it, std::pair(ptr_to_free, nbytes)); } // Check for overlap with the previous entry if (it != free_.begin()) { auto it_prev = it; it_prev--; - CHECK(it_prev->first + it_prev->second >= ptr_to_free) << "free_ is in an inconsistent state, freed block overlaps with previous"; + CHECK(it_prev->first + it_prev->second <= ptr_to_free) << "free_ is in an inconsistent state, freed block overlaps with previous"; if (it_prev->first + it_prev->second == ptr_to_free) { it_prev->second += nbytes; free_.erase(it); @@ -166,12 +161,13 @@ void HexagonVtcmPool::Free(void* ptr, size_t nbytes) { void HexagonVtcmPool::DebugDump() { + LOG(INFO) << "VTCM list state"; for (auto it = allocations_.begin(); it != allocations_.end(); it++) { - LOG(INFO) << "jlsfix vtcm alloc ptr: " << (void*)it->first << " size: " << it->second; + LOG(INFO) << "VTCM alloc: " << (void*)it->first << " " << it->second; } for (auto it = free_.begin(); it != free_.end(); it++) { - LOG(INFO) << "jlsfix vtcm free ptr: " << (void*)it->first << " size: " << it->second; + LOG(INFO) << "VTCM free: " << (void*)it->first << " " << it->second; } } diff --git a/src/runtime/hexagon/hexagon_vtcm_pool.h b/src/runtime/hexagon/hexagon_vtcm_pool.h index 799d1bc9d338..4c8b61ea7c09 100644 --- a/src/runtime/hexagon/hexagon_vtcm_pool.h +++ b/src/runtime/hexagon/hexagon_vtcm_pool.h @@ -68,12 +68,11 @@ class HexagonVtcmPool { void Free(void* ptr, size_t nbytes); //! \brief Returns the total number of bytes in this pool - size_t TotalBytes() {return vtcm_size_; } + size_t TotalBytes() {return (size_t)vtcm_size_; } private: //! \brief Context for HAP_compute_res_* - // TODO(janetsc) get the size programmatically - const size_t vtcm_size_ = 1024*1024; + unsigned int vtcm_size_; //! \brief Context for HAP_compute_res_* void* vtcm_data_; diff --git a/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc b/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc index f043e917d17f..d13261f8b272 100644 --- a/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc +++ b/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc @@ -26,7 +26,7 @@ using namespace tvm::runtime::hexagon; class HexagonVtcmPoolTest : public ::testing::Test { void SetUp() override { - vtcm_pool = std::make_unique(); + vtcm_pool = std::make_unique(); // jlsfix - get pointer from device API later } void TearDown() override { vtcm_pool.reset(); @@ -77,7 +77,7 @@ TEST_F(HexagonVtcmPoolTest, free_with_wrong_size) { vtcm_pool->Free(ptr, two_k_block*2); } -TEST_F(HexagonVtcmPoolTest, free_alloc_in_middle) { +TEST_F(HexagonVtcmPoolTest, free_alloc_combinations) { void* ptr1; void* ptr2; void* ptr3; @@ -113,4 +113,11 @@ TEST_F(HexagonVtcmPoolTest, free_alloc_in_middle) { vtcm_pool->Free(ptr3, two_k_block); vtcm_pool->Free(ptr4, max_less_3_blocks); vtcm_pool->Free(ptr1, two_k_block); + + ptr1 = vtcm_pool->Allocate(two_k_block); + ptr2 = vtcm_pool->Allocate(two_k_block); + ptr3 = vtcm_pool->Allocate(two_k_block); + vtcm_pool->Free(ptr1, two_k_block); + vtcm_pool->Free(ptr3, two_k_block); + vtcm_pool->Free(ptr2, two_k_block); } From 1f8a73692c8a62d1f36ea55ac705504bd8136ebd Mon Sep 17 00:00:00 2001 From: Janet Schneider Date: Thu, 29 Sep 2022 14:44:21 -0700 Subject: [PATCH 07/14] integration with hexagon_buffer, failing unit test --- src/runtime/hexagon/hexagon_buffer.cc | 39 +++++++------------ src/runtime/hexagon/hexagon_device_api.h | 8 ++-- src/runtime/hexagon/hexagon_vtcm_pool.cc | 30 +++++++------- .../hexagon/hexagon_device_api_tests.cc | 14 +++---- .../hexagon/hexagon_vtcm_pool_tests.cc | 5 +-- 5 files changed, 40 insertions(+), 56 deletions(-) diff --git a/src/runtime/hexagon/hexagon_buffer.cc b/src/runtime/hexagon/hexagon_buffer.cc index 3ba1b5be3d3d..95bfcaca58ac 100644 --- a/src/runtime/hexagon/hexagon_buffer.cc +++ b/src/runtime/hexagon/hexagon_buffer.cc @@ -24,7 +24,7 @@ #include #include -#include "HAP_compute_res.h" +#include "hexagon_device_api.h" #include "hexagon_common.h" namespace tvm { @@ -57,35 +57,24 @@ struct DDRAllocation : public Allocation { struct VTCMAllocation : public Allocation { VTCMAllocation(size_t nbytes, size_t alignment) : Allocation(nbytes, alignment) { - compute_res_attr_t res_info; - HEXAGON_SAFE_CALL(HAP_compute_res_attr_init(&res_info)); - - // allocate nbytes of vtcm on a single page - HEXAGON_SAFE_CALL(HAP_compute_res_attr_set_vtcm_param(&res_info, /*vtcm_size = */ nbytes, - /*b_single_page = */ 0)); - - // TODO(HWE): Investigate why a non-zero timeout results in - // hanging, both in the simulator and on hardware. - context_id_ = HAP_compute_res_acquire(&res_info, /*timeout = */ 0); - - if (context_id_) { - data_ = HAP_compute_res_attr_get_vtcm_ptr(&res_info); - if (!data_) { - LOG(ERROR) << "ERROR: HAP_compute_res_acquire returned nullptr when allocating VTCM."; - HEXAGON_SAFE_CALL(HAP_compute_res_release(context_id_)); - return; + CHECK(allocation_nbytes_ == nbytes); + CHECK(alignment <= 0x800) << "VTCMAllocation called for invalid alignment"; + if ((nbytes & 0x7FF) && ((alignment & 0x7FF) == 0)) { + nbytes = nbytes >> 11; + nbytes = nbytes << 11; + nbytes += 0x800; + LOG(INFO) << "VTCMAllocation size adjusted for alignment " << allocation_nbytes_ << " to " << nbytes; + allocation_nbytes_ = nbytes; } - } else { - LOG(FATAL) << "FATAL: HAP_compute_res_acquire failed to acquire requested VTCM resource."; - throw std::runtime_error( - "HAP_compute_res_acquire failed to acquire requested VTCM resource."); - } + + data_ = HexagonDeviceAPI::Global()->VtcmPool()->Allocate(allocation_nbytes_); + LOG(INFO) << "VTCMAllocation " << data_ << " " << allocation_nbytes_ << " " << alignment; } ~VTCMAllocation() { - HEXAGON_SAFE_CALL(HAP_compute_res_release(context_id_)); + LOG(INFO) << "~VTCMAllocation " << data_ << " " << allocation_nbytes_; + HexagonDeviceAPI::Global()->VtcmPool()->Free(data_, allocation_nbytes_); data_ = nullptr; } - unsigned int context_id_{0}; }; template diff --git a/src/runtime/hexagon/hexagon_device_api.h b/src/runtime/hexagon/hexagon_device_api.h index d7c1d1b6c9eb..66b96e2c85ef 100644 --- a/src/runtime/hexagon/hexagon_device_api.h +++ b/src/runtime/hexagon/hexagon_device_api.h @@ -59,8 +59,8 @@ class HexagonDeviceAPI final : public DeviceAPI { runtime_hexbuffs = std::make_unique(); mgr = runtime_hexbuffs.get(); - // CHECK_EQ(runtime_vtcm, nullptr); - // runtime_vtcm = std::make_unique(); + CHECK_EQ(runtime_vtcm, nullptr); + runtime_vtcm = std::make_unique(); CHECK_EQ(runtime_threads, nullptr); runtime_threads = std::make_unique(threads, stack_size, pipe_size); @@ -77,8 +77,8 @@ class HexagonDeviceAPI final : public DeviceAPI { CHECK(runtime_threads) << "runtime_threads was not created in AcquireResources"; runtime_threads.reset(); - // CHECK(runtime_vtcm) << "runtime_vtcm was not created in AcquireResources"; - // runtime_vtcm.reset(); + CHECK(runtime_vtcm) << "runtime_vtcm was not created in AcquireResources"; + runtime_vtcm.reset(); CHECK(runtime_hexbuffs) << "runtime_hexbuffs was not created in AcquireResources"; if (runtime_hexbuffs && !runtime_hexbuffs->empty()) { diff --git a/src/runtime/hexagon/hexagon_vtcm_pool.cc b/src/runtime/hexagon/hexagon_vtcm_pool.cc index 23bb61a1aca5..fd53681183bf 100644 --- a/src/runtime/hexagon/hexagon_vtcm_pool.cc +++ b/src/runtime/hexagon/hexagon_vtcm_pool.cc @@ -59,16 +59,20 @@ HexagonVtcmPool::~HexagonVtcmPool() { void* HexagonVtcmPool::Allocate(size_t nbytes) { std::lock_guard lock(mutex_); + CHECK(!free_.empty()) << "No free VTCM"; + + // If this is not aligned on a 2k block, allocate from the end to avoid fragmentation if (nbytes & size_t(0x7FF)) { - size_t nbytes_requested = nbytes; - nbytes = nbytes >> 11; - nbytes = nbytes << 11; - nbytes += 0x800; - LOG(INFO) << "nbytes requested: " << nbytes_requested << " nbytes (UPDATED): " << nbytes; + LOG(INFO) << "VTCM nbytes requested: " << nbytes << " allocate from the end"; + auto last_free_entry = free_.rbegin(); + CHECK(last_free_entry->second >= nbytes) << "Not enough contiguous VTCM space at the end to allocate"; + char* ptr = last_free_entry->first + (last_free_entry->second-nbytes); + allocations_.emplace_back(std::pair(ptr, nbytes)); + last_free_entry->second -= nbytes; + DebugDump(); + return ptr; } - CHECK(!free_.empty()) << "No free VTCM"; - std::pair& entry_to_allocate = free_.front(); for(auto entry : free_) { if ((entry.second < entry_to_allocate.second) && (entry.second >= nbytes)) @@ -97,21 +101,13 @@ void* HexagonVtcmPool::Allocate(size_t nbytes) { DebugDump(); - return (void*)ptr; + return ptr; } void HexagonVtcmPool::Free(void* ptr, size_t nbytes) { char* ptr_to_free = (char*)ptr; std::lock_guard lock(mutex_); - if (nbytes & size_t(0x7FF)) { - size_t nbytes_requested = nbytes; - nbytes = nbytes >> 11; - nbytes = nbytes << 11; - nbytes += 0x800; - LOG(INFO) << "nbytes requested: " << nbytes_requested << " nbytes (UPDATED): " << nbytes; - } - bool found_allocation_entry = false; for (auto it = allocations_.begin(); it != allocations_.end(); it++) { @@ -167,7 +163,7 @@ void HexagonVtcmPool::DebugDump() } for (auto it = free_.begin(); it != free_.end(); it++) { - LOG(INFO) << "VTCM free: " << (void*)it->first << " " << it->second; + LOG(INFO) << "VTCM free: " << (void*)it->first << " " << it->second; } } diff --git a/tests/cpp-runtime/hexagon/hexagon_device_api_tests.cc b/tests/cpp-runtime/hexagon/hexagon_device_api_tests.cc index df597d48a0bf..2139aa78f7ae 100644 --- a/tests/cpp-runtime/hexagon/hexagon_device_api_tests.cc +++ b/tests/cpp-runtime/hexagon/hexagon_device_api_tests.cc @@ -187,10 +187,10 @@ TEST_F(HexagonDeviceAPITest, user_dma) { // 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(); -// } +TEST_F(HexagonDeviceAPITest, vtcm_pool) { + HexagonVtcmPool* vtcm_pool = hexapi->VtcmPool(); + CHECK(vtcm_pool != nullptr); + hexapi->ReleaseResources(); + EXPECT_THROW(hexapi->VtcmPool(), InternalError); + hexapi->AcquireResources(); +} diff --git a/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc b/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc index d13261f8b272..19bcf7e1d083 100644 --- a/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc +++ b/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc @@ -26,14 +26,13 @@ using namespace tvm::runtime::hexagon; class HexagonVtcmPoolTest : public ::testing::Test { void SetUp() override { - vtcm_pool = std::make_unique(); // jlsfix - get pointer from device API later + vtcm_pool = HexagonDeviceAPI::Global()->VtcmPool(); } void TearDown() override { - vtcm_pool.reset(); } public: - std::unique_ptr vtcm_pool; + HexagonVtcmPool* vtcm_pool; }; TEST_F(HexagonVtcmPoolTest, basic) { From b984bb92143b44eea1f1f18a1d97cb3f259ea425 Mon Sep 17 00:00:00 2001 From: Janet Schneider Date: Thu, 29 Sep 2022 16:28:31 -0700 Subject: [PATCH 08/14] fixing bugs uncoverd by unit tests --- src/runtime/hexagon/hexagon_device_api.h | 13 +++++++------ src/runtime/hexagon/hexagon_vtcm_pool.cc | 2 +- .../cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc | 7 ++++++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/runtime/hexagon/hexagon_device_api.h b/src/runtime/hexagon/hexagon_device_api.h index 66b96e2c85ef..d5182fe362e0 100644 --- a/src/runtime/hexagon/hexagon_device_api.h +++ b/src/runtime/hexagon/hexagon_device_api.h @@ -55,13 +55,14 @@ class HexagonDeviceAPI final : public DeviceAPI { //! \brief Ensures resource managers are in a good state for the runtime void AcquireResources() { + + CHECK_EQ(runtime_vtcm, nullptr); + runtime_vtcm = std::make_unique(); + CHECK_EQ(runtime_hexbuffs, nullptr); runtime_hexbuffs = std::make_unique(); mgr = runtime_hexbuffs.get(); - CHECK_EQ(runtime_vtcm, nullptr); - runtime_vtcm = std::make_unique(); - CHECK_EQ(runtime_threads, nullptr); runtime_threads = std::make_unique(threads, stack_size, pipe_size); @@ -77,15 +78,15 @@ class HexagonDeviceAPI final : public DeviceAPI { CHECK(runtime_threads) << "runtime_threads was not created in AcquireResources"; runtime_threads.reset(); - CHECK(runtime_vtcm) << "runtime_vtcm was not created in AcquireResources"; - runtime_vtcm.reset(); - CHECK(runtime_hexbuffs) << "runtime_hexbuffs was not created in AcquireResources"; if (runtime_hexbuffs && !runtime_hexbuffs->empty()) { LOG(INFO) << "runtime_hexbuffs was not empty in ReleaseResources"; } mgr = &hexbuffs; runtime_hexbuffs.reset(); + + CHECK(runtime_vtcm) << "runtime_vtcm was not created in AcquireResources"; + runtime_vtcm.reset(); } /*! \brief Currently unimplemented interface to specify the active diff --git a/src/runtime/hexagon/hexagon_vtcm_pool.cc b/src/runtime/hexagon/hexagon_vtcm_pool.cc index fd53681183bf..c187053287b5 100644 --- a/src/runtime/hexagon/hexagon_vtcm_pool.cc +++ b/src/runtime/hexagon/hexagon_vtcm_pool.cc @@ -147,7 +147,7 @@ void HexagonVtcmPool::Free(void* ptr, size_t nbytes) { auto it_prev = it; it_prev--; CHECK(it_prev->first + it_prev->second <= ptr_to_free) << "free_ is in an inconsistent state, freed block overlaps with previous"; if (it_prev->first + it_prev->second == ptr_to_free) { - it_prev->second += nbytes; + it_prev->second += it->second; free_.erase(it); } } diff --git a/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc b/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc index 19bcf7e1d083..b3f1228d39bc 100644 --- a/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc +++ b/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc @@ -107,7 +107,7 @@ TEST_F(HexagonVtcmPoolTest, free_alloc_combinations) { new_ptr = vtcm_pool->Allocate(two_k_block); CHECK(new_ptr==ptr2); - // Free in order to exercise different deletion scenarios + // Exercise different deletion scenarios vtcm_pool->Free(ptr2, two_k_block); vtcm_pool->Free(ptr3, two_k_block); vtcm_pool->Free(ptr4, max_less_3_blocks); @@ -119,4 +119,9 @@ TEST_F(HexagonVtcmPoolTest, free_alloc_combinations) { vtcm_pool->Free(ptr1, two_k_block); vtcm_pool->Free(ptr3, two_k_block); vtcm_pool->Free(ptr2, two_k_block); + + // Make sure at the end we have the full amount + // available again + ptr4 = vtcm_pool->Allocate(max_less_3_blocks); + vtcm_pool->Free(ptr4, max_less_3_blocks); } From 52726eb1c14b7e456a9109358644b90389ec486b Mon Sep 17 00:00:00 2001 From: Janet Schneider Date: Thu, 29 Sep 2022 20:05:56 -0700 Subject: [PATCH 09/14] lint --- src/runtime/hexagon/hexagon_buffer.cc | 28 ++++---- src/runtime/hexagon/hexagon_device_api.h | 1 - src/runtime/hexagon/hexagon_vtcm_pool.cc | 64 +++++++++---------- src/runtime/hexagon/hexagon_vtcm_pool.h | 6 +- .../hexagon/hexagon_vtcm_pool_tests.cc | 31 ++++----- 5 files changed, 62 insertions(+), 68 deletions(-) diff --git a/src/runtime/hexagon/hexagon_buffer.cc b/src/runtime/hexagon/hexagon_buffer.cc index 95bfcaca58ac..77ecd7c5673c 100644 --- a/src/runtime/hexagon/hexagon_buffer.cc +++ b/src/runtime/hexagon/hexagon_buffer.cc @@ -24,8 +24,8 @@ #include #include -#include "hexagon_device_api.h" #include "hexagon_common.h" +#include "hexagon_device_api.h" namespace tvm { namespace runtime { @@ -57,21 +57,21 @@ struct DDRAllocation : public Allocation { struct VTCMAllocation : public Allocation { VTCMAllocation(size_t nbytes, size_t alignment) : Allocation(nbytes, alignment) { - CHECK(allocation_nbytes_ == nbytes); - CHECK(alignment <= 0x800) << "VTCMAllocation called for invalid alignment"; - if ((nbytes & 0x7FF) && ((alignment & 0x7FF) == 0)) { - nbytes = nbytes >> 11; - nbytes = nbytes << 11; - nbytes += 0x800; - LOG(INFO) << "VTCMAllocation size adjusted for alignment " << allocation_nbytes_ << " to " << nbytes; - allocation_nbytes_ = nbytes; - } - - data_ = HexagonDeviceAPI::Global()->VtcmPool()->Allocate(allocation_nbytes_); - LOG(INFO) << "VTCMAllocation " << data_ << " " << allocation_nbytes_ << " " << alignment; + CHECK(allocation_nbytes_ == nbytes); + CHECK(alignment <= 0x800) << "VTCMAllocation called for invalid alignment"; + if ((nbytes & 0x7FF) && ((alignment & 0x7FF) == 0)) { + nbytes = nbytes >> 11; + nbytes = nbytes << 11; + nbytes += 0x800; + DLOG(INFO) << "VTCMAllocation size adjusted for alignment " << allocation_nbytes_ << " to " + << nbytes; + allocation_nbytes_ = nbytes; + } + data_ = HexagonDeviceAPI::Global()->VtcmPool()->Allocate(allocation_nbytes_); + DLOG(INFO) << "VTCMAllocation " << data_ << " " << allocation_nbytes_ << " " << alignment; } ~VTCMAllocation() { - LOG(INFO) << "~VTCMAllocation " << data_ << " " << allocation_nbytes_; + DLOG(INFO) << "~VTCMAllocation " << data_ << " " << allocation_nbytes_; HexagonDeviceAPI::Global()->VtcmPool()->Free(data_, allocation_nbytes_); data_ = nullptr; } diff --git a/src/runtime/hexagon/hexagon_device_api.h b/src/runtime/hexagon/hexagon_device_api.h index d5182fe362e0..1c802f353062 100644 --- a/src/runtime/hexagon/hexagon_device_api.h +++ b/src/runtime/hexagon/hexagon_device_api.h @@ -55,7 +55,6 @@ class HexagonDeviceAPI final : public DeviceAPI { //! \brief Ensures resource managers are in a good state for the runtime void AcquireResources() { - CHECK_EQ(runtime_vtcm, nullptr); runtime_vtcm = std::make_unique(); diff --git a/src/runtime/hexagon/hexagon_vtcm_pool.cc b/src/runtime/hexagon/hexagon_vtcm_pool.cc index c187053287b5..026a465ceeb2 100644 --- a/src/runtime/hexagon/hexagon_vtcm_pool.cc +++ b/src/runtime/hexagon/hexagon_vtcm_pool.cc @@ -30,14 +30,14 @@ HexagonVtcmPool::HexagonVtcmPool() { HEXAGON_SAFE_CALL(HAP_compute_res_attr_init(&res_info)); // TODO(HWE): get the max and min size programmatically - const unsigned int max_size = 4*1024*1024; - const unsigned int min_size = 1024*1024; + const unsigned int max_size = 4 * 1024 * 1024; + const unsigned int min_size = 1024 * 1024; // allocate nbytes of vtcm on a single page HEXAGON_SAFE_CALL(HAP_compute_res_attr_set_vtcm_param_v2(&res_info, - /*vtcm_size = */ max_size, - /*min_page_size = */ 0, - /*min_vtcm_size = */ min_size)); + /*vtcm_size = */ max_size, + /*min_page_size = */ 1, + /*min_vtcm_size = */ min_size)); // TODO(HWE): Investigate why a non-zero timeout results in // hanging, both in the simulator and on hardware. @@ -46,15 +46,13 @@ HexagonVtcmPool::HexagonVtcmPool() { HEXAGON_SAFE_CALL(HAP_compute_res_attr_get_vtcm_ptr_v2(&res_info, &vtcm_data_, &vtcm_size_)); CHECK(vtcm_data_ != nullptr) << "HAP_compute_res_acquire returned nullptr when allocating VTCM."; CHECK(vtcm_size_ >= min_size) - << "HAP_compute_res_acquire failed to allocate minimum amount of VTCM"; - free_.emplace_back(std::pair((char*)vtcm_data_, vtcm_size_)); + << "HAP_compute_res_acquire failed to allocate minimum amount of VTCM"; + free_.emplace_back(std::pair(static_cast(vtcm_data_), vtcm_size_)); - DebugDump(); + // DebugDump(); } -HexagonVtcmPool::~HexagonVtcmPool() { - HEXAGON_SAFE_CALL(HAP_compute_res_release(context_id_)); -} +HexagonVtcmPool::~HexagonVtcmPool() { HEXAGON_SAFE_CALL(HAP_compute_res_release(context_id_)); } void* HexagonVtcmPool::Allocate(size_t nbytes) { std::lock_guard lock(mutex_); @@ -63,20 +61,20 @@ void* HexagonVtcmPool::Allocate(size_t nbytes) { // If this is not aligned on a 2k block, allocate from the end to avoid fragmentation if (nbytes & size_t(0x7FF)) { - LOG(INFO) << "VTCM nbytes requested: " << nbytes << " allocate from the end"; + DLOG(INFO) << "VTCM nbytes requested: " << nbytes << " allocate from the end"; auto last_free_entry = free_.rbegin(); - CHECK(last_free_entry->second >= nbytes) << "Not enough contiguous VTCM space at the end to allocate"; - char* ptr = last_free_entry->first + (last_free_entry->second-nbytes); + CHECK(last_free_entry->second >= nbytes) + << "Not enough contiguous VTCM space at the end to allocate"; + char* ptr = last_free_entry->first + (last_free_entry->second - nbytes); allocations_.emplace_back(std::pair(ptr, nbytes)); last_free_entry->second -= nbytes; - DebugDump(); + // DebugDump(); return ptr; } std::pair& entry_to_allocate = free_.front(); - for(auto entry : free_) { - if ((entry.second < entry_to_allocate.second) && (entry.second >= nbytes)) - { + for (auto entry : free_) { + if ((entry.second < entry_to_allocate.second) && (entry.second >= nbytes)) { entry_to_allocate = entry; if (entry_to_allocate.second == nbytes) { break; @@ -99,18 +97,17 @@ void* HexagonVtcmPool::Allocate(size_t nbytes) { } } - DebugDump(); + // DebugDump(); return ptr; } void HexagonVtcmPool::Free(void* ptr, size_t nbytes) { - char* ptr_to_free = (char*)ptr; + char* ptr_to_free = static_cast(ptr); std::lock_guard lock(mutex_); bool found_allocation_entry = false; - for (auto it = allocations_.begin(); it != allocations_.end(); it++) - { + for (auto it = allocations_.begin(); it != allocations_.end(); it++) { if (ptr_to_free == it->first) { CHECK(it->second == nbytes) << "Attempted to free a different size than was allocated"; allocations_.erase(it); @@ -121,10 +118,11 @@ void HexagonVtcmPool::Free(void* ptr, size_t nbytes) { CHECK(found_allocation_entry) << "Attempted to free a pointer that had not been allocated"; auto it = free_.begin(); - for ( ; it != free_.end(); it++) { + for (; it != free_.end(); it++) { CHECK(ptr_to_free != it->first) << "Attempting to free a pointer that was already free"; if (ptr_to_free < it->first) { - CHECK(ptr_to_free + nbytes <= it->first) << "free_ is in an inconsistent state, freed block overlaps with next"; + CHECK(ptr_to_free + nbytes <= it->first) + << "free_ is in an inconsistent state, freed block overlaps with next"; if (ptr_to_free + nbytes == it->first) { // Make this entry bigger it->first = ptr_to_free; @@ -138,32 +136,32 @@ void HexagonVtcmPool::Free(void* ptr, size_t nbytes) { } if (it == free_.end()) { - // Insert an entry before this + // Insert an entry at the end it = free_.emplace(it, std::pair(ptr_to_free, nbytes)); } // Check for overlap with the previous entry if (it != free_.begin()) { - auto it_prev = it; it_prev--; - CHECK(it_prev->first + it_prev->second <= ptr_to_free) << "free_ is in an inconsistent state, freed block overlaps with previous"; + auto it_prev = it; + it_prev--; + CHECK(it_prev->first + it_prev->second <= ptr_to_free) + << "free_ is in an inconsistent state, freed block overlaps with previous"; if (it_prev->first + it_prev->second == ptr_to_free) { it_prev->second += it->second; free_.erase(it); } } - DebugDump(); + // DebugDump(); } -void HexagonVtcmPool::DebugDump() -{ +void HexagonVtcmPool::DebugDump() { LOG(INFO) << "VTCM list state"; for (auto it = allocations_.begin(); it != allocations_.end(); it++) { - LOG(INFO) << "VTCM alloc: " << (void*)it->first << " " << it->second; + LOG(INFO) << "VTCM alloc: " << static_cast(it->first) << " " << it->second; } - for (auto it = free_.begin(); it != free_.end(); it++) { - LOG(INFO) << "VTCM free: " << (void*)it->first << " " << it->second; + LOG(INFO) << "VTCM free: " << static_cast(it->first) << " " << it->second; } } diff --git a/src/runtime/hexagon/hexagon_vtcm_pool.h b/src/runtime/hexagon/hexagon_vtcm_pool.h index 4c8b61ea7c09..0938ce1433ee 100644 --- a/src/runtime/hexagon/hexagon_vtcm_pool.h +++ b/src/runtime/hexagon/hexagon_vtcm_pool.h @@ -26,8 +26,8 @@ #include #include -#include -#include +#include +#include namespace tvm { namespace runtime { @@ -68,7 +68,7 @@ class HexagonVtcmPool { void Free(void* ptr, size_t nbytes); //! \brief Returns the total number of bytes in this pool - size_t TotalBytes() {return (size_t)vtcm_size_; } + size_t TotalBytes() { return reinterpret_cast(vtcm_size_); } private: //! \brief Context for HAP_compute_res_* diff --git a/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc b/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc index b3f1228d39bc..766b414cd0a5 100644 --- a/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc +++ b/tests/cpp-runtime/hexagon/hexagon_vtcm_pool_tests.cc @@ -25,11 +25,8 @@ using namespace tvm::runtime; using namespace tvm::runtime::hexagon; class HexagonVtcmPoolTest : public ::testing::Test { - void SetUp() override { - vtcm_pool = HexagonDeviceAPI::Global()->VtcmPool(); - } - void TearDown() override { - } + void SetUp() override { vtcm_pool = HexagonDeviceAPI::Global()->VtcmPool(); } + void TearDown() override {} public: HexagonVtcmPool* vtcm_pool; @@ -63,17 +60,17 @@ TEST_F(HexagonVtcmPoolTest, not_enough_free_vtcm) { void* ptr; size_t max_bytes = vtcm_pool->TotalBytes(); size_t two_k_block = 2048; - ptr = vtcm_pool->Allocate(max_bytes-two_k_block); - EXPECT_THROW(vtcm_pool->Allocate(two_k_block*2), InternalError); - vtcm_pool->Free(ptr, max_bytes-two_k_block); + ptr = vtcm_pool->Allocate(max_bytes - two_k_block); + EXPECT_THROW(vtcm_pool->Allocate(two_k_block * 2), InternalError); + vtcm_pool->Free(ptr, max_bytes - two_k_block); } TEST_F(HexagonVtcmPoolTest, free_with_wrong_size) { void* ptr; size_t two_k_block = 2048; - ptr = vtcm_pool->Allocate(two_k_block*2); + ptr = vtcm_pool->Allocate(two_k_block * 2); EXPECT_THROW(vtcm_pool->Free(ptr, two_k_block), InternalError); - vtcm_pool->Free(ptr, two_k_block*2); + vtcm_pool->Free(ptr, two_k_block * 2); } TEST_F(HexagonVtcmPoolTest, free_alloc_combinations) { @@ -83,29 +80,29 @@ TEST_F(HexagonVtcmPoolTest, free_alloc_combinations) { void* ptr4; void* new_ptr; size_t two_k_block = 2048; - size_t max_less_3_blocks = vtcm_pool->TotalBytes()-(3*two_k_block); + size_t max_less_3_blocks = vtcm_pool->TotalBytes() - (3 * two_k_block); ptr1 = vtcm_pool->Allocate(two_k_block); ptr2 = vtcm_pool->Allocate(two_k_block); ptr3 = vtcm_pool->Allocate(two_k_block); ptr4 = vtcm_pool->Allocate(max_less_3_blocks); // Make sure pointers are 2k apart from each other - CHECK((char*)ptr1+two_k_block == (char*)ptr2); - CHECK((char*)ptr2+two_k_block == (char*)ptr3); - CHECK((char*)ptr3+two_k_block == (char*)ptr4); + CHECK(static_cast(ptr1) + two_k_block == static_cast(ptr2)); + CHECK(static_cast(ptr2) + two_k_block == static_cast(ptr3)); + CHECK(static_cast(ptr3) + two_k_block == static_cast(ptr4)); // Free 2, realloc it, make sure it is the same as before vtcm_pool->Free(ptr2, two_k_block); new_ptr = vtcm_pool->Allocate(two_k_block); - CHECK(new_ptr==ptr2); + CHECK(new_ptr == ptr2); // Free 1 and 2, re-alloc and make sure they are the same vtcm_pool->Free(ptr1, two_k_block); vtcm_pool->Free(ptr2, two_k_block); new_ptr = vtcm_pool->Allocate(two_k_block); - CHECK(new_ptr==ptr1); + CHECK(new_ptr == ptr1); new_ptr = vtcm_pool->Allocate(two_k_block); - CHECK(new_ptr==ptr2); + CHECK(new_ptr == ptr2); // Exercise different deletion scenarios vtcm_pool->Free(ptr2, two_k_block); From a6dcf6f0074a0364ba57fcd606307b70de75a2c7 Mon Sep 17 00:00:00 2001 From: Janet Schneider Date: Fri, 30 Sep 2022 13:53:15 -0700 Subject: [PATCH 10/14] disable test_conf2d_fp16_intrin --- src/runtime/hexagon/hexagon_vtcm_pool.cc | 4 ---- .../contrib/test_hexagon/topi/test_conv2d_fp16_intrin.py | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/runtime/hexagon/hexagon_vtcm_pool.cc b/src/runtime/hexagon/hexagon_vtcm_pool.cc index 026a465ceeb2..9dedfa51cd46 100644 --- a/src/runtime/hexagon/hexagon_vtcm_pool.cc +++ b/src/runtime/hexagon/hexagon_vtcm_pool.cc @@ -48,7 +48,6 @@ HexagonVtcmPool::HexagonVtcmPool() { CHECK(vtcm_size_ >= min_size) << "HAP_compute_res_acquire failed to allocate minimum amount of VTCM"; free_.emplace_back(std::pair(static_cast(vtcm_data_), vtcm_size_)); - // DebugDump(); } @@ -96,9 +95,7 @@ void* HexagonVtcmPool::Allocate(size_t nbytes) { break; } } - // DebugDump(); - return ptr; } @@ -151,7 +148,6 @@ void HexagonVtcmPool::Free(void* ptr, size_t nbytes) { free_.erase(it); } } - // DebugDump(); } diff --git a/tests/python/contrib/test_hexagon/topi/test_conv2d_fp16_intrin.py b/tests/python/contrib/test_hexagon/topi/test_conv2d_fp16_intrin.py index e8efdb369590..e7946d04608e 100644 --- a/tests/python/contrib/test_hexagon/topi/test_conv2d_fp16_intrin.py +++ b/tests/python/contrib/test_hexagon/topi/test_conv2d_fp16_intrin.py @@ -195,7 +195,7 @@ class TestConv2dIntrin: inp_offset = tvm.testing.parameter((0, 0), ids=["offset0x0"]) @tvm.testing.requires_hexagon - def test_conv2d(self, act_shape, wgt_shape, inp_stride, inp_offset, hexagon_session): + def DISABLED_test_conv2d(self, act_shape, wgt_shape, inp_stride, inp_offset, hexagon_session): """Test conv2d intrinsic implementation""" assert act_shape[3] == wgt_shape[2] From 40d4790d0fe708454537d0fa0e58bc8485b7f82f Mon Sep 17 00:00:00 2001 From: Janet Schneider Date: Mon, 3 Oct 2022 07:07:49 -0700 Subject: [PATCH 11/14] PR feedback --- src/runtime/hexagon/hexagon_vtcm_pool.cc | 26 +++++++++--------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/runtime/hexagon/hexagon_vtcm_pool.cc b/src/runtime/hexagon/hexagon_vtcm_pool.cc index 9dedfa51cd46..30d03ee538a5 100644 --- a/src/runtime/hexagon/hexagon_vtcm_pool.cc +++ b/src/runtime/hexagon/hexagon_vtcm_pool.cc @@ -103,19 +103,13 @@ void HexagonVtcmPool::Free(void* ptr, size_t nbytes) { char* ptr_to_free = static_cast(ptr); std::lock_guard lock(mutex_); - bool found_allocation_entry = false; - for (auto it = allocations_.begin(); it != allocations_.end(); it++) { - if (ptr_to_free == it->first) { - CHECK(it->second == nbytes) << "Attempted to free a different size than was allocated"; - allocations_.erase(it); - found_allocation_entry = true; - break; - } - } - CHECK(found_allocation_entry) << "Attempted to free a pointer that had not been allocated"; + auto it = std::find_if(allocations_.begin(), allocations_.end(), + [&](auto entry) { return entry.first == ptr_to_free; }); + CHECK(it != allocations_.end()) << "Attempted to free a pointer that had not been allocated"; + CHECK(it->second == nbytes) << "Attempted to free a different size than was allocated"; + allocations_.erase(it); - auto it = free_.begin(); - for (; it != free_.end(); it++) { + for (it = free_.begin(); it != free_.end(); it++) { CHECK(ptr_to_free != it->first) << "Attempting to free a pointer that was already free"; if (ptr_to_free < it->first) { CHECK(ptr_to_free + nbytes <= it->first) @@ -153,11 +147,11 @@ void HexagonVtcmPool::Free(void* ptr, size_t nbytes) { void HexagonVtcmPool::DebugDump() { LOG(INFO) << "VTCM list state"; - for (auto it = allocations_.begin(); it != allocations_.end(); it++) { - LOG(INFO) << "VTCM alloc: " << static_cast(it->first) << " " << it->second; + for (auto entry : allocations_) { + LOG(INFO) << "VTCM alloc: " << static_cast(entry.first) << " " << entry.second; } - for (auto it = free_.begin(); it != free_.end(); it++) { - LOG(INFO) << "VTCM free: " << static_cast(it->first) << " " << it->second; + for (auto entry : free_) { + LOG(INFO) << "VTCM free: " << static_cast(entry.first) << " " << entry.second; } } From b25631be545a2f9e7a9820aa4ceadca075203965 Mon Sep 17 00:00:00 2001 From: Janet Schneider Date: Mon, 3 Oct 2022 10:26:50 -0700 Subject: [PATCH 12/14] PR feedback round 2 --- src/runtime/hexagon/hexagon_vtcm_pool.cc | 60 ++++++++++-------------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/src/runtime/hexagon/hexagon_vtcm_pool.cc b/src/runtime/hexagon/hexagon_vtcm_pool.cc index 30d03ee538a5..1f02e2748ff6 100644 --- a/src/runtime/hexagon/hexagon_vtcm_pool.cc +++ b/src/runtime/hexagon/hexagon_vtcm_pool.cc @@ -71,29 +71,24 @@ void* HexagonVtcmPool::Allocate(size_t nbytes) { return ptr; } - std::pair& entry_to_allocate = free_.front(); - for (auto entry : free_) { - if ((entry.second < entry_to_allocate.second) && (entry.second >= nbytes)) { - entry_to_allocate = entry; - if (entry_to_allocate.second == nbytes) { + auto entry_to_allocate = free_.begin(); + for (auto it = free_.begin(); it != free_.end(); it++) { + if ((it->second < entry_to_allocate->second) && (it->second >= nbytes)) { + entry_to_allocate = it; + if (entry_to_allocate->second == nbytes) { break; } } } - CHECK(entry_to_allocate.second >= nbytes) << "Not enough contiguous VTCM space to allocate"; - char* ptr = entry_to_allocate.first; + CHECK(entry_to_allocate->second >= nbytes) << "Not enough contiguous VTCM space to allocate"; + char* ptr = entry_to_allocate->first; allocations_.emplace(allocations_.end(), std::pair(ptr, nbytes)); - for (auto it = free_.begin(); it != free_.end(); it++) { - if (ptr == it->first) { - if (it->second == nbytes) { - free_.erase(it); - } else { - it->first = it->first + nbytes; - it->second = it->second - nbytes; - } - break; - } + if (entry_to_allocate->second == nbytes) { + free_.erase(entry_to_allocate); + } else { + entry_to_allocate->first = entry_to_allocate->first + nbytes; + entry_to_allocate->second = entry_to_allocate->second - nbytes; } // DebugDump(); return ptr; @@ -109,26 +104,23 @@ void HexagonVtcmPool::Free(void* ptr, size_t nbytes) { CHECK(it->second == nbytes) << "Attempted to free a different size than was allocated"; allocations_.erase(it); - for (it = free_.begin(); it != free_.end(); it++) { - CHECK(ptr_to_free != it->first) << "Attempting to free a pointer that was already free"; - if (ptr_to_free < it->first) { - CHECK(ptr_to_free + nbytes <= it->first) - << "free_ is in an inconsistent state, freed block overlaps with next"; - if (ptr_to_free + nbytes == it->first) { - // Make this entry bigger - it->first = ptr_to_free; - it->second += nbytes; - } else { - // Insert an entry before this - it = free_.emplace(it, std::pair(ptr_to_free, nbytes)); - } - break; - } - } - + it = std::lower_bound(free_.begin(), free_.end(), std::pair(ptr_to_free, nbytes), + [](auto p, auto q) { return p.first <= q.first; }); if (it == free_.end()) { // Insert an entry at the end it = free_.emplace(it, std::pair(ptr_to_free, nbytes)); + } else { + CHECK(ptr_to_free != it->first) << "Attempting to free a pointer that was already free"; + CHECK(ptr_to_free + nbytes <= it->first) + << "free_ is in an inconsistent state, freed block overlaps with next"; + if (ptr_to_free + nbytes == it->first) { + // Make this entry bigger + it->first = ptr_to_free; + it->second += nbytes; + } else { + // Insert an entry before this + it = free_.emplace(it, std::pair(ptr_to_free, nbytes)); + } } // Check for overlap with the previous entry From 3b5fd4b75c6b1a7ce74ea4f8dac40ee4324fc01c Mon Sep 17 00:00:00 2001 From: Janet Schneider Date: Mon, 3 Oct 2022 10:49:15 -0700 Subject: [PATCH 13/14] Use vectors instead of lists --- src/runtime/hexagon/hexagon_vtcm_pool.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/hexagon/hexagon_vtcm_pool.h b/src/runtime/hexagon/hexagon_vtcm_pool.h index 0938ce1433ee..71306d144a89 100644 --- a/src/runtime/hexagon/hexagon_vtcm_pool.h +++ b/src/runtime/hexagon/hexagon_vtcm_pool.h @@ -81,10 +81,10 @@ class HexagonVtcmPool { unsigned int context_id_{0}; //! \brief List of allocations - std::list> allocations_; + std::vector> allocations_; //! \brief List of free segments - std::list> free_; + std::vector> free_; //! \brief Mutext to protect access to the lists std::mutex mutex_; From 3225011c006c902580bcf953fb49aa9ccdf09214 Mon Sep 17 00:00:00 2001 From: Janet Schneider Date: Mon, 3 Oct 2022 11:27:03 -0700 Subject: [PATCH 14/14] Lint, add comment on alignment --- src/runtime/hexagon/hexagon_buffer.cc | 4 +++- src/runtime/hexagon/hexagon_vtcm_pool.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/runtime/hexagon/hexagon_buffer.cc b/src/runtime/hexagon/hexagon_buffer.cc index 77ecd7c5673c..861a8d9f4f7a 100644 --- a/src/runtime/hexagon/hexagon_buffer.cc +++ b/src/runtime/hexagon/hexagon_buffer.cc @@ -57,9 +57,11 @@ struct DDRAllocation : public Allocation { struct VTCMAllocation : public Allocation { VTCMAllocation(size_t nbytes, size_t alignment) : Allocation(nbytes, alignment) { - CHECK(allocation_nbytes_ == nbytes); + // TODO(HWE): Handle alignments greater than 2k CHECK(alignment <= 0x800) << "VTCMAllocation called for invalid alignment"; if ((nbytes & 0x7FF) && ((alignment & 0x7FF) == 0)) { + // Caller has requested 2k alignment, but the size is not a multiple of 2k + // Adjust size to be a multiple of 2k so that we will allocate from the front of the pool nbytes = nbytes >> 11; nbytes = nbytes << 11; nbytes += 0x800; diff --git a/src/runtime/hexagon/hexagon_vtcm_pool.h b/src/runtime/hexagon/hexagon_vtcm_pool.h index 71306d144a89..e1292e4e10d7 100644 --- a/src/runtime/hexagon/hexagon_vtcm_pool.h +++ b/src/runtime/hexagon/hexagon_vtcm_pool.h @@ -26,8 +26,8 @@ #include #include -#include #include +#include namespace tvm { namespace runtime {