Skip to content

Commit 2694033

Browse files
pmenonapavlo
authored andcommitted
Added ART index
1 parent 4dbbf3f commit 2694033

File tree

14 files changed

+3105
-5
lines changed

14 files changed

+3105
-5
lines changed

CMakeLists.txt

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,20 @@ endif()
9797
# ---[ Warnings
9898
peloton_warnings_disable(CMAKE_CXX_FLAGS -Wno-strict-aliasing -Wno-implicit-fallthrough)
9999

100-
# Turn on sanitizers if necessary.
100+
# ---[ Check if we should use the GNU Gold linker
101+
set(USE_GOLD true CACHE BOOL "Use the GNU Gold linker if available")
102+
if (USE_GOLD)
103+
execute_process(COMMAND ${CMAKE_C_COMPILER} -fuse-ld=gold -Wl,--version ERROR_QUIET OUTPUT_VARIABLE LD_VERSION)
104+
if ("${LD_VERSION}" MATCHES "GNU gold")
105+
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold -Wl,--disable-new-dtags")
106+
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold -Wl,--disable-new-dtags")
107+
else ()
108+
message(WARNING "GNU gold linker isn't available, using the default system linker.")
109+
set(USE_LD_GOLD OFF)
110+
endif ()
111+
endif()
112+
113+
# ---[ Turn on sanitizers if necessary.
101114
if(USE_SANITIZER)
102115
if (USE_SANITIZER STREQUAL "Address")
103116
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
@@ -117,9 +130,6 @@ if(USE_SANITIZER)
117130
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize-address-use-after-scope")
118131
endif()
119132
endif()
120-
if (CMAKE_COMPILER_IS_GNUCC)
121-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=gold")
122-
endif()
123133
endif()
124134

125135
# -- [ Coverage

