Merge "API to query which cores are exclusively assigned." into nyc-dev

am: 2612bbc0f5

* commit '2612bbc0f5ae5422ba3e8e685ae375b2b8626fda':
  API to query which cores are exclusively assigned.
This commit is contained in:
Martijn Coenen
2016-03-09 10:37:45 +00:00
committed by android-build-merger
5 changed files with 164 additions and 0 deletions

View File

@@ -29124,6 +29124,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 long getStartElapsedRealtime();
method public static final long getStartUptimeMillis();

View File

@@ -31412,6 +31412,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 long getStartElapsedRealtime();
method public static final long getStartUptimeMillis();

View File

@@ -29135,6 +29135,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 long getStartElapsedRealtime();
method public static final long getStartUptimeMillis();

View File

@@ -997,6 +997,31 @@ public class Process {
public static final native int getProcessGroup(int pid)
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.

View File

@@ -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},