OSTEP-第四章

第四章课后题

课后实验在github上——指导书纯英文无汉化,罢了罢了

第1题

用以下标志运行程序:./process-run.py -l 5:100,5:100

CPU 利用率(CPU 使用时间的百分比)应该是多少?为什么你知道这一点?

利用 -c 标记查看你的答案是否正确。

先看一眼README,说此程序是用来看进程状态是如何随着运行变化的,列出了四种状态,running ready blocked done,
输入操作数和CPU占比,模拟os的实际时间片分配

回到题目,指令的意思是两个进程,各5条指令,不涉及io操作,cpu使用率还是100%

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        RUN:cpu         READY             1
  6           DONE       RUN:cpu             1
  7           DONE       RUN:cpu             1
  8           DONE       RUN:cpu             1
  9           DONE       RUN:cpu             1
 10           DONE       RUN:cpu             1

没问题

第二题

现在用这些标志运行:./process-run.py -l 4:100,1:0。这些标志指定了一个包含 4 条指令的进程(都要使用 CPU),并且只是简单地发出 I/O 并等待它完成。完成这两个进程需要
多长时间?利用-c 检查你的答案是否正确。

两个进程,第一个4指令无io,4时钟周期,另一个是一个io指令

 # python ./process-run.py -l 4:100,1:0
Produce a trace of what would happen when you run these processes:
Process 0
  cpu
  cpu
  cpu
  cpu

Process 1
  io
  io_done

Important behaviors:
  System will switch when the current process is FINISHED or ISSUES AN IO
  After IOs, the process issuing the IO will run LATER (when it is its turn)

也就是说一个io需要发起异常、完成两个时间周期,以及一个io操作?

#  python ./process-run.py -l 4:100,1:0 -c
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

CPU用时6,周期,等待io阻塞了5周期,累积是11周期

第三题

现在交换进程的顺序:./process-run.py -l 1:0,4:100。现在发生了什么?交换顺序是否
重要?为什么?同样,用-c 看看你的答案是否正确。

应该是在阻塞期间运行了无io的进程,直接看答案吧:

# python ./process-run.py -l 1:0,4:100 -c

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

猜想完全正确

第四题

现在探索另一些标志。一个重要的标志是-S,它决定了当进程发出 I/O 时系统如何
反应。将标志设置为 SWITCH_ON_END,在进程进行 I/O 操作时,系统将不会切换到另一
个进程,而是等待进程完成。当你运行以下两个进程时,会发生什么情况?一个执行 I/O,
另一个执行 CPU 工作。(-l 1:0,4:100 -c -S SWITCH_ON_END)

阻塞了调度呗

# python ./process-run.py -l 1:0,4:100 -c -S SWITCH_ON_END

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

没有问题,io操作的阻塞期间没被调度走

第五题

现在,运行相同的进程,但切换行为设置,在等待 I/O 时切换到另一个进程(-l 1:0,4:100
-c -S SWITCH_ON_IO)。现在会发生什么?利用-c 来确认你的答案是否正确。

预期:和最初等价,即阻塞期间被调度走

# python ./process-run.py -l 1:0,4:100 -c -S SWITCH_ON_IO 
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

符合预期

第六题

另一个重要的行为是 I/O 完成时要做什么。利用-I IO_RUN_LATER,当 I/O 完成时,
发出它的进程不一定马上运行。相反,当时运行的进程一直运行。当你运行这个进程组合
时会发生什么?(./process-run.py -l 3:0,5:100,5:100,5:100 -S SWITCH_ON_IO -I IO_RUN_LATER -c -p)系统资源是否被有效利用?

四个进程,一个为3次io,其余都是cpu操作,运行一下看看

python ./process-run.py -l 3:0,5:100,5:100,5:100 -S SWITCH_ON_IO -I IO_RUN_LATER -c -p
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%)

可以看到pid 0 完成一次io之后就干等着,一直到pid 3执行完才继续,后续的阻塞cpu就浪费着,所以利用率不高,不合理

第七题

现在运行相同的进程,但使用-I IO_RUN_IMMEDIATE 设置,该设置立即运行发出
I/O 的进程。这种行为有何不同?为什么运行一个刚刚完成 I/O 的进程会是一个好主意?

 python ./process-run.py -l 3:0,5:100,5:100,5:100 -S SWITCH_ON_IO -I IO_RUN_IMMEDIATE -c -p
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%)

现在的策略是io结束了控制就回到pid 0继续,这样每一个io的阻塞期间都有进程运行,cpu得到了充分利用。

至于为什么运行一个刚刚完成 I/O 的进程会是一个好主意,如果认为程序有良好的局部性在一次io之后接着io的可能性比较大,那么考虑到io操作较长时间的阻塞,把其它cpu操作尽可能放在阻塞期间执行显然是好主意

第八题

现在运行一些随机生成的进程,例如-s 1 -l 3:50,3:50, -s 2 -l 3:50,3:50, -s 3 -l 3:50,3:50。
看看你是否能预测追踪记录会如何变化?当你使用-I IO_RUN_IMMEDIATE 与-I IO_RUN_
LATER 时会发生什么?当你使用-S SWITCH_ON_IO 与-S SWITCH_ON_END 时会发生什么?

先看一眼-s参数的含义:SEED, --seed=SEED the random seed 用于生成随机数的
也就是两个进程,各3个操作,期中cpu操作和io操作的概率为各50%

开放性试题,随便做几个试一试:

# python .\process-run.py -s 2 -l 3:50,3:50 -I IO_RUN_IMMEDIATE -c
Time        PID: 0        PID: 1           CPU           IOs
  1         RUN:io         READY             1
  2        BLOCKED       RUN:cpu             1             1
  3        BLOCKED        RUN:io             1             1
  4        BLOCKED       BLOCKED                           2
  5        BLOCKED       BLOCKED                           2
  6        BLOCKED       BLOCKED                           2
  7*   RUN:io_done       BLOCKED             1             1
  8         RUN:io       BLOCKED             1             1
  9*       BLOCKED   RUN:io_done             1             1
 10        BLOCKED        RUN:io             1             1
 11        BLOCKED       BLOCKED                           2
 12        BLOCKED       BLOCKED                           2
 13        BLOCKED       BLOCKED                           2
 14*   RUN:io_done       BLOCKED             1             1
 15        RUN:cpu       BLOCKED             1             1
 16*          DONE   RUN:io_done             1
# python .\process-run.py -s 2 -l 3:50,3:50 -I IO_RUN_LATER -c 
Time        PID: 0        PID: 1           CPU           IOs
  1         RUN:io         READY             1
  2        BLOCKED       RUN:cpu             1             1
  3        BLOCKED        RUN:io             1             1
  4        BLOCKED       BLOCKED                           2
  5        BLOCKED       BLOCKED                           2
  6        BLOCKED       BLOCKED                           2
  7*   RUN:io_done       BLOCKED             1             1
  8         RUN:io       BLOCKED             1             1
  9*       BLOCKED   RUN:io_done             1             1
 10        BLOCKED        RUN:io             1             1
 11        BLOCKED       BLOCKED                           2
 12        BLOCKED       BLOCKED                           2
 13        BLOCKED       BLOCKED                           2
 14*   RUN:io_done       BLOCKED             1             1
 15        RUN:cpu       BLOCKED             1             1
 16*          DONE   RUN:io_done             1

嗯,这一组没体现出区别。io结束之后立即切换和下一次阻塞时切换两种策略的结果一致。

python .\process-run.py -s 2 -l 3:50,3:50 -S SWITCH_ON_END -c
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         RUN:io         READY             1
  9        BLOCKED         READY                           1
 10        BLOCKED         READY                           1
 11        BLOCKED         READY                           1
 12        BLOCKED         READY                           1
 13        BLOCKED         READY                           1
 14*   RUN:io_done         READY             1
 15        RUN:cpu         READY             1
 16           DONE       RUN:cpu             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:io             1
 25           DONE       BLOCKED                           1
 26           DONE       BLOCKED                           1
 27           DONE       BLOCKED                           1
 28           DONE       BLOCKED                           1
 29           DONE       BLOCKED                           1
 30*          DONE   RUN:io_done             1

io结束才切换,程序变成了全异步的。-S SWITCH_ON_IO应该和前两种是一致的,也做一下:

# python .\process-run.py -s 2 -l 3:50,3:50 -S SWITCH_ON_IO -c 
Time        PID: 0        PID: 1           CPU           IOs
  1         RUN:io         READY             1
  2        BLOCKED       RUN:cpu             1             1
  3        BLOCKED        RUN:io             1             1
  4        BLOCKED       BLOCKED                           2
  5        BLOCKED       BLOCKED                           2
  6        BLOCKED       BLOCKED                           2
  7*   RUN:io_done       BLOCKED             1             1
  8         RUN:io       BLOCKED             1             1
  9*       BLOCKED   RUN:io_done             1             1
 10        BLOCKED        RUN:io             1             1
 11        BLOCKED       BLOCKED                           2
 12        BLOCKED       BLOCKED                           2
 13        BLOCKED       BLOCKED                           2
 14*   RUN:io_done       BLOCKED             1             1
 15        RUN:cpu       BLOCKED             1             1
 16*          DONE   RUN:io_done             1

符合预期