Skip to content

Commit 5fe84df

Browse files
committed
Added new version of Romulus that works with Optane DC PM
1 parent 4e418b5 commit 5fe84df

4 files changed

Lines changed: 476 additions & 330 deletions

File tree

ptms/romuluslog/RomulusLog.cpp

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,215 @@ RomulusLog gRomLog {};
2323
*
2424
*
2525
*/
26+
#ifdef USE_ESLOCO
27+
#else
28+
mspace create_mspace_with_base(void* base, size_t capacity, int locked);
29+
#endif
30+
//
31+
// Private methods
32+
//
2633

34+
// Copy the data from 'main' to 'back'
35+
void RomulusLog::copyMainToBack() {
36+
uint64_t size = std::min(per->used_size,g_main_size);
37+
std::memcpy(back_addr, main_addr, size);
38+
flush_range(back_addr, size);
39+
}
40+
41+
// Copy the data from 'back' to 'main'
42+
void RomulusLog::copyBackToMain() {
43+
uint64_t size = std::min(per->used_size,g_main_size);
44+
std::memcpy(main_addr, back_addr, size);
45+
flush_range(main_addr, size);
46+
}
47+
48+
RomulusLog::RomulusLog() : dommap{true},maxThreads{128} {
49+
fc = new std::atomic< std::function<void()>* >[maxThreads*CLPAD];
50+
for (int i = 0; i < maxThreads; i++) {
51+
fc[i*CLPAD].store(nullptr, std::memory_order_relaxed);
52+
}
53+
// Filename for the mapping file
54+
if (dommap) {
55+
base_addr = (uint8_t*)0x7fdd40000000;
56+
max_size = PM_REGION_SIZE;
57+
// Check if the file already exists or not
58+
struct stat buf;
59+
if (stat(MMAP_FILENAME, &buf) == 0) {
60+
// File exists
61+
//std::cout << "Re-using memory region\n";
62+
fd = open(MMAP_FILENAME, O_RDWR|O_CREAT, 0755);
63+
assert(fd >= 0);
64+
// mmap() memory range
65+
uint8_t* got_addr = (uint8_t *)mmap(base_addr, max_size, (PROT_READ | PROT_WRITE), MAP_SHARED_VALIDATE | PM_FLAGS, fd, 0);
66+
if (got_addr == MAP_FAILED || got_addr != base_addr) {
67+
perror("ERROR: mmap() is not working !!! ");
68+
printf("got_addr = %p instead of %p\n", got_addr, base_addr);
69+
assert(false);
70+
}
71+
per = reinterpret_cast<PersistentHeader*>(base_addr);
72+
if (per->id != MAGIC_ID) createFile();
73+
g_main_size = (max_size - sizeof(PersistentHeader))/2;
74+
main_addr = base_addr + sizeof(PersistentHeader);
75+
back_addr = main_addr + g_main_size;
76+
g_main_addr = main_addr;
77+
recover();
78+
} else {
79+
createFile();
80+
}
81+
}
82+
}
2783

2884

