Bug 1082290 - Add memory cgroup support to FxOS process control. r=gsvelto

This commit is contained in:
Dave Hylands 2015-01-13 12:12:32 -08:00
parent fc7c0ecc40
commit adf1953f29
2 changed files with 124 additions and 30 deletions

View File

@ -730,22 +730,30 @@ pref("hal.processPriorityManager.gonk.BACKGROUND.KillUnderKB", 20480);
pref("hal.processPriorityManager.gonk.BACKGROUND.cgroup", "apps/bg_non_interactive");
// Control group definitions (i.e., CPU priority groups) for B2G processes.
//
// memory_swappiness - 0 - The kernel will swap only to avoid an out of memory condition
// memory_swappiness - 60 - The default value.
// memory_swappiness - 100 - The kernel will swap aggressively.
// Foreground apps
pref("hal.processPriorityManager.gonk.cgroups.apps.cpu_shares", 1024);
pref("hal.processPriorityManager.gonk.cgroups.apps.cpu_notify_on_migrate", 1);
pref("hal.processPriorityManager.gonk.cgroups.apps.memory_swappiness", 10);
// 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);
pref("hal.processPriorityManager.gonk.cgroups.apps/critical.memory_swappiness", 0);
// 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);
pref("hal.processPriorityManager.gonk.cgroups.apps/bg_perceivable.memory_swappiness", 60);
// 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);
pref("hal.processPriorityManager.gonk.cgroups.apps/bg_non_interactive.memory_swappiness", 100);
// 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.

View File

