Commit 9fb9ee6d authored by Brian Geffon's avatar Brian Geffon Committed by Commit Bot

chromeos: Add a feature to lock the browser text

On ChromeOS we have a kernel memory change which allows us to
fix the amount of page cache is available. This is primarily
used to try to keep the browser process resident while under
memory pressure to avoid user jank. This feature/experiment
will compare the performance of locking the browser text
directly while also lowering the min_filelist_kb kernel
tunable from https://crrev.com/c/1880966

For more context see go/min_filelist_kb

BUG=chromium:1014871
TESTED=On a betty image

Change-Id: I8fe9b3fd71b26c95097c71f42d6b2200ececbecc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1885298Reviewed-by: default avatarJay Civelli <jcivelli@chromium.org>
Reviewed-by: default avatarGeorge Burgess <gbiv@chromium.org>
Commit-Queue: Brian Geffon <bgeffon@chromium.org>
Cr-Commit-Position: refs/heads/master@{#711963}
parent ae6f919e
......@@ -114,6 +114,7 @@
#include "chromeos/constants/chromeos_switches.h"
#include "chromeos/hugepage_text/hugepage_text.h"
#include "chromeos/memory/kstaled.h"
#include "chromeos/memory/memory.h"
#include "chromeos/memory/swap_configuration.h"
#endif
......@@ -604,6 +605,10 @@ void ChromeMainDelegate::PostFieldTrialInitialization() {
#if defined(OS_CHROMEOS)
chromeos::ConfigureSwap();
chromeos::InitializeKstaled();
// If we're in an experimental group that locks the browser text we will do
// that now.
chromeos::LockMainProgramText();
#endif
}
}
......
......@@ -46,6 +46,8 @@ component("chromeos") {
"hugepage_text/hugepage_text.h",
"memory/kstaled.cc",
"memory/kstaled.h",
"memory/memory.cc",
"memory/memory.h",
"memory/swap_configuration.cc",
"memory/swap_configuration.h",
"policy/weekly_time/time_utils.cc",
......
......@@ -56,6 +56,9 @@ namespace chromeos {
#define MADV_HUGEPAGE 14
#endif
const base::Feature kCrOSHugepageRemapAndLockZygote{
"CrOSHugepageRemapAndLockInZygote", base::FEATURE_ENABLED_BY_DEFAULT};
const int kHpageShift = 21;
const int kHpageSize = (1 << kHpageShift);
const int kHpageMask = (~(kHpageSize - 1));
......@@ -296,7 +299,9 @@ static int FilterElfHeader(struct dl_phdr_info* info, size_t size, void* data) {
// the hugepages. Any errors will cause the failing piece of this to be rolled
// back, so nothing world-ending can come from this function (hopefully ;) ).
void InitHugepagesAndMlockSelf(void) {
dl_iterate_phdr(FilterElfHeader, 0);
if (base::FeatureList::IsEnabled(chromeos::kCrOSHugepageRemapAndLockZygote)) {
dl_iterate_phdr(FilterElfHeader, 0);
}
}
} // namespace chromeos
......@@ -13,6 +13,9 @@
#define CHROMEOS_HUGEPAGE_TEXT_HUGEPAGE_TEXT_H_
#include <string>
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
#include "chromeos/chromeos_export.h"
#if defined(__clang__) || defined(__GNUC__)
......@@ -23,6 +26,10 @@
namespace chromeos {
// A feature which controls remapping the zygotes hot text section as hugepages
// and locking.
extern const base::Feature kCrOSHugepageRemapAndLockZygote;
// This function will scan ELF segments and attempt to do two things:
// - Reload some of .text into hugepages
// - Lock some of .text into memory, so it can't be swapped out.
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/memory/memory.h"
#include <link.h>
#include <sys/mman.h>
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
namespace chromeos {
const base::Feature kCrOSLockMainProgramText{"CrOSLockMainProgramText",
base::FEATURE_DISABLED_BY_DEFAULT};
// The maximum number of bytes that the browser will attempt to lock.
const base::FeatureParam<int> kCrOSLockMainProgramTextMaxSize{
&kCrOSLockMainProgramText, "CrOSLockMainProgramTextMaxSize", -1};
namespace {
int ParseElfHeaderAndMlockBinaryText(struct dl_phdr_info* info,
size_t size,
void* data) {
// From dl_iterate_phdr's man page: "The first object visited by callback is
// the main program. For the main program, the dlpi_name field will be an
// empty string." Hence, no "is this the Chrome we're looking for?" checks are
// necessary.
for (int i = 0; i < info->dlpi_phnum; i++) {
if (info->dlpi_phdr[i].p_type == PT_LOAD &&
info->dlpi_phdr[i].p_flags == (PF_R | PF_X)) {
void* vaddr =
bit_cast<void*>(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
size_t segsize = info->dlpi_phdr[i].p_filesz;
ssize_t max_lockable_size = kCrOSLockMainProgramTextMaxSize.Get();
if (max_lockable_size > -1) {
// Note mlock/mlock2 do not require a page multiple.
segsize = std::min(static_cast<ssize_t>(segsize), max_lockable_size);
}
PLOG_IF(ERROR, !MlockMapping(vaddr, segsize))
<< "Unable to lock memory region " << vaddr;
return 1;
}
}
return -1;
}
// MlockAllText will attempt to lock the memory associated with the main
// program.
void MlockAllText() {
int res = dl_iterate_phdr(ParseElfHeaderAndMlockBinaryText, nullptr);
LOG_IF(ERROR, res == -1)
<< "Unable to lock main program text unable to find entry.";
}
} // namespace
// MlockMapping will attempt to lock a mapping using the newer mlock2 (if
// available on kernels 4.4+) with the MLOCK_ONFAULT flag, if the kernel does
// not support it then it will fall back to mlock.
bool MlockMapping(void* addr, size_t size) {
#if defined(__NR_mlock2)
int res = mlock2(addr, size, MLOCK_ONFAULT);
if (res == 0) {
return true;
}
// If the kernel returns ENOSYS it doesn't support mlock2 (pre v4.4) so just
// fall back to mlock.
if (res == -1 && errno != ENOSYS) {
return false;
}
#endif
return mlock(addr, size) == 0;
}
CHROMEOS_EXPORT void LockMainProgramText() {
if (base::FeatureList::IsEnabled(chromeos::kCrOSLockMainProgramText)) {
MlockAllText();
}
}
} // namespace chromeos
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_MEMORY_MEMORY_H_
#define CHROMEOS_MEMORY_MEMORY_H_
#include <cstddef>
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
#include "chromeos/chromeos_export.h"
namespace chromeos {
// MlockMaping will attempt to mlock a mapping using the newer mlock2 syscall
// if available using the MLOCK_ONFAULT option. This will allow pages to be
// locked as they are faulted in. If the running kernel does not support
// mlock2, it was added in kernel 4.4, it will fall back to mlock where it
// will lock all pages immediately by faulting them in.
CHROMEOS_EXPORT bool MlockMapping(void* addr, size_t length);
// A feature which controls the locking the main program text.
extern const base::Feature kCrOSLockMainProgramText;
// The maximum number of bytes that the browser will attempt to lock, -1 will
// disable the max size and is the default option.
extern const base::FeatureParam<int> kCrOSLockMainProgramTextMaxSize;
// Lock main program text segments fully.
CHROMEOS_EXPORT void LockMainProgramText();
} // namespace chromeos
#endif // CHROMEOS_MEMORY_MEMORY_H_
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