Skip to main content
 首页 » 操作系统

Linux 调度器之PELT算法下util_avg的增速和减速

2022年07月19日26cmt

这个程序用于 debug 若一个任务突然一直跑下去,其 util_avg 增加的速度。util_avg 是对一个正在运行的任务计算的,若其不允许了,对系统的 util 的影响应该是0,若是 n 个 periods(周期1024us) 后又开始运行了,其 uitl_avg 直接乘以 y^n 即可。

一、测试增速

1. 测试程序

#include <stdio.h> 
#include <math.h> 
#include <stdlib.h> 
 
#define HALFLIFE_32 32 
#define LOAD_AVG_MAX_32 47742 
 
#define HALFLIFE_8 8 
#define LOAD_AVG_MAX_8 12326 
 
#define HALFLIFE_4 4 
#define LOAD_AVG_MAX_4 6430 
 
#define HALFLIFE_3 3 
#define LOAD_AVG_MAX_3 4959 
 
#define HALFLIFE_2 2 
#define LOAD_AVG_MAX_2 3493 
 
 
void calc_converged_max(double y) 
{ 
    int n = -1; 
    /* first period */ 
    long max = 1024; 
    long last = 0, y_inv = ((1UL << 32) - 1) * y; 
 
    for (; ; n++) { 
        if (n > -1) { 
            max = ((max * y_inv) >> 32) + 1024; 
            /* This is the same as: max = max*y + 1024; */ 
        } 
        if (last == max) 
            break; 
 
        last = max; 
    } 
    n--; 
 
    printf("#define LOAD_AVG_MAX %ld\n", max); 
    printf("#define LOAD_AVG_MAX_N %d\n\n", n); 
} 
 
 
int util_avg_from_sudden_running_all_time(double y, int periods, int load_avg_max) { 
    int i; 
    double util_avg; 
    double util_sum = 0; 
     
    for (i = 0; i < periods; i++) { 
        util_sum += 1024 * pow(y, i); 
 
        util_avg = util_sum / load_avg_max; 
     
        printf("util_sum=%d, periods=%d, util_avg=%%%d\n", (int)util_sum, i+1, (int)(util_avg * 100)); 
    } 
     
    return 0; 
} 
 
 
void main(int argc, char *argv[]) 
{ 
    double y; 
    int choose = 32, periods = 200; 
 
    if (argc == 2) { 
        choose = atoi(argv[1]); 
    } 
 
    if (argc == 3) { 
        choose = atoi(argv[1]); 
        periods = atoi(argv[2]); 
    } 
     
    printf("y^%d=0.5, periods=%d\n", choose, periods); 
 
    switch(choose) { 
        case 32: 
            y = pow(0.5, 1/(double)HALFLIFE_32); 
            calc_converged_max(y); //47742 
            util_avg_from_sudden_running_all_time(y, periods, LOAD_AVG_MAX_32); 
            break; 
        case 8: 
            y = pow(0.5, 1/(double)HALFLIFE_8); 
            calc_converged_max(y); //12326 
            util_avg_from_sudden_running_all_time(y, periods, LOAD_AVG_MAX_8); 
            break; 
        case 4: 
            y = pow(0.5, 1/(double)HALFLIFE_4); 
            calc_converged_max(y); //6430 
            util_avg_from_sudden_running_all_time(y, periods, LOAD_AVG_MAX_4); 
            break; 
        case 3: 
            y = pow(0.5, 1/(double)HALFLIFE_3); 
            calc_converged_max(y); //4959 
            util_avg_from_sudden_running_all_time(y, periods, LOAD_AVG_MAX_3); 
            break; 
        case 2: 
            y = pow(0.5, 1/(double)HALFLIFE_2); 
            calc_converged_max(y); //3493 
            util_avg_from_sudden_running_all_time(y, periods, LOAD_AVG_MAX_2); 
            break; 
        default: break; 
    } 
}

2. 测试结果

