Bug 1814798 - pt 2. Add a PHCManager component to control PHC r=glandium,emilio

This change adds the PHCManager class which observes a pref to control PHC.
The pref can be changed at runtime and will affect the parent and content
processes.

Differential Revision: https://phabricator.services.mozilla.com/D178754
This commit is contained in:
Paul Bone 2023-09-18 06:48:06 +00:00
Родитель accac535a0
Коммит cda96811f8
12 изменённых файлов: 160 добавлений и 4 удалений

Просмотреть файл

@ -324,7 +324,7 @@ static const size_t kAllPagesSize = kNumAllPages * kPageSize;
static const size_t kAllPagesJemallocSize = kAllPagesSize - kPageSize;
// The default state for PHC. Either Enabled or OnlyFree.
#define DEFAULT_STATE mozilla::phc::Enabled
#define DEFAULT_STATE mozilla::phc::OnlyFree
// The junk value used to fill new allocation in debug builds. It's same value
// as the one used by mozjemalloc. PHC applies it unconditionally in debug
@ -1399,8 +1399,6 @@ MOZ_ALWAYS_INLINE static void* PageRealloc(const Maybe<arena_id_t>& aArenaId,
return nullptr;
}
MOZ_ASSERT(aNewSize > kPageSize);
Delay reuseDelay = ReuseDelay(lock);
// Copy the usable size rather than the requested size, because the user

Просмотреть файл

