文章目录
- Common.h
- ObjectPool.h
- ThreadCache.h
- ThreadCache.cpp
- ConcurrentAlloc.h
- CentralCache.h
- CentralCache.cpp
- PageMap.h
- PageCache.h
- PageCache.cpp
- 测试代码BenchMark.cpp
Common.h
#pragma once
#include
#include
#include
#include
#include
#include
#include
using std::cout;
using std::endl;
#ifdef _WIN64
typedef unsigned long long PAGE_ID;
#elif _WIN32
typedef size_t PAGE_ID;
#else
#endif
#ifdef _WIN32
#include
#else
#endif
static const size_t MAX_BYTES = 256 * 1024;
static const size_t TCFREELIST = 208;
static const size_t CCFREELIST = 208;
static const size_t PCSPANLIST = 129;
static const size_t PAGE_SHIFT = 13;
inline static void* SystemAlloc(size_t kpage)
{
#ifdef _WIN32
void* ptr = VirtualAlloc(0, kpage << 13, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
#else
#endif
if (ptr == nullptr)
throw std::bad_alloc();
return ptr;
}
inline static void SystemFree(void* ptr)
{
#ifdef _WIN32
VirtualFree(ptr, 0, MEM_RELEASE);
#else
#endif
}
static void*& NextObj(void* obj)
{
return *(void**)obj;
}
class FreeList
{
public:
void Push(void* obj)
{
assert(obj);
NextObj(obj) = _freelist;
_freelist = obj;
++size;
}
void PushRang(void* start, void* end, size_t n)
{
assert(start);
assert(end);
NextObj(end) = _freelist;
_freelist = start;
size += n;
}
void* Pop()
{
assert(_freelist);
void* obj = _freelist;
_freelist = NextObj(obj);
--size;
return obj;
}
void PopRang(void*& start, void*& end, size_t n)
{
assert(n <= size);
start = _freelist;
end = start;
for (size_t i = 0; i < n - 1; ++i)
{
end = NextObj(end);
}
_freelist = NextObj(end);
NextObj(end) = nullptr;
size -= n;
}
bool Empty()
{
return _freelist == nullptr;
}
size_t& MaxSize()
{
return _MaxSize;
}
size_t Size()
{
return size;
}
private:
void* _freelist = nullptr;
size_t _MaxSize = 1;
size_t size = 0;
};
class SizeClass
{
private:
static inline size_t _RoundUp(size_t bytes, size_t alignNum)
{
return ((bytes + alignNum - 1) & ~(alignNum - 1));
}
static inline size_t _Index(size_t bytes, size_t align_shift)
{
return ((bytes + (1 << align_shift) - 1) >> align_shift) - 1;
}
public:
static inline size_t RoundUp(size_t size)
{
if (size <= 128)
{
return _RoundUp(size, 8);
}
else if (size <= 1024)
{
return _RoundUp(size, 16);
}
else if (size <= 8 * 1024)
{
return _RoundUp(size, 128);
}
else if (size <= 64 * 1024)
{
return _RoundUp(size, 1024);
}
else if (size <= 256 * 1024)
{
return _RoundUp(size, 8 * 1024);
}
else
{
return _RoundUp(size, 1 << PAGE_SHIFT);
}
}
static inline size_t Index(size_t bytes)
{
assert(bytes <= MAX_BYTES);
static int group_array[4] = { 16, 56, 56, 56 };
if (bytes <= 128)
{
return _Index(bytes, 3);
}
else if (bytes <= 1024)
{
return _Index(bytes - 128, 4) + group_array[0];
}
else if (bytes <= 8 * 1024)
{
return _Index(bytes - 1024, 7) + group_array[0] + group_array[1];
}
else if (bytes <= 64 * 1024)
{
return _Index(bytes - 8 * 1024, 10) + group_array[0] + group_array[1] + group_array[2];
}
else if (bytes <= 256 * 1024)
{
return _Index(bytes - 64 * 1024, 13) + group_array[0] + group_array[1] + group_array[2] + group_array[3];
}
else
{
assert(false);
return -1;
}
}
static size_t GetNumofSizeFromCentralCache(size_t size)
{
assert(size > 0);
int num = MAX_BYTES / size;
if (num < 2)
num = 2;
if (num > 512)
num = 512;
return num;
}
static size_t GetNumofPageFromPageCache(size_t size)
{
size_t num = GetNumofSizeFromCentralCache(size);
size_t npage = num * size;
npage >>= PAGE_SHIFT;
if (npage == 0)
npage = 1;
return npage;
}
};
class Span
{
public:
PAGE_ID _pageId = 0;
size_t _n = 0;
Span* _next = nullptr;
Span* _prev = nullptr;
size_t _useCount = 0;
void* _freeList = nullptr;
bool _isUse = false;
size_t objsize = 0;
};
class SpanList
{
public:
SpanList()
{
_head = new Span;
_head->_next = _head;
_head->_prev = _head;
}
void PushFront(Span* span)
{
Insert(_head->_next, span);
}
void Insert(Span* pos,Span* newSpan)
{
assert(pos);
assert(newSpan);
Span* prev = pos->_prev;
prev->_next = newSpan;
newSpan->_prev = prev;
newSpan->_next = pos;
pos->_prev = newSpan;
prev = nullptr;
}
Span* PopFront()
{
assert(_head != _head->_next);
Span* front = _head->_next;
Erase(_head->_next);
return front;
}
void Erase(Span* pos)
{
assert(pos);
assert(pos != _head);
Span* prev = pos->_prev;
Span* next = pos->_next;
prev->_next = next;
if(next)
next->_prev = prev;
pos = nullptr;
}
std::mutex& GetMutex()
{
return _mtx;
}
Span* Begin()
{
return _head->_next;
}
Span* End()
{
return _head;
}
bool Empty()
{
return _head == _head->_next;
}
private:
Span* _head;
std::mutex _mtx;
};
ObjectPool.h
#pragma once
#include "Common.h"
template<class T>
class ObjectPool
{
public:
T* New()
{
T* obj = nullptr;
if (_freeList)
{
void* next = *((void**)_freeList);
obj = (T*)_freeList;
_freeList = next;
}
else
{
if (_remainBytes < sizeof(T))
{
_remainBytes = 128 * 1024;
_memory = (char*)SystemAlloc(_remainBytes >> 13);
if (_memory == nullptr)
{
throw std::bad_alloc();
}
}
obj = (T*)_memory;
if (obj == nullptr)
{
int x = 0;
}
size_t objSize = sizeof(T) < sizeof(void*) ? sizeof(void*) : sizeof(T);
_memory += objSize;
_remainBytes -= objSize;
}
new(obj) T;
return obj;
}
void Delete(T* obj)
{
obj->~T();
*(void**)obj = _freeList;
_freeList = obj;
}
private:
char* _memory = nullptr;
size_t _remainBytes = 0;
void* _freeList = nullptr;
};
ThreadCache.h
#pragma once
#include "Common.h"
class ThreadCache
{
public:
void* Allocate(size_t size);
void Deallocate(void* ptr, size_t size);
void* FetchFromCentralCache(size_t index, size_t size);
void ListTooLong(FreeList& list, size_t size);
private:
FreeList _freelists[TCFREELIST];
};
static _declspec(thread) ThreadCache* pTLSThreadCache = nullptr;
ThreadCache.cpp
#include "ThreadCache.h"
#include "CentralCache.h"
void* ThreadCache::FetchFromCentralCache(size_t index, size_t size)
{
size_t batchNum = min(SizeClass::GetNumofSizeFromCentralCache(size),_freelists[index].MaxSize());
if (batchNum == _freelists[index].MaxSize())
{
_freelists[index].MaxSize() *= 2;
}
void* start = nullptr;
void* end = nullptr;
size_t actualNum = CentralCache::GetInstance()->FetchRangeObj(start, end, batchNum, size);
assert(start);
assert(end);
assert(actualNum > 0);
void* cur = start;
size_t i = 0;
while (cur != end)
{
cur = NextObj(cur);
++i;
}
++i;
if (i == actualNum)
{
int x = 0;
}
if (actualNum == 1)
{
assert(start == end);
NextObj(start) = nullptr;
}
else
{
_freelists[index].PushRang(NextObj(start), end, actualNum - 1);
NextObj(start) = nullptr;
}
return start;
}
void* ThreadCache::Allocate(size_t size)
{
assert(size <= MAX_BYTES);
size_t ObjSize = SizeClass::RoundUp(size);
size_t ObjIndex = SizeClass::Index(size);
void* obj = nullptr;
if (!_freelists[ObjIndex].Empty())
{
obj = _freelists[ObjIndex].Pop();
}
else
{
obj = FetchFromCentralCache(ObjIndex, ObjSize);
}
return obj;
}
void ThreadCache::Deallocate(void* ptr, size_t size)
{
assert(ptr);
assert(size <= MAX_BYTES);
size_t ObjIndex = SizeClass::Index(size);
_freelists[ObjIndex].Push(ptr);
ptr = nullptr;
size_t n = min(SizeClass::GetNumofSizeFromCentralCache(size), _freelists[ObjIndex].MaxSize()) - 1;
if (n == SizeClass::GetNumofSizeFromCentralCache(size) - 1)
{
n += 1;
}
if (_freelists[ObjIndex].Size() >= n)
{
ListTooLong(_freelists[ObjIndex], size);
}
}
void ThreadCache::ListTooLong(FreeList& list, size_t size)
{
void* start = nullptr;
void* end = nullptr;
size_t n = min(SizeClass::GetNumofSizeFromCentralCache(size), list.MaxSize()) - 1;
if (n == SizeClass::GetNumofSizeFromCentralCache(size) - 1)
{
n += 1;
}
list.PopRang(start, end, n);
CentralCache::GetInstance()->ReleaseListToSpans(start, size);
}
ConcurrentAlloc.h
#pragma once
#include "ThreadCache.h"
#include "PageCache.h"
void* ConcurrentAlloc(size_t size)
{
if (size > MAX_BYTES)
{
size_t alignSize = SizeClass::RoundUp(size);
size_t kpage = alignSize >> PAGE_SHIFT;
PageCache::GetInstance()->GetMutex().lock();
Span* span = PageCache::GetInstance()->NewSpan(kpage);
span->_isUse = true;
span->objsize = alignSize;
PageCache::GetInstance()->GetMutex().unlock();
void* ptr = (void*)(span->_pageId << PAGE_SHIFT);
return ptr;
}
else
{
assert(size <= MAX_BYTES);
if (pTLSThreadCache == nullptr)
{
ObjectPool<ThreadCache> tcpool;
pTLSThreadCache = tcpool.New();
}
return pTLSThreadCache->Allocate(size);
}
}
void ConcurrentFree(void* ptr)
{
assert(ptr);
Span* span = PageCache::GetInstance()->MapObjectToSpan(ptr);
size_t size = span->objsize;
if (size > MAX_BYTES)
{
PageCache::GetInstance()->GetMutex().lock();
PageCache::GetInstance()->ReleaseSpanToPageCache(span);
PageCache::GetInstance()->GetMutex().unlock();
}
else
{
assert(pTLSThreadCache);
pTLSThreadCache->Deallocate(ptr, size);
}
}
CentralCache.h
#pragma once
#include "Common.h"
class CentralCache
{
public:
static CentralCache* GetInstance()
{
return &_Instance;
}
Span* GetOneSpan(SpanList& Spanlist, size_t size);
size_t FetchRangeObj(void*& start, void*& end, size_t batchNum, size_t size);
void ReleaseListToSpans(void* start, size_t size);
private:
CentralCache()
{}
CentralCache(const CentralCache& _Instance) = delete;
private:
SpanList _SpanFreeLists[CCFREELIST];
static CentralCache _Instance;
};
CentralCache.cpp
#include "CentralCache.h"
#include "PageCache.h"
CentralCache CentralCache::_Instance;
Span* CentralCache::GetOneSpan(SpanList& Spanlist, size_t size)
{
Span* it = Spanlist.Begin();
while (it != Spanlist.End())
{
if (it->_freeList != nullptr)
{
return it;
}
else
{
it = it->_next;
}
}
Spanlist.GetMutex().unlock();
PageCache::GetInstance()->GetMutex().lock();
Span* span = PageCache::GetInstance()->NewSpan(SizeClass::GetNumofPageFromPageCache(size));
span->_isUse = true;
span->objsize = size;
PageCache::GetInstance()->GetMutex().unlock();
assert(span);
char* start = (char*)(span->_pageId << PAGE_SHIFT);
size_t bytes = (span->_n << PAGE_SHIFT);
char* end = start + bytes;
span->_freeList = start;
void* tail = start;
start += size;
while (start < end)
{
NextObj(tail) = start;
tail = start;
start += size;
}
NextObj(tail) = nullptr;
Spanlist.GetMutex().lock();
Spanlist.PushFront(span);
return span;
}
size_t CentralCache::FetchRangeObj(void*& start, void*& end, size_t batchNum, size_t size)
{
size_t Index = SizeClass::Index(size);
_SpanFreeLists[Index].GetMutex().lock();
Span* span = GetOneSpan(_SpanFreeLists[Index], size);
assert(span);
if (span->_freeList == nullptr)
{
int x = 0;
}
assert(span->_freeList);
start = span->_freeList;
end = start;
size_t i = 0;
size_t actualNum = 1;
while (i < batchNum - 1 && NextObj(end) != nullptr)
{
end = NextObj(end);
++i;
++actualNum;
}
span->_freeList = NextObj(end);
NextObj(end) = nullptr;
span->_useCount += actualNum;
_SpanFreeLists[Index].GetMutex().unlock();
return actualNum;
}
void CentralCache::ReleaseListToSpans(void* start, size_t size)
{
size_t index = SizeClass::Index(size);
_SpanFreeLists[index].GetMutex().lock();
while (start)
{
void* next = NextObj(start);
Span* span = PageCache::GetInstance()->MapObjectToSpan(start);
NextObj(start) = span->_freeList;
span->_freeList = start;
span->_useCount--;
if (span->_useCount == 0)
{
_SpanFreeLists[index].Erase(span);
span->_freeList = nullptr;
span->_next = nullptr;
span->_prev = nullptr;
_SpanFreeLists[index].GetMutex().unlock();
PageCache::GetInstance()->GetMutex().lock();
PageCache::GetInstance()->ReleaseSpanToPageCache(span);
PageCache::GetInstance()->GetMutex().unlock();
_SpanFreeLists[index].GetMutex().lock();
}
start = next;
}
_SpanFreeLists[index].GetMutex().unlock();
}
PageMap.h
#pragma once
#include "Common.h"
#include "ObjectPool.h"
template <int BITS>
class TCMalloc_PageMap1 {
private:
static const int LENGTH = 1 << BITS;
void** array_;
public:
typedef uintptr_t Number;
explicit TCMalloc_PageMap1() {
size_t size = sizeof(void*) << BITS;
size_t alignSize = SizeClass::RoundUp(size);
array_ = (void**)SystemAlloc(alignSize >> PAGE_SHIFT);
memset(array_, 0, sizeof(void*) << BITS);
}
void* get(Number k) const {
if ((k >> BITS) > 0) {
return NULL;
}
return array_[k];
}
void set(Number k, void* v) {
array_[k] = v;
}
};
template <int BITS>
class TCMalloc_PageMap2 {
private:
static const int ROOT_BITS = 5;
static const int ROOT_LENGTH = 1 << ROOT_BITS;
static const int LEAF_BITS = BITS - ROOT_BITS;
static const int LEAF_LENGTH = 1 << LEAF_BITS;
struct Leaf {
void* values[LEAF_LENGTH];
};
Leaf* root_[ROOT_LENGTH];
void* (*allocator_)(size_t);
public:
typedef uintptr_t Number;
explicit TCMalloc_PageMap2() {
memset(root_, 0, sizeof(root_));
PreallocateMoreMemory();
}
void* get(Number k) const {
const Number i1 = k >> LEAF_BITS;
const Number i2 = k & (LEAF_LENGTH - 1);
if ((k >> BITS) > 0 || root_[i1] == NULL) {
return NULL;
}
return root_[i1]->values[i2];
}
void set(Number k, void* v) {
const Number i1 = k >> LEAF_BITS;
const Number i2 = k & (LEAF_LENGTH - 1);
ASSERT(i1 < ROOT_LENGTH);
root_[i1]->values[i2] = v;
}
bool Ensure(Number start, size_t n) {
for (Number key = start; key <= start + n - 1;) {
const Number i1 = key >> LEAF_BITS;
if (i1 >= ROOT_LENGTH)
return false;
if (root_[i1] == NULL) {
static ObjectPool<Leaf> leafPool;
Leaf* leaf = (Leaf*)leafPool.New();
memset(leaf, 0, sizeof(*leaf));
root_[i1] = leaf;
}
key = ((key >> LEAF_BITS) + 1) << LEAF_BITS;
}
return true;
}
void PreallocateMoreMemory() {
Ensure(0, 1 << BITS);
}
};
template <int BITS>
class TCMalloc_PageMap3 {
private:
static const int INTERIOR_BITS = (BITS + 2) / 3;
static const int INTERIOR_LENGTH = 1 << INTERIOR_BITS;
static const int LEAF_BITS = BITS - 2 * INTERIOR_BITS;
static const int LEAF_LENGTH = 1 << LEAF_BITS;
struct Node {
Node* ptrs[INTERIOR_LENGTH];
};
struct Leaf {
void* values[LEAF_LENGTH];
};
Node* root_;
void* (*allocator_)(size_t);
Node* NewNode() {
Node* result = reinterpret_cast<Node*>((*allocator_)(sizeof(Node)));
if (result != NULL) {
memset(result, 0, sizeof(*result));
}
return result;
}
public:
typedef uintptr_t Number;
explicit TCMalloc_PageMap3(void* (*allocator)(size_t)) {
allocator_ = allocator;
root_ = NewNode();
}
void* get(Number k) const {
const Number i1 = k >> (LEAF_BITS + INTERIOR_BITS);
const Number i2 = (k >> LEAF_BITS) & (INTERIOR_LENGTH - 1);
const Number i3 = k & (LEAF_LENGTH - 1);
if ((k >> BITS) > 0 ||
root_->ptrs[i1] == NULL || root_->ptrs[i1]->ptrs[i2] == NULL) {
return NULL;
}
return reinterpret_cast<Leaf*>(root_->ptrs[i1]->ptrs[i2])->values[i3];
}
void set(Number k, void* v) {
ASSERT(k >> BITS == 0);
const Number i1 = k >> (LEAF_BITS + INTERIOR_BITS);
const Number i2 = (k >> LEAF_BITS) & (INTERIOR_LENGTH - 1);
const Number i3 = k & (LEAF_LENGTH - 1);
reinterpret_cast<Leaf*>(root_->ptrs[i1]->ptrs[i2])->values[i3] = v;
}
bool Ensure(Number start, size_t n) {
for (Number key = start; key <= start + n - 1;) {
const Number i1 = key >> (LEAF_BITS + INTERIOR_BITS);
const Number i2 = (key >> LEAF_BITS) & (INTERIOR_LENGTH - 1);
if (i1 >= INTERIOR_LENGTH || i2 >= INTERIOR_LENGTH)
return false;
if (root_->ptrs[i1] == NULL) {
Node* n = NewNode();
if (n == NULL) return false;
root_->ptrs[i1] = n;
}
if (root_->ptrs[i1]->ptrs[i2] == NULL) {
Leaf* leaf = reinterpret_cast<Leaf*>((*allocator_)(sizeof(Leaf)));
if (leaf == NULL) return false;
memset(leaf, 0, sizeof(*leaf));
root_->ptrs[i1]->ptrs[i2] = reinterpret_cast<Node*>(leaf);
}
key = ((key >> LEAF_BITS) + 1) << LEAF_BITS;
}
return true;
}
void PreallocateMoreMemory() {
}
};
PageCache.h
#pragma once
#include "Common.h"
#include "ObjectPool.h"
#include "PageMap.h"
class PageCache
{
public:
static PageCache* GetInstance()
{
return &_Instance;
}
Span* NewSpan(size_t size);
std::mutex& GetMutex()
{
return _mtx;
}
Span* MapObjectToSpan(void* obj);
void ReleaseSpanToPageCache(Span* span);
private:
PageCache()
{}
PageCache(const PageCache& _Instance) = delete;
private:
SpanList _SpanLists[PCSPANLIST];
static PageCache _Instance;
std::mutex _mtx;
TCMalloc_PageMap1<32 - PAGE_SHIFT> _idSpanMap;
ObjectPool<Span> _spanPool;
};
PageCache.cpp
#include "PageCache.h"
PageCache PageCache::_Instance;
Span* PageCache::NewSpan(size_t k)
{
assert(k > 0);
if (k > PCSPANLIST - 1)
{
void* ptr = SystemAlloc(k);
Span* kspan = _spanPool.New();
kspan->_pageId = ((PAGE_ID)ptr >> PAGE_SHIFT);
kspan->_n = k;
_idSpanMap.set(kspan->_pageId, kspan);
return kspan;
}
if (!_SpanLists[k].Empty())
{
Span* span = _SpanLists[k].PopFront();
for (size_t i = 0; i < k; i++)
{
_idSpanMap.set(span->_pageId + i, span);
}
return span;
}
for (size_t i = k + 1; i < PCSPANLIST; i++)
{
if (!_SpanLists[i].Empty())
{
Span* nspan = _SpanLists[i].PopFront();
Span* kspan = _spanPool.New();
kspan->_pageId = nspan->_pageId;
kspan->_n = k;
for (size_t i = 0; i < k; i++)
{
_idSpanMap.set(kspan->_pageId + i, kspan);
}
nspan->_pageId = nspan->_pageId + k;
nspan->_n = nspan->_n - k;
_idSpanMap.set(nspan->_pageId, nspan);
_idSpanMap.set(nspan->_pageId + nspan->_n - 1, nspan);
_SpanLists[nspan->_n].PushFront(nspan);
return kspan;
}
}
Span* span = _spanPool.New();
void* ptr = SystemAlloc(PCSPANLIST - 1);
span->_pageId = ((PAGE_ID)ptr >> PAGE_SHIFT);
span->_n = PCSPANLIST - 1;
_SpanLists[span->_n].PushFront(span);
return NewSpan(k);
}
Span* PageCache::MapObjectToSpan(void* obj)
{
PAGE_ID id = ((PAGE_ID)obj >> PAGE_SHIFT);
auto ret = (Span*)_idSpanMap.get(id);
assert(ret);
return ret;
}
void PageCache::ReleaseSpanToPageCache(Span* span)
{
if (span->_n > PCSPANLIST - 1)
{
void* ptr = (void*)(span->_pageId << PAGE_SHIFT);
SystemFree(ptr);
_spanPool.Delete(span);
return;
}
while (1)
{
PAGE_ID PrevSpanId = span->_pageId - 1;
auto ret = (Span*)_idSpanMap.get(PrevSpanId);
if (ret == nullptr)
{
break;
}
Span* PrevSpan = ret;
if (PrevSpan->_isUse)
{
break;
}
if (PrevSpan->_n + span->_n > PCSPANLIST - 1)
{
break;
}
span->_pageId = PrevSpan->_pageId;
span->_n += PrevSpan->_n;
_SpanLists[PrevSpan->_n].Erase(PrevSpan);
_spanPool.Delete(PrevSpan);
}
while (1)
{
PAGE_ID NextSpanId = span->_pageId + span->_n;
auto ret = (Span*)_idSpanMap.get(NextSpanId);
if (ret == nullptr)
{
break;
}
Span* NextSpan = ret;
if (NextSpan->_isUse)
{
break;
}
if (NextSpan->_n + span->_n > PCSPANLIST - 1)
{
break;
}
span->_n += NextSpan->_n;
_SpanLists[NextSpan->_n].Erase(NextSpan);
_spanPool.Delete(NextSpan);
}
_SpanLists[span->_n].PushFront(span);
span->_isUse = false;
_idSpanMap.set(span->_pageId, span);
_idSpanMap.set(span->_pageId + span->_n - 1, span);
}
测试代码BenchMark.cpp
#include "ConcurrentAlloc.h"
void BenchmarkMalloc(size_t ntimes, size_t nworks, size_t rounds)
{
std::vector<std::thread> vthread(nworks);
std::atomic<size_t> malloc_costtime = 0;
std::atomic<size_t> free_costtime = 0;
for (size_t k = 0; k < nworks; ++k)
{
vthread[k] = std::thread([&, k]() {
std::vector<void*> v;
v.reserve(ntimes);
for (size_t j = 0; j < rounds; ++j)
{
size_t begin1 = clock();
for (size_t i = 0; i < ntimes; i++)
{
v.push_back(malloc(16));
}
size_t end1 = clock();
size_t begin2 = clock();
for (size_t i = 0; i < ntimes; i++)
{
free(v[i]);
}
size_t end2 = clock();
v.clear();
malloc_costtime += (end1 - begin1);
free_costtime += (end2 - begin2);
}
});
}
for (auto& t : vthread)
{
t.join();
}
printf("%u 个线程并发执行 % u轮次,每轮次malloc % u次: ",nworks, rounds, ntimes);
cout << "花费:" << malloc_costtime << "ms"<< endl;
printf("%u个线程并发执行%u轮次,每轮次free %u次:",nworks, rounds, ntimes);
cout << "花费:" << free_costtime << "ms" << endl;
printf("%u个线程并发malloc&free %u次",nworks, nworks * rounds * ntimes);
cout << "总计花费:" << malloc_costtime + free_costtime << "ms" << endl;
}
void BenchmarkConcurrentMalloc(size_t ntimes, size_t nworks, size_t rounds)
{
std::vector<std::thread> vthread(nworks);
std::atomic<size_t> malloc_costtime = 0;
std::atomic<size_t> free_costtime = 0;
for (size_t k = 0; k < nworks; ++k)
{
vthread[k] = std::thread([&]() {
std::vector<void*> v;
v.reserve(ntimes);
for (size_t j = 0; j < rounds; ++j)
{
size_t begin1 = clock();
for (size_t i = 0; i < ntimes; i++)
{
v.push_back(ConcurrentAlloc(16));
}
size_t end1 = clock();
size_t begin2 = clock();
for (size_t i = 0; i < ntimes; i++)
{
ConcurrentFree(v[i]);
}
size_t end2 = clock();
v.clear();
malloc_costtime += (end1 - begin1);
free_costtime += (end2 - begin2);
}
});
}
for (auto& t : vthread)
{
t.join();
}
printf("%u 个线程并发执行 % u轮次,每轮次ConcurrentMalloc % u次: ", nworks, rounds, ntimes);
cout << "花费:" << malloc_costtime << "ms" << endl;
printf("%u个线程并发执行%u轮次,每轮次Concurrentfree %u次:", nworks, rounds, ntimes);
cout << "花费:" << free_costtime << "ms" << endl;
printf("%u个线程并发ConcurrentMalloc&Concurrentfree %u次", nworks, nworks * rounds * ntimes);
cout << "总计花费:" << malloc_costtime + free_costtime << "ms" << endl;
}
int main()
{
size_t n = 10000;
cout << "==========================================================" << endl;
BenchmarkConcurrentMalloc(n, 4, 10);
cout << endl << endl;
BenchmarkMalloc(n, 4, 10);
cout << "==========================================================" << endl;
return 0;
}