Chapter 4 Abstraction: Processes
第 4 章 抽象:进程
进程就是运行中的程序。程序本身是没有生命周期的,它只是存在磁盘上面的一些指令(也可能是一些静态数据)。
操作系统通过虚拟化(virtualizing)CPU来提供这种假象(提供无数个CPU)。
关键技术点:
低级机制
mechanism,低级方法或协议,实现了所需功能
context switch,上下文切换,停止运行一个程序,并运行另一个程序
分时机制
高级智能
policy,策略,操作系统内做出某种决定的算法
scheduling policy,调度策略,综合考量(历史信息,工作负载知识,性能指标)
1. 抽象:进程概念
process 进程。
1.1. 需要理解以下内容:
机器状态 machine state
程序在运行时可以读取或更新的内容
内存
进程可以访问的内润,地址空间,address space
寄存器
许多指令明确地读取或更新寄存器
特殊的寄存器:
程序计数器 Program Counter,PC
有时称为 指令指针,Instruction Pointer,IP
告诉我们程序将执行哪个指令
栈指针 stack pointer 和 帧指针 frame pointer
用于管理函数参数栈、局部变量和返回地址
分离 policy and mechism:modularity 模块化
机制 mechanism 解决 how 的问题
策略 policy 解决 which 的问题
2. 进程 API
进程的接口,真正的 API 会在后面学习...
创建 create
创建新进程
销毁 destroy
强制销毁进程
等待 wait
等待进程停止...
其他控制 miscellaneous control
暂停进程 或者 恢复运行 等等
状态 status
获取进程信息:运行了多久?处于什么状态?
3. 进程创建:更多细节
程序 - 进程 的转变...
3.1. 第一步:代码 + 静态数据 加载到 内存
load to disk(early) or SSD(now)
早期:eagerly
运行程序之前全部完成
现代:lazily
在程序执行期间需要加载的代码或数据片段才会加载
3.2. 第二步:为程序的运行时栈 分配 一些内存
(run-time stack 或 stack)
举例:在 C 语言中会使用栈来存放局部变量,函数参数和返回地址...
操作系统分配这些内存,并提供给进程...
3.3. 第三步:可能为程序的堆分配一些内存
heap...
在 C 程序中,堆用于显式请求的动态内存分配数据。
malloc() 请求空间,free() 释放空间
数据结构
链表、散列表、树 and other...也需要堆
3.4. 第四步:执行一些其他初始化任务
特别是与 I/O 输入/输出 相关的任务
UNIX 系统
默认打开 3 个文件描述符 file descriptor 用于 标准输入、输出和错误
3.5. OS 现在 终于 为程序执行搭好了舞台
他还有最后一项任务
启动程序
在入口处运行,main()
4. 进程状态
简而言之,进程可以处于以下 3 种状态之一
4.1. 运行 running
进程正在处理器上运行,正在执行指令
4.2. 就绪 ready
程序已准备好运行,但处于某种原因,操作系统选择不在此时执行
4.3. 阻塞 blocked
一个进程执行了某种操作,直到发生其他时间时才会准备运行
一个例子:当进程向磁盘发起I/O请求时,它会被阻塞,因此其他进程可以使用处理器....
4.4. 操作系统的决定
需要决定如何进行调度,一个程序就绪时要不要立即执行?阻塞时候等还是不等?所有一切都需要一个好的 policy...
5. 数据结构
操作系统和其他程序一样,有一些关键的数据结构来跟踪各种相关的信息...
5.1. 例子:为了跟踪每个进程的状态
OS 会为所有就虚的进程保留某种进程列表,以及跟踪当前正在运行的进程和一些附加信息...
OS 还必须以某种方式跟踪被阻塞的进程
当 I/O 时间完成时,OS 应确保唤醒正确的进程,让它准备好再次运行
5.2. xv6 内核的 proc 结构
#include <wtypes.h>
#define ulong ULONG
#define uint UINT
#define NOFILE 10
// the registers xv6 will save and restore
// to stop and subsequently restrat a process
struct context
{
int eip;
int esp;
int ebx;
int ecx;
int edx;
int esi;
int edi;
int ebp;
};
// the different states a process can be in
enum proc_state
{
UNUSED,
EMBRYO,
SLEEPING,
RUNNABLE,
RUNNING,
ZOMBIE
};
// the information xv6 tracks about a process
// including its register context and state
struct proc
{
char *mem; // Start of process memory
uint sz; // Size of process memory
char *kstack; // Bottom of kernel stack for this process
enum proc_state state; // Process state
int pid; // Process ID
struct proc *parent; // Parent process
void *chan; // If non-zero, sleeping on chan
int killed; // If non-zero, have been killed
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory
struct context context; // Switch here to run process
struct trapframe *tf; // Trap frame for the current interrupt
};
代码中除了 running、ready and blocked 之外,还有一些状态
System 一开始会有一个 initial 状态 表示进程在创建时处于的状态
final 状态 使得进程可以处于已退出但尚未清理的最终状态 僵尸状态
5.3. 补充
数据结构 - 进程列表
process list
6. 作业:模拟作业
6.1. ./process-run.py -l 5:100,5:100
Run process-run.py with the following flags: -l 5:100,5:100. What should the CPU utilization be (e.g., the percent of time the CPU is in use?) Why do you know this? Use the -c and -p flags to see if you were right.
6.2. ./process-run.py -l 4:100,1:0
Now run with these flags: ./process-run.py -l 4:100,1:0. These flags specify one process with 4 instructions (all to use the CPU), and one that simply issues an I/O and waits for it to be done. How long does it take to complete both processes? Use -c and -p to find out if you were right.
root@LAPTOP-GT06V0GS:/mnt/d/CSLab/osTEP/chapter4/homework# ./process-run.py -l 4:100,1:0 -c -p
Time PID: 0 PID: 1 CPU IOs
1 RUN:cpu READY 1
2 RUN:cpu READY 1
3 RUN:cpu READY 1
4 RUN:cpu READY 1
5 DONE RUN:io 1
6 DONE BLOCKED 1
7 DONE BLOCKED 1
8 DONE BLOCKED 1
9 DONE BLOCKED 1
10 DONE BLOCKED 1
11* DONE RUN:io_done 1
Stats: Total Time 11
Stats: CPU Busy 6 (54.55%)
Stats: IO Busy 5 (45.45%)
PID 0 先全程占用 CPU,随后处理 PID 1,发出 IO 请求后 CPU 空闲...占用 IO。可以看到 CPU 占用率仅 54.55%...
所以能不能先处理 PID 1 然后在 1 Blocked 的时候 处理 PID 0...
6.3. ./process-run.py -l 1:0,4:100. -c -p
Switch the order of the processes: -l 1:0,4:100. What happens now? Does switching the order matter? Why? (As always, use -c and -p to see if you were right)
root@LAPTOP-GT06V0GS:/mnt/d/CSLab/osTEP/chapter4/homework# ./process-run.py -l 1:0,4:100. -c -p
Time PID: 0 PID: 1 CPU IOs
1 RUN:io READY 1
2 BLOCKED RUN:cpu 1 1
3 BLOCKED RUN:cpu 1 1
4 BLOCKED RUN:cpu 1 1
5 BLOCKED RUN:cpu 1 1
6 BLOCKED DONE 1
7* RUN:io_done DONE 1
Stats: Total Time 7
Stats: CPU Busy 6 (85.71%)
Stats: IO Busy 5 (71.43%)
交换处理顺序后可以看到,CPU 占用率大大增加...提高了运行效率...
6.4. ./process-run.py -l 1:0,4:100 -c -S SWITCH ON END
We’ll now explore some of the other flags. One important flag is -S, which determines how the system reacts when a process issues an I/O. With the flag set to SWITCH ON END, the system will NOT switch to another process while one is doing I/O, instead waiting until the process is completely finished. What happens when you run the following two processes (-l 1:0,4:100 -c -S SWITCH_ON_END), one doing I/O and the other doing CPU work?
root@LAPTOP-GT06V0GS:/mnt/d/CSLab/osTEP/chapter4/homework# ./process-run.py -l 1:0,4:100 -c -S SWITCH_ON_END -p
Time PID: 0 PID: 1 CPU IOs
1 RUN:io READY 1
2 BLOCKED READY 1
3 BLOCKED READY 1
4 BLOCKED READY 1
5 BLOCKED READY 1
6 BLOCKED READY 1
7* RUN:io_done READY 1
8 DONE RUN:cpu 1
9 DONE RUN:cpu 1
10 DONE RUN:cpu 1
11 DONE RUN:cpu 1
Stats: Total Time 11
Stats: CPU Busy 6 (54.55%)
Stats: IO Busy 5 (45.45%)
加上 -S 之后,在 PID 0 被 blocked 之后,CPU 并不会处理 PID 1,而是等待 PID 0 完成...可以看到 CPU 效率也会因此降低...
6.5. ./process-run.py -l 1:0,4:100 -c -S SWITCH_ON_IO
Now, run the same processes, but with the switching behavior set to switch to another process whenever one is WAITING for I/O (-l 1:0,4:100 -c -S SWITCH_ON_IO). What happens now? Use -c and -p to confirm that you are right.
root@LAPTOP-GT06V0GS:/mnt/d/CSLab/osTEP/chapter4/homework# ./process-run.py -l 1:0,4:100 -c -S SWITCH_ON_IO -p
Time PID: 0 PID: 1 CPU IOs
1 RUN:io READY 1
2 BLOCKED RUN:cpu 1 1
3 BLOCKED RUN:cpu 1 1
4 BLOCKED RUN:cpu 1 1
5 BLOCKED RUN:cpu 1 1
6 BLOCKED DONE 1
7* RUN:io_done DONE 1
Stats: Total Time 7
Stats: CPU Busy 6 (85.71%)
Stats: IO Busy 5 (71.43%)
这时候其实有点像 Q 3 的那个,应该是默认的设置...不会等待,而是哪个空处理哪个...
6.6. ./process-run.py -l 3:0,5:100,5:100,5:100 -S SWITCH_ON_IO -c -p -I IO_RUN_LATER
One other important behavior is what to do when an I/O completes. With -I IO RUN LATER, when an I/O completes, the process that issued it is not necessarily run right away; rather, whatever was running at the time keeps running. What happens when you run this combination of processes? (./process-run.py -l 3:0,5:100,5:100,5:100 -S SWITCH_ON_IO -c -p -I IO_RUN_LATER) Are system resources being effectively utilized?
root@LAPTOP-GT06V0GS:/mnt/d/CSLab/osTEP/chapter4/homework# ./process-run.py -l 3:0,5:100,5:100,5:100 -S SWITCH_ON_IO -c -p -I IO_RUN_LATER
Time PID: 0 PID: 1 PID: 2 PID: 3 CPU IOs
1 RUN:io READY READY READY 1
2 BLOCKED RUN:cpu READY READY 1 1
3 BLOCKED RUN:cpu READY READY 1 1
4 BLOCKED RUN:cpu READY READY 1 1
5 BLOCKED RUN:cpu READY READY 1 1
6 BLOCKED RUN:cpu READY READY 1 1
7* READY DONE RUN:cpu READY 1
8 READY DONE RUN:cpu READY 1
9 READY DONE RUN:cpu READY 1
10 READY DONE RUN:cpu READY 1
11 READY DONE RUN:cpu READY 1
12 READY DONE DONE RUN:cpu 1
13 READY DONE DONE RUN:cpu 1
14 READY DONE DONE RUN:cpu 1
15 READY DONE DONE RUN:cpu 1
16 READY DONE DONE RUN:cpu 1
17 RUN:io_done DONE DONE DONE 1
18 RUN:io DONE DONE DONE 1
19 BLOCKED DONE DONE DONE 1
20 BLOCKED DONE DONE DONE 1
21 BLOCKED DONE DONE DONE 1
22 BLOCKED DONE DONE DONE 1
23 BLOCKED DONE DONE DONE 1
24* RUN:io_done DONE DONE DONE 1
25 RUN:io DONE DONE DONE 1
26 BLOCKED DONE DONE DONE 1
27 BLOCKED DONE DONE DONE 1
28 BLOCKED DONE DONE DONE 1
29 BLOCKED DONE DONE DONE 1
30 BLOCKED DONE DONE DONE 1
31* RUN:io_done DONE DONE DONE 1
Stats: Total Time 31
Stats: CPU Busy 21 (67.74%)
Stats: IO Busy 15 (48.39%)
当一个 process 的 io block 结束之后,CPU 不会马上继续处理这个 process 而是继续往下执行...最后才会回来执行,这有时候会拖慢 CPU 的效率...
6.7. ./process-run.py -l 3:0,5:100,5:100,5:100 -S SWITCH_ON_IO -c -p -I IO_RUN_IMMEDIATE
Now run the same processes, but with -I IO RUN_IMMEDIATE set, which immediately runs the process that issued the I/O. How does this behavior differ? Why might running a process that just completed an I/O again be a good idea?
root@LAPTOP-GT06V0GS:/mnt/d/CSLab/osTEP/chapter4/homework# ./process-run.py -l 3:0,5:100,5:100,5:100 -S SWITCH_ON_IO -c -p -I IO_RUN_IMMEDIATE
Time PID: 0 PID: 1 PID: 2 PID: 3 CPU IOs
1 RUN:io READY READY READY 1
2 BLOCKED RUN:cpu READY READY 1 1
3 BLOCKED RUN:cpu READY READY 1 1
4 BLOCKED RUN:cpu READY READY 1 1
5 BLOCKED RUN:cpu READY READY 1 1
6 BLOCKED RUN:cpu READY READY 1 1
7* RUN:io_done DONE READY READY 1
8 RUN:io DONE READY READY 1
9 BLOCKED DONE RUN:cpu READY 1 1
10 BLOCKED DONE RUN:cpu READY 1 1
11 BLOCKED DONE RUN:cpu READY 1 1
12 BLOCKED DONE RUN:cpu READY 1 1
13 BLOCKED DONE RUN:cpu READY 1 1
14* RUN:io_done DONE DONE READY 1
15 RUN:io DONE DONE READY 1
16 BLOCKED DONE DONE RUN:cpu 1 1
17 BLOCKED DONE DONE RUN:cpu 1 1
18 BLOCKED DONE DONE RUN:cpu 1 1
19 BLOCKED DONE DONE RUN:cpu 1 1
20 BLOCKED DONE DONE RUN:cpu 1 1
21* RUN:io_done DONE DONE DONE 1
Stats: Total Time 21
Stats: CPU Busy 21 (100.00%)
Stats: IO Busy 15 (71.43%)
当把参数设置为 immediate 之后,process 会在 block 之后立即被 CPU 处理...为什么这是一个好主意?
在操作系统中,将进程在阻塞(block)之后立即被CPU处理的调度策略称为“立即调度”(Immediate Scheduling)。
这种策略通常用于需要快速响应的场景,尤其是在实时系统中。
提高响应速度
quick response
reduce wait
增强系统的实时性
reduce jitter
抖动是指任务执行时间的不稳定性。立即调度可以减少任务在就绪队列中的等待时间,从而降低抖动,提高系统的稳定性。
提高系统吞吐量
increse CPU efficiency
提高系统的公平性
avoid hungry phenomenen
dynamic adjust prior
适应动态变化的系统需求
6.8. ./process-run.py -s 1 -l 3:50,3:50 or -s 2 -l 3:50,3:50 or -s 3 -l 3:50,3:50 -c -p
Now run with some randomly generated processes using flags -s 1 -l 3:50,3:50 or -s 2 -l 3:50,3:50 or -s 3 -l 3:50, 3:50. See if you can predict how the trace will turn out. What happens when you use the flag -I IO_RUN_IMMEDIATE versus that flag -I IO_ RUN_LATER? What happens when you use the flag -S SWITCH_ON_IO versus -S SWITCH_ON_END?
无 -I -S 参数版本
root@LAPTOP-GT06V0GS:/mnt/d/CSLab/osTEP/chapter4/homework# ./process-run.py -s 1 -l 3:50,3:50 or -s 2 -l 3:50,3:50 or -s 3 -l 3:50,3:50 -c -p
Time PID: 0 PID: 1 CPU IOs
1 RUN:cpu READY 1
2 RUN:io READY 1
3 BLOCKED RUN:io 1 1
4 BLOCKED BLOCKED 2
5 BLOCKED BLOCKED 2
6 BLOCKED BLOCKED 2
7 BLOCKED BLOCKED 2
8* RUN:io_done BLOCKED 1 1
9* RUN:cpu READY 1
10 DONE RUN:io_done 1
11 DONE RUN:io 1
12 DONE BLOCKED 1
13 DONE BLOCKED 1
14 DONE BLOCKED 1
15 DONE BLOCKED 1
16 DONE BLOCKED 1
17* DONE RUN:io_done 1
18 DONE RUN:cpu 1
Stats: Total Time 18
Stats: CPU Busy 9 (50.00%)
Stats: IO Busy 11 (61.11%)
程序行为应该是两个都需要 io 的进程...
-I IO_RUN_IMMEDIATE
root@LAPTOP-GT06V0GS:/mnt/d/CSLab/osTEP/chapter4/homework# ./process-run.py -s 1 -l 3:50,3:50 or -s 2 -l 3:50,3:50 or -s 3 -l 3:50,3:50 -I IO_RUN_IMMEDIATE -c -p
Time PID: 0 PID: 1 CPU IOs
1 RUN:cpu READY 1
2 RUN:io READY 1
3 BLOCKED RUN:io 1 1
4 BLOCKED BLOCKED 2
5 BLOCKED BLOCKED 2
6 BLOCKED BLOCKED 2
7 BLOCKED BLOCKED 2
8* RUN:io_done BLOCKED 1 1
9* READY RUN:io_done 1
10 READY RUN:io 1
11 RUN:cpu BLOCKED 1 1
12 DONE BLOCKED 1
13 DONE BLOCKED 1
14 DONE BLOCKED 1
15 DONE BLOCKED 1
16* DONE RUN:io_done 1
17 DONE RUN:cpu 1
Stats: Total Time 17
Stats: CPU Busy 9 (52.94%)
Stats: IO Busy 11 (64.71%)
-I IO_ RUN_LATER
和无参数的时候一样啊,证明默认应该是继续执行,而不是回头?
root@LAPTOP-GT06V0GS:/mnt/d/CSLab/osTEP/chapter4/homework# ./process-run.py -s 1 -l 3:50,3:50 or -s 2 -l 3:50,3:50 or -s 3 -l 3:50,3:50 -I IO_RUN_LATER -c -p
Time PID: 0 PID: 1 CPU IOs
1 RUN:cpu READY 1
2 RUN:io READY 1
3 BLOCKED RUN:io 1 1
4 BLOCKED BLOCKED 2
5 BLOCKED BLOCKED 2
6 BLOCKED BLOCKED 2
7 BLOCKED BLOCKED 2
8* RUN:io_done BLOCKED 1 1
9* RUN:cpu READY 1
10 DONE RUN:io_done 1
11 DONE RUN:io 1
12 DONE BLOCKED 1
13 DONE BLOCKED 1
14 DONE BLOCKED 1
15 DONE BLOCKED 1
16 DONE BLOCKED 1
17* DONE RUN:io_done 1
18 DONE RUN:cpu 1
Stats: Total Time 18
Stats: CPU Busy 9 (50.00%)
Stats: IO Busy 11 (61.11%)
-S SWITCH_ON_IO
root@LAPTOP-GT06V0GS:/mnt/d/CSLab/osTEP/chapter4/homework# ./process-run.py -s 1 -l 3:50,3:50 or -s 2 -l 3:50,3:50 or -s 3 -l 3:50,3:50 -S SWITCH_ON_IO -c -p
Time PID: 0 PID: 1 CPU IOs
1 RUN:cpu READY 1
2 RUN:io READY 1
3 BLOCKED RUN:io 1 1
4 BLOCKED BLOCKED 2
5 BLOCKED BLOCKED 2
6 BLOCKED BLOCKED 2
7 BLOCKED BLOCKED 2
8* RUN:io_done BLOCKED 1 1
9* RUN:cpu READY 1
10 DONE RUN:io_done 1
11 DONE RUN:io 1
12 DONE BLOCKED 1
13 DONE BLOCKED 1
14 DONE BLOCKED 1
15 DONE BLOCKED 1
16 DONE BLOCKED 1
17* DONE RUN:io_done 1
18 DONE RUN:cpu 1
Stats: Total Time 18
Stats: CPU Busy 9 (50.00%)
Stats: IO Busy 11 (61.11%)
-S SWITCH_ON_END
root@LAPTOP-GT06V0GS:/mnt/d/CSLab/osTEP/chapter4/homework# ./process-run.py -s 1 -l 3:50,3:50 or -s 2 -l 3:50,3:50 or -s 3 -l 3:50,3:50 -S SWITCH_ON_END -c -p
Time PID: 0 PID: 1 CPU IOs
1 RUN:cpu READY 1
2 RUN:io READY 1
3 BLOCKED READY 1
4 BLOCKED READY 1
5 BLOCKED READY 1
6 BLOCKED READY 1
7 BLOCKED READY 1
8* RUN:io_done READY 1
9 RUN:cpu READY 1
10 DONE RUN:io 1
11 DONE BLOCKED 1
12 DONE BLOCKED 1
13 DONE BLOCKED 1
14 DONE BLOCKED 1
15 DONE BLOCKED 1
16* DONE RUN:io_done 1
17 DONE RUN:io 1
18 DONE BLOCKED 1
19 DONE BLOCKED 1
20 DONE BLOCKED 1
21 DONE BLOCKED 1
22 DONE BLOCKED 1
23* DONE RUN:io_done 1
24 DONE RUN:cpu 1
Stats: Total Time 24
Stats: CPU Busy 9 (37.50%)
Stats: IO Busy 15 (62.50%)
总结
总觉得有点乱啊...
找AI帮忙总结一下
-I IO_RUN_IMMEDIATE
当一个进程完成 I/O 操作后,操作系统立即切换到该进程,让其继续运行。
进程完成 I/O 操作后,操作系统会立即将其状态设置为 READY ,并立即切换到该进程。
如果此时 CPU 是空闲的,该进程会立即获得 CPU 资源并继续执行。
如果 CPU 正在运行其他进程,操作系统会中断当前运行的进程,切换到完成 I/O 的进程。
-I IO_RUN_LATER
当一个进程完成 I/O 操作后,操作系统不会立即切换到该进程,而是将其放入就绪队列,等待调度器调度。
进程完成 I/O 操作后,操作系统将其状态设置为 READY ,并将其放入就绪队列。
调度器会在合适的时机选择该进程运行,而不是立即切换。
-S SWITCH_ON_IO
当一个进程发起 I/O 操作时,操作系统立即切换到另一个进程。
进程发起 I/O 操作时,操作系统将其状态设置为 WAIT ,并立即切换到另一个就绪的进程。
这种切换发生在 I/O 操作开始时,而不是 I/O 操作完成时。
-S SWITCH_ON_END
当一个进程完成其所有操作后,操作系统才切换到另一个进程。
进程在完成其所有操作(包括 I/O 和 CPU 操作)后,操作系统才切换到另一个就绪的进程。
这种切换发生在进程结束时,而不是在 I/O 操作开始时。
总的来说是这样,-I IO_RUN_IMMEDIATE 在 IO 结束后会立即切换回去...LATER则不然。-S SWITCH_ON_IO会在发起IO时,换成别的线程,END则是等待...
各自有优点吧...CPU效率最大化应该是-I IO_RUN_IMMEDIATE + -S SWITCH_ON_IO
但这样不总是对的,考虑的还有上下文切换的成本之类的。
实际应用中的选择
CPU 密集型任务:使用 -S SWITCH_ON_END ,减少上下文切换开销,提高 CPU 利用率。
I/O 密集型任务:使用 -S SWITCH_ON_IO ,避免 I/O 阻塞,提高系统吞吐量。
需要快速响应 I/O 完成的场景:使用 -I IO_RUN_IMMEDIATE ,减少等待时间,提高响应速度。
需要减少上下文切换开销的场景:使用 -I IO_RUN_LATER ,提高系统吞吐量。
CPU效率最高 同时 IO效率最高 (在这道题)...
root@LAPTOP-GT06V0GS:/mnt/d/CSLab/osTEP/chapter4/homework# ./process-run.py -s 1 -l 3:50,3:50 or -s 2 -l 3:50,3:50 or -s 3 -l 3:50,3:50 -I IO_RUN_IMMEDIATE -S SWITCH_ON_IO -c -p
Time PID: 0 PID: 1 CPU IOs
1 RUN:cpu READY 1
2 RUN:io READY 1
3 BLOCKED RUN:io 1 1
4 BLOCKED BLOCKED 2
5 BLOCKED BLOCKED 2
6 BLOCKED BLOCKED 2
7 BLOCKED BLOCKED 2
8* RUN:io_done BLOCKED 1 1
9* READY RUN:io_done 1
10 READY RUN:io 1
11 RUN:cpu BLOCKED 1 1
12 DONE BLOCKED 1
13 DONE BLOCKED 1
14 DONE BLOCKED 1
15 DONE BLOCKED 1
16* DONE RUN:io_done 1
17 DONE RUN:cpu 1
Stats: Total Time 17
Stats: CPU Busy 9 (52.94%)
Stats: IO Busy 11 (64.71%)
Last updated