85+
RomulusLog::~RomulusLog() {
86+
delete[] fc;
87+
// Must do munmap() if we did mmap()
88+
if (dommap) {
89+
//destroy_mspace(ms);
90+
munmap(base_addr, max_size);
91+
close(fd);
92+
}
93+
if(histoflag){
94+
for(int i=0;i<300;i++){
95+
std::cout<<i<<":"<<histo[i]<<"\n";
96+
}
97+
}
98+
}
99+
100+
void RomulusLog::createFile(){
101+
// File doesn't exist
102+
fd = open(MMAP_FILENAME, O_RDWR|O_CREAT, 0755);
103+
assert(fd >= 0);
104+
if (lseek(fd, max_size-1, SEEK_SET) == -1) {
105+
perror("lseek() error");
106+
}
107+
if (write(fd, "", 1) == -1) {
108+
perror("write() error");
109+
}
110+
// mmap() memory range
111+
uint8_t* got_addr = (uint8_t *)mmap(base_addr, max_size, (PROT_READ | PROT_WRITE), MAP_SHARED_VALIDATE | PM_FLAGS, fd, 0);
112+
if (got_addr == MAP_FAILED || got_addr != base_addr) {
113+
perror("ERROR: mmap() is not working !!! ");
114+
printf("got_addr = %p instead of %p\n", got_addr, base_addr);
115+
assert(false);
116+
}
117+
// No data in persistent memory, initialize
118+
per = new (base_addr) PersistentHeader;
119+
g_main_size = (max_size - sizeof(PersistentHeader))/2;
120+
main_addr = base_addr + sizeof(PersistentHeader);
121+
back_addr = main_addr + g_main_size;
122+
g_main_addr = main_addr;
123+
PWB(&per->id);
124+
PWB(&per->state);
125+
// We need to call create_mspace_with_base() from within a transaction so that
126+
// the modifications on 'main' get replicated on 'back'. This means we temporarily
127+
// need to set the 'used_size' to 'main_size' to make sure everything is copied.
128+
begin_transaction();
129+
// Just to force the copy of the whole main region
130+
per->used_size = g_main_size;
131+
#ifdef USE_ESLOCO
132+
esloco = new EsLoco<persist>(main_addr, g_main_size, false);
133+
per->objects = (void**)esloco->malloc(sizeof(void*)*100);
134+
#else
135+
per->ms = create_mspace_with_base(main_addr, g_main_size, false);
136+
per->objects = (void**)mspace_malloc(per->ms, sizeof(void*)*100);
137+
#endif
138+
for (int i = 0; i < 100; i++) {
139+
per->objects[i] = nullptr;
140+
add_to_log(&per->objects[i],sizeof(void*));
141+
PWB(&per->objects[i]);
142+
}
143+
end_transaction();
144+
// The used bytes in the main region
145+
per->used_size = (uint8_t*)(&per->used_size) - ((uint8_t*)base_addr+sizeof(PersistentHeader))+128;
146+
flush_range((uint8_t*)per,sizeof(PersistentHeader));
147+
PFENCE();
148+
// Finally, set the id to confirm that the whole initialization process has completed
149+
per->id = MAGIC_ID;
150+
PWB(&per->id);
151+
PSYNC();
152+
}
153+
154+
void RomulusLog::ns_reset(){
155+
per->id = MAGIC_ID;
156+
PWB(&per->id);
157+
PFENCE();
158+
std::memset(base_addr,0,max_size);
159+
160+
// No data in persistent memory, initialize
161+
per = new (base_addr) PersistentHeader;
162+
g_main_size = (max_size - sizeof(PersistentHeader))/2;
163+
main_addr = base_addr + sizeof(PersistentHeader);
164+
back_addr = main_addr + g_main_size;
165+
PWB(&per->id);
166+
PWB(&per->state);
167+
// We need to call create_mspace_with_base() from within a transaction so that
168+
// the modifications on 'main' get replicated on 'back'. This means we temporarily
169+
// need to set the 'used_size' to 'main_size' to make sure everything is copied.
170+
begin_transaction();
171+
// Just to force the copy of the whole main region
172+
per->used_size = g_main_size;
173+
#ifdef USE_ESLOCO
174+
esloco = new EsLoco<persist>(main_addr, g_main_size, false);
175+
per->objects = (void**)esloco->malloc(sizeof(void*)*100);
176+
#else
177+
per->ms = create_mspace_with_base(main_addr, g_main_size, false);
178+
per->objects = (void**)mspace_malloc(per->ms, sizeof(void*)*100);
179+
#endif
180+
for (int i = 0; i < 100; i++) {
181+
per->objects[i] = nullptr;
182+
add_to_log(&per->objects[i],sizeof(void*));
183+
PWB(&per->objects[i]);
184+
}
185+
end_transaction();
186+
// The used bytes in the main region
187+
per->used_size = (uint8_t*)(&per->used_size) - ((uint8_t*)base_addr+sizeof(PersistentHeader))+128;
188+
flush_range((uint8_t*)per,sizeof(PersistentHeader));
189+
PFENCE();
190+
// Finally, set the id to confirm that the whole initialization process has completed
191+
per->id = MAGIC_ID;
192+
PWB(&per->id);
193+
PSYNC();
194+
}
195+
196+
void RomulusLog::reset(){
197+
gRomLog.ns_reset();
198+
}
199+
200+
/*
201+
* Recovers from an incomplete transaction if needed
202+
*/
203+
inline void RomulusLog::recover() {
204+
int lstate = per->state.load(std::memory_order_relaxed);
205+
if (lstate == IDLE) {
206+
return;
207+
} else if (lstate == COPYING) {
208+
printf("RomulusLog: Recovery from COPYING...\n");
209+
copyMainToBack();
210+
} else if (lstate == MUTATING) {
211+
printf("RomulusLog: Recovery from MUTATING...\n");
212+
copyBackToMain();
213+
} else {
214+
assert(false);
215+
// ERROR: corrupted state
216+
}
217+
PFENCE();
218+
per->state.store(IDLE, std::memory_order_relaxed);
219+
return;
220+
}
221+
222+
223+
/*
224+
* Meant to be called from user code when something bad happens and the
225+
* whole transaction needs to be aborted.
226+
* TODO: fix this for nested transactions.
227+
*/
228+
inline void RomulusLog::abort_transaction(void) {
229+
// Check for nested transaction
230+
--tl_nested_write_trans;
231+
if (tl_nested_write_trans != 0) return;
232+
// Apply the log to rollback the modifications
233+
apply_log(back_addr, main_addr);
234+
235+
}
29236

30237
}

0 commit comments

Comments
 (0)