Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2612bbc0 authored by Martijn Coenen's avatar Martijn Coenen Committed by Android (Google) Code Review
Browse files

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

parents 502bc4e7 cd4bdf3e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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();
+1 −0
Original line number Diff line number Diff line
@@ -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();
+1 −0
Original line number Diff line number Diff line
@@ -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();
+25 −0
Original line number Diff line number Diff line
@@ -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.
+136 −0
Original line number Diff line number Diff line
@@ -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},