From 92b6ca7127ce4032a3b24f001d67cb798512a734 Mon Sep 17 00:00:00 2001 From: Liangfu Chen Date: Tue, 27 Aug 2019 00:36:23 +0800 Subject: [PATCH] [VTA][TSIM] Introduce Virtual Memory for TSIM Driver (#3686) * initial virtual memory; * initial integration; * include the header file in cmake; * implement allocation with virtual to logical address mapping; * virtual memory for tsim_driver; * implement the missing memory release function; * readability improvement; * readability improvement; * address review comments; * improved robustness in virtual memory allocation; * remove VTA_TSIM_USE_VIRTUAL_MEMORY macro and use virtual memory for tsim by default; * link tvm against vta library; * merge with master * build virtual memory system without linking tvm against vta; * minor change; * reuse VTA_PAGE_BYTES; * using DRAM class from sim_driver as VirtualMemoryManager; * satisfy linter; * add comments in code; * undo changes to Makefile * undo changes to Makefile * retrigger ci; * retrigger ci; * directly call into VirtualMemoryManager::Global() --- cmake/modules/VTA.cmake | 2 + vta/src/dpi/module.cc | 9 ++- vta/src/sim/sim_driver.cc | 110 +------------------------------- vta/src/tsim/tsim_driver.cc | 13 ++-- vta/src/vmem/virtual_memory.cc | 140 +++++++++++++++++++++++++++++++++++++++++ vta/src/vmem/virtual_memory.h | 130 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 290 insertions(+), 114 deletions(-) create mode 100644 vta/src/vmem/virtual_memory.cc create mode 100644 vta/src/vmem/virtual_memory.h diff --git a/cmake/modules/VTA.cmake b/cmake/modules/VTA.cmake index 59903db..fe423ce 100644 --- a/cmake/modules/VTA.cmake +++ b/cmake/modules/VTA.cmake @@ -42,6 +42,7 @@ elseif(PYTHON) # Add fsim driver sources file(GLOB FSIM_RUNTIME_SRCS vta/src/*.cc) list(APPEND FSIM_RUNTIME_SRCS vta/src/sim/sim_driver.cc) + list(APPEND FSIM_RUNTIME_SRCS vta/src/vmem/virtual_memory.cc vta/src/vmem/virtual_memory.h) # Target lib: vta_fsim add_library(vta_fsim SHARED ${FSIM_RUNTIME_SRCS}) target_include_directories(vta_fsim PUBLIC vta/include) @@ -61,6 +62,7 @@ elseif(PYTHON) file(GLOB TSIM_RUNTIME_SRCS vta/src/*.cc) list(APPEND TSIM_RUNTIME_SRCS vta/src/tsim/tsim_driver.cc) list(APPEND TSIM_RUNTIME_SRCS vta/src/dpi/module.cc) + list(APPEND TSIM_RUNTIME_SRCS vta/src/vmem/virtual_memory.cc vta/src/vmem/virtual_memory.h) # Target lib: vta_tsim add_library(vta_tsim SHARED ${TSIM_RUNTIME_SRCS}) target_include_directories(vta_tsim PUBLIC vta/include) diff --git a/vta/src/dpi/module.cc b/vta/src/dpi/module.cc index c1dcbb7..6ef6af8 100644 --- a/vta/src/dpi/module.cc +++ b/vta/src/dpi/module.cc @@ -33,6 +33,9 @@ #include #include #include +#include + +#include "../vmem/virtual_memory.h" namespace vta { namespace dpi { @@ -179,12 +182,14 @@ void HostDevice::WaitPopResponse(HostResponse* r) { void MemDevice::SetRequest(uint8_t opcode, uint64_t addr, uint32_t len) { std::lock_guard lock(mutex_); + void * vaddr = vta::vmem::VirtualMemoryManager::Global()->GetAddr(addr); + if (opcode == 1) { wlen_ = len + 1; - waddr_ = reinterpret_cast(addr); + waddr_ = reinterpret_cast(vaddr); } else { rlen_ = len + 1; - raddr_ = reinterpret_cast(addr); + raddr_ = reinterpret_cast(vaddr); } } diff --git a/vta/src/sim/sim_driver.cc b/vta/src/sim/sim_driver.cc index 04fba6b..eb49712 100644 --- a/vta/src/sim/sim_driver.cc +++ b/vta/src/sim/sim_driver.cc @@ -32,6 +32,8 @@ #include #include +#include "../vmem/virtual_memory.h" + namespace vta { namespace sim { @@ -125,113 +127,7 @@ class BitPacker { * \brief DRAM memory manager * Implements simple paging to allow physical address translation. */ -class DRAM { - public: - /*! - * \brief Get virtual address given physical address. - * \param phy_addr The simulator phyiscal address. - * \return The true virtual address; - */ - void* GetAddr(uint64_t phy_addr) { - CHECK_NE(phy_addr, 0) - << "trying to get address that is nullptr"; - std::lock_guard lock(mutex_); - uint64_t loc = (phy_addr >> kPageBits) - 1; - CHECK_LT(loc, ptable_.size()) - << "phy_addr=" << phy_addr; - Page* p = ptable_[loc]; - CHECK(p != nullptr); - size_t offset = (loc - p->ptable_begin) << kPageBits; - offset += phy_addr & (kPageSize - 1); - return reinterpret_cast(p->data) + offset; - } - /*! - * \brief Get physical address - * \param buf The virtual address. - * \return The true physical address; - */ - vta_phy_addr_t GetPhyAddr(void* buf) { - std::lock_guard lock(mutex_); - auto it = pmap_.find(buf); - CHECK(it != pmap_.end()); - Page* p = it->second.get(); - return (p->ptable_begin + 1) << kPageBits; - } - /*! - * \brief Allocate memory from manager - * \param size The size of memory - * \return The virtual address - */ - void* Alloc(size_t size) { - std::lock_guard lock(mutex_); - size_t npage = (size + kPageSize - 1) / kPageSize; - auto it = free_map_.lower_bound(npage); - if (it != free_map_.end()) { - Page* p = it->second; - free_map_.erase(it); - return p->data; - } - size_t start = ptable_.size(); - std::unique_ptr p(new Page(start, npage)); - // insert page entry - ptable_.resize(start + npage, p.get()); - void* data = p->data; - pmap_[data] = std::move(p); - return data; - } - /*! - * \brief Free the memory. - * \param size The size of memory - * \return The virtual address - */ - void Free(void* data) { - std::lock_guard lock(mutex_); - if (pmap_.size() == 0) return; - auto it = pmap_.find(data); - CHECK(it != pmap_.end()); - Page* p = it->second.get(); - free_map_.insert(std::make_pair(p->num_pages, p)); - } - - static DRAM* Global() { - static DRAM inst; - return &inst; - } - - - private: - // The bits in page table - static constexpr vta_phy_addr_t kPageBits = VTA_PAGE_BITS; - // page size, also the maximum allocable size 16 K - static constexpr vta_phy_addr_t kPageSize = VTA_PAGE_BYTES; - /*! \brief A page in the DRAM */ - struct Page { - /*! \brief Data Type */ - using DType = typename std::aligned_storage::type; - /*! \brief Start location in page table */ - size_t ptable_begin; - /*! \brief The total number of pages */ - size_t num_pages; - /*! \brief Data */ - DType* data{nullptr}; - // construct a new page - explicit Page(size_t ptable_begin, size_t num_pages) - : ptable_begin(ptable_begin), num_pages(num_pages) { - data = new DType[num_pages]; - } - ~Page() { - delete [] data; - } - }; - // Internal lock - std::mutex mutex_; - // Physical address -> page - std::vector ptable_; - // virtual addres -> page - std::unordered_map > pmap_; - // Free map - std::multimap free_map_; -}; +using DRAM = ::vta::vmem::VirtualMemoryManager; /*! * \brief Register file. diff --git a/vta/src/tsim/tsim_driver.cc b/vta/src/tsim/tsim_driver.cc index a7bcc3c..77ca266 100644 --- a/vta/src/tsim/tsim_driver.cc +++ b/vta/src/tsim/tsim_driver.cc @@ -22,6 +22,8 @@ #include #include +#include "../vmem/virtual_memory.h" + namespace vta { namespace tsim { @@ -208,12 +210,13 @@ TVM_REGISTER_GLOBAL("vta.tsim.profiler_status") } // namespace vta void* VTAMemAlloc(size_t size, int cached) { - void *p = malloc(size); - return p; + void * addr = vta::vmem::VirtualMemoryManager::Global()->Alloc(size); + return reinterpret_cast(vta::vmem::VirtualMemoryManager::Global()->GetPhyAddr(addr)); } void VTAMemFree(void* buf) { - free(buf); + void * addr = vta::vmem::VirtualMemoryManager::Global()->GetAddr(reinterpret_cast(buf)); + vta::vmem::VirtualMemoryManager::Global()->Free(addr); } vta_phy_addr_t VTAMemGetPhyAddr(void* buf) { @@ -221,11 +224,11 @@ vta_phy_addr_t VTAMemGetPhyAddr(void* buf) { } void VTAMemCopyFromHost(void* dst, const void* src, size_t size) { - memcpy(dst, src, size); + vta::vmem::VirtualMemoryManager::Global()->MemCopyFromHost(dst, src, size); } void VTAMemCopyToHost(void* dst, const void* src, size_t size) { - memcpy(dst, src, size); + vta::vmem::VirtualMemoryManager::Global()->MemCopyToHost(dst, src, size); } void VTAFlushCache(void* vir_addr, vta_phy_addr_t phy_addr, int size) { diff --git a/vta/src/vmem/virtual_memory.cc b/vta/src/vmem/virtual_memory.cc new file mode 100644 index 0000000..18dc1df --- /dev/null +++ b/vta/src/vmem/virtual_memory.cc @@ -0,0 +1,140 @@ +/* + * 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. + */ + +/*! + * Copyright (c) 2019 by Contributors + * \file virtual_memory.cc + * \brief Thread-safe virtal memory manager + */ + +#include "virtual_memory.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace vta { +namespace vmem { + +/*! + * \brief Get virtual address given physical address. + * \param phy_addr The simulator phyiscal address. + * \return The true virtual address; + */ +void* VirtualMemoryManager::GetAddr(uint64_t phy_addr) { + CHECK_NE(phy_addr, 0) + << "trying to get address that is nullptr"; + std::lock_guard lock(mutex_); + uint64_t loc = (phy_addr >> kPageBits) - 1; + CHECK_LT(loc, ptable_.size()) + << "phy_addr=" << phy_addr; + Page* p = ptable_[loc]; + CHECK(p != nullptr); + size_t offset = (loc - p->ptable_begin) << kPageBits; + offset += phy_addr & (kPageSize - 1); + return reinterpret_cast(p->data) + offset; +} + +/*! + * \brief Get physical address + * \param buf The virtual address. + * \return The true physical address; + */ +vta_phy_addr_t VirtualMemoryManager::GetPhyAddr(void* buf) { + std::lock_guard lock(mutex_); + auto it = pmap_.find(buf); + CHECK(it != pmap_.end()); + Page* p = it->second.get(); + return (p->ptable_begin + 1) << kPageBits; +} + +/*! + * \brief Allocate memory from manager + * \param size The size of memory + * \return The virtual address + */ +void* VirtualMemoryManager::Alloc(size_t size) { + std::lock_guard lock(mutex_); + size_t npage = (size + kPageSize - 1) / kPageSize; + auto it = free_map_.lower_bound(npage); + if (it != free_map_.end()) { + Page* p = it->second; + free_map_.erase(it); + return p->data; + } + size_t start = ptable_.size(); + std::unique_ptr p(new Page(start, npage)); + // insert page entry + ptable_.resize(start + npage, p.get()); + void* data = p->data; + pmap_[data] = std::move(p); + return data; +} + +/*! + * \brief Free the memory. + * \param size The size of memory + * \return The virtual address + */ +void VirtualMemoryManager::Free(void* data) { + std::lock_guard lock(mutex_); + if (pmap_.size() == 0) return; + auto it = pmap_.find(data); + CHECK(it != pmap_.end()); + Page* p = it->second.get(); + free_map_.insert(std::make_pair(p->num_pages, p)); +} + +/*! + * \brief Copy from the host memory to device memory (virtual). + * \param dst The device memory address (virtual) + * \param src The host memory address + * \param size The size of memory + */ +void VirtualMemoryManager::MemCopyFromHost(void* dst, const void * src, size_t size) { + void * addr = this->GetAddr(reinterpret_cast(dst)); + memcpy(addr, src, size); +} + +/*! + * \brief Copy from the device memory (virtual) to host memory. + * \param dst The host memory address + * \param src The device memory address (virtual) + * \param size The size of memory + */ +void VirtualMemoryManager::MemCopyToHost(void* dst, const void * src, size_t size) { + void * addr = this->GetAddr(reinterpret_cast(src)); + memcpy(dst, addr, size); +} + +VirtualMemoryManager* VirtualMemoryManager::Global() { + static VirtualMemoryManager inst; + return &inst; +} + +} // namespace vmem +} // namespace vta diff --git a/vta/src/vmem/virtual_memory.h b/vta/src/vmem/virtual_memory.h new file mode 100644 index 0000000..9f1cbc1 --- /dev/null +++ b/vta/src/vmem/virtual_memory.h @@ -0,0 +1,130 @@ +/* + * 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. + */ + +/*! + * Copyright (c) 2019 by Contributors + * \file virtual_memory.h + * \brief The virtual memory manager for device simulation + */ + +#ifndef VTA_VMEM_VIRTUAL_MEMORY_H_ +#define VTA_VMEM_VIRTUAL_MEMORY_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +enum VMemCopyType { + kVirtualMemCopyFromHost = 0, + kVirtualMemCopyToHost = 1 +}; + +namespace vta { +namespace vmem { + +/*! + * \brief DRAM memory manager + * Implements simple paging to allow physical address translation. + */ +class VirtualMemoryManager { + public: + /*! + * \brief Get virtual address given physical address. + * \param phy_addr The simulator phyiscal address. + * \return The true virtual address; + */ + void* GetAddr(uint64_t phy_addr); + /*! + * \brief Get physical address + * \param buf The virtual address. + * \return The true physical address; + */ + vta_phy_addr_t GetPhyAddr(void* buf); + /*! + * \brief Allocate memory from manager + * \param size The size of memory + * \return The virtual address + */ + void* Alloc(size_t size); + /*! + * \brief Free the memory. + * \param size The size of memory + * \return The virtual address + */ + void Free(void* data); + /*! + * \brief Copy from the host memory to device memory (virtual). + * \param dst The device memory address (virtual) + * \param src The host memory address + * \param size The size of memory + */ + void MemCopyFromHost(void* dst, const void * src, size_t size); + /*! + * \brief Copy from the device memory (virtual) to host memory. + * \param dst The host memory address + * \param src The device memory address (virtual) + * \param size The size of memory + */ + void MemCopyToHost(void* dst, const void * src, size_t size); + static VirtualMemoryManager* Global(); + + private: + // The bits in page table + static constexpr vta_phy_addr_t kPageBits = VTA_PAGE_BITS; + // page size, also the maximum allocable size 16 K + static constexpr vta_phy_addr_t kPageSize = VTA_PAGE_BYTES; + /*! \brief A page in the DRAM */ + struct Page { + /*! \brief Data Type */ + using DType = typename std::aligned_storage::type; + /*! \brief Start location in page table */ + size_t ptable_begin; + /*! \brief The total number of pages */ + size_t num_pages; + /*! \brief Data */ + DType* data{nullptr}; + // construct a new page + explicit Page(size_t ptable_begin, size_t num_pages) + : ptable_begin(ptable_begin), num_pages(num_pages) { + data = new DType[num_pages]; + } + ~Page() { + delete [] data; + } + }; + // Internal lock + std::mutex mutex_; + // Physical address -> page + std::vector ptable_; + // virtual addres -> page + std::unordered_map > pmap_; + // Free map + std::multimap free_map_; +}; + + +} // namespace vmem +} // namespace vta + +#endif // VTA_VMEM_VIRTUAL_MEMORY_H_ -- 2.7.4