2012-12-07 12:32:24 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
2015-09-04 08:45:53 +03:00
|
|
|
#ifdef MOZ_JEMALLOC4
|
2012-12-07 12:32:24 +04:00
|
|
|
|
2012-12-07 12:32:24 +04:00
|
|
|
#define MOZ_JEMALLOC_IMPL
|
|
|
|
|
2015-08-20 09:50:42 +03:00
|
|
|
/* mozmemory_wrap.h needs to be included before MFBT headers */
|
2012-12-07 12:32:24 +04:00
|
|
|
#include "mozmemory_wrap.h"
|
2015-08-20 09:50:42 +03:00
|
|
|
#include <mozilla/Assertions.h>
|
2012-12-07 12:32:24 +04:00
|
|
|
#include "mozilla/Types.h"
|
|
|
|
|
2015-12-01 19:39:33 +03:00
|
|
|
#if defined(MOZ_NATIVE_JEMALLOC)
|
2015-12-01 19:54:44 +03:00
|
|
|
#include MALLOC_H
|
2015-12-01 19:39:33 +03:00
|
|
|
#else
|
2015-08-20 09:50:42 +03:00
|
|
|
#define DLLEXPORT
|
|
|
|
#include "jemalloc/jemalloc.h"
|
2015-12-01 19:39:33 +03:00
|
|
|
#endif
|
2015-08-20 09:50:42 +03:00
|
|
|
|
|
|
|
#ifdef XP_WIN
|
|
|
|
#include <windows.h>
|
|
|
|
#endif
|
|
|
|
#ifdef XP_DARWIN
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#endif
|
|
|
|
|
2012-12-07 12:32:24 +04:00
|
|
|
/* Override some jemalloc defaults */
|
2014-12-23 15:44:00 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
#define MOZ_MALLOC_BUILD_OPTIONS ",junk:true"
|
|
|
|
#else
|
|
|
|
#define MOZ_MALLOC_BUILD_OPTIONS ",junk:free"
|
|
|
|
#endif
|
|
|
|
|
2015-09-08 04:13:47 +03:00
|
|
|
#define MOZ_MALLOC_OPTIONS "narenas:1,tcache:false"
|
2015-09-02 05:04:42 +03:00
|
|
|
MFBT_DATA const char* je_(malloc_conf) =
|
Bug 1203840 - Trigger dirty pages purge after CC. r=njn,r=smaug,r=mccr8
Jemalloc 4 purges dirty pages regularly during free() when the ratio of dirty
pages compared to active pages is higher than 1 << lg_dirty_mult. We set
lg_dirty_mult in jemalloc_config to limit RSS usage, but it also has an impact
on performance.
So instead of enforcing a high ratio to force more pages being purged, we keep
jemalloc's default ratio of 8, and force a regular purge of all dirty pages,
after cycle collection.
Keeping jemalloc's default ratio avoids cycle-collection-triggered purge to
have to go through really all dirty pages when there are a lot, in which case
the normal jemalloc purge during free() will already have kicked in. It also
takes care of everything that doesn't run the cycle collector still having
a level of purge, like plugins in the plugin-container.
At the same time, since jemalloc_purge_freed_pages does nothing with jemalloc 4,
repurpose the MEMORY_FREE_PURGED_PAGES_MS telemetry probe to track the time
spent in this cycle-collector-triggered purge.
2015-09-11 08:12:21 +03:00
|
|
|
MOZ_MALLOC_OPTIONS MOZ_MALLOC_BUILD_OPTIONS;
|
2012-12-07 12:32:24 +04:00
|
|
|
|
|
|
|
#ifdef ANDROID
|
|
|
|
#include <android/log.h>
|
|
|
|
|
|
|
|
static void
|
2015-09-02 05:04:42 +03:00
|
|
|
_je_malloc_message(void* cbopaque, const char* s)
|
2012-12-07 12:32:24 +04:00
|
|
|
{
|
|
|
|
__android_log_print(ANDROID_LOG_INFO, "GeckoJemalloc", "%s", s);
|
|
|
|
}
|
|
|
|
|
2015-09-02 05:04:42 +03:00
|
|
|
void (*je_(malloc_message))(void*, const char* s) = _je_malloc_message;
|
2012-12-07 12:32:24 +04:00
|
|
|
#endif
|
|
|
|
|
2015-08-20 09:50:42 +03:00
|
|
|
/* Jemalloc supports hooks that are called on chunk
|
|
|
|
* allocate/deallocate/commit/decommit/purge/etc.
|
|
|
|
*
|
|
|
|
* We currently only hook commit, decommit and purge. We do this to tweak
|
|
|
|
* the way chunks are handled so that RSS stays lower than it normally
|
|
|
|
* would with the default jemalloc uses.
|
|
|
|
* This somewhat matches the behavior of mozjemalloc, except it doesn't
|
|
|
|
* rely on a double purge on mac, instead purging directly. (Yes, this
|
|
|
|
* means we can get rid of jemalloc_purge_freed_pages at some point)
|
|
|
|
*
|
|
|
|
* The default for jemalloc is to do the following:
|
|
|
|
* - commit, decommit: nothing
|
|
|
|
* - purge: MEM_RESET on Windows, MADV_FREE on Mac/BSD, MADV_DONTNEED on Linux
|
|
|
|
*
|
|
|
|
* The hooks we setup do the following:
|
|
|
|
* on Windows:
|
|
|
|
* - commit: MEM_COMMIT
|
|
|
|
* - decommit: MEM_DECOMMIT
|
|
|
|
* on Mac:
|
|
|
|
* - purge: mmap new anonymous memory on top of the chunk
|
|
|
|
*
|
|
|
|
* We only set the above hooks, others are left with the default.
|
|
|
|
*/
|
|
|
|
#if defined(XP_WIN) || defined(XP_DARWIN)
|
|
|
|
class JemallocInit {
|
|
|
|
public:
|
|
|
|
JemallocInit()
|
|
|
|
{
|
|
|
|
chunk_hooks_t hooks;
|
|
|
|
size_t hooks_len;
|
|
|
|
unsigned narenas;
|
|
|
|
size_t mib[3];
|
|
|
|
size_t size;
|
2012-12-07 12:32:24 +04:00
|
|
|
|
2015-08-20 09:50:42 +03:00
|
|
|
size = sizeof(narenas);
|
|
|
|
je_(mallctl)("arenas.narenas", &narenas, &size, nullptr, 0);
|
|
|
|
|
|
|
|
size = sizeof(mib) / sizeof(mib[0]);
|
|
|
|
je_(mallctlnametomib)("arena.0.chunk_hooks", mib, &size);
|
|
|
|
|
|
|
|
/* Set the hooks on all the existing arenas. */
|
|
|
|
for (unsigned arena = 0; arena < narenas; arena++) {
|
|
|
|
mib[1] = arena;
|
|
|
|
hooks_len = sizeof(hooks);
|
|
|
|
je_(mallctlbymib)(mib, size, &hooks, &hooks_len, nullptr, 0);
|
|
|
|
|
|
|
|
#ifdef XP_WIN
|
|
|
|
hooks.commit = CommitHook;
|
|
|
|
hooks.decommit = DecommitHook;
|
|
|
|
#endif
|
|
|
|
#ifdef XP_DARWIN
|
|
|
|
hooks.purge = PurgeHook;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
je_(mallctlbymib)(mib, size, nullptr, nullptr, &hooks, hooks_len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
#ifdef XP_WIN
|
|
|
|
static bool
|
|
|
|
CommitHook(void* chunk, size_t size, size_t offset, size_t length,
|
|
|
|
unsigned arena_ind)
|
|
|
|
{
|
|
|
|
void* addr = reinterpret_cast<void*>(
|
|
|
|
reinterpret_cast<uintptr_t>(chunk) + static_cast<uintptr_t>(offset));
|
|
|
|
|
|
|
|
if (!VirtualAlloc(addr, length, MEM_COMMIT, PAGE_READWRITE))
|
2015-09-15 20:53:38 +03:00
|
|
|
return true;
|
2015-08-20 09:50:42 +03:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
DecommitHook(void* chunk, size_t size, size_t offset, size_t length,
|
|
|
|
unsigned arena_ind)
|
|
|
|
{
|
|
|
|
void* addr = reinterpret_cast<void*>(
|
|
|
|
reinterpret_cast<uintptr_t>(chunk) + static_cast<uintptr_t>(offset));
|
|
|
|
|
|
|
|
if (!VirtualFree(addr, length, MEM_DECOMMIT))
|
|
|
|
MOZ_CRASH();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef XP_DARWIN
|
|
|
|
static bool
|
|
|
|
PurgeHook(void* chunk, size_t size, size_t offset, size_t length,
|
|
|
|
unsigned arena_ind)
|
|
|
|
{
|
|
|
|
void* addr = reinterpret_cast<void*>(
|
|
|
|
reinterpret_cast<uintptr_t>(chunk) + static_cast<uintptr_t>(offset));
|
|
|
|
|
|
|
|
void* new_addr = mmap(addr, length, PROT_READ | PROT_WRITE,
|
|
|
|
MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
|
|
|
|
return (new_addr != addr);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
/* For the static constructor from the class above */
|
|
|
|
JemallocInit gJemallocInit;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#else
|
2012-12-07 12:32:24 +04:00
|
|
|
#include <mozilla/Assertions.h>
|
2015-09-04 08:45:53 +03:00
|
|
|
#endif /* MOZ_JEMALLOC4 */
|
2012-12-07 12:32:24 +04:00
|
|
|
|
2015-08-20 09:50:42 +03:00
|
|
|
/* Provide an abort function for use in jemalloc code */
|
2015-09-02 05:04:42 +03:00
|
|
|
extern "C" void moz_abort() {
|
2012-12-07 12:32:24 +04:00
|
|
|
MOZ_CRASH();
|
|
|
|
}
|