vm: Add support for changing the scheduler group for a thread.
Also temporarily bumps the scheduler group for background threads while performing GC
Signed-off-by: San Mehat <san@google.com>
diff --git a/vm/Thread.c b/vm/Thread.c
index 42b527e..680755c 100644
--- a/vm/Thread.c
+++ b/vm/Thread.c
@@ -43,6 +43,9 @@
#undef __KERNEL__
#endif
+// Change this to enable logging on cgroup errors
+#define ENABLE_CGROUP_ERR_LOGGING 0
+
// change this to LOGV/LOGD to debug thread activity
#define LOG_THREAD LOGVV
@@ -2745,6 +2748,41 @@
};
/*
+ * Change the scheduler cgroup of a pid
+ */
+int dvmChangeThreadSchedulerGroup(const char *cgroup)
+{
+#ifdef HAVE_ANDROID_OS
+ FILE *fp;
+ char path[255];
+ int rc;
+
+ sprintf(path, "/dev/cpuctl/%s/tasks", (cgroup ? cgroup : ""));
+
+ if (!(fp = fopen(path, "w"))) {
+#if ENABLE_CGROUP_ERR_LOGGING
+ LOGW("Unable to open %s (%s)\n", path, strerror(errno));
+#endif
+ return -errno;
+ }
+
+ rc = fprintf(fp, "0");
+ fclose(fp);
+
+ if (rc < 0) {
+#if ENABLE_CGROUP_ERR_LOGGING
+ LOGW("Unable to move pid %d to cgroup %s (%s)\n", getpid(),
+ (cgroup ? cgroup : "<default>"), strerror(errno));
+#endif
+ }
+
+ return (rc < 0) ? errno : 0;
+#else // HAVE_ANDROID_OS
+ return 0;
+#endif
+}
+
+/*
* Change the priority of a system thread to match that of the Thread object.
*
* We map a priority value from 1-10 to Linux "nice" values, where lower
@@ -2761,6 +2799,12 @@
}
newNice = kNiceValues[newPriority-1];
+ if (newPriority == ANDROID_PRIORITY_BACKGROUND) {
+ dvmChangeThreadSchedulerGroup("bg_non_interactive");
+ } else if (getpriority(PRIO_PROCESS, pid) == ANDROID_PRIORITY_BACKGROUND) {
+ dvmChangeThreadSchedulerGroup(NULL);
+ }
+
if (setpriority(PRIO_PROCESS, pid, newNice) != 0) {
char* str = dvmGetThreadName(thread);
LOGI("setPriority(%d) '%s' to prio=%d(n=%d) failed: %s\n",
diff --git a/vm/Thread.h b/vm/Thread.h
index b64f9b7..86a7845 100644
--- a/vm/Thread.h
+++ b/vm/Thread.h
@@ -398,6 +398,11 @@
INLINE void dvmSetThreadJNIEnv(Thread* self, JNIEnv* env) { self->jniEnv = env;}
/*
+ * Change the scheduler group of the current process
+ */
+int dvmChangeThreadSchedulerGroup(const char *group);
+
+/*
* Update the priority value of the underlying pthread.
*/
void dvmChangeThreadPriority(Thread* thread, int newPriority);
diff --git a/vm/alloc/Heap.c b/vm/alloc/Heap.c
index 6c1e680..09954ea 100644
--- a/vm/alloc/Heap.c
+++ b/vm/alloc/Heap.c
@@ -774,6 +774,11 @@
/* Current value is numerically greater than "normal", which
* in backward UNIX terms means lower priority.
*/
+
+ if (priorityResult == ANDROID_PRIORITY_BACKGROUND) {
+ dvmChangeThreadSchedulerGroup(NULL);
+ }
+
if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL) != 0) {
LOGI_HEAP("Unable to elevate priority from %d to %d\n",
priorityResult, ANDROID_PRIORITY_NORMAL);
@@ -1019,6 +1024,10 @@
} else {
LOGD_HEAP("Reset priority to %d\n", oldThreadPriority);
}
+
+ if (oldThreadPriority == ANDROID_PRIORITY_BACKGROUND) {
+ dvmChangeThreadSchedulerGroup("bg_non_interactive");
+ }
}
gcElapsedTime = (dvmGetRelativeTimeUsec() - gcHeap->gcStartTime) / 1000;
if (gcElapsedTime < 10000) {