diff options
| -rw-r--r-- | api/current.txt | 1 | ||||
| -rw-r--r-- | api/system-current.txt | 1 | ||||
| -rw-r--r-- | api/test-current.txt | 1 | ||||
| -rw-r--r-- | core/java/android/os/Process.java | 25 | ||||
| -rw-r--r-- | core/jni/android_util_Process.cpp | 136 |
5 files changed, 164 insertions, 0 deletions
diff --git a/api/current.txt b/api/current.txt index 07505b35ccae..e03dcd207311 100644 --- a/api/current.txt +++ b/api/current.txt @@ -29046,6 +29046,7 @@ package android.os { public class Process { ctor public Process(); method public static final long getElapsedCpuTime(); + method public static final int[] getExclusiveCores(); method public static final int getGidForName(java.lang.String); method public static final int getThreadPriority(int) throws java.lang.IllegalArgumentException; method public static final int getUidForName(java.lang.String); diff --git a/api/system-current.txt b/api/system-current.txt index 089ccd367c3b..d4c33ca1a1b5 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -31338,6 +31338,7 @@ package android.os { public class Process { ctor public Process(); method public static final long getElapsedCpuTime(); + method public static final int[] getExclusiveCores(); method public static final int getGidForName(java.lang.String); method public static final int getThreadPriority(int) throws java.lang.IllegalArgumentException; method public static final int getUidForName(java.lang.String); diff --git a/api/test-current.txt b/api/test-current.txt index 21a9db03d4c2..b0640f25838a 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -29057,6 +29057,7 @@ package android.os { public class Process { ctor public Process(); method public static final long getElapsedCpuTime(); + method public static final int[] getExclusiveCores(); method public static final int getGidForName(java.lang.String); method public static final int getThreadPriority(int) throws java.lang.IllegalArgumentException; method public static final int getUidForName(java.lang.String); diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 9984755d316f..38d5b34dcef7 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -975,6 +975,31 @@ public class Process { throws IllegalArgumentException, SecurityException; /** + * On some devices, the foreground process may have one or more CPU + * cores exclusively reserved for it. This method can be used to + * retrieve which cores that are (if any), so the calling process + * can then use sched_setaffinity() to lock a thread to these cores. + * Note that the calling process must currently be running in the + * foreground for this method to return any cores. + * + * The CPU core(s) exclusively reserved for the foreground process will + * stay reserved for as long as the process stays in the foreground. + * + * As soon as a process leaves the foreground, those CPU cores will + * no longer be reserved for it, and will most likely be reserved for + * the new foreground process. It's not necessary to change the affinity + * of your process when it leaves the foreground (if you had previously + * set it to use a reserved core); the OS will automatically take care + * of resetting the affinity at that point. + * + * @return an array of integers, indicating the CPU cores exclusively + * reserved for this process. The array will have length zero if no + * CPU cores are exclusively reserved for this process at this point + * in time. + */ + public static final native int[] getExclusiveCores(); + + /** * Set the priority of the calling thread, based on Linux priorities. See * {@link #setThreadPriority(int, int)} for more information. * diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index ee8fb195002d..f7a5e8a07fc0 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -17,6 +17,8 @@ #define LOG_TAG "Process" +// To make sure cpu_set_t is included from sched.h +#define _GNU_SOURCE 1 #include <utils/Log.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> @@ -288,6 +290,139 @@ jint android_os_Process_getProcessGroup(JNIEnv* env, jobject clazz, jint pid) return (int) sp; } +#ifdef ENABLE_CPUSETS +/** Sample CPUset list format: + * 0-3,4,6-8 + */ +static void parse_cpuset_cpus(char *cpus, cpu_set_t *cpu_set) { + unsigned int start, end, matched, i; + char *cpu_range = strtok(cpus, ","); + while (cpu_range != NULL) { + start = end = 0; + matched = sscanf(cpu_range, "%u-%u", &start, &end); + cpu_range = strtok(NULL, ","); + if (start >= CPU_SETSIZE) { + ALOGE("parse_cpuset_cpus: ignoring CPU number larger than %d.", CPU_SETSIZE); + continue; + } else if (end >= CPU_SETSIZE) { + ALOGE("parse_cpuset_cpus: ignoring CPU numbers larger than %d.", CPU_SETSIZE); + end = CPU_SETSIZE - 1; + } + if (matched == 1) { + CPU_SET(start, cpu_set); + } else if (matched == 2) { + for (i = start; i <= end; i++) { + CPU_SET(i, cpu_set); + } + } else { + ALOGE("Failed to match cpus"); + } + } + return; +} + +/** + * Stores the CPUs assigned to the cpuset corresponding to the + * SchedPolicy in the passed in cpu_set. + */ +static void get_cpuset_cores_for_policy(SchedPolicy policy, cpu_set_t *cpu_set) +{ + FILE *file; + const char *filename; + + CPU_ZERO(cpu_set); + + switch (policy) { + case SP_BACKGROUND: + filename = "/dev/cpuset/background/cpus"; + break; + case SP_FOREGROUND: + case SP_AUDIO_APP: + case SP_AUDIO_SYS: + filename = "/dev/cpuset/foreground/cpus"; + break; + case SP_TOP_APP: + filename = "/dev/cpuset/top-app/cpus"; + break; + default: + filename = NULL; + } + + if (!filename) return; + + file = fopen(filename, "re"); + if (file != NULL) { + // Parse cpus string + char *line = NULL; + size_t len = 0; + ssize_t num_read = getline(&line, &len, file); + fclose (file); + if (num_read > 0) { + parse_cpuset_cpus(line, cpu_set); + } else { + ALOGE("Failed to read %s", filename); + } + free(line); + } + return; +} +#endif + + +/** + * Determine CPU cores exclusively assigned to the + * cpuset corresponding to the SchedPolicy and store + * them in the passed in cpu_set_t + */ +void get_exclusive_cpuset_cores(SchedPolicy policy, cpu_set_t *cpu_set) { +#ifdef ENABLE_CPUSETS + int i; + cpu_set_t tmp_set; + get_cpuset_cores_for_policy(policy, cpu_set); + for (i = 0; i < SP_CNT; i++) { + if ((SchedPolicy) i == policy) continue; + get_cpuset_cores_for_policy((SchedPolicy)i, &tmp_set); + // First get cores exclusive to one set or the other + CPU_XOR(&tmp_set, cpu_set, &tmp_set); + // Then get the ones only in cpu_set + CPU_AND(cpu_set, cpu_set, &tmp_set); + } +#else + (void) policy; + CPU_ZERO(cpu_set); +#endif + return; +} + +jintArray android_os_Process_getExclusiveCores(JNIEnv* env, jobject clazz) { + SchedPolicy sp; + cpu_set_t cpu_set; + jintArray cpus; + int pid = getpid(); + if (get_sched_policy(pid, &sp) != 0) { + signalExceptionForGroupError(env, errno); + return NULL; + } + get_exclusive_cpuset_cores(sp, &cpu_set); + int num_cpus = CPU_COUNT(&cpu_set); + cpus = env->NewIntArray(num_cpus); + if (cpus == NULL) { + jniThrowException(env, "java/lang/OutOfMemoryError", NULL); + return NULL; + } + + jint* cpu_elements = env->GetIntArrayElements(cpus, 0); + int count = 0; + for (int i = 0; i < CPU_SETSIZE && count < num_cpus; i++) { + if (CPU_ISSET(i, &cpu_set)) { + cpu_elements[count++] = i; + } + } + + env->ReleaseIntArrayElements(cpus, cpu_elements, 0); + return cpus; +} + static void android_os_Process_setCanSelfBackground(JNIEnv* env, jobject clazz, jboolean bgOk) { // Establishes the calling thread as illegal to put into the background. // Typically used only for the system process's main looper. @@ -1053,6 +1188,7 @@ static const JNINativeMethod methods[] = { {"setThreadGroup", "(II)V", (void*)android_os_Process_setThreadGroup}, {"setProcessGroup", "(II)V", (void*)android_os_Process_setProcessGroup}, {"getProcessGroup", "(I)I", (void*)android_os_Process_getProcessGroup}, + {"getExclusiveCores", "()[I", (void*)android_os_Process_getExclusiveCores}, {"setSwappiness", "(IZ)Z", (void*)android_os_Process_setSwappiness}, {"setArgV0", "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0}, {"setUid", "(I)I", (void*)android_os_Process_setUid}, |