cmake/Targets.cmake

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ function(peloton_pickup_peloton_sources root)
8888
# jsoncpp
8989
file(GLOB_RECURSE jsoncpp_srcs ${root}/third_party/jsoncpp/*.cpp)
9090

91+
# ART
92+
file(GLOB_RECURSE art_srcs ${root}/third_party/adaptive_radix_tree/*.cpp)
93+
9194
# date
9295
file(GLOB_RECURSE jsoncpp_srcs ${root}/third_party/date/*.cpp)
9396
set(date_hdrs ${root}/third_party/date/)
@@ -99,7 +102,7 @@ function(peloton_pickup_peloton_sources root)
99102

100103
# add proto to make them editable in IDEs too
101104
file(GLOB_RECURSE proto_files ${root}/src/peloton/*.proto)
102-
list(APPEND srcs ${proto_files} ${murmur_srcs} ${libcount_srcs} ${libcds_srcs} ${jsoncpp_srcs})
105+
list(APPEND srcs ${proto_files} ${murmur_srcs} ${libcount_srcs} ${art_srcs} ${jsoncpp_srcs})
103106

104107
# propogate to parent scope
105108
set(srcs ${srcs} PARENT_SCOPE)
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
2+
#pragma once
3+
4+
#include <atomic>
5+
#include <array>
6+
7+
#include "libcuckoo/cuckoohash_map.hh"
8+
9+
namespace art {
10+
11+
using Deleter = void (*)(void *);
12+
13+
struct Garbage {
14+
void *n;
15+
Deleter deleter_func;
16+
17+
Garbage() : n(nullptr), deleter_func() {}
18+
Garbage(void *_n, Deleter _deleter_func)
19+
: n(_n), deleter_func(_deleter_func) {
20+
assert(n);
21+
assert(deleter_func);
22+
}
23+
24+
// TODO(pmenon): Give this a better name?
25+
void Delete() {
26+
assert(n);
27+
assert(deleter_func);
28+
deleter_func(n);
29+
}
30+
};
31+
32+
struct LabelDelete {
33+
std::array<Garbage, 32> nodes;
34+
uint64_t epoch;
35+
std::size_t nodesCount;
36+
LabelDelete *next;
37+
};
38+
39+
class DeletionList {
40+
LabelDelete *headDeletionList = nullptr;
41+
LabelDelete *freeLabelDeletes = nullptr;
42+
std::size_t deletitionListCount = 0;
43+
44+
public:
45+
std::atomic<uint64_t> localEpoch;
46+
size_t thresholdCounter{0};
47+
48+
~DeletionList();
49+
50+
LabelDelete *head();
51+
52+
void add(void *n, Deleter deleter_func, uint64_t globalEpoch);
53+
54+
void remove(LabelDelete *label, LabelDelete *prev);
55+
56+
std::size_t size();
57+
58+
std::uint64_t deleted = 0;
59+
std::uint64_t added = 0;
60+
};
61+
62+
class Epoch;
63+
class EpochGuard;
64+
65+
class ThreadInfo {
66+
friend class Epoch;
67+
friend class EpochGuard;
68+
Epoch &epoch;
69+
DeletionList &deletionList;
70+
71+
DeletionList &getDeletionList() const;
72+
73+
public:
74+
explicit ThreadInfo(Epoch &epoch);
75+
76+
ThreadInfo(const ThreadInfo &ti) = default;
77+
78+
~ThreadInfo();
79+
80+
Epoch &getEpoch() const;
81+
};
82+
83+
class Epoch {
84+
friend class ThreadInfo;
85+
std::atomic<uint64_t> currentEpoch{0};
86+
87+
// A container mapping all threads to their garbage
88+
cuckoohash_map<std::thread::id, DeletionList *> deletionLists;
89+
90+
size_t startGCThreshhold;
91+
92+
public:
93+
Epoch(size_t startGCThreshhold) : startGCThreshhold(startGCThreshhold) {}
94+
95+
~Epoch();
96+
97+
void enterEpoch(ThreadInfo &threadInfo);
98+
99+
void markNodeForDeletion(void *n, ThreadInfo &threadInfo);
100+
void markNodeForDeletion(void *n, Deleter deleter_func,
101+
ThreadInfo &threadInfo);
102+
103+
void exitEpochAndCleanup(ThreadInfo &threadInfo);
104+
105+
void showDeleteRatio();
106+
107+
DeletionList &getDeletionList();
108+
};
109+
110+
class EpochGuard {
111+
ThreadInfo &threadEpochInfo;
112+
113+
public:
114+
EpochGuard(ThreadInfo &threadEpochInfo) : threadEpochInfo(threadEpochInfo) {
115+
threadEpochInfo.getEpoch().enterEpoch(threadEpochInfo);
116+
}
117+
118+
~EpochGuard() {
119+
threadEpochInfo.getEpoch().exitEpochAndCleanup(threadEpochInfo);
120+
}
121+
};
122+
123+
class EpochGuardReadonly {
124+
public:
125+
EpochGuardReadonly(ThreadInfo &threadEpochInfo) {
126+
threadEpochInfo.getEpoch().enterEpoch(threadEpochInfo);
127+
}
128+
129+
~EpochGuardReadonly() {}
130+
};
131+
132+
inline ThreadInfo::~ThreadInfo() {
133+
deletionList.localEpoch.store(std::numeric_limits<uint64_t>::max());
134+
}
135+
136+
} // namespace art
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
//
2+
// Created by florian on 22.10.15.
3+
//
4+
5+
#include <assert.h>
6+
#include <iostream>
7+
#include <mutex>
8+
#include <vector>
9+
10+
#include "Epoch.h"
11+
12+
namespace art {
13+
14+
DeletionList::~DeletionList() {
15+
assert(deletitionListCount == 0 && headDeletionList == nullptr);
16+
LabelDelete *cur = nullptr, *next = freeLabelDeletes;
17+
while (next != nullptr) {
18+
cur = next;
19+
next = cur->next;
20+
delete cur;
21+
}
22+
freeLabelDeletes = nullptr;
23+
}
24+
25+
std::size_t DeletionList::size() { return deletitionListCount; }
26+
27+
void DeletionList::remove(LabelDelete *label, LabelDelete *prev) {
28+
if (prev == nullptr) {
29+
headDeletionList = label->next;
30+
} else {
31+
prev->next = label->next;
32+
}
33+
deletitionListCount -= label->nodesCount;
34+
35+
label->next = freeLabelDeletes;
36+
freeLabelDeletes = label;
37+
deleted += label->nodesCount;
38+
}
39+
40+
void DeletionList::add(void *n, Deleter deleter_func, uint64_t globalEpoch) {
41+
deletitionListCount++;
42+
LabelDelete *label;
43+
if (headDeletionList != nullptr &&
44+
headDeletionList->nodesCount < headDeletionList->nodes.size()) {
45+
label = headDeletionList;
46+
} else {
47+
if (freeLabelDeletes != nullptr) {
48+
label = freeLabelDeletes;
49+
freeLabelDeletes = freeLabelDeletes->next;
50+
} else {
51+
label = new LabelDelete();
52+
}
53+
label->nodesCount = 0;
54+
label->next = headDeletionList;
55+
headDeletionList = label;
56+
}
57+
label->nodes[label->nodesCount] = Garbage{n, deleter_func};
58+
label->nodesCount++;
59+
label->epoch = globalEpoch;
60+
61+
added++;
62+
}
63+
64+
LabelDelete *DeletionList::head() { return headDeletionList; }
65+
66+
void Epoch::enterEpoch(ThreadInfo &threadInfo) {
67+
unsigned long curEpoch = currentEpoch.load(std::memory_order_relaxed);
68+
threadInfo.getDeletionList().localEpoch.store(curEpoch,
69+
std::memory_order_release);
70+
}
71+
72+
namespace {
73+
void stdOperatorDelete(void *n) {
74+
operator delete(n);
75+
}
76+
} // anonymous namespace
77+
78+
void Epoch::markNodeForDeletion(void *n, ThreadInfo &threadInfo) {
79+
markNodeForDeletion(n, stdOperatorDelete, threadInfo);
80+
}
81+
82+
void Epoch::markNodeForDeletion(void *n, Deleter deleter_func,
83+
ThreadInfo &threadInfo) {
84+
threadInfo.getDeletionList().add(n, deleter_func, currentEpoch.load());
85+
threadInfo.getDeletionList().thresholdCounter++;
86+
}
87+
88+
void Epoch::exitEpochAndCleanup(ThreadInfo &threadInfo) {
89+
DeletionList &deletionList = threadInfo.getDeletionList();
90+
if ((deletionList.thresholdCounter & (64 - 1)) == 1) {
91+
currentEpoch++;
92+
}
93+
if (deletionList.thresholdCounter > startGCThreshhold) {
94+
if (deletionList.size() == 0) {
95+
deletionList.thresholdCounter = 0;
96+
return;
97+
}
98+
deletionList.localEpoch.store(std::numeric_limits<uint64_t>::max());
99+
100+
uint64_t oldestEpoch = std::numeric_limits<uint64_t>::max();
101+
{
102+
auto locked_table = deletionLists.lock_table();
103+
for (auto &iter : locked_table) {
104+
auto &dl = iter.second;
105+
auto e = dl->localEpoch.load();
106+
if (e < oldestEpoch) {
107+
oldestEpoch = e;
108+
}
109+
}
110+
}
111+
112+
LabelDelete *cur = deletionList.head(), *next, *prev = nullptr;
113+
while (cur != nullptr) {
114+
next = cur->next;
115+
116+
if (cur->epoch < oldestEpoch) {
117+
for (std::size_t i = 0; i < cur->nodesCount; ++i) {
118+
cur->nodes[i].Delete();
119+
}
120+
deletionList.remove(cur, prev);
121+
} else {
122+
prev = cur;
123+
}
124+
cur = next;
125+
}
126+
deletionList.thresholdCounter = 0;
127+
}
128+
}
129+
130+
Epoch::~Epoch() {
131+
uint64_t oldestEpoch = std::numeric_limits<uint64_t>::max();
132+
auto locked_table = deletionLists.lock_table();
133+
for (auto &iter : locked_table) {
134+
auto *deletionList = iter.second;
135+
auto e = deletionList->localEpoch.load();
136+
if (e < oldestEpoch) {
137+
oldestEpoch = e;
138+
}
139+
}
140+
for (auto &iter : locked_table) {
141+
auto *deletionList = iter.second;
142+
LabelDelete *cur = deletionList->head(), *next, *prev = nullptr;
143+
while (cur != nullptr) {
144+
next = cur->next;
145+
146+
assert(cur->epoch < oldestEpoch);
147+
for (std::size_t i = 0; i < cur->nodesCount; ++i) {
148+
cur->nodes[i].Delete();
149+
}
150+
deletionList->remove(cur, prev);
151+
cur = next;
152+
}
153+
delete deletionList;
154+
}
155+
}
156+
157+
void Epoch::showDeleteRatio() {
158+
auto locked_table = deletionLists.lock_table();
159+
for (auto &iter : locked_table) {
160+
auto *dl = iter.second;
161+
std::cout << "deleted " << dl->deleted << " of " << dl->added << std::endl;
162+
}
163+
}
164+
165+
DeletionList &Epoch::getDeletionList() {
166+
DeletionList *threadLocalDeletionList = nullptr;
167+
auto my_tid = std::this_thread::get_id();
168+
bool found = deletionLists.find(my_tid, threadLocalDeletionList);
169+
if (!found) {
170+
threadLocalDeletionList = new DeletionList();
171+
deletionLists.insert(my_tid, threadLocalDeletionList);
172+
}
173+
return *threadLocalDeletionList;
174+
}
175+
176+
ThreadInfo::ThreadInfo(Epoch &epoch)
177+
: epoch(epoch), deletionList(epoch.getDeletionList()) {}
178+
179+
DeletionList &ThreadInfo::getDeletionList() const { return deletionList; }
180+
181+
Epoch &ThreadInfo::getEpoch() const { return epoch; }
182+
183+
} // namespace art

0 commit comments

Comments
 (0)