@ -49,6 +49,8 @@ static const size_t kPageSize = 4096;
TEST(PHC, TestPHCAllocations)
{
ReplaceMalloc::SetPHCState(phc::PHCState::Enabled);
// First, check that allocations of various sizes all get put at the end of
// their page as expected. Also, check their sizes are as expected.
@ -259,6 +261,8 @@ static void TestFreedAllocation(uint8_t* aPtr, size_t aSize) {
TEST(PHC, TestPHCInfo)
{
ReplaceMalloc::SetPHCState(phc::PHCState::Enabled);
int stackVar;
phc::AddrInfo phcInfo;
@ -289,8 +293,10 @@ TEST(PHC, TestPHCInfo)
// possible to reliably get ahold of such a page.
}
TEST(PHC, TestPHCDisabling)
TEST(PHC, TestPHCDisablingThread)
{
ReplaceMalloc::SetPHCState(phc::PHCState::Enabled);
uint8_t* p = GetPHCAllocation(32);
uint8_t* q = GetPHCAllocation(32);
if (!p || !q) {
@ -329,6 +335,49 @@ TEST(PHC, TestPHCDisabling)
free(s);
}
TEST(PHC, TestPHCDisablingGlobal)
{
ReplaceMalloc::SetPHCState(phc::PHCState::Enabled);
uint8_t* p1 = GetPHCAllocation(32);
uint8_t* p2 = GetPHCAllocation(32);
uint8_t* q = GetPHCAllocation(32);
if (!p1 || !p2 || !q) {
MOZ_CRASH("failed to get a PHC allocation");
}
ReplaceMalloc::SetPHCState(phc::PHCState::OnlyFree);
// Test realloc() on a PHC allocation while PHC is disabled on the thread.
uint8_t* p3 = (uint8_t*)realloc(p1, 128);
// The small realloc is evicted from PHC because in "OnlyFree" state PHC
// tries to reduce its memory impact.
ASSERT_TRUE(p3 != p1);
ASSERT_FALSE(ReplaceMalloc::IsPHCAllocation(p3, nullptr));
free(p3);
uint8_t* p4 = (uint8_t*)realloc(p2, 8192);
// The big realloc is not in-place, and the result is not a PHC
// allocation, regardless of PHC's state.
ASSERT_TRUE(p4 != p2);
ASSERT_FALSE(ReplaceMalloc::IsPHCAllocation(p4, nullptr));
free(p4);
// Test free() on a PHC allocation while PHC is disabled on the thread.
free(q);
// These must not be PHC allocations.
uint8_t* r = GetPHCAllocation(32); // This will fail.
ASSERT_FALSE(!!r);
ReplaceMalloc::SetPHCState(phc::PHCState::Enabled);
// If it really was reenabled we should be able to get PHC allocations
// again.
uint8_t* s = GetPHCAllocation(32); // This should succeed.
ASSERT_TRUE(!!s);
free(s);
}
// This test is disabled for now, see Bug 1845017 and Bug 1845655.
// TEST(PHC, TestPHCExhaustion)
// {

Просмотреть файл

@ -10959,6 +10959,19 @@
mirror: always
#endif
#---------------------------------------------------------------------------
# Prefs starting with "memory."
#---------------------------------------------------------------------------
- name: memory.phc.enabled
type: bool
#if defined(MOZ_PHC)
value: true
#else
value: false
#endif
mirror: always
#---------------------------------------------------------------------------
# Prefs starting with "midi."
#---------------------------------------------------------------------------

Просмотреть файл

@ -62,6 +62,7 @@ pref_groups = [
"layout",
"mathml",
"media",
"memory",
"midi",
"mousewheel",
"mozilla",
@ -172,3 +173,6 @@ else:
FINAL_TARGET_PP_FILES += [
"greprefs.js",
]
if CONFIG["MOZ_PHC"]:
DEFINES["MOZ_PHC"] = True

Просмотреть файл

@ -7,6 +7,7 @@ export var CrashTestUtils = {
dumpHasStream: null,
dumpHasInstructionPointerMemory: null,
dumpWin64CFITestSymbols: null,
enablePHC: null,
// Constants for crash()
// Keep these in sync with nsTestCrasher.cpp!
@ -61,6 +62,11 @@ CrashTestUtils.saveAppMemory = lib.declare(
ctypes.default_abi,
ctypes.uint64_t
);
CrashTestUtils.enablePHC = lib.declare(
"EnablePHC",
ctypes.default_abi,
ctypes.void_t
);
try {
CrashTestUtils.TryOverrideExceptionHandler = lib.declare(

Просмотреть файл

@ -323,6 +323,12 @@ extern "C" NS_EXPORT void Crash(int16_t how) {
}
}
extern "C" NS_EXPORT void EnablePHC() {
#ifdef MOZ_PHC
ReplaceMalloc::SetPHCState(mozilla::phc::PHCState::Enabled);
#endif
};
char testData[32];
extern "C" NS_EXPORT uint64_t SaveAppMemory() {

Просмотреть файл

@ -27,3 +27,6 @@ const { CrashTestUtils } = ChromeUtils.importESModule(
);
var crashType = CrashTestUtils.CRASH_INVALID_POINTER_DEREF;
var shouldDelay = false;
// Turn PHC on so that the PHC tests work.
CrashTestUtils.enablePHC();

35
xpcom/base/PHCManager.cpp Normal file
Просмотреть файл

@ -0,0 +1,35 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#include "PHCManager.h"
#include "replace_malloc_bridge.h"
#include "mozilla/Preferences.h"
#include "mozilla/StaticPrefs_memory.h"
namespace mozilla {
using namespace phc;
static const char kPHCPref[] = "memory.phc.enabled";
static PHCState GetPHCStateFromPref() {
return StaticPrefs::memory_phc_enabled() ? Enabled : OnlyFree;
}
static void PrefChangeCallback(const char* aPrefName, void* aNull) {
MOZ_ASSERT(0 == strcmp(aPrefName, kPHCPref));
ReplaceMalloc::SetPHCState(GetPHCStateFromPref());
}
void InitPHCState() {
ReplaceMalloc::SetPHCState(GetPHCStateFromPref());
Preferences::RegisterCallback(PrefChangeCallback, kPHCPref);
}
}; // namespace mozilla

18
xpcom/base/PHCManager.h Normal file
Просмотреть файл

@ -0,0 +1,18 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#ifndef mozilla_PHCManager_h
#define mozilla_PHCManager_h
namespace mozilla {
// Read the PHC pref and potentially initialise PHC. Also register a
// callback for the pref to update PHC as the pref changes.
void InitPHCState();
}; // namespace mozilla
#endif // mozilla_PHCManager_h

Просмотреть файл

@ -257,3 +257,15 @@ LOCAL_INCLUDES += [
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
CXXFLAGS += CONFIG["MOZ_GTK3_CFLAGS"]
if CONFIG["MOZ_PHC"]:
EXPORTS.mozilla += [
"PHCManager.h",
]
DEFINES["MOZ_PHC"] = 1
UNIFIED_SOURCES += ["PHCManager.cpp"]
with Files("PHCManager.*"):
BUG_COMPONENT = ("Core", "Memory Allocator")

Просмотреть файл

@ -89,6 +89,9 @@
#include "mozilla/AvailableMemoryTracker.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/CountingAllocatorBase.h"
#ifdef MOZ_PHC
# include "mozilla/PHCManager.h"
#endif
#include "mozilla/UniquePtr.h"
#include "mozilla/ServoStyleConsts.h"
@ -448,6 +451,12 @@ NS_InitXPCOM(nsIServiceManager** aResult, nsIFile* aBinDirectory,
NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
}
#ifdef MOZ_PHC
// This is the earliest possible moment we can start PHC while still being
// able to read prefs.
mozilla::InitPHCState();
#endif
// After autoreg, but before we actually instantiate any components,
// add any services listed in the "xpcom-directory-providers" category
// to the directory service.

Просмотреть файл

@ -103,3 +103,6 @@ if CONFIG["MOZ_VPX"]:
LOCAL_INCLUDES += [
"/media/libvpx",
]
if CONFIG["MOZ_PHC"]:
DEFINES["MOZ_PHC"] = 1