mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 23:02:20 +00:00
Backed out changesets 59452425e446 and a13166f0d914 (bug 1081871) for causing bug 1122119.
This commit is contained in:
parent
e6acb1c0c4
commit
83b898f175
@ -693,57 +693,50 @@ pref("dom.ipc.processPriorityManager.backgroundLRUPoolLevels", 5);
|
|||||||
// Kernel parameters for process priorities. These affect how processes are
|
// Kernel parameters for process priorities. These affect how processes are
|
||||||
// killed on low-memory and their relative CPU priorities.
|
// killed on low-memory and their relative CPU priorities.
|
||||||
//
|
//
|
||||||
|
// Note: The maximum nice value on Linux is 19, but the max value you should
|
||||||
|
// use here is 18. NSPR adds 1 to some threads' nice values, to mark
|
||||||
|
// low-priority threads. If the process priority manager were to renice a
|
||||||
|
// process (and all its threads) to 19, all threads would have the same
|
||||||
|
// niceness. Then when we reniced the process to (say) 10, all threads would
|
||||||
|
// /still/ have the same niceness; we'd effectively have erased NSPR's thread
|
||||||
|
// priorities.
|
||||||
|
|
||||||
// The kernel can only accept 6 (OomScoreAdjust, KillUnderKB) pairs. But it is
|
// The kernel can only accept 6 (OomScoreAdjust, KillUnderKB) pairs. But it is
|
||||||
// okay, kernel will still kill processes with larger OomScoreAdjust first even
|
// okay, kernel will still kill processes with larger OomScoreAdjust first even
|
||||||
// its OomScoreAdjust don't have a corresponding KillUnderKB.
|
// its OomScoreAdjust don't have a corresponding KillUnderKB.
|
||||||
|
|
||||||
pref("hal.processPriorityManager.gonk.MASTER.OomScoreAdjust", 0);
|
pref("hal.processPriorityManager.gonk.MASTER.OomScoreAdjust", 0);
|
||||||
pref("hal.processPriorityManager.gonk.MASTER.KillUnderKB", 4096);
|
pref("hal.processPriorityManager.gonk.MASTER.KillUnderKB", 4096);
|
||||||
pref("hal.processPriorityManager.gonk.MASTER.cgroup", "");
|
pref("hal.processPriorityManager.gonk.MASTER.Nice", 0);
|
||||||
|
|
||||||
pref("hal.processPriorityManager.gonk.PREALLOC.OomScoreAdjust", 67);
|
pref("hal.processPriorityManager.gonk.PREALLOC.OomScoreAdjust", 67);
|
||||||
pref("hal.processPriorityManager.gonk.PREALLOC.cgroup", "apps/bg_non_interactive");
|
pref("hal.processPriorityManager.gonk.PREALLOC.Nice", 18);
|
||||||
|
|
||||||
pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.OomScoreAdjust", 67);
|
pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.OomScoreAdjust", 67);
|
||||||
pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.KillUnderKB", 5120);
|
pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.KillUnderKB", 5120);
|
||||||
pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.cgroup", "apps/critical");
|
pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.Nice", 0);
|
||||||
|
|
||||||
pref("hal.processPriorityManager.gonk.FOREGROUND.OomScoreAdjust", 134);
|
pref("hal.processPriorityManager.gonk.FOREGROUND.OomScoreAdjust", 134);
|
||||||
pref("hal.processPriorityManager.gonk.FOREGROUND.KillUnderKB", 6144);
|
pref("hal.processPriorityManager.gonk.FOREGROUND.KillUnderKB", 6144);
|
||||||
pref("hal.processPriorityManager.gonk.FOREGROUND.cgroup", "apps");
|
pref("hal.processPriorityManager.gonk.FOREGROUND.Nice", 1);
|
||||||
|
|
||||||
pref("hal.processPriorityManager.gonk.FOREGROUND_KEYBOARD.OomScoreAdjust", 200);
|
pref("hal.processPriorityManager.gonk.FOREGROUND_KEYBOARD.OomScoreAdjust", 200);
|
||||||
pref("hal.processPriorityManager.gonk.FOREGROUND_KEYBOARD.cgroup", "apps");
|
pref("hal.processPriorityManager.gonk.FOREGROUND_KEYBOARD.Nice", 1);
|
||||||
|
|
||||||
pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.OomScoreAdjust", 400);
|
pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.OomScoreAdjust", 400);
|
||||||
pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.KillUnderKB", 7168);
|
pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.KillUnderKB", 7168);
|
||||||
pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.cgroup", "apps/bg_perceivable");
|
pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.Nice", 7);
|
||||||
|
|
||||||
pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.OomScoreAdjust", 534);
|
pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.OomScoreAdjust", 534);
|
||||||
pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.KillUnderKB", 8192);
|
pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.KillUnderKB", 8192);
|
||||||
pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.cgroup", "apps/bg_non_interactive");
|
pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.Nice", 18);
|
||||||
|
|
||||||
pref("hal.processPriorityManager.gonk.BACKGROUND.OomScoreAdjust", 667);
|
pref("hal.processPriorityManager.gonk.BACKGROUND.OomScoreAdjust", 667);
|
||||||
pref("hal.processPriorityManager.gonk.BACKGROUND.KillUnderKB", 20480);
|
pref("hal.processPriorityManager.gonk.BACKGROUND.KillUnderKB", 20480);
|
||||||
pref("hal.processPriorityManager.gonk.BACKGROUND.cgroup", "apps/bg_non_interactive");
|
pref("hal.processPriorityManager.gonk.BACKGROUND.Nice", 18);
|
||||||
|
|
||||||
// Control group definitions (i.e., CPU priority groups) for B2G processes.
|
// Processes get this niceness when they have low CPU priority.
|
||||||
|
pref("hal.processPriorityManager.gonk.LowCPUNice", 18);
|
||||||
// Foreground apps
|
|
||||||
pref("hal.processPriorityManager.gonk.cgroups.apps.cpu_shares", 1024);
|
|
||||||
pref("hal.processPriorityManager.gonk.cgroups.apps.cpu_notify_on_migrate", 1);
|
|
||||||
|
|
||||||
// Foreground apps with high priority, 16x more CPU than foreground ones
|
|
||||||
pref("hal.processPriorityManager.gonk.cgroups.apps/critical.cpu_shares", 16384);
|
|
||||||
pref("hal.processPriorityManager.gonk.cgroups.apps/critical.cpu_notify_on_migrate", 1);
|
|
||||||
|
|
||||||
// Background perceivable apps, ~10x less CPU than foreground ones
|
|
||||||
pref("hal.processPriorityManager.gonk.cgroups.apps/bg_perceivable.cpu_shares", 103);
|
|
||||||
pref("hal.processPriorityManager.gonk.cgroups.apps/bg_perceivable.cpu_notify_on_migrate", 0);
|
|
||||||
|
|
||||||
// Background apps, ~20x less CPU than foreground ones and ~2x less than perceivable ones
|
|
||||||
pref("hal.processPriorityManager.gonk.cgroups.apps/bg_non_interactive.cpu_shares", 52);
|
|
||||||
pref("hal.processPriorityManager.gonk.cgroups.apps/bg_non_interactive.cpu_notify_on_migrate", 0);
|
|
||||||
|
|
||||||
// By default the compositor thread on gonk runs without real-time priority. RT
|
// By default the compositor thread on gonk runs without real-time priority. RT
|
||||||
// priority can be enabled by setting this pref to a value between 1 and 99.
|
// priority can be enabled by setting this pref to a value between 1 and 99.
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/klog.h>
|
#include <sys/klog.h>
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@ -48,7 +47,6 @@
|
|||||||
#include "HalImpl.h"
|
#include "HalImpl.h"
|
||||||
#include "HalLog.h"
|
#include "HalLog.h"
|
||||||
#include "mozilla/ArrayUtils.h"
|
#include "mozilla/ArrayUtils.h"
|
||||||
#include "mozilla/ClearOnShutdown.h"
|
|
||||||
#include "mozilla/dom/battery/Constants.h"
|
#include "mozilla/dom/battery/Constants.h"
|
||||||
#include "mozilla/DebugOnly.h"
|
#include "mozilla/DebugOnly.h"
|
||||||
#include "mozilla/FileUtils.h"
|
#include "mozilla/FileUtils.h"
|
||||||
@ -630,6 +628,28 @@ namespace {
|
|||||||
/**
|
/**
|
||||||
* RAII class to help us remember to close file descriptors.
|
* RAII class to help us remember to close file descriptors.
|
||||||
*/
|
*/
|
||||||
|
const char *wakeLockFilename = "/sys/power/wake_lock";
|
||||||
|
const char *wakeUnlockFilename = "/sys/power/wake_unlock";
|
||||||
|
|
||||||
|
template<ssize_t n>
|
||||||
|
bool ReadFromFile(const char *filename, char (&buf)[n])
|
||||||
|
{
|
||||||
|
int fd = open(filename, O_RDONLY);
|
||||||
|
ScopedClose autoClose(fd);
|
||||||
|
if (fd < 0) {
|
||||||
|
HAL_LOG("Unable to open file %s.", filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t numRead = read(fd, buf, n);
|
||||||
|
if (numRead < 0) {
|
||||||
|
HAL_LOG("Error reading from file %s.", filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[std::min(numRead, n - 1)] = '\0';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool WriteToFile(const char *filename, const char *toWrite)
|
bool WriteToFile(const char *filename, const char *toWrite)
|
||||||
{
|
{
|
||||||
@ -755,9 +775,6 @@ static Monitor* sInternalLockCpuMonitor = nullptr;
|
|||||||
static void
|
static void
|
||||||
UpdateCpuSleepState()
|
UpdateCpuSleepState()
|
||||||
{
|
{
|
||||||
const char *wakeLockFilename = "/sys/power/wake_lock";
|
|
||||||
const char *wakeUnlockFilename = "/sys/power/wake_unlock";
|
|
||||||
|
|
||||||
sInternalLockCpuMonitor->AssertCurrentThreadOwns();
|
sInternalLockCpuMonitor->AssertCurrentThreadOwns();
|
||||||
bool allowed = sCpuSleepAllowed && !sInternalLockCpuCount;
|
bool allowed = sCpuSleepAllowed && !sInternalLockCpuCount;
|
||||||
WriteToFile(allowed ? wakeUnlockFilename : wakeLockFilename, "gecko");
|
WriteToFile(allowed ? wakeUnlockFilename : wakeLockFilename, "gecko");
|
||||||
@ -1269,6 +1286,7 @@ OomVictimLogger::Observe(
|
|||||||
lineTimestampFound = true;
|
lineTimestampFound = true;
|
||||||
mLastLineChecked = lineTimestamp;
|
mLastLineChecked = lineTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Log interesting lines
|
// Log interesting lines
|
||||||
for (size_t i = 0; i < regex_count; i++) {
|
for (size_t i = 0; i < regex_count; i++) {
|
||||||
@ -1294,261 +1312,6 @@ OomVictimLogger::Observe(
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Wraps a particular ProcessPriority, giving us easy access to the prefs that
|
|
||||||
* are relevant to it.
|
|
||||||
*
|
|
||||||
* Creating a PriorityClass also ensures that the control group is created.
|
|
||||||
*/
|
|
||||||
class PriorityClass
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Create a PriorityClass for the given ProcessPriority. This implicitly
|
|
||||||
* reads the relevant prefs and opens the cgroup.procs file of the relevant
|
|
||||||
* control group caching its file descriptor for later use.
|
|
||||||
*/
|
|
||||||
PriorityClass(ProcessPriority aPriority);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes the file descriptor for the cgroup.procs file of the associated
|
|
||||||
* control group.
|
|
||||||
*/
|
|
||||||
~PriorityClass();
|
|
||||||
|
|
||||||
PriorityClass(const PriorityClass& aOther);
|
|
||||||
PriorityClass& operator=(const PriorityClass& aOther);
|
|
||||||
|
|
||||||
ProcessPriority Priority()
|
|
||||||
{
|
|
||||||
return mPriority;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t OomScoreAdj()
|
|
||||||
{
|
|
||||||
return clamped<int32_t>(mOomScoreAdj, OOM_SCORE_ADJ_MIN, OOM_SCORE_ADJ_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t KillUnderKB()
|
|
||||||
{
|
|
||||||
return mKillUnderKB;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCString CGroup()
|
|
||||||
{
|
|
||||||
return mGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a process to this priority class, this moves the process' PID into
|
|
||||||
* the associated control group.
|
|
||||||
*
|
|
||||||
* @param aPid The PID of the process to be added.
|
|
||||||
*/
|
|
||||||
void AddProcess(int aPid);
|
|
||||||
|
|
||||||
private:
|
|
||||||
ProcessPriority mPriority;
|
|
||||||
int32_t mOomScoreAdj;
|
|
||||||
int32_t mKillUnderKB;
|
|
||||||
int mCGroupProcsFd;
|
|
||||||
nsCString mGroup;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a string that identifies where we can find the value of aPref
|
|
||||||
* that's specific to mPriority. For example, we might return
|
|
||||||
* "hal.processPriorityManager.gonk.FOREGROUND_HIGH.oomScoreAdjust".
|
|
||||||
*/
|
|
||||||
nsCString PriorityPrefName(const char* aPref)
|
|
||||||
{
|
|
||||||
return nsPrintfCString("hal.processPriorityManager.gonk.%s.%s",
|
|
||||||
ProcessPriorityToString(mPriority), aPref);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the full path of the cgroup.procs file associated with the group.
|
|
||||||
*/
|
|
||||||
nsCString CGroupProcsFilename()
|
|
||||||
{
|
|
||||||
nsCString cgroupName = mGroup;
|
|
||||||
|
|
||||||
/* If mGroup is empty, our cgroup.procs file is the root procs file,
|
|
||||||
* located at /dev/cpuctl/cgroup.procs. Otherwise our procs file is
|
|
||||||
* /dev/cpuctl/NAME/cgroup.procs. */
|
|
||||||
|
|
||||||
if (!mGroup.IsEmpty()) {
|
|
||||||
cgroupName.AppendLiteral("/");
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_LITERAL_CSTRING("/dev/cpuctl/") + cgroupName +
|
|
||||||
NS_LITERAL_CSTRING("cgroup.procs");
|
|
||||||
}
|
|
||||||
|
|
||||||
int OpenCGroupProcs()
|
|
||||||
{
|
|
||||||
return open(CGroupProcsFilename().get(), O_WRONLY);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Try to create the cgroup for the given PriorityClass, if it doesn't already
|
|
||||||
* exist. This essentially implements mkdir -p; that is, we create parent
|
|
||||||
* cgroups as necessary. The group parameters are also set according to
|
|
||||||
* the corresponding preferences.
|
|
||||||
*
|
|
||||||
* @param aGroup The name of the group.
|
|
||||||
* @return true if we successfully created the cgroup, or if it already
|
|
||||||
* exists. Otherwise, return false.
|
|
||||||
*/
|
|
||||||
static bool
|
|
||||||
EnsureCGroupExists(const nsACString &aGroup)
|
|
||||||
{
|
|
||||||
NS_NAMED_LITERAL_CSTRING(kDevCpuCtl, "/dev/cpuctl/");
|
|
||||||
NS_NAMED_LITERAL_CSTRING(kSlash, "/");
|
|
||||||
|
|
||||||
nsAutoCString prefPrefix("hal.processPriorityManager.gonk.cgroups.");
|
|
||||||
|
|
||||||
/* If cgroup is not empty, append the cgroup name and a dot to obtain the
|
|
||||||
* group specific preferences. */
|
|
||||||
if (!aGroup.IsEmpty()) {
|
|
||||||
prefPrefix += aGroup + NS_LITERAL_CSTRING(".");
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoCString cpuSharesPref(prefPrefix + NS_LITERAL_CSTRING("cpu_shares"));
|
|
||||||
int cpuShares = Preferences::GetInt(cpuSharesPref.get());
|
|
||||||
|
|
||||||
nsAutoCString cpuNotifyOnMigratePref(prefPrefix
|
|
||||||
+ NS_LITERAL_CSTRING("cpu_notify_on_migrate"));
|
|
||||||
int cpuNotifyOnMigrate = Preferences::GetInt(cpuNotifyOnMigratePref.get());
|
|
||||||
|
|
||||||
// Create mCGroup and its parent directories, as necessary.
|
|
||||||
nsCString cgroupIter = aGroup + kSlash;
|
|
||||||
|
|
||||||
int32_t offset = 0;
|
|
||||||
while ((offset = cgroupIter.FindChar('/', offset)) != -1) {
|
|
||||||
nsAutoCString path = kDevCpuCtl + Substring(cgroupIter, 0, offset);
|
|
||||||
int rv = mkdir(path.get(), 0744);
|
|
||||||
|
|
||||||
if (rv == -1 && errno != EEXIST) {
|
|
||||||
HAL_LOG("Could not create the %s control group.", path.get());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoCString pathPrefix(kDevCpuCtl + aGroup + kSlash);
|
|
||||||
nsAutoCString cpuSharesPath(pathPrefix + NS_LITERAL_CSTRING("cpu.shares"));
|
|
||||||
if (cpuShares && !WriteToFile(cpuSharesPath.get(),
|
|
||||||
nsPrintfCString("%d", cpuShares).get())) {
|
|
||||||
HAL_LOG("Could not set the cpu share for group %s", cpuSharesPath.get());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoCString notifyOnMigratePath(pathPrefix
|
|
||||||
+ NS_LITERAL_CSTRING("cpu.notify_on_migrate"));
|
|
||||||
if (!WriteToFile(notifyOnMigratePath.get(),
|
|
||||||
nsPrintfCString("%d", cpuNotifyOnMigrate).get())) {
|
|
||||||
HAL_LOG("Could not set the cpu migration notification flag for group %s",
|
|
||||||
notifyOnMigratePath.get());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
PriorityClass::PriorityClass(ProcessPriority aPriority)
|
|
||||||
: mPriority(aPriority)
|
|
||||||
, mOomScoreAdj(0)
|
|
||||||
, mKillUnderKB(0)
|
|
||||||
, mCGroupProcsFd(-1)
|
|
||||||
{
|
|
||||||
DebugOnly<nsresult> rv;
|
|
||||||
|
|
||||||
rv = Preferences::GetInt(PriorityPrefName("OomScoreAdjust").get(),
|
|
||||||
&mOomScoreAdj);
|
|
||||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "Missing oom_score_adj preference");
|
|
||||||
|
|
||||||
rv = Preferences::GetInt(PriorityPrefName("KillUnderKB").get(),
|
|
||||||
&mKillUnderKB);
|
|
||||||
|
|
||||||
rv = Preferences::GetCString(PriorityPrefName("cgroup").get(), &mGroup);
|
|
||||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "Missing control group preference");
|
|
||||||
|
|
||||||
if (EnsureCGroupExists(mGroup)) {
|
|
||||||
mCGroupProcsFd = OpenCGroupProcs();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PriorityClass::~PriorityClass()
|
|
||||||
{
|
|
||||||
close(mCGroupProcsFd);
|
|
||||||
}
|
|
||||||
|
|
||||||
PriorityClass::PriorityClass(const PriorityClass& aOther)
|
|
||||||
: mPriority(aOther.mPriority)
|
|
||||||
, mOomScoreAdj(aOther.mOomScoreAdj)
|
|
||||||
, mKillUnderKB(aOther.mKillUnderKB)
|
|
||||||
, mGroup(aOther.mGroup)
|
|
||||||
{
|
|
||||||
mCGroupProcsFd = OpenCGroupProcs();
|
|
||||||
}
|
|
||||||
|
|
||||||
PriorityClass& PriorityClass::operator=(const PriorityClass& aOther)
|
|
||||||
{
|
|
||||||
mPriority = aOther.mPriority;
|
|
||||||
mOomScoreAdj = aOther.mOomScoreAdj;
|
|
||||||
mKillUnderKB = aOther.mKillUnderKB;
|
|
||||||
mGroup = aOther.mGroup;
|
|
||||||
mCGroupProcsFd = OpenCGroupProcs();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PriorityClass::AddProcess(int aPid)
|
|
||||||
{
|
|
||||||
if (mCGroupProcsFd < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsPrintfCString str("%d", aPid);
|
|
||||||
|
|
||||||
if (write(mCGroupProcsFd, str.get(), strlen(str.get())) < 0) {
|
|
||||||
HAL_ERR("Couldn't add PID %d to the %s control group", aPid, mGroup.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the PriorityClass associated with the given ProcessPriority.
|
|
||||||
*
|
|
||||||
* If you pass an invalid ProcessPriority value, we return null.
|
|
||||||
*
|
|
||||||
* The pointers returned here are owned by GetPriorityClass (don't free them
|
|
||||||
* yourself). They are guaranteed to stick around until shutdown.
|
|
||||||
*/
|
|
||||||
PriorityClass*
|
|
||||||
GetPriorityClass(ProcessPriority aPriority)
|
|
||||||
{
|
|
||||||
static StaticAutoPtr<nsTArray<PriorityClass>> priorityClasses;
|
|
||||||
|
|
||||||
// Initialize priorityClasses if this is the first time we're running this
|
|
||||||
// method.
|
|
||||||
if (!priorityClasses) {
|
|
||||||
priorityClasses = new nsTArray<PriorityClass>();
|
|
||||||
ClearOnShutdown(&priorityClasses);
|
|
||||||
|
|
||||||
for (int32_t i = 0; i < NUM_PROCESS_PRIORITY; i++) {
|
|
||||||
priorityClasses->AppendElement(PriorityClass(ProcessPriority(i)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aPriority < 0 ||
|
|
||||||
static_cast<uint32_t>(aPriority) >= priorityClasses->Length()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return &(*priorityClasses)[aPriority];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
EnsureKernelLowMemKillerParamsSet()
|
EnsureKernelLowMemKillerParamsSet()
|
||||||
{
|
{
|
||||||
@ -1589,12 +1352,21 @@ EnsureKernelLowMemKillerParamsSet()
|
|||||||
// The system doesn't function correctly if we're missing these prefs, so
|
// The system doesn't function correctly if we're missing these prefs, so
|
||||||
// crash loudly.
|
// crash loudly.
|
||||||
|
|
||||||
PriorityClass* pc = GetPriorityClass(static_cast<ProcessPriority>(i));
|
ProcessPriority priority = static_cast<ProcessPriority>(i);
|
||||||
|
|
||||||
int32_t oomScoreAdj = pc->OomScoreAdj();
|
int32_t oomScoreAdj;
|
||||||
int32_t killUnderKB = pc->KillUnderKB();
|
if (!NS_SUCCEEDED(Preferences::GetInt(
|
||||||
|
nsPrintfCString("hal.processPriorityManager.gonk.%s.OomScoreAdjust",
|
||||||
|
ProcessPriorityToString(priority)).get(),
|
||||||
|
&oomScoreAdj))) {
|
||||||
|
MOZ_CRASH();
|
||||||
|
}
|
||||||
|
|
||||||
if (killUnderKB == 0) {
|
int32_t killUnderKB;
|
||||||
|
if (!NS_SUCCEEDED(Preferences::GetInt(
|
||||||
|
nsPrintfCString("hal.processPriorityManager.gonk.%s.KillUnderKB",
|
||||||
|
ProcessPriorityToString(priority)).get(),
|
||||||
|
&killUnderKB))) {
|
||||||
// ProcessPriority values like PROCESS_PRIORITY_FOREGROUND_KEYBOARD,
|
// ProcessPriority values like PROCESS_PRIORITY_FOREGROUND_KEYBOARD,
|
||||||
// which has only OomScoreAdjust but lacks KillUnderMB value, will not
|
// which has only OomScoreAdjust but lacks KillUnderMB value, will not
|
||||||
// create new LMK parameters.
|
// create new LMK parameters.
|
||||||
@ -1625,8 +1397,7 @@ EnsureKernelLowMemKillerParamsSet()
|
|||||||
minfreeParams.Cut(minfreeParams.Length() - 1, 1);
|
minfreeParams.Cut(minfreeParams.Length() - 1, 1);
|
||||||
if (!adjParams.IsEmpty() && !minfreeParams.IsEmpty()) {
|
if (!adjParams.IsEmpty() && !minfreeParams.IsEmpty()) {
|
||||||
WriteToFile("/sys/module/lowmemorykiller/parameters/adj", adjParams.get());
|
WriteToFile("/sys/module/lowmemorykiller/parameters/adj", adjParams.get());
|
||||||
WriteToFile("/sys/module/lowmemorykiller/parameters/minfree",
|
WriteToFile("/sys/module/lowmemorykiller/parameters/minfree", minfreeParams.get());
|
||||||
minfreeParams.get());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the low-memory-notification threshold.
|
// Set the low-memory-notification threshold.
|
||||||
@ -1648,6 +1419,148 @@ EnsureKernelLowMemKillerParamsSet()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
SetNiceForPid(int aPid, int aNice)
|
||||||
|
{
|
||||||
|
errno = 0;
|
||||||
|
int origProcPriority = getpriority(PRIO_PROCESS, aPid);
|
||||||
|
if (errno) {
|
||||||
|
HAL_LOG("Unable to get nice for pid=%d; error %d. SetNiceForPid bailing.",
|
||||||
|
aPid, errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rv = setpriority(PRIO_PROCESS, aPid, aNice);
|
||||||
|
if (rv) {
|
||||||
|
HAL_LOG("Unable to set nice for pid=%d; error %d. SetNiceForPid bailing.",
|
||||||
|
aPid, errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On Linux, setpriority(aPid) modifies the priority only of the main
|
||||||
|
// thread of that process. We have to modify the priorities of all of the
|
||||||
|
// process's threads as well, so iterate over all the threads and increase
|
||||||
|
// each of their priorites by aNice - origProcPriority (and also ensure that
|
||||||
|
// none of the tasks has a lower priority than the main thread).
|
||||||
|
//
|
||||||
|
// This is horribly racy.
|
||||||
|
|
||||||
|
DIR* tasksDir = opendir(nsPrintfCString("/proc/%d/task/", aPid).get());
|
||||||
|
if (!tasksDir) {
|
||||||
|
HAL_LOG("Unable to open /proc/%d/task. SetNiceForPid bailing.", aPid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Be careful not to leak tasksDir; after this point, we must call closedir().
|
||||||
|
|
||||||
|
while (struct dirent* de = readdir(tasksDir)) {
|
||||||
|
char* endptr = nullptr;
|
||||||
|
long tidlong = strtol(de->d_name, &endptr, /* base */ 10);
|
||||||
|
if (*endptr || tidlong < 0 || tidlong > INT32_MAX || tidlong == aPid) {
|
||||||
|
// if dp->d_name was not an integer, was negative (?!) or too large, or
|
||||||
|
// was the same as aPid, we're not interested.
|
||||||
|
//
|
||||||
|
// (The |tidlong == aPid| check is very important; without it, we'll
|
||||||
|
// renice aPid twice, and the second renice will be relative to the
|
||||||
|
// priority set by the first renice.)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tid = static_cast<int>(tidlong);
|
||||||
|
|
||||||
|
// Do not set the priority of threads running with a real-time policy
|
||||||
|
// as part of the bulk process adjustment. These threads need to run
|
||||||
|
// at their specified priority in order to meet timing guarantees.
|
||||||
|
int schedPolicy = sched_getscheduler(tid);
|
||||||
|
if (schedPolicy == SCHED_FIFO || schedPolicy == SCHED_RR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
// Get and set the task's new priority.
|
||||||
|
int origtaskpriority = getpriority(PRIO_PROCESS, tid);
|
||||||
|
if (errno) {
|
||||||
|
HAL_LOG("Unable to get nice for tid=%d (pid=%d); error %d. This isn't "
|
||||||
|
"necessarily a problem; it could be a benign race condition.",
|
||||||
|
tid, aPid, errno);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int newtaskpriority =
|
||||||
|
std::max(origtaskpriority - origProcPriority + aNice, aNice);
|
||||||
|
|
||||||
|
// Do not reduce priority of threads already running at priorities greater
|
||||||
|
// than normal. These threads are likely special service threads that need
|
||||||
|
// elevated priorities to process audio, display composition, etc.
|
||||||
|
if (newtaskpriority > origtaskpriority &&
|
||||||
|
origtaskpriority < ANDROID_PRIORITY_NORMAL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = setpriority(PRIO_PROCESS, tid, newtaskpriority);
|
||||||
|
|
||||||
|
if (rv) {
|
||||||
|
HAL_LOG("Unable to set nice for tid=%d (pid=%d); error %d. This isn't "
|
||||||
|
"necessarily a problem; it could be a benign race condition.",
|
||||||
|
tid, aPid, errno);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HAL_LOG("Changed nice for pid %d from %d to %d.",
|
||||||
|
aPid, origProcPriority, aNice);
|
||||||
|
|
||||||
|
closedir(tasksDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used to store the nice value adjustments and oom_adj values for the various
|
||||||
|
* process priority levels.
|
||||||
|
*/
|
||||||
|
struct ProcessPriorityPrefs {
|
||||||
|
bool initialized;
|
||||||
|
int lowPriorityNice;
|
||||||
|
struct {
|
||||||
|
int nice;
|
||||||
|
int oomScoreAdj;
|
||||||
|
} priorities[NUM_PROCESS_PRIORITY];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reads the preferences for the various process priority levels and sets up
|
||||||
|
* watchers so that if they're dynamically changed the change is reflected on
|
||||||
|
* the appropriate variables.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
EnsureProcessPriorityPrefs(ProcessPriorityPrefs* prefs)
|
||||||
|
{
|
||||||
|
if (prefs->initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the preferences for process priority levels
|
||||||
|
for (int i = PROCESS_PRIORITY_BACKGROUND; i < NUM_PROCESS_PRIORITY; i++) {
|
||||||
|
ProcessPriority priority = static_cast<ProcessPriority>(i);
|
||||||
|
|
||||||
|
// Read the nice values
|
||||||
|
const char* processPriorityStr = ProcessPriorityToString(priority);
|
||||||
|
nsPrintfCString niceStr("hal.processPriorityManager.gonk.%s.Nice",
|
||||||
|
processPriorityStr);
|
||||||
|
Preferences::AddIntVarCache(&prefs->priorities[i].nice, niceStr.get());
|
||||||
|
|
||||||
|
// Read the oom_adj scores
|
||||||
|
nsPrintfCString oomStr("hal.processPriorityManager.gonk.%s.OomScoreAdjust",
|
||||||
|
processPriorityStr);
|
||||||
|
Preferences::AddIntVarCache(&prefs->priorities[i].oomScoreAdj,
|
||||||
|
oomStr.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
Preferences::AddIntVarCache(&prefs->lowPriorityNice,
|
||||||
|
"hal.processPriorityManager.gonk.LowCPUNice");
|
||||||
|
|
||||||
|
prefs->initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SetProcessPriority(int aPid,
|
SetProcessPriority(int aPid,
|
||||||
ProcessPriority aPriority,
|
ProcessPriority aPriority,
|
||||||
@ -1666,23 +1579,49 @@ SetProcessPriority(int aPid,
|
|||||||
// SetProcessPriority being called early in startup.
|
// SetProcessPriority being called early in startup.
|
||||||
EnsureKernelLowMemKillerParamsSet();
|
EnsureKernelLowMemKillerParamsSet();
|
||||||
|
|
||||||
PriorityClass* pc = GetPriorityClass(aPriority);
|
static ProcessPriorityPrefs prefs = { 0 };
|
||||||
|
EnsureProcessPriorityPrefs(&prefs);
|
||||||
|
|
||||||
int oomScoreAdj = pc->OomScoreAdj();
|
int oomScoreAdj = prefs.priorities[aPriority].oomScoreAdj;
|
||||||
|
|
||||||
RoundOomScoreAdjUpWithBackroundLRU(oomScoreAdj, aBackgroundLRU);
|
RoundOomScoreAdjUpWithBackroundLRU(oomScoreAdj, aBackgroundLRU);
|
||||||
|
|
||||||
// We try the newer interface first, and fall back to the older interface
|
int clampedOomScoreAdj = clamped<int>(oomScoreAdj, OOM_SCORE_ADJ_MIN,
|
||||||
// on failure.
|
OOM_SCORE_ADJ_MAX);
|
||||||
if (!WriteToFile(nsPrintfCString("/proc/%d/oom_score_adj", aPid).get(),
|
if (clampedOomScoreAdj != oomScoreAdj) {
|
||||||
nsPrintfCString("%d", oomScoreAdj).get()))
|
HAL_LOG("Clamping OOM adjustment for pid %d to %d", aPid,
|
||||||
{
|
clampedOomScoreAdj);
|
||||||
WriteToFile(nsPrintfCString("/proc/%d/oom_adj", aPid).get(),
|
} else {
|
||||||
nsPrintfCString("%d", OomAdjOfOomScoreAdj(oomScoreAdj)).get());
|
HAL_LOG("Setting OOM adjustment for pid %d to %d", aPid,
|
||||||
|
clampedOomScoreAdj);
|
||||||
}
|
}
|
||||||
|
|
||||||
HAL_LOG("Assigning pid %d to cgroup %s", aPid, pc->CGroup().get());
|
// We try the newer interface first, and fall back to the older interface
|
||||||
pc->AddProcess(aPid);
|
// on failure.
|
||||||
|
|
||||||
|
if (!WriteToFile(nsPrintfCString("/proc/%d/oom_score_adj", aPid).get(),
|
||||||
|
nsPrintfCString("%d", clampedOomScoreAdj).get()))
|
||||||
|
{
|
||||||
|
int oomAdj = OomAdjOfOomScoreAdj(clampedOomScoreAdj);
|
||||||
|
|
||||||
|
WriteToFile(nsPrintfCString("/proc/%d/oom_adj", aPid).get(),
|
||||||
|
nsPrintfCString("%d", oomAdj).get());
|
||||||
|
}
|
||||||
|
|
||||||
|
int nice = 0;
|
||||||
|
|
||||||
|
if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) {
|
||||||
|
nice = prefs.priorities[aPriority].nice;
|
||||||
|
} else if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) {
|
||||||
|
nice = prefs.lowPriorityNice;
|
||||||
|
} else {
|
||||||
|
HAL_ERR("Unknown aCPUPriority value %d", aCPUPriority);
|
||||||
|
MOZ_ASSERT(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HAL_LOG("Setting nice for pid %d to %d", aPid, nice);
|
||||||
|
SetNiceForPid(aPid, nice);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
Loading…
Reference in New Issue
Block a user