美文网首页
Android中关于cpu/cpuset/schedtune的应

Android中关于cpu/cpuset/schedtune的应

作者: superme_ | 来源:发表于2022-08-09 09:05 被阅读0次

    Android中关于cpu/cpuset/schedtune的应用都是基于进程优先级的,根据不同优先级划分进程类型。AMS(ActivityManagerService)和PMS(PackageManagerService)等通过class Process设置进程优先级、调度策略等;android/osProcess JNI通过调用libcutils.so/libutils.so执行getpriority/setpriority/sched_setscheduler/sched_getschedler系统调用或者直接操作CGroup文件节点以达到设置优先级,限制进程CPU资源的目的。

    根据优先级,通过设置CGroup的cpu/cpuset/stune控制进程获得CPU执行时间、可调度CPU范围等,以达到对不同优先级进程的控制。

                                                      Android关于cpu/cpuset/schedtune的框架结构

    Android关于cpu/cpuset/schedtune的框架结构

    进程优先级和调度策略从上到下贯穿其中,但是在不同的层级的名称有一些变化。下面逐一介绍。

    class Process以及android/os/Process JNI

    frameworks/base/core/java/android/os/Process.java

    其他服务通过class Process来设置进程优先级、调度侧率等。

    class Process中优先级划分:

    public static final int THREAD_PRIORITY_DEFAULT = 0; 应用的默认优先级

    /*

    * ***************************************

    * ** Keep in sync with utils/threads.h **

    * ***************************************

    */

    public static final int THREAD_PRIORITY_LOWEST = 19; 线程的最低优先级

    public static final int THREAD_PRIORITY_BACKGROUND = 10; 后台线程的默认优先级

    public static final int THREAD_PRIORITY_FOREGROUND = -2; 前台进程的标准优先级

    public static final int THREAD_PRIORITY_DISPLAY = -4; 系统用于显示功能的优先级

    public static final int THREAD_PRIORITY_URGENT_DISPLAY = -8; 系统用于重要显示功能的优先级

    public static final int THREAD_PRIORITY_AUDIO = -16; 音频线程默认优先级

    public static final int THREAD_PRIORITY_URGENT_AUDIO = -19; 重要音频线程默认优先级

    调度策略划分:

    public static final int SCHED_OTHER = 0; 默认调度策略,对应CFS调度类

    public static final int SCHED_FIFO = 1; FIFO调度策略,对应RT调度类

    public static final int SCHED_RR = 2; RR调度策略,对应RT调度类

    public static final int SCHED_BATCH = 3; 批调度策略,对应CFS调度类

    public static final int SCHED_IDLE = 5; idle调度策略

    class Process相关API,主要用于:

    public static final native void setThreadPriority(int tid, int priority)

    throws IllegalArgumentException, SecurityException;

    public static final native void setThreadScheduler(int tid, int policy, int priority)

    throws IllegalArgumentException;

    public static final native void setThreadPriority(int tid, int priority)

    throws IllegalArgumentException, SecurityException;

    public static final native int getThreadPriority(int tid)

    throws IllegalArgumentException;

    public static final native int getThreadScheduler(int tid)

    throws IllegalArgumentException;

    public static final native void setThreadGroup(int tid, int group)

    throws IllegalArgumentException, SecurityException;

    public static final native void setProcessGroup(int pid, int group)

    throws IllegalArgumentException, SecurityException;

    frameworks/base/core/jni/android_util_Process.cpp

    对应JNINativeMethod如下:

    static const JNINativeMethod methods[] = {

    {"setThreadPriority",   "(II)V", (void*)android_os_Process_setThreadPriority},

    {"setThreadScheduler",  "(III)V", (void*)android_os_Process_setThreadScheduler},

    {"setCanSelfBackground", "(Z)V", (void*)android_os_Process_setCanSelfBackground},

    {"setThreadPriority",   "(I)V", (void*)android_os_Process_setCallingThreadPriority},

    {"getThreadPriority",   "(I)I", (void*)android_os_Process_getThreadPriority},

    {"getThreadScheduler",   "(I)I", (void*)android_os_Process_getThreadScheduler},

    {"setThreadGroup",      "(II)V", (void*)android_os_Process_setThreadGroup},

    {"setProcessGroup",     "(II)V", (void*)android_os_Process_setProcessGroup},

    {"getProcessGroup",     "(I)I", (void*)android_os_Process_getProcessGroup},

    };

    scheduler相关API直接调用sched_setscheduler/sched_getscheduler。

    libcutils.so/libutils.so

    在介绍这个函数之前先介绍一下此处所使用的优先级定义,可以看出和class Process中是完全的对应关系:

    ANDROID_PRIORITY_LOWEST         =  19,

    /* use for background tasks */

    ANDROID_PRIORITY_BACKGROUND     =  10,

    /* most threads run at normal priority */

    ANDROID_PRIORITY_NORMAL         =   0,

    /* threads currently running a UI that the user is interacting with */

    ANDROID_PRIORITY_FOREGROUND     =  -2,

    /* the main UI thread has a slightly more favorable priority */

    ANDROID_PRIORITY_DISPLAY        =  -4,

    /* ui service treads might want to run at a urgent display (uncommon) */

    ANDROID_PRIORITY_URGENT_DISPLAY =  HAL_PRIORITY_URGENT_DISPLAY,

    /* all normal audio threads */

    ANDROID_PRIORITY_AUDIO          = -16,

    /* service audio threads (uncommon) */

    ANDROID_PRIORITY_URGENT_AUDIO   = -19,

    /* should never be used in practice. regular process might not

    * be allowed to use this level */

    ANDROID_PRIORITY_HIGHEST        = -20,

    ANDROID_PRIORITY_DEFAULT        = ANDROID_PRIORITY_NORMAL,

    还需要在研究一下,Sched Policy中使用的优先级映射关系:

    /* Keep in sync with THREAD_GROUP_* in frameworks/base/core/java/android/os/Process.java */

    typedef enum {

    SP_DEFAULT    = -1,

    SP_BACKGROUND = 0,

    SP_FOREGROUND = 1,

    SP_SYSTEM     = 2,  // can't be used with set_sched_policy()

    SP_AUDIO_APP  = 3,

    SP_AUDIO_SYS  = 4,

    SP_TOP_APP    = 5,

    SP_CNT,

    SP_MAX        = SP_CNT - 1,

    SP_SYSTEM_DEFAULT = SP_FOREGROUND,

    } SchedPolicy;

    Threads.cpp中定义了androidSetThreadPriority用于设置线程的优先级。

    int androidSetThreadPriority(pid_t tid, int pri)

    {

    int rc = 0;

    int lasterr = 0;

    if (pri >= ANDROID_PRIORITY_BACKGROUND) { 如果priority大于等于BACKGROUND,则设置为BACKGROUND类型的调度策略。

    rc = set_sched_policy(tid, SP_BACKGROUND);

    } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) { 如果priority小于BACKGROUND,且当线程为BACKGROUND类型,则设置为FOREGROUND类型。

    rc = set_sched_policy(tid, SP_FOREGROUND);

    }

    if (rc) {

    lasterr = errno;

    }

    if (setpriority(PRIO_PROCESS, tid, pri) < 0) { 设置优先级

    rc = INVALID_OPERATION;

    } else {

    errno = lasterr;

    }

    return rc;

    }

    set_cpuset_policy根据SchedPolicy类型将tid写入cpuset和schedtune子系统中。

    有下面的函数可以得出cpuset、schedtune和不同类型SchedPolicy之间的对应关系:

    /dev/cpuset/foreground/tasks  SP_FOREGROUND SP_AUDIO_APP SP_AUDIO_SYS

    /dev/cpuset/background/tasks  SP_BACKGROUND

    /dev/cpuset/system-background/tasks  SP_SYSTEM

    /dev/cpuset/top-app/tasks  SP_TOP_APP

    /dev/stune/top-app/tasks  SP_TOP_APP

    /dev/stune/foreground/tasks  SP_FOREGROUND SP_AUDIO_APP SP_AUDIO_SYS

    /dev/stune/background/tasks  SP_BACKGROUND

    int set_cpuset_policy(int tid, SchedPolicy policy)

    {

    // in the absence of cpusets, use the old sched policy

    #ifndef USE_CPUSETS

    return set_sched_policy(tid, policy);

    #else

    if (tid == 0) {

    tid = gettid();

    }

    policy = _policy(policy);

    pthread_once(&the_once, __initialize);

    int fd = -1;

    int boost_fd = -1;

    switch (policy) {

    case SP_BACKGROUND:

    fd = bg_cpuset_fd;

    boost_fd = bg_schedboost_fd;

    break;

    case SP_FOREGROUND:

    case SP_AUDIO_APP:

    case SP_AUDIO_SYS:

    fd = fg_cpuset_fd;

    boost_fd = fg_schedboost_fd;

    break;

    case SP_TOP_APP :

    fd = ta_cpuset_fd;

    boost_fd = ta_schedboost_fd;

    break;

    case SP_SYSTEM:

    fd = system_bg_cpuset_fd;

    break;

    default:

    boost_fd = fd = -1;

    break;

    }

    if (add_tid_to_cgroup(tid, fd) != 0) {

    if (errno != ESRCH && errno != ENOENT)

    return -errno;

    }

    #ifdef USE_SCHEDBOOST

    if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {

    if (errno != ESRCH && errno != ENOENT)

    return -errno;

    }

    #endif

    return 0;

    #endif

    }

    set_sched_policy设置cpu/schedtune两个子系统,子系统节点和SchedPolicy类型对应如下:

    /dev/cpuctl/tasks  SP_FOREGROUND SP_AUDIO_APP SP_AUDIO_SYS

    /dev/cpuctl/bg_non_interactive/tasks  SP_BACKGROUND

    /dev/stune/top-app/tasks  SP_TOP_APP

    /dev/stune/foreground/tasks  SP_FOREGROUND SP_AUDIO_APP SP_AUDIO_SYS

    /dev/stune/background/tasks  SP_BACKGROUND

    int set_sched_policy(int tid, SchedPolicy policy)

    {

    if (tid == 0) {

    tid = gettid();

    }

    policy = _policy(policy);

    pthread_once(&the_once, __initialize);

    #if POLICY_DEBUG

    char statfile[64];

    char statline[1024];

    char thread_name[255];

    snprintf(statfile, sizeof(statfile), "/proc/%d/stat", tid);

    memset(thread_name, 0, sizeof(thread_name));

    int fd = open(statfile, O_RDONLY | O_CLOEXEC);

    if (fd >= 0) {

    int rc = read(fd, statline, 1023);

    close(fd);

    statline[rc] = 0;

    char *p = statline;

    char *q;

    for (p = statline; *p != '('; p++);

    p++;

    for (q = p; *q != ')'; q++);

    strncpy(thread_name, p, (q-p));

    }

    switch (policy) {

    case SP_BACKGROUND:

    SLOGD("vvv tid %d (%s)", tid, thread_name);

    break;

    case SP_FOREGROUND:

    case SP_AUDIO_APP:

    case SP_AUDIO_SYS:

    case SP_TOP_APP:

    SLOGD("^^^ tid %d (%s)", tid, thread_name);

    break;

    case SP_SYSTEM:

    SLOGD("/// tid %d (%s)", tid, thread_name);

    break;

    default:

    SLOGD("??? tid %d (%s)", tid, thread_name);

    break;

    }

    #endif

    if (__sys_supports_schedgroups) { 是否使能schedtune CGroup

    int fd = -1;

    int boost_fd = -1;

    switch (policy) {

    case SP_BACKGROUND:

    fd = bg_cgroup_fd;

    boost_fd = bg_schedboost_fd;

    break;

    case SP_FOREGROUND:

    case SP_AUDIO_APP:

    case SP_AUDIO_SYS:

    fd = fg_cgroup_fd;

    boost_fd = fg_schedboost_fd;

    break;

    case SP_TOP_APP:

    fd = fg_cgroup_fd;

    boost_fd = ta_schedboost_fd;

    break;

    default:

    fd = -1;

    boost_fd = -1;

    break;

    }

    if (add_tid_to_cgroup(tid, fd) != 0) {

    if (errno != ESRCH && errno != ENOENT)

    return -errno;

    }

    #ifdef USE_SCHEDBOOST

    if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {

    if (errno != ESRCH && errno != ENOENT)

    return -errno;

    }

    #endif

    } else { 如果没有使能schedtune CGroup,则使用系统调用sched_setscheduler设置为SCHED_BATCH或者SCHED_NORMAL

    struct sched_param param;

    param.sched_priority = 0;

    sched_setscheduler(tid,

    (policy == SP_BACKGROUND) ?

    SCHED_BATCH : SCHED_NORMAL,

    ¶m);

    }

    if (__sys_supports_timerslack) {

    set_timerslack_ns(tid, policy == SP_BACKGROUND ?

    TIMER_SLACK_BG : TIMER_SLACK_FG);

    }

    return 0;

    }

    相关文章

      网友评论

          本文标题:Android中关于cpu/cpuset/schedtune的应

          本文链接:https://www.haomeiwen.com/subject/lldybrtx.html