交互性评分与优先级
交互性评分与优先级
Freebsd的ULE调度,采用了与Linux不同的思想。它采用了优先级比较的方式,目的是改善交互式进程的响应。
ULE主要是从线程的行为来识别该线程是否是交互式进程:一般交互式进程都是在等待输入事件,当获取到输入事件后进行相应的处理,最后再进入到输入事件等待中。这种等待事件-处理事件的特征,其时在现代的程序中都在使用,尤其是一些守护进程/后台服务都是在等待客户进程发送任务请求。唯一不同的是:在获取到输入事件后交互式进程的处理过程一般都很短,所以在ULE调度中就采用了主动睡眠时间/工作时间的比值来计算交互性评估,然后再将该评分换算成进程的优先级。
交互性评分算法
- 当线程的睡眠时间大于运行时间时:
交互性评分 = 比例因子 睡眠时间 / 运行时间 交互性评分 = \frac{比例因子}{睡眠时间/运行时间} 交互性评分=睡眠时间/运行时间比例因子
- 当线程的睡眠时间小于运行时间时:
交互性评分 = 比例因子 运行时间 / 睡眠时间 + 比例因子 交互性评分 = \frac{比例因子}{运行时间/睡眠时间} + 比例因子 交互性评分=运行时间/睡眠时间比例因子+比例因子
- 当线程的睡眠时间等于运行时间,且都不为0时:
交互性评分 = 50 交互性评分 = 50 交互性评分=50
- 当线程的睡眠时间等于运行时间,且都为 0时:
交互性评分 = 0 交互性评分 = 0 交互性评分=0
该算法使用睡眠时间与工作时间的比值来作为交互性判定,并通过比例因子归一化到 [ 0 : 100 ] [0:100] [0:100]之间。
交互评分换算成优先级
- 当评分小于域值的时候
优先级 = 最小交互性优先级 + 交互性优先级范围 × 交互性评分 交互性域值 优先级 = 最小交互性优先级 + 交互性优先级范围 \times \frac{交互性评分}{交互性域值} 优先级=最小交互性优先级+交互性优先级范围×交互性域值交互性评分
- 当评分大于等于域值的时候
优先级 = 基础优先级 + 累积运行时间 线程存在时间 × 优先级范围 + n i c e 优先级 = 基础优先级 + \frac{累积运行时间}{线程存在时间} \times 优先级范围 + nice 优先级=基础优先级+线程存在时间累积运行时间×优先级范围+nice
数据约束
- 交互性时间更新
在 FreeBSD 系统中使用睡眠时间和工作时间的比值来计算交互性评分。为了防止出现交互性评分过大过小的情况,系统使用 SCHED_SLP_RUN_MAX 对历史调度记录做了最大限制。
- 当睡眠时间和工作时间总和小于 SCHED_SLP_RUN_MAX 时:
不做任何处理
- 当睡眠时间和工作时间总和大于 SCHED_SLP_RUN_MAX 时:
工作时间 = 工作时间 5 × 4 工作时间 = \frac{工作时间}{5} \times 4 工作时间=5工作时间×4
睡眠时间 = 睡眠时间 5 × 4 睡眠时间 = \frac{睡眠时间}{5} \times 4 睡眠时间=5睡眠时间×4
- 当睡眠时间和工作时间总和大于 1.2 倍的 SCHED_SLP_RUN_MAX 时:
工作时间 = 工作时间 2 工作时间 = \frac{工作时间}{2} 工作时间=2工作时间
睡眠时间 = 睡眠时间 2 睡眠时间 = \frac{睡眠时间}{2} 睡眠时间=2睡眠时间
-
当睡眠时间和工作时间总和大于 2 倍的 SCHED_SLP_RUN_MAX 时:
-
运行时间 大于 睡眠时间:
工作时间 = S C H E D _ S L P _ R U N _ M A X 工作时间 = SCHED\_SLP\_RUN\_MAX 工作时间=SCHED_SLP_RUN_MAX睡眠时间 = 1 睡眠时间 = 1 睡眠时间=1
-
运行时间 小于等于 睡眠时间:
-
工作时间 = 1 工作时间 = 1 工作时间=1
睡眠时间 = S C H E D _ S L P _ R U N _ M A X 睡眠时间 = SCHED\_SLP\_RUN\_MAX 睡眠时间=SCHED_SLP_RUN_MAX
- CPU 利用率评估更新
在 FreeBSD 中使用累积运行时间和线程存在时间的比值来定义 CPU 的利用率。为了防止出现利用率过大/过小的情况,系统又定义了线程一次过程最大计时时间 SCHED_TICK_TARG 和线程持续运行最大计时时间 SCHED_TICK_MAX 。
-
当一次过程大于等于 SCHED_TICK_TARG 时:
- 复位累积运行时间;
- 重新设置线程开始时间;
-
当持续运行时间大于等于 SCHED_TICK_MAX 时:
-
累计运行时间:
累积运行时间 = 上次测量的累积运行时间 上次测量的存在时间 × (本地运行时间 + S C H E D _ T I C K _ T A R G ) 累积运行时间 = \frac{上次测量的累积运行时间}{上次测量的存在时间} \times (本地运行时间 + SCHED\_TICK\_TARG) 累积运行时间=上次测量的存在时间上次测量的累积运行时间×(本地运行时间+SCHED_TICK_TARG) -
重新设置线程开始时间;
-
当线程处于运行态,则累积运行时间:
累积运行时间
=
上次累积运行时间
+
本次运行时间
累积运行时间 = 上次累积运行时间 + 本次运行时间
累积运行时间=上次累积运行时间+本次运行时间
总结
从上面可以看出,运行时间越长、随眠时间越短优先级越低。
其时这里我觉得 ULE 调度其时是改善了程序的响应速度,并不单单针对交互式进程;而那些长期占用 CPU 资源的程序会遭到惩罚——降低优先级从而减少运行的时间。