《操作系统》的实验代码。

174 lignes
7.5 KiB

  1. This program, mlfq.py, allows you to see how the MLFQ scheduler
  2. presented in this chapter behaves. As before, you can use this to generate
  3. problems for yourself using random seeds, or use it to construct a
  4. carefully-designed experiment to see how MLFQ works under different
  5. circumstances. To run the program, type:
  6. prompt> ./mlfq.py
  7. Use the help flag (-h) to see the options:
  8. Usage: mlfq.py [options]
  9. Options:
  10. -h, --help show this help message and exit
  11. -s SEED, --seed=SEED the random seed
  12. -n NUMQUEUES, --numQueues=NUMQUEUES
  13. number of queues in MLFQ (if not using -Q)
  14. -q QUANTUM, --quantum=QUANTUM
  15. length of time slice (if not using -Q)
  16. -Q QUANTUMLIST, --quantumList=QUANTUMLIST
  17. length of time slice per queue level,
  18. specified as x,y,z,... where x is the
  19. quantum length for the highest-priority
  20. queue, y the next highest, and so forth
  21. -j NUMJOBS, --numJobs=NUMJOBS
  22. number of jobs in the system
  23. -m MAXLEN, --maxlen=MAXLEN
  24. max run-time of a job (if random)
  25. -M MAXIO, --maxio=MAXIO
  26. max I/O frequency of a job (if random)
  27. -B BOOST, --boost=BOOST
  28. how often to boost the priority of all
  29. jobs back to high priority (0 means never)
  30. -i IOTIME, --iotime=IOTIME
  31. how long an I/O should last (fixed constant)
  32. -S, --stay reset and stay at same priority level
  33. when issuing I/O
  34. -l JLIST, --jlist=JLIST
  35. a comma-separated list of jobs to run,
  36. in the form x1,y1,z1:x2,y2,z2:... where
  37. x is start time, y is run time, and z
  38. is how often the job issues an I/O request
  39. -c compute answers for me
  40. ]
  41. There are a few different ways to use the simulator. One way is to generate
  42. some random jobs and see if you can figure out how they will behave given the
  43. MLFQ scheduler. For example, if you wanted to create a randomly-generated
  44. three-job workload, you would simply type:
  45. prompt> ./mlfq.py -j 3
  46. What you would then see is the specific problem definition:
  47. Here is the list of inputs:
  48. OPTIONS jobs 3
  49. OPTIONS queues 3
  50. OPTIONS quantum length for queue 2 is 10
  51. OPTIONS quantum length for queue 1 is 10
  52. OPTIONS quantum length for queue 0 is 10
  53. OPTIONS boost 0
  54. OPTIONS ioTime 0
  55. OPTIONS stayAfterIO False
  56. For each job, three defining characteristics are given:
  57. startTime : at what time does the job enter the system
  58. runTime : the total CPU time needed by the job to finish
  59. ioFreq : every ioFreq time units, the job issues an I/O
  60. (the I/O takes ioTime units to complete)
  61. Job List:
  62. Job 0: startTime 0 - runTime 84 - ioFreq 7
  63. Job 1: startTime 0 - runTime 42 - ioFreq 2
  64. Job 2: startTime 0 - runTime 51 - ioFreq 4
  65. Compute the execution trace for the given workloads.
  66. If you would like, also compute the response and turnaround
  67. times for each of the jobs.
  68. Use the -c flag to get the exact results when you are finished.
  69. This generates a random workload of three jobs (as specified), on the default
  70. number of queues with a number of default settings. If you run again with the
  71. solve flag on (-c), you'll see the same print out as above, plus the
  72. following:
  73. Execution Trace:
  74. [time 0] JOB BEGINS by JOB 0
  75. [time 0] JOB BEGINS by JOB 1
  76. [time 0] JOB BEGINS by JOB 2
  77. [time 0] Run JOB 0 at PRI 2 [TICKSLEFT 9 RUNTIME 84 TIMELEFT 83]
  78. [time 1] Run JOB 0 at PRI 2 [TICKSLEFT 8 RUNTIME 84 TIMELEFT 82]
  79. [time 2] Run JOB 0 at PRI 2 [TICKSLEFT 7 RUNTIME 84 TIMELEFT 81]
  80. [time 3] Run JOB 0 at PRI 2 [TICKSLEFT 6 RUNTIME 84 TIMELEFT 80]
  81. [time 4] Run JOB 0 at PRI 2 [TICKSLEFT 5 RUNTIME 84 TIMELEFT 79]
  82. [time 5] Run JOB 0 at PRI 2 [TICKSLEFT 4 RUNTIME 84 TIMELEFT 78]
  83. [time 6] Run JOB 0 at PRI 2 [TICKSLEFT 3 RUNTIME 84 TIMELEFT 77]
  84. [time 7] IO_START by JOB 0
  85. [time 7] Run JOB 1 at PRI 2 [TICKSLEFT 9 RUNTIME 42 TIMELEFT 41]
  86. [time 8] Run JOB 1 at PRI 2 [TICKSLEFT 8 RUNTIME 42 TIMELEFT 40]
  87. [time 9] IO_START by JOB 1
  88. ...
  89. Final statistics:
  90. Job 0: startTime 0 - response 0 - turnaround 175
  91. Job 1: startTime 0 - response 7 - turnaround 191
  92. Job 2: startTime 0 - response 9 - turnaround 168
  93. Avg 2: startTime n/a - response 5.33 - turnaround 178.00
  94. ]
  95. The trace shows exactly, on a millisecond-by-millisecond time scale, what the
  96. scheduler decided to do. In this example, it begins by running Job 0 for 7 ms
  97. until Job 0 issues an I/O; this is entirely predictable, as Job 0's I/O
  98. frequency is set to 7 ms, meaning that every 7 ms it runs, it will issue an
  99. I/O and wait for it to complete before continuing. At that point, the
  100. scheduler switches to Job 1, which only runs 2 ms before issuing an I/O.
  101. The scheduler prints the entire execution trace in this manner, and
  102. finally also computes the response and turnaround times for each job
  103. as well as an average.
  104. You can also control various other aspects of the simulation. For example, you
  105. can specify how many queues you'd like to have in the system (-n) and what the
  106. quantum length should be for all of those queues (-q); if you want even more
  107. control and varied quanta length per queue, you can instead specify the length
  108. of the quantum for each queue with -Q, e.g., -Q 10,20,30] simulates a
  109. scheduler with three queues, with the highest-priority queue having a 10-ms
  110. time slice, the next-highest a 20-ms time-slice, and the low-priority queue a
  111. 30-ms time slice.
  112. If you are randomly generating jobs, you can also control how long they might
  113. run for (-m), or how often they generate I/O (-M). If you, however, want more
  114. control over the exact characteristics of the jobs running in the system, you
  115. can use -l (lower-case L) or --jlist, which allows you to specify the exact
  116. set of jobs you wish to simulate. The list is of the form:
  117. x1,y1,z1:x2,y2,z2:... where x is the start time of the job, y is the run time
  118. (i.e., how much CPU time it needs), and z the I/O frequency (i.e., after
  119. running z ms, the job issues an I/O; if z is 0, no I/Os are issued).
  120. For example, if you wanted to recreate the example in Figure 8.3
  121. you would specify a job list as follows:
  122. prompt> ./mlfq.py --jlist 0,180,0:100,20,0 -Q 10,10,10
  123. Running the simulator in this way creates a three-level MLFQ, with each level
  124. having a 10-ms time slice. Two jobs are created: Job 0 which starts at time 0,
  125. runs for 180 ms total, and never issues an I/O; Job 1 starts at 100 ms, needs
  126. only 20 ms of CPU time to complete, and also never issues I/Os.
  127. Finally, there are three more parameters of interest. The -B flag, if set to a
  128. non-zero value, boosts all jobs to the highest-priority queue every N
  129. milliseconds, when invoked as such:
  130. prompt> ./mlfq.py -B N
  131. The scheduler uses this feature to avoid starvation as discussed in the
  132. chapter. However, it is off by default.
  133. The -S flag invokes older Rules 4a and 4b, which means that if a job issues an
  134. I/O before completing its time slice, it will return to that same priority
  135. queue when it resumes execution, with its full time-slice intact. This
  136. enables gaming of the scheduler.
  137. Finally, you can easily change how long an I/O lasts by using the -i flag. By
  138. default in this simplistic model, each I/O takes a fixed amount of time of 5
  139. milliseconds or whatever you set it to with this flag.
  140. You can also play around with whether jobs that just complete an I/O are moved
  141. to the head of the queue they are in or to the back, with the -I flag. Check
  142. it out.