/* 
$ ./pp 8 20 
y^8=0.5, periods=20 
#define LOAD_AVG_MAX 12326 
#define LOAD_AVG_MAX_N 85 
 
util_sum=1024, periods=1, util_avg=%8 
util_sum=1963, periods=2, util_avg=%15 
util_sum=2824, periods=3, util_avg=%22 
util_sum=3613, periods=4, util_avg=%29 
util_sum=4337, periods=5, util_avg=%35 
util_sum=5001, periods=6, util_avg=%40 
util_sum=5610, periods=7, util_avg=%45 
util_sum=6168, periods=8, util_avg=%50 
util_sum=6680, periods=9, util_avg=%54 
util_sum=7150, periods=10, util_avg=%57 
util_sum=7581, periods=11, util_avg=%61 
util_sum=7975, periods=12, util_avg=%64 
util_sum=8337, periods=13, util_avg=%67 
util_sum=8669, periods=14, util_avg=%70 
util_sum=8974, periods=15, util_avg=%72 
util_sum=9253, periods=16, util_avg=%75 
util_sum=9509, periods=17, util_avg=%77 
util_sum=9744, periods=18, util_avg=%78 
util_sum=9959, periods=19, util_avg=%80 
util_sum=10156, periods=20, util_avg=%82 
*/

二、测试递减

1. 测试程序

#include <stdio.h> 
#include <math.h> 
#include <stdlib.h> 
 
#define HALFLIFE_32 32 
#define HALFLIFE_8 8 
#define HALFLIFE_4 4 
#define HALFLIFE_3 3 
#define HALFLIFE_2 2 
 
int util_avg_from_sudden_sleep_all_time(double y, int periods) { 
    int i; 
    double util_avg; 
    double util_sum = 0; 
     
    for (i = 0; i < periods; i++) { 
        util_avg = 1 * pow(y, i); 
        printf("periods=%d, util_avg=%%%d\n", i+1, (int)(util_avg * 100)); 
    } 
     
    return 0; 
} 
 
void main(int argc, char *argv[]) 
{ 
    double y; 
    int choose = 32, periods = 200; 
 
    if (argc == 2) { 
        choose = atoi(argv[1]); 
    } 
 
    if (argc == 3) { 
        choose = atoi(argv[1]); 
        periods = atoi(argv[2]); 
    } 
     
    printf("y^%d=0.5, periods=%d\n\n", choose, periods); 
 
    switch(choose) { 
        case 32: 
            y = pow(0.5, 1/(double)HALFLIFE_32); 
            util_avg_from_sudden_sleep_all_time(y, periods); 
            break; 
        case 8: 
            y = pow(0.5, 1/(double)HALFLIFE_8); 
            util_avg_from_sudden_sleep_all_time(y, periods); 
            break; 
        case 4: 
            y = pow(0.5, 1/(double)HALFLIFE_4); 
            util_avg_from_sudden_sleep_all_time(y, periods); 
            break; 
        case 3: 
            y = pow(0.5, 1/(double)HALFLIFE_3); 
            util_avg_from_sudden_sleep_all_time(y, periods); 
            break; 
        case 2: 
            y = pow(0.5, 1/(double)HALFLIFE_2); 
            util_avg_from_sudden_sleep_all_time(y, periods); 
            break; 
        default: break; 
    } 
}

2. 执行结果

$ ./pp 8 10 
y^8=0.5, periods=10 
 
periods=1, util_avg=%100 
periods=2, util_avg=%91 
periods=3, util_avg=%84 
periods=4, util_avg=%77 
periods=5, util_avg=%70 
periods=6, util_avg=%64 
periods=7, util_avg=%59 
periods=8, util_avg=%54 
periods=9, util_avg=%49 
periods=10, util_avg=%45

三、补充

1. 测试取 8 和 32,PELT 下连续慢跑 10 个周期 util_avg 的变化情况

               y^8=0.5      y^32=0.5                     
y              0.917004043  0.978572062                     
y^10           0.420448208  0.805245166                     
1-y^10         0.579551792  0.194754834                     
1-y            0.082995957  0.021427938                     
(1-q^10)/(1-y) 6.982891875  9.088827624                     
util_avg       0.698289188  0.908882762

y越大(指数N越小),满跑的情况下,负载增加的越快。同理衰减的越慢,越利于性能越不利于功耗。

2. 满载增速:

q = (1/2)^32 
LOAD_AVG_MAX = 47742 
util_avg = (1-q^n)/(1-q) * 1024(1ms~=1024us) * 1024(scale)

一直满载后一直休眠的util_avg的减速:

util_avg = 1024(scale) * q^n

 

3. 5.10 GKI后的内核支持半衰期窗口个数配置为8还是32,通过如下方式配置

/* 
chosen: chosen { 
    bootargs = "pelt=8 ..."; 
}; 
*/ 
early_param("pelt", set_pelt); //pelt.c

本文参考链接:https://www.cnblogs.com/hellokitty2/p/15361706.html