Skip to content

Commit 9eff1d2

Browse files
liangfutmoreau89
authored andcommitted
[VTA][TSIM] Introduce Virtual Memory for TSIM Driver (apache#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()
1 parent 1a207bf commit 9eff1d2

5 files changed

Lines changed: 288 additions & 114 deletions

File tree

src/dpi/module.cc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
#include <queue>
3434
#include <thread>
3535
#include <condition_variable>
36+
#include <fstream>
37+
38+
#include "../vmem/virtual_memory.h"
3639

3740
namespace vta {
3841
namespace dpi {
@@ -179,12 +182,14 @@ void HostDevice::WaitPopResponse(HostResponse* r) {
179182

180183
void MemDevice::SetRequest(uint8_t opcode, uint64_t addr, uint32_t len) {
181184
std::lock_guard<std::mutex> lock(mutex_);
185+
void * vaddr = vta::vmem::VirtualMemoryManager::Global()->GetAddr(addr);
186+
182187
if (opcode == 1) {
183188
wlen_ = len + 1;
184-
waddr_ = reinterpret_cast<uint64_t*>(addr);
189+
waddr_ = reinterpret_cast<uint64_t*>(vaddr);
185190
} else {
186191
rlen_ = len + 1;
187-
raddr_ = reinterpret_cast<uint64_t*>(addr);
192+
raddr_ = reinterpret_cast<uint64_t*>(vaddr);
188193
}
189194
}
190195

src/sim/sim_driver.cc

Lines changed: 3 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
#include <cstring>
3333
#include <sstream>
3434

35+
#include "../vmem/virtual_memory.h"
36+
3537
namespace vta {
3638
namespace sim {
3739

@@ -125,113 +127,7 @@ class BitPacker {
125127
* \brief DRAM memory manager
126128
* Implements simple paging to allow physical address translation.
127129
*/
128-
class DRAM {
129-
public:
130-
/*!
131-
* \brief Get virtual address given physical address.
132-
* \param phy_addr The simulator phyiscal address.
133-
* \return The true virtual address;
134-
*/
135-
void* GetAddr(uint64_t phy_addr) {
136-
CHECK_NE(phy_addr, 0)
137-
<< "trying to get address that is nullptr";
138-
std::lock_guard<std::mutex> lock(mutex_);
139-
uint64_t loc = (phy_addr >> kPageBits) - 1;
140-
CHECK_LT(loc, ptable_.size())
141-
<< "phy_addr=" << phy_addr;
142-
Page* p = ptable_[loc];
143-
CHECK(p != nullptr);
144-
size_t offset = (loc - p->ptable_begin) << kPageBits;
145-
offset += phy_addr & (kPageSize - 1);
146-
return reinterpret_cast<char*>(p->data) + offset;
147-
}
148-
/*!
149-
* \brief Get physical address
150-
* \param buf The virtual address.
151-
* \return The true physical address;
152-
*/
153-
vta_phy_addr_t GetPhyAddr(void* buf) {
154-
std::lock_guard<std::mutex> lock(mutex_);
155-
auto it = pmap_.find(buf);
156-
CHECK(it != pmap_.end());
157-
Page* p = it->second.get();
158-
return (p->ptable_begin + 1) << kPageBits;
159-
}
160-
/*!
161-
* \brief Allocate memory from manager
162-
* \param size The size of memory
163-
* \return The virtual address
164-
*/
165-
void* Alloc(size_t size) {
166-
std::lock_guard<std::mutex> lock(mutex_);
167-
size_t npage = (size + kPageSize - 1) / kPageSize;
168-
auto it = free_map_.lower_bound(npage);
169-
if (it != free_map_.end()) {
170-
Page* p = it->second;
171-
free_map_.erase(it);
172-
return p->data;
173-
}
174-
size_t start = ptable_.size();
175-
std::unique_ptr<Page> p(new Page(start, npage));
176-
// insert page entry
177-
ptable_.resize(start + npage, p.get());
178-
void* data = p->data;
179-
pmap_[data] = std::move(p);
180-
return data;
181-
}
182-
/*!
183-
* \brief Free the memory.
184-
* \param size The size of memory
185-
* \return The virtual address
186-
*/
187-
void Free(void* data) {
188-
std::lock_guard<std::mutex> lock(mutex_);
189-
if (pmap_.size() == 0) return;
190-
auto it = pmap_.find(data);
191-
CHECK(it != pmap_.end());
192-
Page* p = it->second.get();
193-
free_map_.insert(std::make_pair(p->num_pages, p));
194-
}
195-
196-
static DRAM* Global() {
197-
static DRAM inst;
198-
return &inst;
199-
}
200-
201-
202-
private:
203-
// The bits in page table
204-
static constexpr vta_phy_addr_t kPageBits = VTA_PAGE_BITS;
205-
// page size, also the maximum allocable size 16 K
206-
static constexpr vta_phy_addr_t kPageSize = VTA_PAGE_BYTES;
207-
/*! \brief A page in the DRAM */
208-
struct Page {
209-
/*! \brief Data Type */
210-
using DType = typename std::aligned_storage<kPageSize, 256>::type;
211-
/*! \brief Start location in page table */
212-
size_t ptable_begin;
213-
/*! \brief The total number of pages */
214-
size_t num_pages;
215-
/*! \brief Data */
216-
DType* data{nullptr};
217-
// construct a new page
218-
explicit Page(size_t ptable_begin, size_t num_pages)
219-
: ptable_begin(ptable_begin), num_pages(num_pages) {
220-
data = new DType[num_pages];
221-
}
222-
~Page() {
223-
delete [] data;
224-
}
225-
};
226-
// Internal lock
227-
std::mutex mutex_;
228-
// Physical address -> page
229-
std::vector<Page*> ptable_;
230-
// virtual addres -> page
231-
std::unordered_map<void*, std::unique_ptr<Page> > pmap_;
232-
// Free map
233-
std::multimap<size_t, Page*> free_map_;
234-
};
130+
using DRAM = ::vta::vmem::VirtualMemoryManager;
235131

236132
/*!
237133
* \brief Register file.

src/tsim/tsim_driver.cc

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include <vta/driver.h>
2323
#include <vta/dpi/module.h>
2424

25+
#include "../vmem/virtual_memory.h"
26+
2527
namespace vta {
2628
namespace tsim {
2729

@@ -208,24 +210,25 @@ TVM_REGISTER_GLOBAL("vta.tsim.profiler_status")
208210
} // namespace vta
209211

210212
void* VTAMemAlloc(size_t size, int cached) {
211-
void *p = malloc(size);
212-
return p;
213+
void * addr = vta::vmem::VirtualMemoryManager::Global()->Alloc(size);
214+
return reinterpret_cast<void*>(vta::vmem::VirtualMemoryManager::Global()->GetPhyAddr(addr));
213215
}
214216

215217
void VTAMemFree(void* buf) {
216-
free(buf);
218+
void * addr = vta::vmem::VirtualMemoryManager::Global()->GetAddr(reinterpret_cast<uint64_t>(buf));
219+
vta::vmem::VirtualMemoryManager::Global()->Free(addr);
217220
}
218221

219222
vta_phy_addr_t VTAMemGetPhyAddr(void* buf) {
220223
return reinterpret_cast<uint64_t>(reinterpret_cast<uint64_t*>(buf));
221224
}
222225

223226
void VTAMemCopyFromHost(void* dst, const void* src, size_t size) {
224-
memcpy(dst, src, size);
227+
vta::vmem::VirtualMemoryManager::Global()->MemCopyFromHost(dst, src, size);
225228
}
226229

227230
void VTAMemCopyToHost(void* dst, const void* src, size_t size) {
228-
memcpy(dst, src, size);
231+
vta::vmem::VirtualMemoryManager::Global()->MemCopyToHost(dst, src, size);
229232
}
230233

231234
void VTAFlushCache(void* vir_addr, vta_phy_addr_t phy_addr, int size) {

src/vmem/virtual_memory.cc

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
/*!
21+
* Copyright (c) 2019 by Contributors
22+
* \file virtual_memory.cc
23+
* \brief Thread-safe virtal memory manager
24+
*/
25+
26+
#include "virtual_memory.h"
27+
28+
#include <dmlc/logging.h>
29+
#include <vta/driver.h>
30+
#include <cstdint>
31+
#include <cstdlib>
32+
#include <cstring>
33+
#include <list>
34+
#include <utility>
35+
#include <iterator>
36+
#include <unordered_map>
37+
#include <map>
38+
#include <mutex>
39+
40+
namespace vta {
41+
namespace vmem {
42+
43+
/*!
44+
* \brief Get virtual address given physical address.
45+
* \param phy_addr The simulator phyiscal address.
46+
* \return The true virtual address;
47+
*/
48+
void* VirtualMemoryManager::GetAddr(uint64_t phy_addr) {
49+
CHECK_NE(phy_addr, 0)
50+
<< "trying to get address that is nullptr";
51+
std::lock_guard<std::mutex> lock(mutex_);
52+
uint64_t loc = (phy_addr >> kPageBits) - 1;
53+
CHECK_LT(loc, ptable_.size())
54+
<< "phy_addr=" << phy_addr;
55+
Page* p = ptable_[loc];
56+
CHECK(p != nullptr);
57+
size_t offset = (loc - p->ptable_begin) << kPageBits;
58+
offset += phy_addr & (kPageSize - 1);
59+
return reinterpret_cast<char*>(p->data) + offset;
60+
}
61+
62+
/*!
63+
* \brief Get physical address
64+
* \param buf The virtual address.
65+
* \return The true physical address;
66+
*/
67+
vta_phy_addr_t VirtualMemoryManager::GetPhyAddr(void* buf) {
68+
std::lock_guard<std::mutex> lock(mutex_);
69+
auto it = pmap_.find(buf);
70+
CHECK(it != pmap_.end());
71+
Page* p = it->second.get();
72+
return (p->ptable_begin + 1) << kPageBits;
73+
}
74+
75+
/*!
76+
* \brief Allocate memory from manager
77+
* \param size The size of memory
78+
* \return The virtual address
79+
*/
80+
void* VirtualMemoryManager::Alloc(size_t size) {
81+
std::lock_guard<std::mutex> lock(mutex_);
82+
size_t npage = (size + kPageSize - 1) / kPageSize;
83+
auto it = free_map_.lower_bound(npage);
84+
if (it != free_map_.end()) {
85+
Page* p = it->second;
86+
free_map_.erase(it);
87+
return p->data;
88+
}
89+
size_t start = ptable_.size();
90+
std::unique_ptr<Page> p(new Page(start, npage));
91+
// insert page entry
92+
ptable_.resize(start + npage, p.get());
93+
void* data = p->data;
94+
pmap_[data] = std::move(p);
95+
return data;
96+
}
97+
98+
/*!
99+
* \brief Free the memory.
100+
* \param size The size of memory
101+
* \return The virtual address
102+
*/
103+
void VirtualMemoryManager::Free(void* data) {
104+
std::lock_guard<std::mutex> lock(mutex_);
105+
if (pmap_.size() == 0) return;
106+
auto it = pmap_.find(data);
107+
CHECK(it != pmap_.end());
108+
Page* p = it->second.get();
109+
free_map_.insert(std::make_pair(p->num_pages, p));
110+
}
111+
112+
/*!
113+
* \brief Copy from the host memory to device memory (virtual).
114+
* \param dst The device memory address (virtual)
115+
* \param src The host memory address
116+
* \param size The size of memory
117+
*/
118+
void VirtualMemoryManager::MemCopyFromHost(void* dst, const void * src, size_t size) {
119+
void * addr = this->GetAddr(reinterpret_cast<uint64_t>(dst));
120+
memcpy(addr, src, size);
121+
}
122+
123+
/*!
124+
* \brief Copy from the device memory (virtual) to host memory.
125+
* \param dst The host memory address
126+
* \param src The device memory address (virtual)
127+
* \param size The size of memory
128+
*/
129+
void VirtualMemoryManager::MemCopyToHost(void* dst, const void * src, size_t size) {
130+
void * addr = this->GetAddr(reinterpret_cast<uint64_t>(src));
131+
memcpy(dst, addr, size);
132+
}
133+
134+
VirtualMemoryManager* VirtualMemoryManager::Global() {
135+
static VirtualMemoryManager inst;
136+
return &inst;
137+
}
138+
139+
} // namespace vmem
140+
} // namespace vta

0 commit comments

Comments
 (0)