diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js index e574d20eda5..13d99dfbbc0 100644 --- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -728,22 +728,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", 0); +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", 0); +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. diff --git a/hal/gonk/GonkHal.cpp b/hal/gonk/GonkHal.cpp index e3b30a8b15c..bda465ef85e 100644 --- a/hal/gonk/GonkHal.cpp +++ b/hal/gonk/GonkHal.cpp @@ -1351,7 +1351,8 @@ private: ProcessPriority mPriority; int32_t mOomScoreAdj; int32_t mKillUnderKB; - int mCGroupProcsFd; + int mCpuCGroupProcsFd; + int mMemCGroupProcsFd; nsCString mGroup; /** @@ -1368,7 +1369,7 @@ private: /** * Get the full path of the cgroup.procs file associated with the group. */ - nsCString CGroupProcsFilename() + nsCString CpuCGroupProcsFilename() { nsCString cgroupName = mGroup; @@ -1384,9 +1385,30 @@ 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); } }; @@ -1401,11 +1423,14 @@ 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, "/"); + nsAutoCString groupName(aGroup); + HAL_LOG("EnsureCpuCGroupExists for group '%s'", groupName.get()); + nsAutoCString prefPrefix("hal.processPriorityManager.gonk.cgroups."); /* If cgroup is not empty, append the cgroup name and a dot to obtain the @@ -1436,6 +1461,7 @@ EnsureCGroupExists(const nsACString &aGroup) offset++; } + HAL_LOG("EnsureCpuCGroupExists created group '%s'", groupName.get()); nsAutoCString pathPrefix(kDevCpuCtl + aGroup + kSlash); nsAutoCString cpuSharesPath(pathPrefix + NS_LITERAL_CSTRING("cpu.shares")); @@ -1457,11 +1483,61 @@ 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 groupName(aGroup); + HAL_LOG("EnsureMemCGroupExists for group '%s'", groupName.get()); + + 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()); + + // Create mCGroup and its parent directories, as necessary. + nsCString cgroupIter = aGroup + kSlash; + + int32_t offset = 0; + while ((offset = cgroupIter.FindChar('/', offset)) != -1) { + nsAutoCString path = kMemCtl + 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++; + } + HAL_LOG("EnsureMemCGroupExists created group '%s'", groupName.get()); + + 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; + } + HAL_LOG("Set memory.swappiness for group %s to %d", memSwappinessPath.get(), memSwappiness); + + return true; +} + PriorityClass::PriorityClass(ProcessPriority aPriority) : mPriority(aPriority) , mOomScoreAdj(0) , mKillUnderKB(0) - , mCGroupProcsFd(-1) + , mCpuCGroupProcsFd(-1) + , mMemCGroupProcsFd(-1) { DebugOnly rv; @@ -1475,14 +1551,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); + close(mCpuCGroupProcsFd); + close(mMemCGroupProcsFd); } PriorityClass::PriorityClass(const PriorityClass& aOther) @@ -1491,7 +1571,8 @@ PriorityClass::PriorityClass(const PriorityClass& aOther) , mKillUnderKB(aOther.mKillUnderKB) , mGroup(aOther.mGroup) { - mCGroupProcsFd = OpenCGroupProcs(); + mCpuCGroupProcsFd = OpenCpuCGroupProcs(); + mMemCGroupProcsFd = OpenMemCGroupProcs(); } PriorityClass& PriorityClass::operator=(const PriorityClass& aOther) @@ -1500,20 +1581,26 @@ 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(), strlen(str.get())) < 0) { + HAL_ERR("Couldn't add PID %d to the %s cpu control group", aPid, mGroup.get()); + } } + if (mMemCGroupProcsFd >= 0) { + nsPrintfCString str("%d", aPid); - 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(), strlen(str.get())) < 0) { + HAL_ERR("Couldn't add PID %d to the %s memory control group", aPid, mGroup.get()); + } } }