Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

VariableAllocator整理(主にコメント追加)

  • Loading branch information...
commit 6c01f14e9df656bc9be0be56f6ac69ba1525bd80 1 parent 3a5935b
@sile authored
View
5 include/imque/allocator/fixed_allocator.hh
@@ -39,9 +39,6 @@ namespace imque {
static const uint32_t SUPER_BLOCKS_SIZE = sizeof(SuperBlock)*SUPER_BLOCK_COUNT;
public:
- typedef uint32_t DESCRIPTOR_TYPE;
-
- public:
FixedAllocator(void* region, uint32_t size)
: super_blocks_(reinterpret_cast<SuperBlock*>(region)),
base_alc_(super_blocks_+SUPER_BLOCK_COUNT,
@@ -120,7 +117,7 @@ namespace imque {
SuperBlock& sb = super_blocks_[sb_id-1];
if(sb.used_count < sb.free_count &&
- base_alc_.fast_release(base_addr_desc)) {
+ base_alc_.fastRelease(base_addr_desc)) {
atomic::sub(&sb.used_count, 1);
return true;
}
View
91 include/imque/allocator/variable_allocator.hh
@@ -41,7 +41,8 @@ namespace imque {
};
}
- // variable-size-block allocator
+ // ロックフリーな可変長ブロックアロケータ。
+ // 一つのインスタンスで扱えるメモリ領域の最大長は sizeof(Chunk)*NODE_COUNT_LIMIT = 512MB
class VariableAllocator {
private:
typedef VariableAllocatorAux::Node Node;
@@ -53,9 +54,6 @@ namespace imque {
static const uint32_t NODE_COUNT_LIMIT = 0x1000000; // 24bit
public:
- typedef uint32_t DESCRIPTOR_TYPE;
-
- public:
VariableAllocator(void* region, uint32_t size)
: node_count_(size/(sizeof(Node)+sizeof(Chunk))),
nodes_(reinterpret_cast<Node*>(region)),
@@ -64,6 +62,8 @@ namespace imque {
operator bool() const { return nodes_ != NULL && node_count_ > 2 && node_count_ < NODE_COUNT_LIMIT; }
+ // 初期化メソッド。
+ // コンストラクタに渡した region につき一回呼び出す必要がある。
void init() {
if(*this) {
nodes_[0].next = 1;
@@ -76,7 +76,14 @@ namespace imque {
}
}
- // TODO: doc: 返り値の上限について
+ // メモリ割当を行う。
+ // 要求したサイズの割当に失敗した場合は 0 を、それ以外はメモリ領域参照用の識別子(記述子)を返す。
+ // (識別子を ptrメソッド に渡すことで、実際のメモリ領域を参照可能)
+ //
+ // メモリ割当は、領域不足以外に、極めて高い競合下で楽観的ロックの試行回数(RETRY_LIMIT)を越えた場合にも失敗する。
+ //
+ // このメソッドが返す識別子の値は NODE_COUNT_LIMIT 未満の値(= 24bitに収まる値)であることが保証されている。
+ // ※ つまり、呼び出し側は、上位8bitが0bitであることを前提にしたコードを書くことができる
uint32_t allocate(uint32_t size) {
if(size == 0) {
return 0; // invalid argument
@@ -85,8 +92,8 @@ namespace imque {
uint32_t need_chunk_count = (size+sizeof(Chunk)-1) / sizeof(Chunk);
NodeSnapshot cand;
- if(find_candidate(IsEnoughChunk(need_chunk_count), cand) == false) {
- return 0; // out of memory
+ if(findCandidate(IsEnoughChunk(need_chunk_count), cand) == false) {
+ return 0; // out of memory (or exceeded retry limit)
}
uint32_t new_count = cand.node().count - need_chunk_count;
@@ -94,28 +101,30 @@ namespace imque {
return allocate(size);
}
- uint32_t allocated_node_index = index(cand) + new_count;
- nodes_[allocated_node_index].version = cand.node().version + 1;
- nodes_[allocated_node_index].count = need_chunk_count;
- nodes_[allocated_node_index].status = Node::AVAILABLE;
-
- return allocated_node_index;
+ uint32_t allocated_node_index = index(cand) + new_count; // memory descriptor
+ nodes_[allocated_node_index] = cand.node().changeCount(need_chunk_count);
+ return allocated_node_index;
}
- bool release(uint32_t descriptor) {
- return release_impl(descriptor, RETRY_LIMIT, false);
+ // allocateメソッドで割り当てたメモリ領域を解放する。
+ // md(メモリ記述子)が 0 の場合は何も行わない。
+ //
+ // メモリ解放は、極めて高い競合下で楽観的ロックの試行回数(RETRY_LIMIT)を越えた場合に失敗することがある。
+ bool release(uint32_t md) {
+ return releaseImpl(md, RETRY_LIMIT, false);
}
- // TODO: note
- bool fast_release(uint32_t descriptor) {
- return release_impl(descriptor, FAST_RETRY_LIMIT, true);
+ // 楽観的ロック失敗時の試行回数が少ない以外は releaseメソッド と同様。
+ bool fastRelease(uint32_t md) {
+ return releaseImpl(md, FAST_RETRY_LIMIT, true);
}
+ // allocateメソッドが返したメモリ記述子から、対応する実際にメモリ領域を取得する
template<typename T>
- T* ptr(uint32_t descriptor) const { return reinterpret_cast<T*>(chunks_ + descriptor); }
+ T* ptr(uint32_t md) const { return reinterpret_cast<T*>(chunks_ + md); }
template<typename T>
- T* ptr(uint32_t descriptor, uint32_t offset) const { return reinterpret_cast<T*>(ptr<char>(descriptor)+offset); }
+ T* ptr(uint32_t md, uint32_t offset) const { return reinterpret_cast<T*>(ptr<char>(md)+offset); }
private:
struct IsEnoughChunk {
@@ -135,17 +144,17 @@ namespace imque {
return node_index_ < curr.node().next;
}
- uint32_t node_index_;
+ const uint32_t node_index_;
};
template<class Callback>
- bool find_candidate(const Callback& fn, NodeSnapshot& node, int retry=RETRY_LIMIT) {
+ bool findCandidate(const Callback& fn, NodeSnapshot& node, int retry=RETRY_LIMIT) {
NodeSnapshot head(&nodes_[0]);
- return find_candidate(fn, head, node, retry);
+ return findCandidate(fn, head, node, retry);
}
template<class Callback>
- bool find_candidate(const Callback& fn, NodeSnapshot& pred, NodeSnapshot& curr, int retry) {
+ bool findCandidate(const Callback& fn, NodeSnapshot& pred, NodeSnapshot& curr, int retry) {
if(retry < 0) {
return false;
}
@@ -154,10 +163,10 @@ namespace imque {
return false;
}
- if(get_next_snapshot(pred, curr) == false ||
- update_node_status(pred, curr) == false ||
- join_nodes_if_need(pred, curr) == false) {
- return find_candidate(fn, curr, retry-1);
+ if(getNextSnapshot(pred, curr) == false ||
+ updateNodeStatus(pred, curr) == false ||
+ joinNodesIfNeed(pred, curr) == false) {
+ return findCandidate(fn, curr, retry-1);
}
if(fn(curr)) {
@@ -165,10 +174,10 @@ namespace imque {
}
pred = curr;
- return find_candidate(fn, pred, curr, retry);
+ return findCandidate(fn, pred, curr, retry);
}
- bool get_next_snapshot(NodeSnapshot& pred, NodeSnapshot& curr) const {
+ bool getNextSnapshot(NodeSnapshot& pred, NodeSnapshot& curr) const {
assert(pred.node().next != node_count_);
curr.update(&nodes_[pred.node().next]);
@@ -185,16 +194,17 @@ namespace imque {
return true;
}
- bool update_node_status(NodeSnapshot& pred, NodeSnapshot& curr) {
+ bool updateNodeStatus(NodeSnapshot& pred, NodeSnapshot& curr) {
if(isJoinable(pred) == false) {
return true;
}
+ // 二つのノードが結合可能(領域が隣接している)なら、ステータスを更新する
return (pred.compare_and_swap(pred.node().changeStatus(pred.node().status | Node::JOIN_HEAD)) &&
curr.compare_and_swap(curr.node().changeStatus(curr.node().status | Node::JOIN_TAIL)));
}
- bool join_nodes_if_need(NodeSnapshot& pred, NodeSnapshot& curr) {
+ bool joinNodesIfNeed(NodeSnapshot& pred, NodeSnapshot& curr) {
if(! (pred.node().isJoinHead() && curr.node().isJoinTail())) {
return true;
}
@@ -217,15 +227,15 @@ namespace imque {
return node.node().next == index(node) + node.node().count;
}
- bool release_impl(uint32_t descriptor, int retry_limit, bool fast) {
- if(descriptor == 0 || descriptor >= node_count_) {
- assert(descriptor < node_count_);
+ bool releaseImpl(uint32_t md, int retry_limit, bool fast) {
+ if(md == 0 || md >= node_count_) {
+ assert(md < node_count_);
return true;
}
- uint32_t node_index = descriptor;
+ uint32_t node_index = md;
NodeSnapshot pred;
- if(find_candidate(IsPredecessor(node_index), pred, retry_limit) == false) {
+ if(findCandidate(IsPredecessor(node_index), pred, retry_limit) == false) {
return false;
}
assert(node_index >= index(pred)+pred.node().count);
@@ -235,6 +245,7 @@ namespace imque {
Node new_pred_node;
bool is_neighbor = node_index == index(pred)+pred.node().count;
if(is_neighbor) {
+ // 隣接している場合は、解放の時点で結合してしまう
new_pred_node = pred.node().changeCount(pred.node().count + node->count);
} else {
new_pred_node = pred.node().changeNext(node_index);
@@ -242,7 +253,7 @@ namespace imque {
}
if(pred.compare_and_swap(new_pred_node) == false) {
- return fast ? false : release_impl(descriptor, retry_limit, fast);
+ return fast ? false : releaseImpl(md, retry_limit, fast);
}
return true;
@@ -250,8 +261,8 @@ namespace imque {
private:
const uint32_t node_count_;
- Node* nodes_;
- Chunk* chunks_;
+ Node* nodes_;
+ Chunk* chunks_;
};
}
}
View
50 src/bin/allocator-test.cc
@@ -125,6 +125,37 @@ long calc_standard_deviation(const std::vector<long>& ary) {
return static_cast<long>(sqrt(sum / count));
}
+class MallocAllocator {
+public:
+ void* allocate(uint32_t size) {
+ return malloc(size);
+ }
+
+ bool release(void* descriptor) {
+ free(descriptor);
+ return true;
+ }
+
+ template<typename T>
+ T* ptr(void* descriptor) { return reinterpret_cast<T*>(descriptor); }
+};
+
+template<typename T>
+struct Descriptor {};
+template<>
+struct Descriptor<imque::allocator::VariableAllocator> {
+ typedef uint32_t TYPE;
+};
+template<>
+struct Descriptor<imque::allocator::FixedAllocator> {
+ typedef uint32_t TYPE;
+};
+template<>
+struct Descriptor<MallocAllocator> {
+ typedef void* TYPE;
+};
+
+
template<class Allocator>
void child_start(Allocator& alc, const Parameter& param) {
srand(time(NULL) + getpid());
@@ -135,7 +166,8 @@ void child_start(Allocator& alc, const Parameter& param) {
uint32_t size = static_cast<uint32_t>((rand() % size_range) + param.alloc_size_min);
NanoTimer t1;
- typename Allocator::DESCRIPTOR_TYPE md = alc.allocate(size);
+ //typename Allocator::DESCRIPTOR_TYPE md = alc.allocate(size);
+ typename Descriptor<Allocator>::TYPE md = alc.allocate(size);
st.allocate_times[i] = t1.elapsed();
st.allocate_ok_count += md==0 ? 0 : 1;
@@ -210,22 +242,6 @@ void parent_start(Allocator& alc, const Parameter& param) {
<< "unknown=" << unknown_num << std::endl;
}
-class MallocAllocator {
-public:
- typedef void* DESCRIPTOR_TYPE;
-
- DESCRIPTOR_TYPE allocate(uint32_t size) {
- return malloc(size);
- }
-
- bool release(DESCRIPTOR_TYPE descriptor) {
- free(descriptor);
- return true;
- }
-
- template<typename T>
- T* ptr(DESCRIPTOR_TYPE descriptor) { return reinterpret_cast<T*>(descriptor); }
-};
int main(int argc, char** argv) {
if(argc != 9) {
Please sign in to comment.
Something went wrong with that request. Please try again.