Commit 9113678d authored by Banit Agrawal's avatar Banit Agrawal Committed by Facebook Github Bot

Never decay the huge pages in JEMalloc

Summary: This diff disables the purging of huge pages and hence they will never be freed and will be counted towards the RSS of the process. This was done to ensure that we don't block on madvise call to get the huge pages and increase memory pressure on the system.

Reviewed By: gdankel

Differential Revision: D18607196

fbshipit-source-id: 79e483a715290fdfbdd1963433ec3918561a0e0e
parent 6a47d8fb
...@@ -69,7 +69,7 @@ static void print_error(int err, const char* msg) { ...@@ -69,7 +69,7 @@ static void print_error(int err, const char* msg) {
class HugePageArena { class HugePageArena {
public: public:
int init(int nr_pages, const JemallocHugePageAllocator::Options& options); int init(int nr_pages);
void* reserve(size_t size, size_t alignment); void* reserve(size_t size, size_t alignment);
bool addressInArena(void* address) { bool addressInArena(void* address) {
...@@ -181,9 +181,7 @@ void* HugePageArena::allocHook( ...@@ -181,9 +181,7 @@ void* HugePageArena::allocHook(
return res; return res;
} }
int HugePageArena::init( int HugePageArena::init(int nr_pages) {
int nr_pages,
const JemallocHugePageAllocator::Options& options) {
DCHECK(start_ == 0); DCHECK(start_ == 0);
DCHECK(usingJEMalloc()); DCHECK(usingJEMalloc());
...@@ -246,10 +244,9 @@ int HugePageArena::init( ...@@ -246,10 +244,9 @@ int HugePageArena::init(
return 0; return 0;
} }
if (options.noDecay) { // Set dirty decay and muzzy decay time to -1, which will cause jemalloc
// Set decay time to 0, which will cause jemalloc to free memory // to never free memory to kernel.
// back to kernel immediately. ssize_t decay_ms = -1;
ssize_t decay_ms = 0;
std::ostringstream dirty_decay_key; std::ostringstream dirty_decay_key;
dirty_decay_key << "arena." << arenaIndex_ << ".dirty_decay_ms"; dirty_decay_key << "arena." << arenaIndex_ << ".dirty_decay_ms";
if (auto ret = mallctl( if (auto ret = mallctl(
...@@ -258,9 +255,19 @@ int HugePageArena::init( ...@@ -258,9 +255,19 @@ int HugePageArena::init(
nullptr, nullptr,
&decay_ms, &decay_ms,
sizeof(decay_ms))) { sizeof(decay_ms))) {
print_error(ret, "Unable to set decay time"); print_error(ret, "Unable to set dirty decay time");
return 0; return 0;
} }
std::ostringstream muzzy_decay_key;
muzzy_decay_key << "arena." << arenaIndex_ << ".muzzy_decay_ms";
if (auto ret = mallctl(
muzzy_decay_key.str().c_str(),
nullptr,
nullptr,
&decay_ms,
sizeof(decay_ms))) {
print_error(ret, "Unable to set muzzy decay time");
return 0;
} }
start_ = freePtr_ = map_pages(nr_pages); start_ = freePtr_ = map_pages(nr_pages);
...@@ -287,14 +294,14 @@ void* HugePageArena::reserve(size_t size, size_t alignment) { ...@@ -287,14 +294,14 @@ void* HugePageArena::reserve(size_t size, size_t alignment) {
int JemallocHugePageAllocator::flags_{0}; int JemallocHugePageAllocator::flags_{0};
bool JemallocHugePageAllocator::init(int nr_pages, const Options& options) { bool JemallocHugePageAllocator::init(int nr_pages) {
if (!usingJEMalloc()) { if (!usingJEMalloc()) {
LOG(ERROR) << "Not linked with jemalloc?"; LOG(ERROR) << "Not linked with jemalloc?";
hugePagesSupported = false; hugePagesSupported = false;
} }
if (hugePagesSupported) { if (hugePagesSupported) {
if (flags_ == 0) { if (flags_ == 0) {
flags_ = arena.init(nr_pages, options); flags_ = arena.init(nr_pages);
} else { } else {
LOG(WARNING) << "Already initialized"; LOG(WARNING) << "Already initialized";
} }
......
...@@ -50,27 +50,17 @@ namespace folly { ...@@ -50,27 +50,17 @@ namespace folly {
* *
* If binary isn't linked with jemalloc, the logic falls back to malloc / free. * If binary isn't linked with jemalloc, the logic falls back to malloc / free.
* *
* Note that the madvise call does not guarantee huge pages, it is best effort. * Please note that as per kernel contract, page faults on an madvised region
* will block, so we pre-allocate all the huge pages by touching the pages.
* So, please only allocate as much you need as this will never be freed
* during the lifetime of the application. If we run out of the free huge pages,
* then huge page allocator falls back to the 4K regular pages.
* *
* 1GB Huge Pages are not supported at this point. * 1GB Huge Pages are not supported at this point.
*/ */
class JemallocHugePageAllocator { class JemallocHugePageAllocator {
public: public:
struct Options { static bool init(int nr_pages);
// Set decay time to 0, which will cause jemalloc to free memory
// back to kernel immediately. It can still be reclaimed later if
// the kernel hasn't reused it for something else.
// This is primarily useful for preventing RSS regressions, but
// can cause the number of available pages to shrink over time
// as the likelihood they get reused by the kernel is increased.
bool noDecay = false;
};
static bool init(int nr_pages) {
return init(nr_pages, Options());
}
static bool init(int nr_pages, const Options& options);
static void* allocate(size_t size) { static void* allocate(size_t size) {
// If uninitialized, flags_ will be 0 and the mallocx behavior // If uninitialized, flags_ will be 0 and the mallocx behavior
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment