tcmalloc+libhugetlbfs使用

tcmalloc是內存管理的一個庫,非常好用以及高效。libhugetlbfs是大頁內存管理,提高tlb命中率,對程序來說也是一個非常好以及高效的一個庫。

現在我們要將兩個庫進行結合。第一:從動態庫的層面來說,兩者如果單獨使用只需要在編譯的時候連接這兩個庫就OK了。但是,但是,但是,如果兩者結合使用,同時連接這兩個庫,你會發現最終的只會是其中的某一個庫在運行,或者說只有tcmalloc在運行,大頁內層根本沒有使用。第一失敗了,那麼就是第二了。第二:從代碼層面說,代碼是無所不能的,那麼我們研究代碼,發現tcmalloc其實也要分配內存,找到它分配內存的地方進行修改。還好大頁內存給了代碼調用的接口。

其實我們在跟蹤的時候,會發現最後在中央內存分配的時候,有幾種分配方式,有sbrk的,有mmap的。

在system-alloc.cc文件中

void InitSystemAllocators(void) {
  MmapSysAllocator *mmap = new (mmap_space) MmapSysAllocator();
  SbrkSysAllocator *sbrk = new (sbrk_space) SbrkSysAllocator();

  // In 64-bit debug mode, place the mmap allocator first since it
  // allocates pointers that do not fit in 32 bits and therefore gives
  // us better testing of code's 64-bit correctness.  It also leads to
  // less false negatives in heap-checking code.  (Numbers are less
  // likely to look like pointers and therefore the conservative gc in
  // the heap-checker is less likely to misinterpret a number as a
  // pointer).
  DefaultSysAllocator *sdef = new (default_space) DefaultSysAllocator();
  if (kDebugMode && sizeof(void*) > 4) {
    sdef->SetChildAllocator(mmap, 0, mmap_name);
    sdef->SetChildAllocator(sbrk, 1, sbrk_name);
  } else {
    sdef->SetChildAllocator(sbrk, 0, sbrk_name);
    sdef->SetChildAllocator(mmap, 1, mmap_name);
  }
  sys_alloc = sdef;
}

那麼我們需要在這個地方添加一個大頁內存的分配方式,代碼如下:

#include <config.h>
#include <errno.h>                      // for EAGAIN, errno
#include <fcntl.h>                      // for open, O_RDWR
#include <stddef.h>                     // for size_t, NULL, ptrdiff_t
#if defined HAVE_STDINT_H
#include <stdint.h>                     // for uintptr_t, intptr_t
#elif defined HAVE_INTTYPES_H
#include <inttypes.h>
#else
#include <sys/types.h>
#endif
#ifdef HAVE_MMAP
#include <sys/mman.h>                   // for munmap, mmap, MADV_DONTNEED, etc
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>                     // for sbrk, getpagesize, off_t
#endif
#include <new>                          // for operator new
#include <gperftools/malloc_extension.h>
#include "base/basictypes.h"
#include "base/commandlineflags.h"
#include "base/spinlock.h"              // for SpinLockHolder, SpinLock, etc
#include "common.h"
#include "internal_logging.h"

extern "C"{
	#include <hugetlbfs.h>
};

extern "C"
{
	extern long gethugepagesize(void);
	extern int gethugepagesizes(long pagesizes[], int n_elem);
	extern int getpagesizes(long pagesizes[], int n_elem);
	extern void *get_huge_pages(size_t len, ghp_t flags);
	extern void free_huge_pages(void *ptr);
    extern void *get_hugepage_region(size_t len, ghr_t flags);
}

//add bu liyu
class HugeSysAllocator : public SysAllocator {
public:
  HugeSysAllocator() : SysAllocator() {
  }
  void* Alloc(size_t size, size_t *actual_size, size_t alignment);
};
static char huge_space[sizeof(HugeSysAllocator)];


//add buy liyu
void* HugeSysAllocator::Alloc(size_t size, size_t *actual_size,
                              size_t alignment) {

  // sbrk will release memory if passed a negative number, so we do
  // a strict check here
  if (static_cast<ptrdiff_t>(size + alignment) < 0) return NULL;

  // This doesn't overflow because TCMalloc_SystemAlloc has already
  // tested for overflow at the alignment boundary.
  size = ((size + alignment - 1) / alignment) * alignment;

  // "actual_size" indicates that the bytes from the returned pointer
  // p up to and including (p + actual_size - 1) have been allocated.
  if (actual_size) {
    *actual_size = size;
  }

  void* result = get_huge_pages(size,GHP_DEFAULT);
  //void* result = get_hugepage_region(size,GHR_DEFAULT);
  if (result == reinterpret_cast<void*>(0)) {
    return NULL;
  }

  // Is it aligned?
  uintptr_t ptr = reinterpret_cast<uintptr_t>(result);
  if ((ptr & (alignment-1)) == 0)  
  	return result;
  else
  {
    ptr += alignment - (ptr & (alignment-1));
  }
  return reinterpret_cast<void*>(ptr);
#endif  // HAVE_HUGE
}

只需要根據sbrk的分配方式加入大頁內存,並優先調用就ok了,如果這個地方調用get_huge_pages()報錯,那麼就使用get_hugepage_region(),記得參數修改,多測試找一個合適的參數。

代碼修改完了,那麼現在就需要修改生成tcmalloc動態庫的連接了。

找到在加載pthread庫的地方,在後面加上 -lhugetlbfs就ok,記得把生成的hugetlbfs庫拷貝到/usr/local/lib下,頭文件拷貝到/usr/local/include/下,還要再ld.so.conf中去添加一下/usr/local/lib哦。

剩下的就可以使用了,效率還是槓槓的,比之前tcmalloc還要好一點哦。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章