Monday 29 July 2013

TCMalloc based NUMA Heap: Source Code View

1: 函数定义
void* operator new(size_t size)
    ATTRIBUTE_SECTION(google_malloc);
void operator delete(void* p)
    __THROW ATTRIBUTE_SECTION(google_malloc);
void* operator new[](size_t size)
    ATTRIBUTE_SECTION(google_malloc);
void operator delete[](void* p)
    __THROW ATTRIBUTE_SECTION(google_malloc);

2: 调用
static inline void* cpp_alloc(size_t size, bool nothrow)

3: 调用
static inline void* do_malloc(size_t size)
这个函数的逻辑:

4: TCMalloc_ThreadCache是入口Class,其它的Class都是透明的。
4.1TCMalloc_ThreadCache* heap = TCMalloc_ThreadCache::GetCache();
-- GetCache()是static function;
--如果是第一次使用,则调用static function InitModule();
--否则,表示该thread已经使用过,因此,调用static function GetThreadHeap();
4.2先说说InitModule()
这个函数是全局的初始化,包括global variables.
-- static PageHeapAllocator<TCMalloc_ThreadCache> threadheap_allocator;
-- static PageHeapAllocator<Span> span_allocator;
-- static PageHeapAllocator<StackTrace> stacktrace_allocator;
-- static TCMalloc_Central_FreeList central_cache[kNumClasses];
-- TCMalloc_PageHeap
4.3 PageHeapAllocator
这个类是一个Pool对象管理器

5:  获取TCMalloc_ThreadCache* heap之后,
if size <= kMaxSize: CheckedMallocResult(heap->Allocate(size));
else: do_malloc_pages(pages(size));

6: 先说说heap->Allocate(size)
If can find the most suitable FreeList, return.
If cannot, go to central list. fetch one.

7:  CheckedMallocResult(Point*)
这个函数的作用是check改指针位置是否符合要求

8:pages(int);
convert byte into pages

9:do_malloc_pages();

10:  目标转移回到Allocate(),如果没有发现合适的space,则调用FetchFromCentralCache获取central space。
Fetch的数量取决num_objects_to_move[]的大小 。
Right now, Use approx 64k transfers between thread and central caches.

11: FetchFromCentralCache
central_cache[cl].RemoveRange
central_cache’s Class is: TCMalloc_Central_FreeList.

////////////////////
// 主要数据结构:
//////////////////

1: TCMalloc_PageHeap
提供最底层服务,为每一个Node保存一个TCMalloc_PageHeap_NodeData;
提供的主要接口:
Span* New(Length n, int *node);
Carve(int node, Span* span, Length n, bool released); 切割Span
void Delete(Span* span);

2: TCMalloc_PageHeap_NodeData
这个类比较简单,contains一系列Span的容器


////////////////////
// 实验数据:
//////////////////
1: Get from global space is not the dominate problem.
    仅占用1000毫秒左右;
2:
1928104    ,2590838    ,662734    ,__tls_get_addr
5522090    ,6820971    ,1298881    ,operator::delete(void*)
2128626    ,2760420    ,631794    ,__strlen_sse42
2761045    ,3711965    ,950920    ,memcpy
7149410    ,9600234    ,2450824    ,operator::new(unsigned
3: 先分析new吧;
为什么new会增加呢?
因为malloc的调用次数没有变化,因此,断定是do_malloc耗时增加
do_malloc只有两种情况:small size than kMaxSize or Large Size
在small size里面:
FetchFromCentralCache function的耗时很少,这一点很大的缩小了问题的范围;
这说明绝大多数的时间是消耗Allocate()
在Large Size里面:
do_malloc_pages function的耗时很少,这一点很大的缩小了问题的范围;

XXX
因为Allocate的函数内容很简单,我发现的主要原因是TCMalloc_ThreadCache处在Node 0的区间里面;

这个问题处理了之后,并没有解决问题,只是有稍微的改善;
于是,我开始考虑Malloc里面的其它语句;
SizeClass(size)
class_array[ClassIndex(size)];
这些变量,都是全局static变量,会产生remote access,因此,产生了局部化的想法;

4:再分析delete吧:
static inline void do_free(void* ptr)
发现相似的问题:
主要的时间消耗在



No comments:

Post a Comment