《操作系统》的实验代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

213 lines
7.5 KiB

  1. This program, called process-run.py, allows you to see how the state of a
  2. process state changes as it runs on a CPU. As described in the chapter,
  3. processes can be in a few different states:
  4. RUNNING - the process is using the CPU right now
  5. READY - the process could be using the CPU right now
  6. but (alas) some other process is
  7. WAITING - the process is waiting on I/O
  8. (e.g., it issued a request to a disk)
  9. DONE - the process is finished executing
  10. In this homework, we'll see how these process states change as a program
  11. runs, and thus learn a little bit better how these things work.
  12. To run the program and get its options, do this:
  13. prompt> ./process-run.py -h
  14. If this doesn't work, type "python" before the command, like this:
  15. prompt> python process-run.py -h
  16. What you should see is this:
  17. Usage: process-run.py [options]
  18. Options:
  19. -h, --help show this help message and exit
  20. -s SEED, --seed=SEED the random seed
  21. -l PROCESS_LIST, --processlist=PROCESS_LIST
  22. a comma-separated list of processes to run, in the
  23. form X1:Y1,X2:Y2,... where X is the number of
  24. instructions that process should run, and Y the
  25. chances (from 0 to 100) that an instruction will use
  26. the CPU or issue an IO
  27. -L IO_LENGTH, --iolength=IO_LENGTH
  28. how long an IO takes
  29. -S PROCESS_SWITCH_BEHAVIOR, --switch=PROCESS_SWITCH_BEHAVIOR
  30. when to switch between processes: SWITCH_ON_IO,
  31. SWITCH_ON_END
  32. -I IO_DONE_BEHAVIOR, --iodone=IO_DONE_BEHAVIOR
  33. type of behavior when IO ends: IO_RUN_LATER,
  34. IO_RUN_IMMEDIATE
  35. -c compute answers for me
  36. -p, --printstats print statistics at end; only useful with -c flag
  37. (otherwise stats are not printed)
  38. The most important option to understand is the PROCESS_LIST (as specified by
  39. the -l or --processlist flags) which specifies exactly what each running
  40. program (or "process") will do. A process consist of instructions, and each
  41. instruction can just do one of two things:
  42. - use the CPU
  43. - issue an IO (and wait for it to complete)
  44. When a process uses the CPU (and does no IO at all), it should simply
  45. alternate between RUNNING on the CPU or being READY to run. For example, here
  46. is a simple run that just has one program being run, and that program only
  47. uses the CPU (it does no IO).
  48. prompt> ./process-run.py -l 5:100 -p
  49. Produce a trace of what would happen when you run these processes:
  50. Process 0
  51. cpu
  52. cpu
  53. cpu
  54. cpu
  55. cpu
  56. Important behaviors:
  57. System will switch when the current process is FINISHED or ISSUES AN IO
  58. After IOs, the process issuing the IO will run LATER (when it is its turn)
  59. prompt>
  60. Here, the process we specified is "5:100" which means it should consist of 5
  61. instructions, and the chances that each instruction is a CPU instruction are
  62. 100%.
  63. You can see what happens to the process by using the -c flag, which computes the
  64. answers for you:
  65. prompt> ./process-run.py -l 5:100 -c
  66. Time PID: 0 CPU IOs
  67. 1 RUN:cpu 1
  68. 2 RUN:cpu 1
  69. 3 RUN:cpu 1
  70. 4 RUN:cpu 1
  71. 5 RUN:cpu 1
  72. This result is not too interesting: the process is simple in the RUN state and
  73. then finishes, using the CPU the whole time and thus keeping the CPU busy the
  74. entire run, and not doing any I/Os.
  75. Let's make it slightly more complex by running two processes:
  76. prompt> ./process-run.py -l 5:100,5:100
  77. Produce a trace of what would happen when you run these processes:
  78. Process 0
  79. cpu
  80. cpu
  81. cpu
  82. cpu
  83. cpu
  84. Process 1
  85. cpu
  86. cpu
  87. cpu
  88. cpu
  89. cpu
  90. Important behaviors:
  91. Scheduler will switch when the current process is FINISHED or ISSUES AN IO
  92. After IOs, the process issuing the IO will run LATER (when it is its turn)
  93. In this case, two different processes run, each again just using the CPU. What
  94. happens when the operating system runs them? Let's find out:
  95. prompt> ./process-run.py -l 5:100,5:100 -c
  96. Time PID: 0 PID: 1 CPU IOs
  97. 1 RUN:cpu READY 1
  98. 2 RUN:cpu READY 1
  99. 3 RUN:cpu READY 1
  100. 4 RUN:cpu READY 1
  101. 5 RUN:cpu READY 1
  102. 6 DONE RUN:cpu 1
  103. 7 DONE RUN:cpu 1
  104. 8 DONE RUN:cpu 1
  105. 9 DONE RUN:cpu 1
  106. 10 DONE RUN:cpu 1
  107. As you can see above, first the process with "process ID" (or "PID") 0 runs,
  108. while process 1 is READY to run but just waits until 0 is done. When 0 is
  109. finished, it moves to the DONE state, while 1 runs. When 1 finishes, the trace
  110. is done.
  111. Let's look at one more example before getting to some questions. In this
  112. example, the process just issues I/O requests.
  113. prompt> ./process-run.py -l 3:0
  114. Produce a trace of what would happen when you run these processes:
  115. Process 0
  116. io-start
  117. io-start
  118. io-start
  119. Important behaviors:
  120. System will switch when the current process is FINISHED or ISSUES AN IO
  121. After IOs, the process issuing the IO will run LATER (when it is its turn)
  122. What do you think the execution trace will look like? Let's find out:
  123. prompt> ./process-run.py -l 3:0 -c
  124. Time PID: 0 CPU IOs
  125. 1 RUN:io-start 1
  126. 2 WAITING 1
  127. 3 WAITING 1
  128. 4 WAITING 1
  129. 5 WAITING 1
  130. 6* RUN:io-start 1
  131. 7 WAITING 1
  132. 8 WAITING 1
  133. 9 WAITING 1
  134. 10 WAITING 1
  135. 11* RUN:io-start 1
  136. 12 WAITING 1
  137. 13 WAITING 1
  138. 14 WAITING 1
  139. 15 WAITING 1
  140. 16* DONE
  141. As you can see, the program just issues three I/Os. When each I/O is issued,
  142. the process moves to a WAITING state, and while the device is busy servicing
  143. the I/O, the CPU is idle.
  144. Let's print some stats (run the same command as above, but with the -p flag)
  145. to see some overall behaviors:
  146. Stats: Total Time 16
  147. Stats: CPU Busy 3 (18.75%)
  148. Stats: IO Busy 12 (75.00%)
  149. As you can see, the trace took 16 clock ticks to run, but the CPU was only
  150. busy less than 20% of the time. The IO device, on the other hand, was quite
  151. busy. In general, we'd like to keep all the devices busy, as that is a better
  152. use of resources.
  153. There are a few other important flags:
  154. -s SEED, --seed=SEED the random seed
  155. this gives you way to create a bunch of different jobs randomly
  156. -L IO_LENGTH, --iolength=IO_LENGTH
  157. this determines how long IOs take to complete (default is 5 ticks)
  158. -S PROCESS_SWITCH_BEHAVIOR, --switch=PROCESS_SWITCH_BEHAVIOR
  159. when to switch between processes: SWITCH_ON_IO, SWITCH_ON_END
  160. this determines when we switch to another process:
  161. - SWITCH_ON_IO, the system will switch when a process issues an IO
  162. - SWITCH_ON_END, the system will only switch when the current process is done
  163. -I IO_DONE_BEHAVIOR, --iodone=IO_DONE_BEHAVIOR
  164. type of behavior when IO ends: IO_RUN_LATER, IO_RUN_IMMEDIATE
  165. this determines when a process runs after it issues an IO:
  166. - IO_RUN_IMMEDIATE: switch to this process right now
  167. - IO_RUN_LATER: switch to this process when it is natural to
  168. (e.g., depending on process-switching behavior)
  169. Now go answer the questions at the back of the chapter to learn more.