@ -1323,7 +1323,8 @@ private:
ProcessPriority mPriority;
int32_t mOomScoreAdj;
int32_t mKillUnderKB;
int mCGroupProcsFd;
int mCpuCGroupProcsFd;
int mMemCGroupProcsFd;
nsCString mGroup;
/**
@ -1340,7 +1341,7 @@ private:
/**
* Get the full path of the cgroup.procs file associated with the group.
*/
nsCString CGroupProcsFilename()
nsCString CpuCGroupProcsFilename()
{
nsCString cgroupName = mGroup;
@ -1356,12 +1357,60 @@ private:
NS_LITERAL_CSTRING("cgroup.procs");
}
int OpenCGroupProcs()
nsCString MemCGroupProcsFilename()
{
return open(CGroupProcsFilename().get(), O_WRONLY);
nsCString cgroupName = mGroup;
/* If mGroup is empty, our cgroup.procs file is the root procs file,
* located at /sys/fs/cgroup/memory/cgroup.procs. Otherwise our procs
* file is /sys/fs/cgroup/memory/NAME/cgroup.procs. */
if (!mGroup.IsEmpty()) {
cgroupName.AppendLiteral("/");
}
return NS_LITERAL_CSTRING("/sys/fs/cgroup/memory/") + cgroupName +
NS_LITERAL_CSTRING("cgroup.procs");
}
int OpenCpuCGroupProcs()
{
return open(CpuCGroupProcsFilename().get(), O_WRONLY);
}
int OpenMemCGroupProcs()
{
return open(MemCGroupProcsFilename().get(), O_WRONLY);
}
};
/**
* Creates a directory and parents (essentially mkdir -p, but
* this only create the directories within the cgroup name).
*/
static bool MakeCGroupDir(const nsACString& aRootDir,
const nsACString& aGroupName)
{
NS_NAMED_LITERAL_CSTRING(kSlash, "/");
// Create directories contained within aGroupName
nsCString cgroupIter = aGroupName + kSlash;
int32_t offset = 0;
while ((offset = cgroupIter.FindChar('/', offset)) != -1) {
nsAutoCString path = aRootDir + 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++;
}
return true;
}
/**
* 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
@ -1373,7 +1422,7 @@ private:
* exists. Otherwise, return false.
*/
static bool
EnsureCGroupExists(const nsACString &aGroup)
EnsureCpuCGroupExists(const nsACString& aGroup)
{
NS_NAMED_LITERAL_CSTRING(kDevCpuCtl, "/dev/cpuctl/");
NS_NAMED_LITERAL_CSTRING(kSlash, "/");
@ -1393,20 +1442,8 @@ EnsureCGroupExists(const nsACString &aGroup)
+ 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++;
if (!MakeCGroupDir(kDevCpuCtl, aGroup)) {
return false;
}
nsAutoCString pathPrefix(kDevCpuCtl + aGroup + kSlash);
@ -1429,11 +1466,46 @@ EnsureCGroupExists(const nsACString &aGroup)
return true;
}
static bool
EnsureMemCGroupExists(const nsACString& aGroup)
{
NS_NAMED_LITERAL_CSTRING(kMemCtl, "/sys/fs/cgroup/memory/");
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 memSwappinessPref(prefPrefix +
NS_LITERAL_CSTRING("memory_swappiness"));
int memSwappiness = Preferences::GetInt(memSwappinessPref.get());
if (!MakeCGroupDir(kMemCtl, aGroup)) {
return false;
}
nsAutoCString pathPrefix(kMemCtl + aGroup + kSlash);
nsAutoCString memSwappinessPath(pathPrefix +
NS_LITERAL_CSTRING("memory.swappiness"));
if (!WriteToFile(memSwappinessPath.get(),
nsPrintfCString("%d", memSwappiness).get())) {
HAL_LOG("Could not set the memory.swappiness for group %s",
memSwappinessPath.get());
return false;
}
return true;
}
PriorityClass::PriorityClass(ProcessPriority aPriority)
: mPriority(aPriority)
, mOomScoreAdj(0)
, mKillUnderKB(0)
, mCGroupProcsFd(-1)
, mCpuCGroupProcsFd(-1)
, mMemCGroupProcsFd(-1)
{
DebugOnly<nsresult> rv;
@ -1447,14 +1519,18 @@ PriorityClass::PriorityClass(ProcessPriority aPriority)
rv = Preferences::GetCString(PriorityPrefName("cgroup").get(), &mGroup);
MOZ_ASSERT(NS_SUCCEEDED(rv), "Missing control group preference");
if (EnsureCGroupExists(mGroup)) {
mCGroupProcsFd = OpenCGroupProcs();
if (EnsureCpuCGroupExists(mGroup)) {
mCpuCGroupProcsFd = OpenCpuCGroupProcs();
}
if (EnsureMemCGroupExists(mGroup)) {
mMemCGroupProcsFd = OpenMemCGroupProcs();
}
}
PriorityClass::~PriorityClass()
{
close(mCGroupProcsFd);
MOZ_TEMP_FAILURE_RETRY(close(mCpuCGroupProcsFd));
MOZ_TEMP_FAILURE_RETRY(close(mMemCGroupProcsFd));
}
PriorityClass::PriorityClass(const PriorityClass& aOther)
@ -1463,7 +1539,8 @@ PriorityClass::PriorityClass(const PriorityClass& aOther)
, mKillUnderKB(aOther.mKillUnderKB)
, mGroup(aOther.mGroup)
{
mCGroupProcsFd = OpenCGroupProcs();
mCpuCGroupProcsFd = OpenCpuCGroupProcs();
mMemCGroupProcsFd = OpenMemCGroupProcs();
}
PriorityClass& PriorityClass::operator=(const PriorityClass& aOther)
@ -1472,20 +1549,29 @@ PriorityClass& PriorityClass::operator=(const PriorityClass& aOther)
mOomScoreAdj = aOther.mOomScoreAdj;
mKillUnderKB = aOther.mKillUnderKB;
mGroup = aOther.mGroup;
mCGroupProcsFd = OpenCGroupProcs();
mCpuCGroupProcsFd = OpenCpuCGroupProcs();
mMemCGroupProcsFd = OpenMemCGroupProcs();
return *this;
}
void PriorityClass::AddProcess(int aPid)
{
if (mCGroupProcsFd < 0) {
return;
if (mCpuCGroupProcsFd >= 0) {
nsPrintfCString str("%d", aPid);
if (write(mCpuCGroupProcsFd, str.get(), str.Length()) < 0) {
HAL_ERR("Couldn't add PID %d to the %s cpu control group",
aPid, mGroup.get());
}
}
nsPrintfCString str("%d", aPid);
if (mMemCGroupProcsFd >= 0) {
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());
if (write(mMemCGroupProcsFd, str.get(), str.Length()) < 0) {
HAL_ERR("Couldn't add PID %d to the %s memory control group",
aPid, mGroup.get());
}
}
}