浏览代码

Removed wrong hw_ folders.

Joshua Rutschmann 7 年前
父节点
当前提交
44f8e512bc
共有 100 个文件被更改,包括 0 次插入7017 次删除
  1. 二进制
      hw0/.gfx/github-pr.xcf
  2. 二进制
      hw0/.gfx/github-pr1.png
  3. 二进制
      hw0/.gfx/github-pr2.png
  4. 0
    37
      hw0/README.md
  5. 0
    81
      hw0/gittask0/README.md
  6. 0
    6
      hw0/gittask0/SOLUTION.md
  7. 0
    47
      hw1/README.md
  8. 0
    35
      hw1/simu1/QUESTIONS.md
  9. 0
    236
      hw1/simu1/README-process-run.md
  10. 0
    325
      hw1/simu1/process-run.py
  11. 0
    18
      hw1/simu2/QUESTIONS.md
  12. 0
    31
      hw1/task1/README.md
  13. 0
    3
      hw1/task1/src/lib.rs
  14. 0
    25
      hw1/task1/tests/task1.rs
  15. 0
    24
      hw1/task2/README.md
  16. 0
    8
      hw1/task2/src/lib.rs
  17. 0
    41
      hw1/task2/tests/task2.rs
  18. 0
    8
      hw1/task3/README.md
  19. 0
    3
      hw1/task3/src/lib.rs
  20. 0
    45
      hw1/task3/tests/task3.rs
  21. 0
    22
      hw1/task4/README.md
  22. 0
    11
      hw1/task4/src/lib.rs
  23. 0
    31
      hw1/task4/tests/task4.rs
  24. 0
    32
      hw1/task5/README.md
  25. 0
    40
      hw1/task5/src/main.rs
  26. 0
    27
      hw1/task5/tests/output.bats
  27. 0
    40
      hw2/README.md
  28. 0
    9
      hw2/simu1/ANSWERS.md
  29. 0
    11
      hw2/simu1/Makefile
  30. 0
    72
      hw2/simu1/QUESTIONS.md
  31. 0
    7
      hw2/simu1/free.c
  32. 0
    7
      hw2/simu1/intArray1.c
  33. 0
    8
      hw2/simu1/intArray2.c
  34. 0
    5
      hw2/simu1/malloc.c
  35. 0
    12
      hw2/simu1/null.c
  36. 0
    6
      hw2/task1/Cargo.toml
  37. 0
    38
      hw2/task1/README.md
  38. 0
    22
      hw2/task1/src/lib.rs
  39. 0
    36
      hw2/task1/tests/task1.rs
  40. 0
    10
      hw2/task2/Cargo.toml
  41. 0
    317
      hw2/task2/README.md
  42. 0
    86
      hw2/task2/src/lib.rs
  43. 0
    28
      hw2/task2/src/main.rs
  44. 0
    41
      hw2/task2/tests/output.bats
  45. 0
    95
      hw2/task2/tests/task2.rs
  46. 0
    6
      hw2/task3/Cargo.toml
  47. 0
    24
      hw2/task3/README.md
  48. 0
    45
      hw2/task3/src/lib.rs
  49. 0
    7
      hw2/task3/src/main.rs
  50. 0
    39
      hw2/task3/tests/task3.rs
  51. 0
    51
      hw3/README.md
  52. 0
    21
      hw3/simu1/ANSWERS.md
  53. 0
    53
      hw3/simu1/QUESTIONS.md
  54. 0
    99
      hw3/simu1/README-relocation.md
  55. 0
    118
      hw3/simu1/relocation.py
  56. 0
    82
      hw3/simu2/ANSWERS.md
  57. 0
    87
      hw3/simu2/QUESTIONS.md
  58. 0
    183
      hw3/simu2/README-segmentation.md
  59. 0
    193
      hw3/simu2/segmentation.py
  60. 0
    111
      hw3/simu3/ANSWERS.md
  61. 0
    41
      hw3/simu3/QUESTIONS.md
  62. 0
    164
      hw3/simu3/README-malloc.md
  63. 0
    253
      hw3/simu3/malloc.py
  64. 0
    14
      hw3/simu4/ANSWERS.md
  65. 0
    69
      hw3/simu4/QUESTIONS.md
  66. 0
    135
      hw3/simu4/README-paging-linear-translate.md
  67. 0
    192
      hw3/simu4/paging-linear-translate.py
  68. 0
    28
      hw4/README.md
  69. 0
    39
      hw4/simu1/ANSWERS.md
  70. 0
    12
      hw4/simu1/QUESTIONS.md
  71. 0
    80
      hw4/simu1/README-paging-multilevel-translate.md
  72. 0
    265
      hw4/simu1/paging-multilevel-translate.py
  73. 0
    31
      hw4/simu2/ANSWERS.md
  74. 0
    6
      hw4/simu2/Makefile
  75. 0
    21
      hw4/simu2/QUESTIONS.md
  76. 0
    92
      hw4/simu2/README-mem-vmstat.md
  77. 0
    67
      hw4/simu2/mem.c
  78. 0
    18
      hw4/simu3/ANSWERS.md
  79. 0
    19
      hw4/simu3/QUESTIONS.md
  80. 0
    128
      hw4/simu3/README-paging-policy.md
  81. 0
    275
      hw4/simu3/paging-policy.py
  82. 0
    25
      hw4/simu3/randomtrace.c
  83. 0
    8
      hw4/task1/Cargo.toml
  84. 0
    277
      hw4/task1/README.md
  85. 0
    95
      hw4/task1/src/main.rs
  86. 0
    95
      hw4/task1/src/pstree.rs
  87. 0
    66
      hw4/task1/src/readproc.rs
  88. 0
    57
      hw4/task1/src/unit_test_pstree.rs
  89. 0
    63
      hw4/task1/src/unit_test_readproc.rs
  90. 0
    45
      hw4/task1/tests/output.bats
  91. 0
    30
      hw5/README.md
  92. 0
    22
      hw5/simu1/QUESTIONS.md
  93. 0
    129
      hw5/simu1/README-scheduler.md
  94. 0
    155
      hw5/simu1/scheduler.py
  95. 0
    27
      hw5/simu2/QUESTIONS.md
  96. 0
    184
      hw5/simu2/README-mlfq.md
  97. 0
    338
      hw5/simu2/mlfq.py
  98. 0
    243
      hw5/task1/README.md
  99. 0
    104
      hw5/task1/tests/output.bats
  100. 0
    0
      hw5/task2/README.md

二进制
hw0/.gfx/github-pr.xcf 查看文件


二进制
hw0/.gfx/github-pr1.png 查看文件


二进制
hw0/.gfx/github-pr2.png 查看文件


+ 0
- 37
hw0/README.md 查看文件

@@ -1,37 +0,0 @@
1
-# HW0 - Git Übung
2
-In dieser Übung wird der Umgang mit `git` auf der Kommandozeile gelernt.
3
-
4
-## Vorbereitung
5
-Updates des Templates herunterladen und neue Feature-Branches für jeden Benutzer erstellen.
6
-
7
-### User A @ Container:
8
-```bash
9
-cd ~/src/htwg-syslab-bsys-ws17/bsys-ws17-grpN
10
-git fetch --all
11
-git checkout hw0
12
-git push origin hw0
13
-git checkout -b hw0-UserA
14
-git push origin hw0-UserA
15
-```
16
-
17
-### User B @ Container:
18
-```bash
19
-cd ~/src/htwg-syslab-bsys-ws17/bsys-ws17-grpN
20
-```
21
-
22
-Hole die neusten Informationen aller Remotes
23
-```bash
24
-git fetch --all
25
-```
26
-
27
-Verwende *origin/hw0* als Basis für die neue lokale *hw0* Branch
28
-```bash
29
-git checkout origin/hw0
30
-git checkout -b hw0
31
-```
32
-
33
-Zweige von *hw0* ab nach *hw0-UserB* und push nach auf den Fork von UserA (origin)
34
-```bash
35
-git checkout -b hw0-UserB
36
-git push origin hw0-UserB
37
-```

+ 0
- 81
hw0/gittask0/README.md 查看文件

@@ -1,81 +0,0 @@
1
-# HW0 - gittask0
2
-
3
-## Vorbereitung
4
-
5
-### User A @ Container
6
-```bash
7
-cd ~/src/htwg-syslab-bsys-ws17/bsys-ws17-grpN
8
-git status # verify that the branch is hw0-UserA
9
-```
10
-
11
-### User B @ Container
12
-```bash
13
-cd ~/src/htwg-syslab-bsys-ws17/bsys-ws17-grpN
14
-git status # verify that the branch is hw0-UserB
15
-```
16
-
17
-## Konflikterzeugung
18
-Beide Benutzer verändern auf ihrer lokalen Kopie eine Datei und laden diese Änderung hoch.
19
-Beim zusammenführen fällt der Konflikt dann auf, und muss von einem Benutzer behoben werden.
20
-
21
-### User A @ Container
22
-* Ersetze die beiden Fragezeichen in der Tabelle mit jeweils Namen und Github Benutzernamen.
23
-* Ersetze das N in der Überschrift durch die Gruppennummer
24
-
25
-```bash
26
-git commit -v SOLUTION.md
27
-git push
28
-```
29
-
30
-### User A @ GitHub
31
-* Erstelle einen Pull-Request von _hw0-UserA_ auf _hw0_.
32
-
33
-    ![PR1](../.gfx/github-pr1.png)
34
-
35
-### User B @ Container
36
-* Ersetze die beiden Fragezeichen in der Tabelle mit jeweils Namen und Github Benutzernamen.
37
-* Ersetze das N in der Überschrift durch die Gruppennummer
38
-
39
-```bash
40
-git commit -v SOLUTION.md
41
-git push
42
-```
43
-
44
-### User B @ GitHub
45
-* Bestätige den Pull-Request von User A
46
-* Erstelle einen Pull-Request von _hw0-UserB_ auf _hw0_.
47
-
48
-    ![PR2](../.gfx/github-pr2.png)
49
-* **Konflikt tritt auf!**
50
-
51
-## Konfliktbehandlung
52
-
53
-### User B @ Container
54
-* Bestätige den Pull-Request von User A
55
-* Erstelle einen Pull-Request von _hw0-UserB_ auf _hw0_.
56
-  **Konflikt tritt auf!**
57
-
58
-### User B @ Container
59
-```bash
60
-git checkout hw0
61
-git pull
62
-git checkout hw0-UserB
63
-git merge hw0
64
-# edit SOLUTIONS.md
65
-git commit -v SOLUTIONS.md
66
-git push
67
-```
68
-
69
-### User A @ GitHub
70
-* Bestätige den Pull-Request von User B
71
-
72
-### User A @ Container
73
-```bash
74
-git checkout hw0
75
-git pull
76
-```
77
-
78
-## Abgabe
79
-
80
-### User A @ GitHub
81
-* Öffne Upstream Repository und erstelle Pull-Request von der _hw0_ von UserA's fork auf _master_ Branch des Upstream Repository

+ 0
- 6
hw0/gittask0/SOLUTION.md 查看文件

@@ -1,6 +0,0 @@
1
-# Gruppe 11
2
-
3
-Name | Github Benutzer
4
---- | ---
5
-Lorenz Bung | LorenzBung
6
-Joshua Rutschmann | themultiplexer

+ 0
- 47
hw1/README.md 查看文件

@@ -1,47 +0,0 @@
1
-# hw1
2
-
3
-## Tasks
4
-To fullfill **hw1** you have to solve:
5
-
6
-- task1
7
-- task2
8
-- task3
9
-- task4
10
-- simu1
11
-
12
-Optinal are (bonus +1P):
13
-
14
-- task5
15
-- simu2
16
-
17
-## Files
18
-You find already files for earch rust task.
19
-
20
-## ASIDE: SIMULATION HOMEWORKS
21
-
22
-Simulation homeworks (`simuN/`) come in the form of simulators you run to
23
-make sure you understand some piece of the material. The simulators are generally python programs that enable you both to generate different problems (using different random seeds) as well as to have the program solve the problem for you (with the `-c` flag) so that you can check your answers. Running any simulator with a `-h` or `--help`flag will provide with more information as to all the options the simulator gives you.
24
-
25
-The README provided with each simulator gives more detail as to how to run it. Each flag is described in some detail therein.
26
-
27
-You find all Files for your simulation homework in the `simuN/` directory.
28
-
29
-## Pull-Reuest
30
-
31
-If you are ready with the homework, all tests run, please create a pull request named **hw1**.
32
-
33
-## Gradings
34
-
35
-### hw1
36
-
37
-| Task | max. Credits | Comment |
38
-|---|---|---|
39
-| simu1 | 1 | |
40
-| task1 | 1 | |
41
-| task2 | 1 | |
42
-| task3 | 0,5 | |
43
-| task4 | 0,5 | |
44
-| simu2 | +0,5 | |
45
-| task5 | +0,5 | |
46
-| Deadline | +1 | |
47
-| = | 6 | |

+ 0
- 35
hw1/simu1/QUESTIONS.md 查看文件

@@ -1,35 +0,0 @@
1
-# Questions 4-Process-Run Simulation Part 1
2
-
3
-This program, `process-run.py`, allows you to see how process states change as programs run and either use the CPU (e.g., perform an add instruction) or do I/O (e.g., send a request to a disk and wait for it to complete). See the README for details.
4
-
5
-Please answer the questions, by giving the result and an explanation, why you got the result. Sometimes it could be helpful, if you compare your result with results of earlier questions. Write your answers in [markdown syntax][]  in the new file `ANSWERS.md.`
6
-
7
-1. Run the program with the following flags:
8
-
9
- ```text
10
-./process-run.py -l 5:100,5:100.
11
- ```
12
-
13
- 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.
14
-
15
-2. Now run with these flags:
16
-
17
- ```text
18
-./process-run.py -l 4:100,1:0.
19
- ```
20
-
21
- 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.
22
-
23
-3. Now switch the order of the processes:
24
-
25
- ```text
26
-./process-run.py -l 1:0,4:100.
27
- ```
28
-
29
- What happens now? Does switching the order matter? Why? (As always, use `-c` and `-p` to see if you were right)
30
-
31
-4. 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, one doing I/O and the other doing CPU work? (`-l 1:0,4:100 -c -S SWITCH_ON_END`)
32
-
33
-5. 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.
34
-
35
-[markdown syntax]: https://guides.github.com/features/mastering-markdown/

+ 0
- 236
hw1/simu1/README-process-run.md 查看文件

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

+ 0
- 325
hw1/simu1/process-run.py 查看文件

@@ -1,325 +0,0 @@
1
-#! /usr/bin/env python
2
-
3
-import sys
4
-from optparse import OptionParser
5
-import random
6
-
7
-# process switch behavior
8
-SCHED_SWITCH_ON_IO = 'SWITCH_ON_IO'
9
-SCHED_SWITCH_ON_END = 'SWITCH_ON_END'
10
-
11
-# io finished behavior
12
-IO_RUN_LATER = 'IO_RUN_LATER'
13
-IO_RUN_IMMEDIATE = 'IO_RUN_IMMEDIATE'
14
-
15
-# process states
16
-STATE_RUNNING = 'RUNNING'
17
-STATE_READY = 'READY'
18
-STATE_DONE = 'DONE'
19
-STATE_WAIT = 'WAITING'
20
-
21
-# members of process structure
22
-PROC_CODE = 'code_'
23
-PROC_PC = 'pc_'
24
-PROC_ID = 'pid_'
25
-PROC_STATE = 'proc_state_'
26
-
27
-# things a process can do
28
-DO_COMPUTE = 'cpu'
29
-DO_IO = 'io'
30
-
31
-
32
-class scheduler:
33
-    def __init__(self, process_switch_behavior, io_done_behavior, io_length):
34
-        # keep set of instructions for each of the processes
35
-        self.proc_info = {}
36
-        self.process_switch_behavior = process_switch_behavior
37
-        self.io_done_behavior = io_done_behavior
38
-        self.io_length = io_length
39
-        return
40
-
41
-    def new_process(self):
42
-        proc_id = len(self.proc_info)
43
-        self.proc_info[proc_id] = {}
44
-        self.proc_info[proc_id][PROC_PC] = 0
45
-        self.proc_info[proc_id][PROC_ID] = proc_id
46
-        self.proc_info[proc_id][PROC_CODE] = []
47
-        self.proc_info[proc_id][PROC_STATE] = STATE_READY
48
-        return proc_id
49
-
50
-    def load_file(self, progfile):
51
-        fd = open(progfile)
52
-        proc_id = self.new_process()
53
-        
54
-        for line in fd:
55
-            tmp = line.split()
56
-            if len(tmp) == 0:
57
-                continue
58
-            opcode = tmp[0]
59
-            if opcode == 'compute':
60
-                assert(len(tmp) == 2)
61
-                for i in range(int(tmp[1])):
62
-                    self.proc_info[proc_id][PROC_CODE].append(DO_COMPUTE)
63
-            elif opcode == 'io':
64
-                assert(len(tmp) == 1)
65
-                self.proc_info[proc_id][PROC_CODE].append(DO_IO)
66
-        fd.close()
67
-        return
68
-
69
-    def load(self, program_description):
70
-        proc_id = self.new_process()
71
-        tmp = program_description.split(':')
72
-        if len(tmp) != 2:
73
-            print 'Bad description (%s): Must be number <x:y>' % program_description
74
-            print '  where X is the number of instructions'
75
-            print '  and Y is the percent change that an instruction is CPU not IO'
76
-            exit(1)
77
-
78
-        num_instructions, chance_cpu = int(tmp[0]), float(tmp[1])/100.0
79
-        for i in range(num_instructions):
80
-            if random.random() < chance_cpu:
81
-                self.proc_info[proc_id][PROC_CODE].append(DO_COMPUTE)
82
-            else:
83
-                self.proc_info[proc_id][PROC_CODE].append(DO_IO)
84
-        return
85
-
86
-    def move_to_ready(self, expected, pid=-1):
87
-        if pid == -1:
88
-            pid = self.curr_proc
89
-        assert(self.proc_info[pid][PROC_STATE] == expected)
90
-        self.proc_info[pid][PROC_STATE] = STATE_READY
91
-        return
92
-
93
-    def move_to_wait(self, expected):
94
-        assert(self.proc_info[self.curr_proc][PROC_STATE] == expected)
95
-        self.proc_info[self.curr_proc][PROC_STATE] = STATE_WAIT
96
-        return
97
-
98
-    def move_to_running(self, expected):
99
-        assert(self.proc_info[self.curr_proc][PROC_STATE] == expected)
100
-        self.proc_info[self.curr_proc][PROC_STATE] = STATE_RUNNING
101
-        return
102
-
103
-    def move_to_done(self, expected):
104
-        assert(self.proc_info[self.curr_proc][PROC_STATE] == expected)
105
-        self.proc_info[self.curr_proc][PROC_STATE] = STATE_DONE
106
-        return
107
-
108
-    def next_proc(self, pid=-1):
109
-        if pid != -1:
110
-            self.curr_proc = pid
111
-            self.move_to_running(STATE_READY)
112
-            return
113
-        for pid in range(self.curr_proc + 1, len(self.proc_info)):
114
-            if self.proc_info[pid][PROC_STATE] == STATE_READY:
115
-                self.curr_proc = pid
116
-                self.move_to_running(STATE_READY)
117
-                return
118
-        for pid in range(0, self.curr_proc + 1):
119
-            if self.proc_info[pid][PROC_STATE] == STATE_READY:
120
-                self.curr_proc = pid
121
-                self.move_to_running(STATE_READY)
122
-                return
123
-        return
124
-
125
-    def get_num_processes(self):
126
-        return len(self.proc_info)
127
-
128
-    def get_num_instructions(self, pid):
129
-        return len(self.proc_info[pid][PROC_CODE])
130
-
131
-    def get_instruction(self, pid, index):
132
-        return self.proc_info[pid][PROC_CODE][index]
133
-
134
-    def get_num_active(self):
135
-        num_active = 0
136
-        for pid in range(len(self.proc_info)):
137
-            if self.proc_info[pid][PROC_STATE] != STATE_DONE:
138
-                num_active += 1
139
-        return num_active
140
-
141
-    def get_num_runnable(self):
142
-        num_active = 0
143
-        for pid in range(len(self.proc_info)):
144
-            if self.proc_info[pid][PROC_STATE] == STATE_READY or \
145
-                   self.proc_info[pid][PROC_STATE] == STATE_RUNNING:
146
-                num_active += 1
147
-        return num_active
148
-
149
-    def get_ios_in_flight(self, current_time):
150
-        num_in_flight = 0
151
-        for pid in range(len(self.proc_info)):
152
-            for t in self.io_finish_times[pid]:
153
-                if t > current_time:
154
-                    num_in_flight += 1
155
-        return num_in_flight
156
-
157
-    def check_for_switch(self):
158
-        return
159
-
160
-    def space(self, num_columns):
161
-        for i in range(num_columns):
162
-            print '%10s' % ' ',
163
-
164
-    def check_if_done(self):
165
-        if len(self.proc_info[self.curr_proc][PROC_CODE]) == 0:
166
-            if self.proc_info[self.curr_proc][PROC_STATE] == STATE_RUNNING:
167
-                self.move_to_done(STATE_RUNNING)
168
-                self.next_proc()
169
-        return
170
-
171
-    def run(self):
172
-        clock_tick = 0
173
-
174
-        if len(self.proc_info) == 0:
175
-            return
176
-
177
-        # track outstanding IOs, per process
178
-        self.io_finish_times = {}
179
-        for pid in range(len(self.proc_info)):
180
-            self.io_finish_times[pid] = []
181
-
182
-        # make first one active
183
-        self.curr_proc = 0
184
-        self.move_to_running(STATE_READY)
185
-
186
-        # OUTPUT: headers for each column
187
-        print '%s' % 'Time', 
188
-        for pid in range(len(self.proc_info)):
189
-            print '%10s' % ('PID:%2d' % (pid)),
190
-        print '%10s' % 'CPU',
191
-        print '%10s' % 'IOs',
192
-        print ''
193
-
194
-        # init statistics
195
-        io_busy = 0
196
-        cpu_busy = 0
197
-
198
-        while self.get_num_active() > 0:
199
-            clock_tick += 1
200
-
201
-            # check for io finish
202
-            io_done = False
203
-            for pid in range(len(self.proc_info)):
204
-                if clock_tick in self.io_finish_times[pid]:
205
-                    io_done = True
206
-                    self.move_to_ready(STATE_WAIT, pid)
207
-                    if self.io_done_behavior == IO_RUN_IMMEDIATE:
208
-                        # IO_RUN_IMMEDIATE
209
-                        if self.curr_proc != pid:
210
-                            if self.proc_info[self.curr_proc][PROC_STATE] == STATE_RUNNING:
211
-                                self.move_to_ready(STATE_RUNNING)
212
-                        self.next_proc(pid)
213
-                    else:
214
-                        # IO_RUN_LATER
215
-                        if self.process_switch_behavior == SCHED_SWITCH_ON_END and self.get_num_runnable() > 1:
216
-                            # this means the process that issued the io should be run
217
-                            self.next_proc(pid)
218
-                        if self.get_num_runnable() == 1:
219
-                            # this is the only thing to run: so run it
220
-                            self.next_proc(pid)
221
-                    self.check_if_done()
222
-            
223
-            # if current proc is RUNNING and has an instruction, execute it
224
-            instruction_to_execute = ''
225
-            if self.proc_info[self.curr_proc][PROC_STATE] == STATE_RUNNING and \
226
-                   len(self.proc_info[self.curr_proc][PROC_CODE]) > 0:
227
-                instruction_to_execute = self.proc_info[self.curr_proc][PROC_CODE].pop(0)
228
-                cpu_busy += 1
229
-
230
-            # OUTPUT: print what everyone is up to
231
-            if io_done:
232
-                print '%3d*' % clock_tick,
233
-            else:
234
-                print '%3d ' % clock_tick,
235
-            for pid in range(len(self.proc_info)):
236
-                if pid == self.curr_proc and instruction_to_execute != '':
237
-                    print '%10s' % ('RUN:'+instruction_to_execute),
238
-                else:
239
-                    print '%10s' % (self.proc_info[pid][PROC_STATE]),
240
-            if instruction_to_execute == '':
241
-                print '%10s' % ' ',
242
-            else:
243
-                print '%10s' % 1,
244
-            num_outstanding = self.get_ios_in_flight(clock_tick)
245
-            if num_outstanding > 0:
246
-                print '%10s' % str(num_outstanding),
247
-                io_busy += 1
248
-            else:
249
-                print '%10s' % ' ',
250
-            print ''
251
-
252
-            # if this is an IO instruction, switch to waiting state
253
-            # and add an io completion in the future
254
-            if instruction_to_execute == DO_IO:
255
-                self.move_to_wait(STATE_RUNNING)
256
-                self.io_finish_times[self.curr_proc].append(clock_tick + self.io_length)
257
-                if self.process_switch_behavior == SCHED_SWITCH_ON_IO:
258
-                    self.next_proc()
259
-
260
-            # ENDCASE: check if currently running thing is out of instructions
261
-            self.check_if_done()
262
-        return (cpu_busy, io_busy, clock_tick)
263
-        
264
-#
265
-# PARSE ARGUMENTS
266
-#
267
-
268
-parser = OptionParser()
269
-parser.add_option('-s', '--seed', default=0, help='the random seed', action='store', type='int', dest='seed')
270
-parser.add_option('-l', '--processlist', default='',
271
-                  help='a comma-separated list of processes to run, in the form X1:Y1,X2:Y2,... where X is the number of instructions that process should run, and Y the chances (from 0 to 100) that an instruction will use the CPU or issue an IO',
272
-                  action='store', type='string', dest='process_list')
273
-parser.add_option('-L', '--iolength', default=5, help='how long an IO takes', action='store', type='int', dest='io_length')
274
-parser.add_option('-S', '--switch', default='SWITCH_ON_IO',
275
-                  help='when to switch between processes: SWITCH_ON_IO, SWITCH_ON_END',
276
-                  action='store', type='string', dest='process_switch_behavior')
277
-parser.add_option('-I', '--iodone', default='IO_RUN_LATER',
278
-                  help='type of behavior when IO ends: IO_RUN_LATER, IO_RUN_IMMEDIATE',
279
-                  action='store', type='string', dest='io_done_behavior')
280
-parser.add_option('-c', help='compute answers for me', action='store_true', default=False, dest='solve')
281
-parser.add_option('-p', '--printstats', help='print statistics at end; only useful with -c flag (otherwise stats are not printed)', action='store_true', default=False, dest='print_stats')
282
-(options, args) = parser.parse_args()
283
-
284
-random.seed(options.seed)
285
-
286
-assert(options.process_switch_behavior == SCHED_SWITCH_ON_IO or \
287
-       options.process_switch_behavior == SCHED_SWITCH_ON_END)
288
-assert(options.io_done_behavior == IO_RUN_IMMEDIATE or \
289
-       options.io_done_behavior == IO_RUN_LATER)
290
-
291
-s = scheduler(options.process_switch_behavior, options.io_done_behavior, options.io_length)
292
-
293
-# example process description (10:100,10:100)
294
-for p in options.process_list.split(','):
295
-    s.load(p)
296
-
297
-if options.solve == False:
298
-    print 'Produce a trace of what would happen when you run these processes:'
299
-    for pid in range(s.get_num_processes()):
300
-        print 'Process %d' % pid
301
-        for inst in range(s.get_num_instructions(pid)):
302
-            print '  %s' % s.get_instruction(pid, inst)
303
-        print ''
304
-    print 'Important behaviors:'
305
-    print '  System will switch when',
306
-    if options.process_switch_behavior == SCHED_SWITCH_ON_IO:
307
-        print 'the current process is FINISHED or ISSUES AN IO'
308
-    else:
309
-        print 'the current process is FINISHED'
310
-    print '  After IOs, the process issuing the IO will',
311
-    if options.io_done_behavior == IO_RUN_IMMEDIATE:
312
-        print 'run IMMEDIATELY'
313
-    else:
314
-        print 'run LATER (when it is its turn)'
315
-    print ''
316
-    exit(0)
317
-
318
-(cpu_busy, io_busy, clock_tick) = s.run()
319
-
320
-if options.print_stats:
321
-    print ''
322
-    print 'Stats: Total Time %d' % clock_tick
323
-    print 'Stats: CPU Busy %d (%.2f%%)' % (cpu_busy, 100.0 * float(cpu_busy)/clock_tick)
324
-    print 'Stats: IO Busy  %d (%.2f%%)' % (io_busy, 100.0 * float(io_busy)/clock_tick)
325
-    print ''

+ 0
- 18
hw1/simu2/QUESTIONS.md 查看文件

@@ -1,18 +0,0 @@
1
-# Questions 4-Process-Run Simulation Part 2
2
-
3
-This program, `process-run.py`, allows you to see how process states change as programs run and either use the CPU (e.g., perform an add instruction) or do I/O (e.g., send a request to a disk and wait for it to complete). See the README for details.
4
-
5
-Please answer the questions, by giving the result and an explanation, why you got the result. Sometimes it could be helpful, if you compare your result with results of earlier questions. Write your answers in markdown syntax in the new file `ANSWERS.md.`
6
-
7
-
8
-1. One  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?
9
-
10
- ```text
11
-./process-run.py -l 3:0,5:100,5:100,5:100 -S SWITCH ON IO -I IO RUN LATER -c -p
12
- ```
13
-
14
- Are system resources being effectively utilized?
15
-
16
-2. 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?
17
-
18
-3. Now run with some randomly generated processes, e.g., `-s 1 -l 3:50,3:50, -s 2 -l 3:50,3:50, -s 3 -l 3:50,3:50`. See if you can predict how the trace will turn out. What happens when you use `-I IO_RUN_IMMEDIATE` vs. `-I IO_RUN_LATER`? What happens when you use `-S SWITCH_ON_IO` vs. `-S SWITCH_ON_END`?

+ 0
- 31
hw1/task1/README.md 查看文件

@@ -1,31 +0,0 @@
1
-# Homework hw1 task 1
2
-
3
-## Vorbereitungen
4
-
5
-Rufen Sie im `task1/` Verzeichnis: `cargo init` auf. Dadurch wird ein Rust Library Projekt in `task1/` angelegt. Mit `cargo build` wird die Library erstellt, der Aufruf `cargo test` ruft die CI Tests im `tests/` Verzeichnis auf und testet Ihre Library.
6
-
7
-## task
8
-
9
-Schreiben Sie die Funktion
10
-
11
-```rust
12
-pub fn is_leap_year(year: i32) -> bool
13
-```
14
-
15
-die überprüft, ob das übergebene Jahr ein Schaltjahr ist.
16
-
17
-Das trickreiche an der Überprüfung ist, dass folgende Bedingungen für das Jahr gelten müssen:
18
-
19
-```plain
20
-on every year that is evenly divisible by 4
21
-  except every year that is evenly divisible by 100
22
-    unless the year is also evenly divisible by 400
23
-```
24
-
25
-Zum Beispiel ist 1997 kein Schaltjahr, aber 1996. 1900 ist kein Schaltjahr aber 2000.
26
-
27
-Verwenden Sie keine Funktionen aus Bibliotheken dafür, sondern implementieren Sie die Funktion selbst.
28
-
29
-## Test
30
-
31
-Testen können Sie Ihre Library durch den Aufruf von `cargo test`. Dann werden alle Tests aus der Datei `tests/task1.rs` ausgeführt.

+ 0
- 3
hw1/task1/src/lib.rs 查看文件

@@ -1,3 +0,0 @@
1
-pub fn is_leap_year(year: i32) -> bool {
2
-    unimplemented!();
3
-}

+ 0
- 25
hw1/task1/tests/task1.rs 查看文件

@@ -1,25 +0,0 @@
1
-extern crate task1;
2
-
3
-#[test]
4
-fn test_vanilla_leap_year() {
5
-    assert_eq!(task1::is_leap_year(1996), true);
6
-}
7
-
8
-#[test]
9
-fn test_any_old_year() {
10
-    assert_eq!(task1::is_leap_year(1995), false);
11
-    assert_eq!(task1::is_leap_year(1997), false);
12
-    assert_eq!(task1::is_leap_year(1998), false);
13
-    assert_eq!(task1::is_leap_year(1999), false);
14
-}
15
-
16
-#[test]
17
-fn test_century() {
18
-    assert_eq!(task1::is_leap_year(1900), false);
19
-}
20
-
21
-#[test]
22
-fn test_exceptional_centuries() {
23
-    assert_eq!(task1::is_leap_year(2000), true);
24
-    assert_eq!(task1::is_leap_year(2400), true);
25
-}

+ 0
- 24
hw1/task2/README.md 查看文件

@@ -1,24 +0,0 @@
1
-# Homework hw1 task 2
2
-
3
-## prepare your task
4
-
5
-Run `cargo init` in your `task2/` directory.
6
-
7
-## task
8
-
9
-Calculate the number of grains of wheat on a chessboard given that the number on each square doubles.
10
-
11
-There once was a wise servant who saved the life of a prince. The king
12
-promised to pay whatever the servant could dream up. Knowing that the
13
-king loved chess, the servant told the king he would like to have grains
14
-of wheat. One grain on the first square of a chess board. Two grains on
15
-the next. Four on the third, and so on.
16
-
17
-There are 64 squares on a chessboard.
18
-
19
-Write code that shows:
20
-
21
-- how many grains were on each square (`fn square(n: u32) -> u64`), and
22
-- the total number of grains (`fn total() -> u64`)
23
-
24
-Use the given file `lib.rs` for your solution.

+ 0
- 8
hw1/task2/src/lib.rs 查看文件

@@ -1,8 +0,0 @@
1
-pub fn square(n: u32) -> u64 {
2
-    unimplemented!()
3
-}
4
-
5
-
6
-pub fn total() -> u64 {
7
-    unimplemented!();
8
-}

+ 0
- 41
hw1/task2/tests/task2.rs 查看文件

@@ -1,41 +0,0 @@
1
-extern crate task2;
2
-
3
-#[test]
4
-fn square_one() {
5
-    assert_eq!(task2::square(1), 1);
6
-}
7
-
8
-#[test]
9
-fn square_two() {
10
-    assert_eq!(task2::square(2), 2);
11
-}
12
-
13
-#[test]
14
-fn square_three() {
15
-    assert_eq!(task2::square(3), 4);
16
-}
17
-
18
-#[test]
19
-fn square_four() {
20
-    assert_eq!(task2::square(4), 8);
21
-}
22
-
23
-#[test]
24
-fn square_sixteen() {
25
-    assert_eq!(task2::square(16), 32_768);
26
-}
27
-
28
-#[test]
29
-fn square_thirty_two() {
30
-    assert_eq!(task2::square(32), 2_147_483_648);
31
-}
32
-
33
-#[test]
34
-fn square_sixty_four() {
35
-    assert_eq!(task2::square(64), 9_223_372_036_854_775_808);
36
-}
37
-
38
-#[test]
39
-fn total_sums_all_squares() {
40
-    assert_eq!(task2::total(), 18_446_744_073_709_551_615);
41
-}

+ 0
- 8
hw1/task3/README.md 查看文件

@@ -1,8 +0,0 @@
1
-# Homework hw1 task 3
2
-
3
-## prepare your task
4
-
5
-Run `cargo init` in your `task3/` directory.
6
-
7
-## task
8
-Schreiben Sie eine Funktion `count(line: &str, c: char) -> u64)` welche zählt, wie oft ein gegebenes Zeichen (c) in einem gegebenen String (line) vorkommt und diese Anzahl zurück gibt. Z.B. soll der Aufruf `count("peter", 'e')` `2` zurückgeben.

+ 0
- 3
hw1/task3/src/lib.rs 查看文件

@@ -1,3 +0,0 @@
1
-pub fn count(line: &str, c: char) -> u64 {
2
-    unimplemented!();
3
-}

+ 0
- 45
hw1/task3/tests/task3.rs 查看文件

@@ -1,45 +0,0 @@
1
-extern crate task3;
2
-
3
-#[test]
4
-fn test_one_char() {
5
-    assert_eq!(
6
-        task3::count("♥ The quick brown fox jumps over the lazy dog. ♥", 'T'),
7
-        1
8
-    );
9
-}
10
-
11
-#[test]
12
-fn test_two_char() {
13
-    assert_eq!(
14
-        task3::count(
15
-            "♥ The quick brown fox jumps over the lazy dog. ♥",
16
-            '♥',
17
-        ),
18
-        2
19
-    );
20
-}
21
-
22
-#[test]
23
-#[should_panic]
24
-fn test_wrong() {
25
-    assert_eq!(
26
-        task3::count("♥ The quick brown fox jumps over the lazy dog. ♥", 'c'),
27
-        2
28
-    );
29
-}
30
-
31
-#[test]
32
-fn test_four_char() {
33
-    assert_eq!(
34
-        task3::count("♥ The quick brown fox jumps over the lazy dog. ♥", 'o'),
35
-        4
36
-    );
37
-}
38
-
39
-#[test]
40
-fn test_no_char() {
41
-    assert_eq!(
42
-        task3::count("♥ The quick brown fox jumps over the lazy dog. ♥", '!'),
43
-        0
44
-    );
45
-}

+ 0
- 22
hw1/task4/README.md 查看文件

@@ -1,22 +0,0 @@
1
-# Homework hw1 task 4
2
-
3
-## prepare your task
4
-
5
-Run `cargo init` in your `task4/` directory.
6
-
7
-## task
8
-
9
-Find the difference between the sum of the squares and the square of the sum of the first N natural numbers.
10
-
11
-The square of the sum of the first ten natural numbers is,
12
-
13
-    (1 + 2 + ... + 10)**2 = 55**2 = 3025
14
-
15
-The sum of the squares of the first ten natural numbers is,
16
-
17
-    1**2 + 2**2 + ... + 10**2 = 385
18
-
19
-Hence the difference between the square of the sum of the first
20
-ten natural numbers and the sum of the squares is 2640:
21
-
22
-    3025 - 385 = 2640

+ 0
- 11
hw1/task4/src/lib.rs 查看文件

@@ -1,11 +0,0 @@
1
-pub fn square_of_sum(n: i32) -> i32 {
2
-    unimplemented!();
3
-}
4
-
5
-pub fn sum_of_squares(n: i32) -> i32 {
6
-    unimplemented!();
7
-}
8
-
9
-pub fn difference(n: i32) -> i32 {
10
-    unimplemented!();
11
-}

+ 0
- 31
hw1/task4/tests/task4.rs 查看文件

@@ -1,31 +0,0 @@
1
-extern crate task4;
2
-
3
-#[test]
4
-fn test_square_of_sum_5() {
5
-    assert_eq!(225, task4::square_of_sum(5));
6
-}
7
-
8
-#[test]
9
-fn test_sum_of_squares_5() {
10
-    assert_eq!(55, task4::sum_of_squares(5));
11
-}
12
-
13
-#[test]
14
-fn test_difference_5() {
15
-    assert_eq!(170, task4::difference(5));
16
-}
17
-
18
-#[test]
19
-fn test_square_of_sum_100() {
20
-    assert_eq!(25502500, task4::square_of_sum(100));
21
-}
22
-
23
-#[test]
24
-fn test_sum_of_squares_100() {
25
-    assert_eq!(338350, task4::sum_of_squares(100));
26
-}
27
-
28
-#[test]
29
-fn test_difference_100() {
30
-    assert_eq!(25164150, task4::difference(100));
31
-}

+ 0
- 32
hw1/task5/README.md 查看文件

@@ -1,32 +0,0 @@
1
-# Homework hw1 task 5
2
-
3
-## Vorbereitungen
4
-
5
-Rufen Sie im `task5/` Verzeichnis: `cargo init --bin` auf. Dadurch wird ein Rust Binary Projekt in `task5/` angelegt. Mit `cargo build` wird die Library erstellt, der Aufruf `cargo run` startet das Programm. Der Aufruf von `cargo test` ruft die UNIT-Tests im `src/main.rs` auf.
6
-
7
-Ausserdem können die korrekten Outputs Ihres Programms auf der Console mit dem Aufruf von `bats tests/output.bats` getestet werden.
8
-
9
-## task
10
-
11
-Schreiben Sie ein Programm, in welchem eine von Ihnen selbst geschriebene Funktion
12
-
13
-```rust
14
-fn is_prime(n: u64) -> bool
15
-```
16
-
17
-genutzt wird, die überprüft, ob eine gegebene Zahl eine Primzahl ist. Die Funktion muss nicht auf Laufzeit optimiert werden.
18
-
19
-Die *main()* Funktion gibt in einer Schleife die Zahlen von 1 bis 30 aus. Die Zahlen, die eine Primzahlt sind werden in der Ausgabe mit einem `*`` Zeichen markiert.
20
-
21
-```
22
-1
23
-2*
24
-3*
25
-4
26
-5*
27
-...
28
-```
29
-
30
-Nutzen Sie die schon vorgegebene Datei `main.rs`!
31
-
32
-Verwenden Sie keine Funktionen aus Bibliotheken dafür, sondern implementieren Sie die Funktion selbst.

+ 0
- 40
hw1/task5/src/main.rs 查看文件

@@ -1,40 +0,0 @@
1
-//! hw01t5: Primzahltest
2
-fn is_prime(n: u64) -> bool {
3
-    unimplemented!();
4
-}
5
-
6
-
7
-fn main() {
8
-    unimplemented!();
9
-}
10
-
11
-#[test]
12
-fn small_primes() {
13
-    assert!(is_prime(2));
14
-    assert!(is_prime(3));
15
-    assert!(is_prime(5));
16
-    assert!(is_prime(7));
17
-}
18
-
19
-#[test]
20
-fn small_composites() {
21
-    assert!(!is_prime(1));
22
-    assert!(!is_prime(4));
23
-    assert!(!is_prime(6));
24
-    assert!(!is_prime(8));
25
-    assert!(!is_prime(9));
26
-}
27
-
28
-#[test]
29
-fn large_primes() {
30
-    assert!(is_prime(1_300_769));
31
-    assert!(is_prime(1_300_297));
32
-    assert!(is_prime(7_367_287));
33
-}
34
-
35
-#[test]
36
-fn large_composites() {
37
-    assert!(!is_prime(908_209));
38
-    assert!(!is_prime(3_073_009));
39
-    assert!(!is_prime(4_897_369));
40
-}

+ 0
- 27
hw1/task5/tests/output.bats 查看文件

@@ -1,27 +0,0 @@
1
-#!/usr/bin/env bats
2
-
3
-
4
-@test "Check that we have a debug output" {
5
-    run stat "$BATS_TEST_DIRNAME/../target/debug/task5"
6
-    [ "$status" -eq 0 ]
7
-}
8
-
9
-@test "Output must be from 1..30 and correct formated" {
10
-    run "$BATS_TEST_DIRNAME/../target/debug/task5"
11
-    [[ "${lines[0]}" =~ "1" ]]
12
-    [[ "${lines[1]}" =~ "2*" ]]
13
-    [[ "${lines[2]}" =~ "3*" ]]
14
-    [[ "${lines[3]}" =~ "4" ]]
15
-    [[ "${lines[4]}" =~ "5" ]]
16
-    [[ "${lines[25]}" =~ "26" ]]
17
-    [[ "${lines[26]}" =~ "27" ]]
18
-    [[ "${lines[27]}" =~ "28" ]]
19
-    [[ "${lines[28]}" =~ "29*" ]]
20
-    [[ "${lines[29]}" =~ "30" ]]
21
-}
22
-
23
-# wc output with white spaces is trimmed by xargs
24
-@test "Output must be exact 30 lines long" {
25
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task5' | wc -l | xargs"
26
-    [ "$output" = "30" ]
27
-}

+ 0
- 40
hw2/README.md 查看文件

@@ -1,40 +0,0 @@
1
-# hw2
2
-
3
-## Tasks
4
-
5
-To fullfill **hw2** you have to solve:
6
-
7
-- task1
8
-- task2
9
-- simu1
10
-
11
-Optional are (bonus +1P):
12
-
13
-- task3 (important: Rust idiomatic code please)
14
-
15
-## Files
16
-
17
-You find already files for each rust task. Please remember to use cargo to
18
-create the relevant projects for each task.
19
-
20
-## ASIDE: `simu1/` dir
21
-
22
-In this homework it's not a simulation homework sitting in `simu1/` but some
23
-questions to have fun with buggy c-files. As not to interfer with rust code,
24
-questions, c-code and your answers should go into `simu1/`.
25
-
26
-## Pull-Request
27
-
28
-Please merge any accepted reviews into your branch. If you are ready with the
29
-homework, all tests run, please create a pull request named **hw2**.
30
-
31
-## Gradings of hw2
32
-
33
-| Task     | max. Credits | Comment |
34
-| -------- | ------------ | ------- |
35
-| task1    | 1            |         |
36
-| task2    | 2            |         |
37
-| task3    | +1           |         |
38
-| simu1    | 1            |         |
39
-| Deadline | +1           |         |
40
-| =        | 6            |         |

+ 0
- 9
hw2/simu1/ANSWERS.md 查看文件

@@ -1,9 +0,0 @@
1
-## Antworten zur Simulation 1 (hw2)
2
-
3
-1. Beim Ausführen stürzt das Programm mit der Fehlermeldung `Segmentation Fault` ab.
4
-2. GDB gibt den Hinweis `Program received signal SIGSEGV, Segmentation fault.` aus.
5
-3. Valgrind zeigt den Fehler `Invalid Read` und sowohl die Adresse im Speicher als auch die Zeile im Code, in der der Fehler auftritt. Das bedeutet, dass auf eine undefinierte Adresse zugegriffen wird. Da die Zeile im Code auch ausgegeben wird, lässt sich der Ursprung des Fehlers leicht eingrenzen.
6
-4. Das Programm `malloc` erzeugt keine Ausgabe und crasht nicht. GDB bestätigt das: `Inferior 1 (process 2982) exited normally`. Mithilfe von Valgrind sehen wir, dass 10 Bytes nicht freigegeben wurden: `LEAK SUMMARY: definitely lost: 10 bytes in 1 blocks`.
7
-5.
8
-6. Das Programm (`intArray2`) gibt den Wert `0` aus und läuft ohne Fehler. Valgrind weist uns auf einen `invalid read` an der betreffenden Stelle hin.
9
-

+ 0
- 11
hw2/simu1/Makefile 查看文件

@@ -1,11 +0,0 @@
1
-CC=gcc
2
-CFLAGS=-g
3
-RM=rm -f
4
-TARGET=null malloc intArray1 intArray2 free
5
-.PHONY: all clean
6
-all: $(TARGET)
7
-clean:
8
-	$(RM) null malloc intArray1 intArray2 free
9
-
10
-$(TARGET): $(TARGET).c
11
-	$(CC) $< $(CFLAGS) -o $@

+ 0
- 72
hw2/simu1/QUESTIONS.md 查看文件

@@ -1,72 +0,0 @@
1
-# Questions 14-Memory-API
2
-
3
-## Overview
4
-
5
-In this task, you will gain some familiarity with memory allocation. First,
6
-you’ll write some buggy programs (fun!). Then, you’ll use some tools to help you
7
-find the bugs you inserted. Then, you will realize how awesome these tools are
8
-and use them in the future, thus making yourself more happy and productive.
9
-
10
-The first tool you’ll use is **gdb**, the debugger. There is a lot to learn
11
-about this debugger; here we’ll only scratch the surface. Here you can find a
12
-[quick reference gdb][]. Also **ddd** is installed on lab workstations.
13
-
14
-The second tool you’ll use is [valgrind][]. This tool helps find memory leaks
15
-and other insidious memory problems in your program.
16
-
17
-Please answer the questions, by giving the result and an explanation, why you
18
-got the result.  Write your answers in markdown syntax in the new file
19
-`ANSWERS.md`. Also checkin your C-Files and one Makefile for all or your
20
-C-Files, so that all binaries are build. Do NOT checkin the binaries!
21
-
22
-The installed gcc wrapper on you workstations does some optimization to your code
23
-examples, which will not show some of the bugs with an "Segmentation fault". We
24
-have already disabled this behavior by setting:
25
-
26
-```text
27
-export hardeningDisable=all
28
-```
29
-
30
-in your labshell bsys environment. So, you don't have to do any further steps to
31
-produce unoptimized code with gcc, if you want to.
32
-
33
-If you struggle with your own systems about some strange gcc optimization
34
-behavior, maybe it helps to check for gcc-wrapper variables like these.
35
-
36
-## Questions
37
-
38
-1. First, write a simple program called `null.c` that creates a pointer to an
39
-   integer, sets it to `NULL`, and then tries to dereference it. Compile this
40
-   into an executable called **null**. What happens when you run this program?
41
-
42
-1. Next, compile this program with symbol information included (with the `-g`
43
-   flag). Doing so let’s put more information into the executable, enabling the
44
-   debugger to access more useful information about variable names and the like.
45
-   Run the program under the debugger by typing `gdb null` and then, once gdb is
46
-   running, typing `run`. What does gdb show you?
47
-
48
-1. Finally, use the valgrind tool on this program. We’ll use the memcheck tool
49
-   that is a part of valgrind to analyze what happens. Run this by typing in the
50
-   following: `valgrind --leak-check=yes ./null`. What happens when you run
51
-   this? Can you interpret the output from the tool?
52
-
53
-1. Write a simple program that allocates memory using `malloc()` but forgets to
54
-   free it before exiting. What happens when this program runs? Can you use
55
-   `gdb` to find any problems with it? How about `valgrind` (again with the
56
-   `--leak-check=yes` flag)?
57
-
58
-1. Write a program that creates an array of integers of size 100 using
59
-   `malloc()`; then, set `data[100]` to zero. What happens when you run this
60
-   program? What happens when you run this program using `valgrind`? Is the
61
-   program correct?
62
-
63
-1. Create a program that allocates an array of integers (as above),frees them,
64
-   and then tries to print the value of one of the elements of the array. Does
65
-   the program run? What happens when you use `valgrind` on it?
66
-
67
-1. Now pass a funny value to free (e.g., a pointer in the middle of the array
68
-   you allocated above). What happens? Do you need tools to find this type of
69
-   problem?
70
-
71
-[valgrind]: http://valgrind.org/downloads/current.html
72
-[quick reference gdb]: https://web.stanford.edu/class/cs107/gdb_refcard.pdf

+ 0
- 7
hw2/simu1/free.c 查看文件

@@ -1,7 +0,0 @@
1
-/* free.c */
2
-#include <stdlib.h>
3
-int main(char* argv[], int argc) {
4
-  char* testString = malloc(10 * sizeof(char));
5
-  free(testString[10]);
6
-  free(testString);
7
-}

+ 0
- 7
hw2/simu1/intArray1.c 查看文件

@@ -1,7 +0,0 @@
1
-/* intArray1.c */
2
-#include <stdlib.h>
3
-int main(char* argv[], int argc) {
4
-  int* intArray = malloc(100 * sizeof(int));
5
-  intArray[100] = 0;
6
-  free(intArray);
7
-}

+ 0
- 8
hw2/simu1/intArray2.c 查看文件

@@ -1,8 +0,0 @@
1
-/* intArray2.c */
2
-#include <stdlib.h>
3
-#include <stdio.h>
4
-int main(char* argv[], int argc) {
5
-  int* intArray = malloc(100 * sizeof(int));
6
-  free(intArray);
7
-  printf("%d", intArray[10]);
8
-}

+ 0
- 5
hw2/simu1/malloc.c 查看文件

@@ -1,5 +0,0 @@
1
-/* malloc.c */
2
-#include <stdlib.h>
3
-int main(char* argv[], int argc) {
4
-  char* testString = malloc(sizeof(char) * 10);
5
-}

+ 0
- 12
hw2/simu1/null.c 查看文件

@@ -1,12 +0,0 @@
1
-#include <stdlib.h>
2
-#include <stdio.h>
3
-int main(char* argv[], int argc)
4
-{
5
-  int i, j;
6
-  int* iPointer;
7
-
8
-  i = 10;
9
-  iPointer = &i;
10
-  iPointer = NULL;
11
-  j = *iPointer;
12
-}

+ 0
- 6
hw2/task1/Cargo.toml 查看文件

@@ -1,6 +0,0 @@
1
-[package]
2
-name = "task1"
3
-version = "0.1.0"
4
-authors = ["Lorenz Bung <lorenz.bung@googlemail.com>"]
5
-
6
-[dependencies]

+ 0
- 38
hw2/task1/README.md 查看文件

@@ -1,38 +0,0 @@
1
-# Homework hw2 task1
2
-
3
-## prepare your task
4
-
5
-Run the cargo command to prepare your task1/ directory as a library
6
-
7
-## task
8
-
9
-Calculate the Hamming difference between two DNA strands by implementing the
10
-library function *hamming_distance(s1: &str, s2: &str) -> Result<usize,
11
-String>*. Do not use any crates.
12
-
13
-A mutation is simply a mistake that occurs during the creation or copying of a
14
-nucleic acid, in particular DNA. Because nucleic acids are vital to cellular
15
-functions, mutations tend to cause a ripple effect throughout the cell. Although
16
-mutations are technically mistakes, a very rare mutation may equip the cell with
17
-a beneficial attribute. In fact, the macro effects of evolution are attributable
18
-by the accumulated result of beneficial microscopic mutations over many
19
-generations.
20
-
21
-The simplest and most common type of nucleic acid mutation is a point mutation,
22
-which replaces one base with another at a single nucleotide.
23
-
24
-By counting the number of differences between two homologous DNA strands taken
25
-from different genomes with a common ancestor, we get a measure of the minimum
26
-number of point mutations that could have occurred on the evolutionary path
27
-between the two strands.
28
-
29
-This is called the 'Hamming distance'.
30
-
31
-It is found by comparing two DNA strands and counting how many of the
32
-nucleotides are different from their equivalent in the other string.
33
-
34
-    GAGCCTACTAACGGGAT
35
-    CATCGTAATGACGGCCT
36
-    ^ ^ ^  ^ ^    ^^
37
-
38
-The Hamming distance between these two DNA strands is 7.

+ 0
- 22
hw2/task1/src/lib.rs 查看文件

@@ -1,22 +0,0 @@
1
-#[cfg(test)]
2
-mod tests {
3
-    #[test]
4
-    fn it_works() {
5
-        assert_eq!(2 + 2, 4);
6
-    }
7
-}
8
-pub fn hamming_distance(s1: &str, s2: &str) -> Result<usize, String> {
9
-    //Check if the given Strings are of different length
10
-    if s1.len() != s2.len() {
11
-        return Err("Strings must be of equal length!".to_string());
12
-    }
13
-    let mut dist: usize = 0;
14
-    for i in 0..s1.len() {
15
-        //Compare each character of the Strings
16
-        if s1.chars().nth(i) != s2.chars().nth(i) {
17
-            //If they don't match, increment hamming distance
18
-            dist += 1
19
-        }
20
-    }
21
-    Ok(dist)
22
-}

+ 0
- 36
hw2/task1/tests/task1.rs 查看文件

@@ -1,36 +0,0 @@
1
-extern crate task1;
2
-
3
-#[test]
4
-fn test_no_difference_between_empty_strands() {
5
-    assert_eq!(task1::hamming_distance("", "").unwrap(), 0);
6
-}
7
-
8
-#[test]
9
-fn test_no_difference_between_identical_strands() {
10
-    assert_eq!(task1::hamming_distance("GGACTGA", "GGACTGA").unwrap(), 0);
11
-}
12
-
13
-#[test]
14
-fn test_complete_hamming_distance_in_small_strand() {
15
-    assert_eq!(task1::hamming_distance("ACT", "GGA").unwrap(), 3);
16
-}
17
-
18
-#[test]
19
-fn test_small_hamming_distance_in_the_middle_somewhere() {
20
-    assert_eq!(task1::hamming_distance("GGACG", "GGTCG").unwrap(), 1);
21
-}
22
-
23
-#[test]
24
-fn test_larger_distance() {
25
-    assert_eq!(task1::hamming_distance("ACCAGGG", "ACTATGG").unwrap(), 2);
26
-}
27
-
28
-#[test]
29
-fn test_first_string_is_longer() {
30
-    assert!(task1::hamming_distance("AAA", "AA").is_err());
31
-}
32
-
33
-#[test]
34
-fn test_second_string_is_longer() {
35
-    assert!(task1::hamming_distance("A", "AA").is_err());
36
-}

+ 0
- 10
hw2/task2/Cargo.toml 查看文件

@@ -1,10 +0,0 @@
1
-[package]
2
-name = "task2"
3
-version = "0.1.0"
4
-authors = ["Joshua Rutschmann <joshua.rutschmann@gmx.de>"]
5
-
6
-[dependencies]
7
-
8
-[[bin]]
9
-doc = false
10
-name = "task2"

+ 0
- 317
hw2/task2/README.md 查看文件

@@ -1,317 +0,0 @@
1
-# Homework hw2 task2
2
-
3
-- [Überblick](#%C3%BCberblick)
4
-- [Vorbereitung](#vorbereitung)
5
-- [Struktur](#struktur)
6
-- [Funktionen](#funktionen)
7
-    - [Programmargumente in Rust](#programmargumente-in-rust)
8
-        - [Warmup Übung](#warmup-%C3%BCbung)
9
-    - [Argumente parsen](#argumente-parsen)
10
-        - [Parsen ohne Fehlerbehandlung](#parsen-ohne-fehlerbehandlung)
11
-        - [Parsen mit Fehlerbehandlung](#parsen-mit-fehlerbehandlung)
12
-    - [Zeichen im String suchen](#zeichen-im-string-suchen)
13
-    - [Ablauf des Programms](#ablauf-des-programms)
14
-        - [Dead Code](#dead-code)
15
-- [Restructuring](#restructuring)
16
-    - [Parsen der Config als Methode](#parsen-der-config-als-methode)
17
-    - [Tests](#tests)
18
-    - [Dokumentation](#dokumentation)
19
-
20
-## Überblick
21
-
22
-In dieser Aufgabe sollen Sie ein Programm entwickeln, welches 2 Parameter
23
-übergeben bekommt:
24
-
25
-- *1.* übergebene Parameter: Zu suchendes Zeichen
26
-- *2.* übergebene Parameter: String in dem die Zeichenkette gesucht werden soll.
27
-
28
-Das Programm gibt die Anzahl gefundener Treffer aus.
29
-
30
-```text
31
-You asked me to count all 'e' in "♥ The quick brown fox jumps over the lazy dog. ♥"
32
-Found 3 'e' in "♥ The quick brown fox jumps over the lazy dog. ♥"
33
-```
34
-
35
-Neben einer klaren Struktur für das Programm soll eine kompetente
36
-Fehlerbehandlung implementiert werden, sodass das Programm robust gegenüber
37
-Eingebefehlern wird. Benutzen Sie keine weiteren Module aus der Standardbibliothek, ausser:
38
-
39
-- std::env
40
-- std::process
41
-
42
-Ziele:
43
-
44
-- Parameter einlesen können
45
-- Weitere String-Funktionen kennen lernen
46
-- Fehlerbehandlung
47
-
48
-## Vorbereitung
49
-
50
-Erstellen Sie im `task2/` Ordner mittels cargo ein Binary Projekt.
51
-
52
-## Struktur
53
-
54
-Das Programm soll aus 3 Funktionen bestehen:
55
-
56
-- *main()*
57
-- *run()*
58
-- *parse_arguments()*
59
-
60
-Die *main()* Funktion ruft zuerst die *parse_arguments()* auf, um danach
61
-geeignet die *run()* Funktion zum Suchen der Zeichenkette zu starten.
62
-
63
-## Funktionen
64
-
65
-### Programmargumente in Rust
66
-
67
-Bisher waren in Ihren Programmen die Parameter fest codiert. Wie kann man in
68
-Rust die Parameter beim Aufruf des Programms auswerten?
69
-
70
-Dazu existiert das [std::env][std::env] Modul, welches Strukturen und Funktionen
71
-für die Prozessumgebung (process environment) bereit stellt.
72
-
73
-Die Funktion, die die Parameter zur weiteren Auswertung liefert heißt
74
-[`args()`][args]. Diese Funktion liefert einen Iterator mit Namen [`Arc`][Arc]
75
-zurück. Was Iteratoren genau sind und was damit alles anzustellen ist werden wir
76
-später im Semester kennen lernen. Zunächst kann man sich einen Iterator einfach
77
-als eine 'Datenquelle' vorstellen, die - wenn wir darauf zugreifen - eine Serie
78
-von Werten liefert. In unserem Fall liefert ein Zugriff auf [`args()`][args] die
79
-dem Programm übergebenen Parameter als Strings, sofern welche übergeben wurden.
80
-
81
-Und damit sind wir auch schon mitten in der Fehlerbehandlung. Auf mögliche
82
-Fehler wird in der Dokumentation bereits hingewiesen. Wir werden im weiteren von
83
-UNIX Systemen und korrektem unicode ausgehen, sodass uns ein paar
84
-Fehlerbehandlungen erspart bleiben.
85
-
86
-Um in unserem Programm auf die Parameter zugreifen zu können, werden wir diese
87
-in einer geeigneten Datentyp speichern. Es bieten sich Arrays oder Vektoren an.
88
-
89
-#### Warmup Übung
90
-
91
-1. Warum sollten Sie für die Argumente den Datentyp Vector vorziehen?
92
-1. Schreiben Sie die Funktion:
93
-
94
-```rust
95
-/// Prints elements of Vec
96
-///
97
-///
98
-/// This function will print all elements of Vec with "args found: <elem>" in
99
-/// each line
100
-///
101
-/// Returns nothing
102
-fn print_arguments(args: &Vec<String>)
103
-```
104
-
105
-Die Funktion gibt den Inhalt des übergeben Vektors zeilenweise aus.
106
-
107
-In der Main Funktion lesen Sie die bei Programmstart übergebenen Parameter ein
108
-und erstellen einen Vektor aus den eingelesenen Parametern, den Sie als Referenz
109
-übergeben.
110
-
111
-> Die Methode [*collect()*][collect] ist Teil des Iterator Traits und bietet
112
-> sich an um den Vector zu füllen. Überlegen Sie sich auch, warum es sinnvoll
113
-> ist den Vector an die Funktion *print_arguments* nur zu leihen ('&')?
114
-
115
-Wenn Sie nun Ihr Projekt mit `cargo run a b c`starten, so erhalten Sie folgende
116
-Ausgabe:
117
-
118
-```text
119
-    Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
120
-     Running `target/debug/task1 a b c`
121
-args found: target/debug/task1
122
-args found: a
123
-args found: b
124
-args found: c
125
-```
126
-
127
-### Argumente parsen
128
-
129
-Unsere Argumente speichern wir am Besten in einer eigenen Datenstruktur
130
-*Config*. Dann sind unsere Parameter als entsprechende Datentypen einfach
131
-verfügbar.
132
-
133
-```rust
134
-/// a struct to hold all of our configuration
135
-#[derive(Debug,PartialEq)]
136
-struct Config{
137
-    search: char,
138
-    line: String,
139
-}
140
-```
141
-
142
-> Mit der *derive* Anweisung lassen wir den Rust Compiler etwas Magie anwenden.
143
-> Denn durch diese Makro Anweisung erhält unsere Datenstruktur automatisch 2
144
-> Traits wodurch wiederum automatisch die nötigen Methoden für uns erzeugt
145
-> werden um unsere Struct zu printen und deren Inhalt vergleichen zu können
146
-> ("==" Abfrage). Letzteres brauchen wir für die Tests.
147
-
148
-#### Parsen ohne Fehlerbehandlung
149
-
150
-1. Implementieren Sie die Funktion
151
-
152
-```rust
153
-/// Parses relevant arguments, returning the filled Config
154
-///
155
-///
156
-/// This function will parse the relevant arguments from the
157
-/// given <Strings>.
158
-/// Returns Config
159
-fn parse_arguments_simple(args: &Vec<String>) -> Config
160
-```
161
-
162
-Sie müssen nun in der Funktion:
163
-
164
-- den 1. String in einen char verwandeln
165
-- den 2. String der Config  Struktur zuweisen
166
-
167
->Beachten Sie, das die Strings, die die Argumente repräsentieren in der Funktion
168
->geliehen sind und somit jemand anderen gehören. Ihre Config Struktur benötigt
169
->somit EIGENE Strings.
170
-
171
-In *main()* geben Sie die geparsten Parameter aus, sodass Sie bei Aufruf Ihres
172
-Programms "cargo run a b c" folgende Ausgabe erhalten:
173
-
174
-```text
175
-    Finished dev [unoptimized + debuginfo] target(s) in 0.27 secs
176
-     Running `target/debug/task1 a b c`
177
-args found: target/debug/task1
178
-args found: a
179
-args found: b
180
-args found: c
181
-Config { search: 'a', line: "b" }
182
-```
183
-
184
-#### Parsen mit Fehlerbehandlung
185
-
186
-1. Unter Umständen ruft ein Benutzer Ihr Programm ohne die benötigten Parameter
187
-   auf. Welche Fehlermeldung erhalten Sie bei dem Aufruf Ihres Programms ohne
188
-   Parameter und warum?
189
-
190
-1. Ein Programmabsturz wäre die falsche Antwort darauf. Besser ist beim
191
-   Auftreten von Eingabefehler ein entsprechender Hinweis, wie das Programm zu
192
-   verwenden ist. Implementieren Sie die Funktion
193
-
194
-```rust
195
-/// Parses relevant arguments, returning the filled Config in Result
196
-///
197
-///
198
-/// This function will parse the relevant arguments from the
199
-/// given <Strings>.
200
-/// Returns Config or Error Message in Result
201
-fn parse_arguments(args: &Vec<String>) -> Result<Config, xx >
202
-```
203
-
204
-Implementieren Sie die folgende Fehlerbehandlung:
205
-
206
-- Werden vom Benutzer zuwenig übergeben, so gibt die Funktion den Fehlerstring
207
-  "not enough arguments" zurück. Werden vom Benutzer zu viele Parameter
208
-  übergeben, so wertet die Funktion nur die ersten beiden aus. In der API der
209
-  Funktion oben ist als Typ xx für den 'String' angedeutet und muss entsprechend
210
-  von Ihnen mit dem richtigen Typen versehen werden.
211
-
212
-- Tritt ein Fehler beim Wandeln des 1. Parameter in einen char auf, so geben Sie
213
-  den String "char mismatch" als Fehlerstring in Result zurück. Wird statt eines
214
-  chars als 1. Parameter ein String übergeben, so werten Sie nur den ersten
215
-  Buchstaben davon aus.
216
-
217
-Die main() Funktion kann keine Return Werte zurückliefern. Um aber der
218
-aufrufenden Shell den Abbruch des Programms mitteilen zu können steht die
219
-Funktion *[process::exit()]* aus der Standardbibliothek zu Verfügung. Durch die
220
-Rückgabe von '1' signalisieren Sie der Shell, dass das Programm abgebrochen
221
-wurde.
222
-
223
-### Zeichen im String suchen
224
-
225
-In Ihrer vorherigen Homework haben Sie bereits eine ähnliche Funktionalität
226
-implementiert, die Sie nun in der *run()* Funktion übernehmen können.
227
-
228
-### Ablauf des Programms
229
-
230
-Zur Abgabe des Programms soll die  *main()* Funktion nur:
231
-
232
-- *parse_arguments()* und
233
-- *run()*
234
-
235
-benutzen. In diesen beiden Funktionen darf kein *unwrap()* mehr verwendet
236
-werden.
237
-
238
-Da die Tests jedoch auch die Funktion *parse_arguments_simple()* benutzt, darf
239
-diese nicht auskommentiert werden.
240
-
241
-#### Dead Code
242
-
243
-Um die Compiler Warnungen vor nicht benutzen Funktionen auszuschalten, fügen Sie
244
-direkt in der Zeile vor der Funktion folgende Anweisung hinzu
245
-
246
-```Rust
247
-#[allow(dead_code)]
248
-fn parse_arguments_simple(args: &Vec<String>) -> Config {
249
-...
250
-```
251
-
252
-## Restructuring
253
-
254
-Bisher ist alles in unserm `src/main.rs` Modul, wodurch dieses im Laufe der Zeit
255
-immer unübersichtlicher werden würde. Ziel ist es nun, das meiste aus der
256
-`main.rs` auszulagern, sodass nur noch die *main()* Funktion in `main.rs` steht.
257
-
258
-Ausgelagert wird der Code in eine Bibliothek, genauer gesagt in die Datei
259
-`src/lib.rs`. Um den Code aus `lib.rs` in `main.rs` verwenden zu können, müssen
260
-Sie ihre derzeitige 'Create' mit den entsprechenden 'extern' und 'use'
261
-Anweisungen in `main.rs`, erreichbar machen. Ergänzen Sie dazu in der
262
-`src/main.rs`:
263
-
264
-```Rust
265
-extern crate task2;
266
-use task2::Config;
267
-```
268
-
269
-Alle *use* Anweisungen stehen in der `main.rs`. Es müssen keine weiteren *use*
270
-Anweisungen in der lib.rs stehen
271
-
272
-### Parsen der Config als Methode
273
-
274
-Die *parse_arguments()* Methode steht noch in keinem Zusammenhang mit der
275
-Struktur, die die Methode mit Daten füllt.
276
-
277
-Schreiben Sie einen Konstruktor *new()* für die Datenstruktur *Config* und
278
-ersetzten Sie damit die *parse_arguments()* Funktion. Verwenden Sie nun Config
279
-geeignet in Ihrer *main()* Funktion.
280
-
281
-### Tests
282
-
283
-Die Test sind ausgelagert in die Datei `tests/task2.rs`. Der Aufruf von cargo
284
-test sucht nach Unit Tests in der `src/main.rs` und im Verzeichnis `tests/`. Die
285
-Tests in `tests/task2.rs` funktionieren erst, wenn eine `src/lib.rs` existiert
286
-(siehe Aufgabenstellung [Restructuring](#restructuring) oben).
287
-
288
-### Dokumentation
289
-
290
-Dokumentieren Sie die Funktionen in Ihrer `lib.rs`, sodass **cargo doc** eine
291
-aussagekräftige Dokumentation erstellt.
292
-
293
-Da Sie im `src/`Verzeichnis eine `main.rs` und eine `lib.rs` vorliegen haben,
294
-beschwert sich **cargo doc**, dass es nicht weiss wie es die Dokumentation
295
-erstellen soll:
296
-
297
-```text
298
-error: cannot document a package where a library and a binary have the same name. Consider renaming one or marking the target as `doc = false`
299
-```
300
-
301
-Damit **cargo doc** Ihre Dokumentation für die Funktionen in `lib.rs` erstellt,
302
-benötigen Sie folgende Erweiterung in Ihrer `Cargo.toml` Datei.
303
-
304
-```text
305
-[[bin]]
306
-doc = false
307
-name = "task2"
308
-```
309
-
310
-Damit weiß cargo, dass es die Dokumentation aus `lib.rs` erstellen soll und
311
-nicht aus `main.rs`.
312
-
313
-[args]: https://doc.rust-lang.org/std/env/fn.args.html
314
-[std::env]:https://doc.rust-lang.org/std/env/index.html
315
-[Arc]: https://doc.rust-lang.org/std/env/struct.Args.html
316
-[collect]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect
317
-[process::exit()]: https://doc.rust-lang.org/std/process/fn.exit.html

+ 0
- 86
hw2/task2/src/lib.rs 查看文件

@@ -1,86 +0,0 @@
1
-/// a struct to hold all of our configuration
2
-#[derive(Debug, PartialEq)]
3
-pub struct Config {
4
-    pub search: char,
5
-    pub line: String,
6
-}
7
-
8
-pub fn run(conf: &Config) -> i32 {
9
-    let mut count = 0;
10
-    for c in conf.line.chars() {
11
-        if c == conf.search {
12
-            count = count + 1;
13
-        }
14
-    }
15
-    count
16
-}
17
-
18
-/// Parses relevant arguments, returning the filled Config in Result
19
-///
20
-///
21
-/// This function will parse the relevant arguments from the
22
-/// given <Strings>.
23
-/// Returns Config or Error Message in Result
24
-#[allow(dead_code)]
25
-fn parse_arguments(args: &Vec<String>) -> Result<Config, String> {
26
-
27
-    if args.len() < 3 {
28
-        return Err("not ennugh parameters".to_string());
29
-    }
30
-
31
-    match args[1].chars().nth(0) {
32
-        Some(value) => {
33
-            Ok(Config {
34
-                search: value,
35
-                line: args[2].clone(),
36
-            })
37
-        }
38
-        None => Err("char mismatch".to_string()),
39
-    }
40
-}
41
-
42
-/// Parses relevant arguments, returning the filled Config
43
-///
44
-///
45
-/// This function will parse the relevant arguments from the
46
-/// given <Strings>.
47
-/// Returns Config
48
-#[allow(dead_code)]
49
-fn parse_arguments_simple(args: &Vec<String>) -> Config {
50
-    Config {
51
-        search: args[1].chars().nth(0).unwrap(),
52
-        line: args[2].clone(),
53
-    }
54
-}
55
-
56
-/// Prints elements of Vec
57
-///
58
-///
59
-/// This function will print all elements of Vec with "args found: <elem>" in
60
-/// each line
61
-///
62
-/// Returns nothing
63
-#[allow(dead_code)]
64
-fn print_arguments(args: &Vec<String>) {
65
-    for s in args {
66
-        println!("args found: {}", s);
67
-    }
68
-}
69
-
70
-impl Config {
71
-    pub fn new(args: &Vec<String>) -> Result<Config, &str> {
72
-        if args.len() < 3 {
73
-            return Err("not enough arguments");
74
-        }
75
-
76
-        match args[1].chars().nth(0) {
77
-            Some(value) => {
78
-                Ok(Config {
79
-                    search: value,
80
-                    line: args[2].clone(),
81
-                })
82
-            }
83
-            None => Err("char mismatch"),
84
-        }
85
-    }
86
-}

+ 0
- 28
hw2/task2/src/main.rs 查看文件

@@ -1,28 +0,0 @@
1
-use std::env;
2
-use std::process;
3
-use task2::Config;
4
-extern crate task2;
5
-
6
-fn main() {
7
-    let args = env::args().collect();
8
-
9
-    let res = Config::new(&args);
10
-    match res {
11
-        Ok(conf) => {
12
-            println!(
13
-                "You asked me to count all '{}' in '{}'",
14
-                conf.search,
15
-                conf.line
16
-            );
17
-            let occ = task2::run(&conf);
18
-            println!("Found {} '{}' in '{}'", occ, conf.search, conf.line);
19
-        }
20
-        Err(message) => {
21
-            println!("{}", message);
22
-            process::exit(1)
23
-        }
24
-    }
25
-
26
-
27
-
28
-}

+ 0
- 41
hw2/task2/tests/output.bats 查看文件

@@ -1,41 +0,0 @@
1
-#!/usr/bin/env bats
2
-
3
-
4
-@test "task2: Check that we have a debug output" {
5
-    run stat "$BATS_TEST_DIRNAME/../target/debug/task2"
6
-    [ "$status" -eq 0 ]
7
-}
8
-
9
-@test "task2: Output Long String: The quick ...." {
10
-    run "$BATS_TEST_DIRNAME/../target/debug/task2" 'q' '♥ The quick brown fox jumps over the lazy dog. ♥'
11
-    [[ "${lines[0]}" =~ "You asked me to count all 'q' in '♥ The quick brown fox jumps over the lazy dog. ♥'" ]]
12
-    [[ "${lines[1]}" =~ "Found 1 'q' in '♥ The quick brown fox jumps over the lazy dog. ♥'" ]]
13
-}
14
-
15
-@test "task2: Output Short String: ababab " {
16
-   run "$BATS_TEST_DIRNAME/../target/debug/task2" 'a' 'ababab'
17
-   [[ "${lines[0]}" =~ "You asked me to count all 'a' in 'ababab'" ]]
18
-   [[ "${lines[1]}" =~ "Found 3 'a' in 'ababab'" ]]
19
-}
20
-
21
-@test "task2: Output Error 1" {
22
-   run "$BATS_TEST_DIRNAME/../target/debug/task2"
23
-   [[ "${lines[0]}" =~ "not enough arguments" ]]
24
-}
25
-
26
-@test "task2: Output Error 2" {
27
-   run "$BATS_TEST_DIRNAME/../target/debug/task2"
28
-   [[ "${lines[0]}" =~ "not enough arguments" ]]
29
-}
30
-
31
-# wc output with white spaces is trimmed by xargs
32
-@test "task2: Output must be exact 2 line long" {
33
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task2' 'a' 'b' 'c' | wc -l | xargs"
34
-    [ "$output" = "2" ]
35
-}
36
-
37
-# wc output with white spaces is trimmed by xargs
38
-@test "task2: Output must be exact 1 line long" {
39
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task2' 'a'  | wc -l | xargs"
40
-    [ "$output" = "1" ]
41
-}

+ 0
- 95
hw2/task2/tests/task2.rs 查看文件

@@ -1,95 +0,0 @@
1
-extern crate task2;
2
-use task2::Config;
3
-
4
-
5
-#[test]
6
-fn test_parse_config_1() {
7
-    let a = vec![
8
-        "Not interested".to_string(),
9
-        "e".to_string(),
10
-        "Numero Due".to_string(),
11
-    ];
12
-    let c = Config {
13
-        search: 'e',
14
-        line: "Numero Due".to_string(),
15
-    };
16
-    assert_eq!(Config::new(&a), Ok(c));
17
-}
18
-
19
-#[test]
20
-#[should_panic]
21
-fn test_parse_config_2() {
22
-    let a = vec![
23
-        "Not interested".to_string(),
24
-        "x".to_string(),
25
-        "Numero Due".to_string(),
26
-    ];
27
-    let c = Config {
28
-        search: 'e',
29
-        line: "Numero Due".to_string(),
30
-    };
31
-    assert_eq!(Config::new(&a), Ok(c));
32
-}
33
-
34
-#[test]
35
-fn test_parse_config_3() {
36
-    let a = vec![
37
-        "Not interested".to_string(),
38
-        "0".to_string(),
39
-        "0".to_string(),
40
-    ];
41
-    let c = Config {
42
-        search: '0',
43
-        line: "0".to_string(),
44
-    };
45
-    assert_eq!(Config::new(&a), Ok(c));
46
-}
47
-
48
-#[test]
49
-fn test_parse_config_err_1() {
50
-    let a = vec!["Not interested".to_string(), "e".to_string()];
51
-    assert_eq!(Config::new(&a), Err("not enough arguments"));
52
-}
53
-
54
-#[test]
55
-fn test_parse_config_err_2() {
56
-    let a = vec!["Not interested".to_string()];
57
-    assert_eq!(Config::new(&a), Err("not enough arguments"));
58
-}
59
-
60
-#[test]
61
-fn test_run_1() {
62
-    let c = Config {
63
-        search: 'e',
64
-        line: "Numero Due".to_string(),
65
-    };
66
-    assert_eq!(task2::run(&c), 2);
67
-}
68
-
69
-#[test]
70
-fn test_run_2() {
71
-    let c = Config {
72
-        search: '♥',
73
-        line: "♥ The quick brown fox jumps over the lazy dog. ♥".to_string(),
74
-    };
75
-    assert_eq!(task2::run(&c), 2);
76
-}
77
-
78
-#[test]
79
-#[should_panic]
80
-fn test_run_3() {
81
-    let c = Config {
82
-        search: 'q',
83
-        line: "♥ The quick brown fox jumps over the lazy dog. ♥".to_string(),
84
-    };
85
-    assert_eq!(task2::run(&c), 2);
86
-}
87
-
88
-#[test]
89
-fn test_run_4() {
90
-    let c = Config {
91
-        search: '!',
92
-        line: "♥ The quick brown fox jumps over the lazy dog. ♥".to_string(),
93
-    };
94
-    assert_eq!(task2::run(&c), 0);
95
-}

+ 0
- 6
hw2/task3/Cargo.toml 查看文件

@@ -1,6 +0,0 @@
1
-[package]
2
-name = "task3"
3
-version = "0.1.0"
4
-authors = ["Lorenz Bung <lorenz.bung@googlemail.com>"]
5
-
6
-[dependencies]

+ 0
- 24
hw2/task3/README.md 查看文件

@@ -1,24 +0,0 @@
1
-# Homework hw2 task3
2
-
3
-## prepare your task
4
-
5
-Run the cargo command to prepare your task3/ directory as a library
6
-
7
-## task
8
-
9
-Compute Pascal's triangle up to a given number of rows. Create the new type
10
-*PascalsTriangle* and implement the methods *new()* and *rows()*. See the
11
-`tests/task3.rs` for more informationen about parameters and returns of the
12
-methods. Do not use any crates.
13
-
14
-In Pascal's Triangle each number is computed by adding the numbers to the right
15
-and left of the current position in the previous row.
16
-
17
-```plain
18
-    1
19
-   1 1
20
-  1 2 1
21
- 1 3 3 1
22
-1 4 6 4 1
23
-# ... etc
24
-```

+ 0
- 45
hw2/task3/src/lib.rs 查看文件

@@ -1,45 +0,0 @@
1
-
2
-#[cfg(test)]
3
-mod tests {
4
-    #[test]
5
-    fn it_works() {
6
-        assert_eq!(2 + 2, 4);
7
-    }
8
-}
9
-
10
-pub struct PascalsTriangle {
11
-    height: u32,
12
-}
13
-
14
-impl PascalsTriangle {
15
-    pub fn new(i: u32) -> Self {
16
-        PascalsTriangle { height: i }
17
-    }
18
-    pub fn rows(&self) -> Vec<Vec<u32>> {
19
-        let rows = self.height as usize;
20
-        let mut matrix = Vec::with_capacity(rows);
21
-
22
-        for line in 0..rows {
23
-            let current = line as usize;
24
-            matrix.push(Vec::with_capacity(current + 1));
25
-            matrix[current].push(1);
26
-
27
-            if current > 1 {
28
-                let previous = current - 1;
29
-                for index in 1..current {
30
-                    let add = matrix[previous][index - 1] + matrix[previous][index];
31
-                    matrix[current].push(add);
32
-                }
33
-            }
34
-
35
-            if current > 0 {
36
-                matrix[current].push(1);
37
-            }
38
-
39
-        }
40
-
41
-        println!("{:?}", matrix);
42
-
43
-        matrix
44
-    }
45
-}

+ 0
- 7
hw2/task3/src/main.rs 查看文件

@@ -1,7 +0,0 @@
1
-extern crate task3;
2
-use task3::PascalsTriangle;
3
-
4
-fn main() {
5
-    let p = PascalsTriangle::new(10);
6
-    p.rows();
7
-}

+ 0
- 39
hw2/task3/tests/task3.rs 查看文件

@@ -1,39 +0,0 @@
1
-extern crate task3;
2
-
3
-use task3::*;
4
-
5
-#[test]
6
-fn no_rows() {
7
-    let pt = PascalsTriangle::new(0);
8
-    let expected: Vec<Vec<u32>> = Vec::new();
9
-    assert_eq!(expected, pt.rows());
10
-}
11
-
12
-
13
-#[test]
14
-fn one_row() {
15
-    let pt = PascalsTriangle::new(1);
16
-    let expected: Vec<Vec<u32>> = vec![vec![1]];
17
-    assert_eq!(expected, pt.rows());
18
-}
19
-
20
-#[test]
21
-fn two_rows() {
22
-    let pt = PascalsTriangle::new(2);
23
-    let expected: Vec<Vec<u32>> = vec![vec![1], vec![1, 1]];
24
-    assert_eq!(expected, pt.rows());
25
-}
26
-
27
-#[test]
28
-fn three_rows() {
29
-    let pt = PascalsTriangle::new(3);
30
-    let expected: Vec<Vec<u32>> = vec![vec![1], vec![1, 1], vec![1, 2, 1]];
31
-    assert_eq!(expected, pt.rows());
32
-}
33
-
34
-#[test]
35
-fn last_of_four_rows() {
36
-    let pt = PascalsTriangle::new(4);
37
-    let expected: Vec<u32> = vec![1, 3, 3, 1];
38
-    assert_eq!(expected, pt.rows().pop().unwrap());
39
-}

+ 0
- 51
hw3/README.md 查看文件

@@ -1,51 +0,0 @@
1
-# hw3
2
-
3
-## Tasks
4
-
5
-To fulfill **hw3** you have to solve:
6
-
7
-- simu1
8
-- simu2
9
-- simu3
10
-- simu4
11
-
12
-## ASIDE: SIMULATION HOMEWORKS
13
-
14
-Simulation homeworks (`simuN/`) come in the form of simulators you run to make
15
-sure you understand some piece of the material. The simulators are generally
16
-python programs that enable you both to generate different problems (using
17
-different random seeds) as well as to have the program solve the problem for you
18
-(with the `-c` flag) so that you can check your answers. Running any simulator
19
-with a `-h` or `--help`flag will provide with more information as to all the
20
-options the simulator gives you.
21
-
22
-The README provided with each simulator gives more detail as to how to run it.
23
-Each flag is described in some detail therein.
24
-
25
-You find all Files for your simulation homework in the `simuN/` directory.
26
-
27
-**IMPORTANT**: This time, there is no possibility to give more
28
-explanations/comments  AFTER the Code Review. You have to give all the asked
29
-explanations and comments before the code review.
30
-
31
-The code review starts after the deadline, so you have enough time to extend
32
-your answers, if your Pull-Request was quite early. After the deadline there
33
-will be no review process (as you already now). This time the review helps you
34
-to only correct your answers in cases, where you solved a problem in a wrong
35
-way.
36
-
37
-## Pull-Request
38
-
39
-Please merge any accepted reviews into your branch. If you are ready with the
40
-homework, all tests run, please create a pull request named **hw3**.
41
-
42
-## Credits for hw3
43
-
44
-| Task     | max. Credits | Comment |
45
-| -------- | ------------ | ------- |
46
-| simu1    | 1            |         |
47
-| simu2    | 1            |         |
48
-| simu3    | 1            |         |
49
-| simu4    | 1            |         |
50
-| Deadline | +1           |         |
51
-| =        | 5            |         |

+ 0
- 21
hw3/simu1/ANSWERS.md 查看文件

@@ -1,21 +0,0 @@
1
-# Simulation 1 - Antworten
2
-
3
-1. Das letzte Segment liegt auf der dezimalen (virtuellen) Adresse 929. Damit dieses Segment in den Adressraum passt, muss dieser mindestens ein Limit von **930** haben.
4
-
5
-2. Der physikalische Adressraum ist 16kB groß und das Limit beträgt 100. 16384 - 100 = 16284
6
-
7
-3. Bei einer Vergrößerung des **Adressraums** (z.B. `-a 2k`) nimmt die Zahl der Segmentation-Fehler zu, da das Programm die Adressen aus einer **größeren Spanne** auswählt, das **Limit** der validen Adressen sich jedoch nicht ändert. Vergrößern wir jedoch die Größe des **physikalischen Speichers**, ändert sich nichts am Ergebnis - die Größe des verfügbaren Speichers hat nämlich *keinen Einfluss* darauf, aus welcher **Reichweite** das Programm Adressen auswählt bzw. bis zu welchem Limit Adressen **valide** sind.
8
-
9
-4.
10
-VA | Seg. Vio.?
11
----|---
12
-0|no
13
-1|yes
14
-2|no
15
-3|no
16
-4|yes
17
-5|yes
18
-6|yes
19
-7|no
20
-8|yes
21
-9|no

+ 0
- 53
hw3/simu1/QUESTIONS.md 查看文件

@@ -1,53 +0,0 @@
1
-# Questions 15-Relocation
2
-
3
-The program `relocation.py` allows you to see how address translations are
4
-performed in a system with base and bounds registers. See the `README` for
5
-details.
6
-
7
-## Warmup
8
-
9
-Run with seeds 1, 2, and 3, and compute whether each virtual address generated
10
-by the process is in or out of bounds. If in bounds, compute the translation.
11
-
12
-Please answer the questions, by giving the result and - if asked - an
13
-explanation, why you got the result. Write your answers in markdown syntax in
14
-the new file `ANSWERS.md.`
15
-
16
-## Questions
17
-
18
-1. Run with these flags: `-s 0 -n 10`. What value do you have set `-l` (the
19
-   bounds register) to in order to ensure that all the generated virtual
20
-   addresses are within bounds?
21
-
22
-1. Run with these flags: `-s 1 -n 10 -l 100`. What is the maximum value that
23
-   base can be set to, such that the address space still fits into physical
24
-   memory in its entirety (explanation)?
25
-
26
-1. Run some of the same problems above, but with larger address spaces (-a) and
27
-   physical memories (-p). How does increasing effect the results (explanation)?
28
-
29
-1. For each virtual address, either write down the physical address it
30
-   translates to OR write down that it is an out-of-bounds address (a
31
-   segmentation violation). For this problem, you should assume a simple virtual
32
-   address space of a given size.
33
-
34
-   ```text
35
-   ARG phys mem size 16k
36
-
37
-   Base-and-Bounds register information:
38
-
39
-     Base   : 0x00003952 (decimal 14674)
40
-     Limit  : 1024
41
-
42
-   Virtual Address Trace
43
-     VA  0: 0x0000024c (decimal:  588) --> PA or segmentation violation?
44
-     VA  1: 0x000004eb (decimal: 1259) --> PA or segmentation violation?
45
-     VA  2: 0x000002bd (decimal:  701) --> PA or segmentation violation?
46
-     VA  3: 0x000000fa (decimal:  250) --> PA or segmentation violation?
47
-     VA  4: 0x00000486 (decimal: 1158) --> PA or segmentation violation?
48
-     VA  5: 0x00000521 (decimal: 1313) --> PA or segmentation violation?
49
-     VA  6: 0x0000065c (decimal: 1628) --> PA or segmentation violation?
50
-     VA  7: 0x000001a3 (decimal:  419) --> PA or segmentation violation?
51
-     VA  8: 0x0000063a (decimal: 1594) --> PA or segmentation violation?
52
-     VA  9: 0x0000034d (decimal:  845) --> PA or segmentation violation?
53
-    ```

+ 0
- 99
hw3/simu1/README-relocation.md 查看文件

@@ -1,99 +0,0 @@
1
-# README Relocation
2
-
3
-This program allows you to see how address translations are performed in a
4
-system with base and bounds registers. As before, there are two steps to running
5
-the program to test out your understanding of base and bounds. First, run
6
-without the -c flag to generate a set of translations and see if you can
7
-correctly perform the address translations yourself. Then, when done, run with
8
-the -c flag to check your answers.
9
-
10
-In this homework, we will assume a slightly different address space than our
11
-canonical one with a heap and stack at opposite ends of the space. Rather, we
12
-will assume that the address space has a code section, then a fixed-sized
13
-(small) stack, and a heap that grows downward right after, looking something
14
-like you see in the Figure below. In this configuration, there is only one
15
-direction of growth, towards higher regions of the address space.
16
-
17
-```text
18
-  -------------- 0KB
19
-  |    Code    |
20
-  -------------- 2KB
21
-  |   Stack    |
22
-  -------------- 4KB
23
-  |    Heap    |
24
-  |     |      |
25
-  |     v      |
26
-  -------------- 7KB
27
-  |   (free)   |
28
-  |     ...    |
29
-```
30
-
31
-In the figure, the bounds register would be set to 7~KB, as that represents the
32
-end of the address space. References to any address within the bounds would be
33
-considered legal; references above this value are out of bounds and thus the
34
-hardware would raise an exception.
35
-
36
-To run with the default flags, type **relocation.py** at the command line. The
37
-result should be something like this:
38
-
39
-```text
40
-prompt> ./relocation.py
41
-...
42
-Base-and-Bounds register information:
43
-
44
-  Base   : 0x00003082 (decimal 12418)
45
-  Limit  : 472
46
-
47
-Virtual Address Trace
48
-  VA  0: 0x01ae (decimal:430) -> PA or violation?
49
-  VA  1: 0x0109 (decimal:265) -> PA or violation?
50
-  VA  2: 0x020b (decimal:523) -> PA or violation?
51
-  VA  3: 0x019e (decimal:414) -> PA or violation?
52
-  VA  4: 0x0322 (decimal:802) -> PA or violation?
53
-
54
-For each virtual address, either write down the physical address it
55
-translates to OR write down that it is an out-of-bounds address
56
-(a segmentation violation). For this problem, you should assume a
57
-simple virtual address space of a given size.
58
-```
59
-
60
-As you can see, the homework simply generates randomized virtual
61
-addresses. For each, you should determine whether it is in bounds, and if so,
62
-determine to which physical address it translates. Running with -c (the
63
-"compute this for me" flag) gives us the results of these translations, i.e.,
64
-whether they are valid or not, and if valid, the resulting physical
65
-addresses. For convenience, all numbers are given both in hex and decimal.
66
-
67
-```text
68
-prompt> ./relocation.py -c
69
-...
70
-Virtual Address Trace VA  0: 0x01ae (decimal:430) -> VALID: 0x00003230
71
-  (dec:12848) VA  1: 0x0109 (decimal:265) -> VALID: 0x0000318b (dec:12683) VA
72
-  2: 0x020b (decimal:523) -> SEGMENTATION VIOLATION VA  3: 0x019e (decimal:414)
73
-  -> VALID: 0x00003220 (dec:12832) VA  4: 0x0322 (decimal:802) -> SEGMENTATION
74
-  VIOLATION
75
-```
76
-
77
-With a base address of 12418 (decimal), address 430 is within bounds (i.e., it
78
-is less than the limit register of 472) and thus translates to 430 added to
79
-12418 or 12848. A few of the addresses shown above are out of bounds (523,
80
-802), as they are in excess of the bounds. Pretty simple, no? Indeed, that is
81
-one of the beauties of base and bounds: it's so darn simple!
82
-
83
-There are a few flags you can use to control what's going on better:
84
-
85
-```text
86
-prompt> ./relocation.py -h Usage: relocation.py [options]
87
-
88
-Options: -h, --help            show this help message and exit -s SEED,
89
-  --seed=SEED  the random seed -a ASIZE, --asize=ASIZE address space size (e.g.,
90
-  16, 64k, 32m) -p PSIZE, --physmem=PSIZE physical memory size (e.g., 16, 64k)
91
-  -n NUM, --addresses=NUM # of virtual addresses to generate -b BASE, --b=BASE
92
-  value of base register -l LIMIT, --l=LIMIT   value of limit register -c,
93
-  --compute         compute answers for me
94
-```
95
-
96
-In particular, you can control the virtual address-space size (-a), the size
97
-of physical memory (-p), the number of virtual addresses to generate (-n), and
98
-the values of the base and bounds registers for this process (-b and -l,
99
-respectively).

+ 0
- 118
hw3/simu1/relocation.py 查看文件

@@ -1,118 +0,0 @@
1
-#! /usr/bin/env python
2
-
3
-import sys
4
-from optparse import OptionParser
5
-import random
6
-import math
7
-
8
-def convert(size):
9
-    length = len(size)
10
-    lastchar = size[length-1]
11
-    if (lastchar == 'k') or (lastchar == 'K'):
12
-        m = 1024
13
-        nsize = int(size[0:length-1]) * m
14
-    elif (lastchar == 'm') or (lastchar == 'M'):
15
-        m = 1024*1024
16
-        nsize = int(size[0:length-1]) * m
17
-    elif (lastchar == 'g') or (lastchar == 'G'):
18
-        m = 1024*1024*1024
19
-        nsize = int(size[0:length-1]) * m
20
-    else:
21
-        nsize = int(size)
22
-    return nsize
23
-
24
-
25
-#
26
-# main program
27
-#
28
-parser = OptionParser()
29
-parser.add_option('-s', '--seed',      default=0,     help='the random seed',                                action='store', type='int', dest='seed')
30
-parser.add_option('-a', '--asize',     default='1k',  help='address space size (e.g., 16, 64k, 32m, 1g)',    action='store', type='string', dest='asize')
31
-parser.add_option('-p', '--physmem',   default='16k', help='physical memory size (e.g., 16, 64k, 32m, 1g)',  action='store', type='string', dest='psize')
32
-parser.add_option('-n', '--addresses', default=5,     help='number of virtual addresses to generate',        action='store', type='int', dest='num')
33
-parser.add_option('-b', '--b',         default='-1',  help='value of base register',                         action='store', type='string', dest='base')
34
-parser.add_option('-l', '--l',         default='-1',  help='value of limit register',                        action='store', type='string', dest='limit')
35
-parser.add_option('-c', '--compute',   default=False, help='compute answers for me',                         action='store_true', dest='solve')
36
-
37
-
38
-(options, args) = parser.parse_args()
39
-
40
-print ''
41
-print 'ARG seed', options.seed
42
-print 'ARG address space size', options.asize
43
-print 'ARG phys mem size', options.psize
44
-print ''
45
-
46
-random.seed(options.seed)
47
-asize = convert(options.asize)
48
-psize = convert(options.psize)
49
-
50
-if psize <= 1:
51
-    print 'Error: must specify a non-zero physical memory size.'
52
-    exit(1)
53
-
54
-if asize == 0:
55
-    print 'Error: must specify a non-zero address-space size.'
56
-    exit(1)
57
-
58
-if psize <= asize:
59
-    print 'Error: physical memory size must be GREATER than address space size (for this simulation)'
60
-    exit(1)
61
-
62
-#
63
-# need to generate base, bounds for segment registers
64
-#
65
-limit = convert(options.limit)
66
-base  = convert(options.base)
67
-
68
-if limit == -1:
69
-    limit = int(asize/4.0 + (asize/4.0 * random.random()))
70
-
71
-# now have to find room for them
72
-if base == -1:
73
-    done = 0
74
-    while done == 0:
75
-        base = int(psize * random.random())
76
-        if (base + limit) < psize:
77
-            done = 1
78
-
79
-print 'Base-and-Bounds register information:'
80
-print ''
81
-print '  Base   : 0x%08x (decimal %d)' % (base, base)
82
-print '  Limit  : %d' % (limit)
83
-print ''
84
-
85
-if base + limit > psize:
86
-    print 'Error: address space does not fit into physical memory with those base/bounds values.'
87
-    print 'Base + Limit:', base + limit, '  Psize:', psize
88
-    exit(1)
89
-
90
-#
91
-# now, need to generate virtual address trace
92
-#
93
-print 'Virtual Address Trace'
94
-for i in range(0,options.num):
95
-    vaddr = int(asize * random.random())
96
-    if options.solve == False:
97
-        print '  VA %2d: 0x%08x (decimal: %4d) --> PA or segmentation violation?' % (i, vaddr, vaddr)
98
-    else:
99
-        paddr = 0
100
-        if (vaddr >= limit):
101
-            print '  VA %2d: 0x%08x (decimal: %4d) --> SEGMENTATION VIOLATION' % (i, vaddr, vaddr)
102
-        else:
103
-            paddr = vaddr + base
104
-            print '  VA %2d: 0x%08x (decimal: %4d) --> VALID: 0x%08x (decimal: %4d)' % (i, vaddr, vaddr, paddr, paddr)
105
-
106
-
107
-print ''
108
-
109
-if options.solve == False:
110
-    print 'For each virtual address, either write down the physical address it translates to'
111
-    print 'OR write down that it is an out-of-bounds address (a segmentation violation). For'
112
-    print 'this problem, you should assume a simple virtual address space of a given size.'
113
-    print ''
114
-
115
-
116
-
117
-
118
-

+ 0
- 82
hw3/simu2/ANSWERS.md 查看文件

@@ -1,82 +0,0 @@
1
-## Warmup
2
-
3
-| VA Number | Virtual Adress     | Physical Adress     | Valid |
4
-| --------- | :----------------- | ------------------- | ----- |
5
-| VA  0     | 0x11  --> 0010001  | 000010001 --> 0x011 | YES   |
6
-| VA  1     | 0x6c  --> 1101100  | 111101100 --> 0x1ec | YES   |
7
-| VA  2     | 0x61  --> 1100001  | 111100001 --> 0x1e1 | NO    |
8
-| VA  3     | 0x20  --> 0100000  | 00100000 --> 0x020  | NO    |
9
-| VA  4     | 0x3f   --> 0111111 | 00111111 --> 0x03f  | NO    |
10
-
11
-
12
-
13
-```
14
- --------------- 0x00000000
15
- |  Segment 0  |
16
- |-------------| 0x00000014
17
- |             |
18
- |             |
19
- |             |
20
- |             |
21
- |-------------| 0x000001ec
22
- |  Segment 1  |
23
- |-------------| 0x00000200
24
-```
25
-
26
-
27
-
28
-## Antworten
29
-
30
-1.  Die höchste erlaubte Adresse in Segment 0 ist 0x00000013. Die niedrigste valide Addresse des Segments 1 ist 0x000001ec. Die niedrigste illegale Adresse ist 0x0000014 und die höchste illegale Adresse ist 0x000001eb im gesamten Adressraum. Um zu testen ob das stimmt kann mann alle validen  virtuellen Adressen der Segmente UND jeweils (mindestens) eine über dem Limit mit `-A` angeben.
31
-
32
-     `-A 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,`
33
-
34
-     `106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127`
35
-
36
-
37
-2.   Der Aufruf muss wie folgt aussehen:
38
-
39
-    > ./segmentation.py -a 16 -p 128 -A 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 **--b0 0 --l0 2 --b1 16 --l1 2** -c
40
-
41
-    Die Flags `-l0` und `-l1` setzten jeweils das Limit für das Segment auf 2:
42
-
43
-    ​	Segment 0 nimmt also die virtuellen Adressen 0 und 1 an und
44
-
45
-    ​	Segment 1 nimmt die Adressen 14 und 15 an
46
-
47
-3.   Man sollte das Limit `-l` so wählen, dass es 90% der Adressen des Adressraums `-a` abdeckt. Dann werden die restlichen 10% der virtuellen Adressen über das gesetzte Limit gehen und einen Segmentation Fault auslösen.
48
-
49
-4.  Man setzt die Limits der Segmente mit `-l 0` auf 0, dann ist keine virtuelle Adresse valide. 
50
-
51
-5.  Im folgenden wird VA für virtuelle Adresse und PA für physikalische Adresse benutzt.
52
-
53
-    `Segment 0: 0x0000 bis 0x0040`
54
-
55
-    `Segment 1: 0x0380 bis 0x0400`
56
-
57
-    Höchste VA **0x16C** -> (mappt auf) höchste PA **0x400**
58
-
59
-    1024 - 364 = 660 (Segment 1 Offset)
60
-
61
-    | VA Nr. | VA HEX     | VA BIN          | Physical Address HEX   | PA DEC |
62
-    | ------ | ---------- | --------------- | ---------------------- | :----: |
63
-    | 0      | 0x0000005c | 00\|1011100     | Segmentation Violation |   -    |
64
-    | 1      | 0x00000011 | 00\|0010001     | **0x00000011**         |   17   |
65
-    | 2      | 0x00000043 | 00\|1000011     | Segmentation Violation |   -    |
66
-    | 3      | 0x00000021 | 00\|0100001     | **0x00000021**         |   33   |
67
-    | 4      | 0x0000006c | 00\|1101100     | Segmentation Violation |   -    |
68
-    | 5      | 0x0000007a | 00\|1111010     | Segmentation Violation |   -    |
69
-    | 6      | 0x00000050 | 00\|1010000     | Segmentation Violation |   -    |
70
-    | 7      | 0x00000037 | 00\|0110111     | **0x00000037**         |   55   |
71
-    | 8      | 0x000000ff | **01**\|1111111 | **0x00000393**         |  915   |
72
-    | 9      | 0x000000e9 | **01**\|1101001 | Segmentation Violation |   -    |
73
-    | 10     | 0x00000001 | 00\|0000001     | **0x00000001**         |   1    |
74
-    | 11     | 0x0000014c | **10**\|1001100 | **0x000003e0**         |  992   |
75
-    | 12     | 0x000000b4 | **01**\|0110100 | Segmentation Violation |   -    |
76
-    | 13     | 0x000000cf | **01**\|1001111 | Segmentation Violation |   -    |
77
-    | 14     | 0x0000012b | **10**\|0101011 | **0x000003bf**         |  959   |
78
-    | 15     | 0x00000084 | **01**\|0000100 | Segmentation Violation |   -    |
79
-
80
-    Zuerst überprüft man in welchem Segment die VA liegt, indem man auf das höchste bit der binären VA schaut. Wenn sie im Segment 0 liegt dann ist VA => PA und man kann prüfen, ob die Adresse im oben berechneten physikalischen Adressbereich von Segment 0 liegt. Wenn nicht => SEG FAULT.
81
-
82
-    Wenn die VA in Segment 1 liegt, dann muss man vorher den berechneten Offset vonn dezimal 660 oder hexadezimal 0x258 aufaddieren. Dann hat man die PA und kann dann schauen ob sie im physikalischen Adressbereich von Segment 1 liegt. Wenn nicht => SEG FAULT.

+ 0
- 87
hw3/simu2/QUESTIONS.md 查看文件

@@ -1,87 +0,0 @@
1
-# Questions 16-Segmentation
2
-
3
-This program allows you to see how address translations are performed in a
4
-system with segmentation. See the `README` for details.
5
-
6
-## Warm-up
7
-
8
-First let’s use a tiny address space to translate some addresses. Here’s a
9
-simple set of parameters with a few different random seeds; can you translate
10
-the addresses?
11
-
12
-```text
13
-      segmentation.py -a 128 -p 512 -b 0 -l 20 -B 512 -L 20 -s 0
14
-      segmentation.py -a 128 -p 512 -b 0 -l 20 -B 512 -L 20 -s 1
15
-      segmentation.py -a 128 -p 512 -b 0 -l 20 -B 512 -L 20 -s 2
16
-```
17
-
18
-## Questions
19
-
20
-1. Now, let’s see if we understand this tiny address space we’ve constructed
21
-   (using the parameters from the warm-up above). What is the highest legal
22
-   virtual address in segment 0? What about the lowest legal virtual address in
23
-   segment 1? What are the lowest and highest illegal addresses in this entire
24
-   address space? Finally, how would you run segmentation.py with the -A flag to
25
-   test if you are right?
26
-
27
-1. Let’s say we have a tiny 16-byte address space in a 128-byte physical memory.
28
-   What base and bounds would you set up so as to get the simulator to generate
29
-   the following translation results for the specified address stream: valid,
30
-   valid, violation, ..., violation, valid, valid? Assume the following
31
-   parameters:
32
-
33
-   ```text
34
-     segmentation.py -a 16 -p 128
35
-         -A 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
36
-         --b0 ? --l0 ? --b1 ? --l1 ?
37
-   ```
38
-
39
-1. Assuming we want to generate a problem where roughly 90% of the
40
-   randomly-generated virtual addresses are valid (i.e., not segmentation
41
-   violations). How should you configure the simulator to do so? Which
42
-   parameters are important (Explanation!)?
43
-
44
-1. Can you run the simulator such that no virtual addresses are valid? How
45
-   (Explanation)?
46
-
47
-1. For each virtual address, either write down the physical address (hex and
48
-   decimal) it translates to OR write down that it is an out-of-bounds address
49
-   (a segmentation violation). For this problem, you should assume a simple
50
-   address space with two segments: the top bit of the virtual address can thus
51
-   be used to check whether the virtual address is in segment 0 (topbit=0) or
52
-   segment 1 (topbit=1). Note that the base/limit pairs given to you grow in
53
-   different directions, depending on the segment, i.e., segment 0 grows in the
54
-   positive direction, whereas segment 1 in the negative.
55
-
56
-   ```text
57
-   ARG address space size 364
58
-   ARG phys mem size 756
59
-
60
-   Segment register information:
61
-
62
-     Segment 0 base  (grows positive) : 0x00000000 (decimal 0)
63
-     Segment 0 limit                  : 64
64
-
65
-     Segment 1 base  (grows negative) : 0x00000400 (decimal 1024)
66
-     Segment 1 limit                  : 128
67
-
68
-   Virtual Address Trace
69
-     VA  0: 0x0000005c (decimal:   92) --> PA or segmentation violation?
70
-     VA  1: 0x00000011 (decimal:   17) --> PA or segmentation violation?
71
-     VA  2: 0x00000043 (decimal:   67) --> PA or segmentation violation?
72
-     VA  3: 0x00000021 (decimal:   33) --> PA or segmentation violation?
73
-     VA  4: 0x0000006c (decimal:  108) --> PA or segmentation violation?
74
-     VA  5: 0x0000007a (decimal:  122) --> PA or segmentation violation?
75
-     VA  6: 0x00000050 (decimal:   80) --> PA or segmentation violation?
76
-     VA  7: 0x00000037 (decimal:   55) --> PA or segmentation violation?
77
-     VA  8: 0x000000ff (decimal:  255) --> PA or segmentation violation?
78
-     VA  9: 0x000000e9 (decimal:  233) --> PA or segmentation violation?
79
-     VA 10: 0x00000001 (decimal:    1) --> PA or segmentation violation?
80
-     VA 11: 0x0000014c (decimal:  332) --> PA or segmentation violation?
81
-     VA 12: 0x000000b4 (decimal:  180) --> PA or segmentation violation?
82
-     VA 13: 0x000000cf (decimal:  207) --> PA or segmentation violation?
83
-     VA 14: 0x0000012b (decimal:  299) --> PA or segmentation violation?
84
-     VA 15: 0x00000084 (decimal:  132) --> PA or segmentation violation?
85
-   ```
86
-
87
-   How did you solve this question?

+ 0
- 183
hw3/simu2/README-segmentation.md 查看文件

@@ -1,183 +0,0 @@
1
-# README Segmentation
2
-
3
-This program allows you to see how address translations are performed in a
4
-system with segmentation. The segmentation that this system uses is pretty
5
-simple: an address space has just *two* segments; further, the top bit of the
6
-virtual address generated by the process determines which segment the address is
7
-in: 0 for segment 0 (where, say, code and the heap would reside) and 1 for
8
-segment 1 (where the stack lives). Segment 0 grows in a positive direction
9
-(towards higher addresses), whereas segment 1 grows in the negative direction.
10
-
11
-Visually, the address space looks like this:
12
-
13
-```text
14
- --------------- virtual address 0
15
- |    seg0     |
16
- |             |
17
- |             |
18
- |-------------|
19
- |             |
20
- |             |
21
- |             |
22
- |             |
23
- |(unallocated)|
24
- |             |
25
- |             |
26
- |             |
27
- |-------------|
28
- |             |
29
- |    seg1     |
30
- |-------------| virtual address max (size of address space)
31
-```
32
-
33
-With segmentation, as you might recall, there is a base/limit pair of registers
34
-per segment. Thus, in this problem, there are two base/limit pairs. The
35
-segment-0 base tells which physical address the *top* of segment 0 has been
36
-placed in physical memory and the limit tells how big the segment is; the
37
-segment-1 base tells where the *bottom* of segment 1 has been placed in physical
38
-memory and the corresponding limit also tells us how big the segment is (or how
39
-far it grows in the negative direction).
40
-
41
-As in `relocation (simu1)`, there are two steps to running the program to test
42
-out your understanding of segmentation. First, run without the "-c" flag to
43
-generate a set of translations and see if you can correctly perform the address
44
-translations yourself. Then, when done, run with the "-c" flag to check your
45
-answers.
46
-
47
-For example, to run with the default flags, type:
48
-
49
-```text
50
-prompt> ./segmentation.py
51
-```
52
-
53
-or
54
-
55
-```text
56
-prompt> python ./segmentation.py
57
-```
58
-
59
-(if the first doesn't work)
60
-
61
-You should see this:
62
-
63
-```text
64
-  ARG seed 0
65
-  ARG address space size 1k
66
-  ARG phys mem size 16k
67
-
68
-  Segment register information:
69
-
70
-    Segment 0 base  (grows positive) : 0x00001aea (decimal 6890)
71
-    Segment 0 limit                  : 472
72
-
73
-    Segment 1 base  (grows negative) : 0x00001254 (decimal 4692)
74
-    Segment 1 limit                  : 450
75
-
76
-  Virtual Address Trace
77
-    VA  0: 0x0000020b (decimal:  523) --> PA or segmentation violation?
78
-    VA  1: 0x0000019e (decimal:  414) --> PA or segmentation violation?
79
-    VA  2: 0x00000322 (decimal:  802) --> PA or segmentation violation?
80
-    VA  3: 0x00000136 (decimal:  310) --> PA or segmentation violation?
81
-    VA  4: 0x000001e8 (decimal:  488) --> PA or segmentation violation?
82
-
83
-  For each virtual address, either write down the physical address it translates
84
-  to OR write down that it is an out-of-bounds address (a segmentation
85
-  violation). For this problem, you should assume a simple address space with
86
-  two segments: the top bit of the virtual address can thus be used to check
87
-  whether the virtual address is in segment 0 (topbit=0) or segment 1
88
-  (topbit=1). Note that the base/limit pairs given to you grow in different
89
-  directions, depending on the segment, i.e., segment 0 grows in the positive
90
-  direction, whereas segment 1 in the negative.
91
-```
92
-
93
-Then, after you have computed the translations in the virtual address trace, run
94
-the program again with the "-c" flag. You will see the following (not including
95
-the redundant information):
96
-
97
-```text
98
-  Virtual Address Trace
99
-    VA  0: 0x0000020b (decimal:  523) --> SEGMENTATION VIOLATION (SEG1)
100
-    VA  1: 0x0000019e (decimal:  414) --> VALID in SEG0: 0x00001c88 (decimal: 7304)
101
-    VA  2: 0x00000322 (decimal:  802) --> VALID in SEG1: 0x00001176 (decimal: 4470)
102
-    VA  3: 0x00000136 (decimal:  310) --> VALID in SEG0: 0x00001c20 (decimal: 7200)
103
-    VA  4: 0x000001e8 (decimal:  488) --> SEGMENTATION VIOLATION (SEG0)
104
-```
105
-
106
-As you can see, with -c, the program translates the addresses for you, and hence
107
-you can check if you understand how a system using segmentation translates
108
-addresses.
109
-
110
-Of course, there are some parameters you can use to give yourself different
111
-problems. One particularly important parameter is the -s or -seed parameter,
112
-which lets you generate different problems by passing in a different random
113
-seed. Of course, make sure to use the same random seed when you are generating a
114
-problem and then solving it.
115
-
116
-There are also some parameters you can use to play with different-sized address
117
-spaces and physical memories. For example, to experiment with segmentation in a
118
-tiny system, you might type:
119
-
120
-```text
121
-  prompt> ./segmentation.py -s 100 -a 16 -p 32
122
-  ARG seed 0
123
-  ARG address space size 16
124
-  ARG phys mem size 32
125
-
126
-  Segment register information:
127
-
128
-    Segment 0 base  (grows positive) : 0x00000018 (decimal 24)
129
-    Segment 0 limit                  : 4
130
-
131
-    Segment 1 base  (grows negative) : 0x00000012 (decimal 18)
132
-    Segment 1 limit                  : 5
133
-
134
-  Virtual Address Trace
135
-    VA  0: 0x0000000c (decimal:   12) --> PA or segmentation violation?
136
-    VA  1: 0x00000008 (decimal:    8) --> PA or segmentation violation?
137
-    VA  2: 0x00000001 (decimal:    1) --> PA or segmentation violation?
138
-    VA  3: 0x00000007 (decimal:    7) --> PA or segmentation violation?
139
-    VA  4: 0x00000000 (decimal:    0) --> PA or segmentation violation?
140
-```
141
-
142
-which tells the program to generate virtual addresses for a 16-byte address
143
-space placed somewhere in a 32-byte physical memory. As you can see, the
144
-resulting virtual addresses are tiny (12, 8, 1, 7, and 0). As you can also see,
145
-the program picks tiny base register and limit values, as appropriate. Run with
146
--c to see the answers.
147
-
148
-This example should also show you exactly what each base pair means. For
149
-example, segment 0's base is set to a physical address of 24 (decimal) and is of
150
-size 4 bytes. Thus, *virtual* addresses 0, 1, 2, and 3 are in segment 0 and
151
-valid, and map to physical addresses 24, 25, 26, and 27, respectively.
152
-
153
-Slightly more tricky is the negative-direction-growing segment 1. In the tiny
154
-example above, segment 1's base register is set to physical address 18, with a
155
-size of 5 bytes. That means that the *last* five bytes of the virtual address
156
-space, in this case 11, 12, 13, 14, and 15, are valid virtual addresses, and
157
-that they map to physical addresses 13, 14, 15, 16, and 17, respectively.
158
-
159
-If that doesn't make sense, read it again -- you will have to make sense of how
160
-this works in order to do any of these problems.
161
-
162
-Note you can specify bigger values by tacking a "k", "m", or even "g" onto the
163
-values you pass in with the -a or -p flags, as in "kilobytes", "megabytes", and
164
-"gigabytes". Thus, if you wanted to do some translations with a 1-MB address
165
-space set in a 32-MB physical memory, you might type:
166
-
167
-```text
168
-prompt> ./segmentation.py -a 1m -p 32m
169
-```
170
-
171
-If you want to get even more specific, you can set the base register and limit
172
-register values yourself, with the --b0, --l0, --b1, and --l1 registers. Try
173
-them and see.
174
-
175
-Finally, you can always run
176
-
177
-```text
178
-prompt> ./segmentation.py -h
179
-```
180
-
181
-to get a complete list of flags and options.
182
-
183
-Enjoy!

+ 0
- 193
hw3/simu2/segmentation.py 查看文件

@@ -1,193 +0,0 @@
1
-#! /usr/bin/env python
2
-
3
-import sys
4
-from optparse import OptionParser
5
-import random
6
-import math
7
-
8
-def convert(size):
9
-    length = len(size)
10
-    lastchar = size[length-1]
11
-    if (lastchar == 'k') or (lastchar == 'K'):
12
-        m = 1024
13
-        nsize = int(size[0:length-1]) * m
14
-    elif (lastchar == 'm') or (lastchar == 'M'):
15
-        m = 1024*1024
16
-        nsize = int(size[0:length-1]) * m
17
-    elif (lastchar == 'g') or (lastchar == 'G'):
18
-        m = 1024*1024*1024
19
-        nsize = int(size[0:length-1]) * m
20
-    else:
21
-        nsize = int(size)
22
-    return nsize
23
-
24
-
25
-#
26
-# main program
27
-#
28
-parser = OptionParser()
29
-parser.add_option("-s", "--seed", default=0, help="the random seed", 
30
-                  action="store", type="int", dest="seed")
31
-parser.add_option("-A", "--addresses", default="-1",
32
-                  help="a set of comma-separated pages to access; -1 means randomly generate", 
33
-                  action="store", type="string", dest="addresses")
34
-parser.add_option("-a", "--asize", default="1k",
35
-                  help="address space size (e.g., 16, 64k, 32m, 1g)", 
36
-                  action="store", type="string", dest="asize")
37
-parser.add_option("-p", "--physmem", default="16k",
38
-                  help="physical memory size (e.g., 16, 64k, 32m, 1g)", 
39
-                  action="store", type="string", dest="psize")
40
-parser.add_option("-n", "--numaddrs", default=5,
41
-                  help="number of virtual addresses to generate",
42
-                  action="store", type="int", dest="num")
43
-parser.add_option("-b", "--b0", default="-1",
44
-                  help="value of segment 0 base register",
45
-                  action="store", type="string", dest="base0")
46
-parser.add_option("-l", "--l0", default="-1",
47
-                  help="value of segment 0 limit register",
48
-                  action="store", type="string", dest="len0")
49
-parser.add_option("-B", "--b1", default="-1",
50
-                  help="value of segment 1 base register",
51
-                  action="store", type="string", dest="base1")
52
-parser.add_option("-L", "--l1", default="-1",
53
-                  help="value of segment 1 limit register",
54
-                  action="store", type="string", dest="len1")
55
-parser.add_option("-c", help="compute answers for me",
56
-                  action="store_true", default=False, dest="solve")
57
-
58
-
59
-(options, args) = parser.parse_args()
60
-
61
-print "ARG seed", options.seed
62
-print "ARG address space size", options.asize
63
-print "ARG phys mem size", options.psize
64
-print ""
65
-
66
-random.seed(options.seed)
67
-asize = convert(options.asize)
68
-psize = convert(options.psize)
69
-addresses = str(options.addresses)
70
-
71
-if psize <= 1:
72
-    print 'Error: must specify a non-zero physical memory size.'
73
-    exit(1)
74
-
75
-if asize == 0:
76
-    print 'Error: must specify a non-zero address-space size.'
77
-    exit(1)
78
-
79
-if psize <= asize:
80
-    print 'Error: physical memory size must be GREATER than address space size (for this simulation)'
81
-    exit(1)
82
-
83
-#
84
-# need to generate base, bounds for segment registers
85
-#
86
-len0 = convert(options.len0)
87
-len1 = convert(options.len1)
88
-base0 = convert(options.base0)
89
-base1 = convert(options.base1)
90
-
91
-if len0 == -1:
92
-    len0 = int(asize/4.0 + (asize/4.0 * random.random()))
93
-
94
-if len1 == -1:
95
-    len1 = int(asize/4.0 + (asize/4.0 * random.random()))
96
-
97
-# now have to find room for them
98
-if base0 == -1:
99
-    done = 0
100
-    while done == 0:
101
-        base0 = int(psize * random.random())
102
-        if (base0 + len0) < psize:
103
-            done = 1
104
-
105
-# internally, base1 points to the lower address, and base1+len1 the higher address
106
-# (this differs from what the user would pass in, for example)
107
-if base1 == -1:
108
-    done = 0
109
-    while done == 0:
110
-        base1 = int(psize * random.random())
111
-        if (base1 + len1) < psize:
112
-            if (base1 > (base0 + len0)) or ((base1 + len1) < base0):
113
-                done = 1
114
-else:
115
-    base1 = base1 - len1
116
-
117
-
118
-if len0 > asize/2.0 or len1 > asize/2.0:
119
-    print 'Error: length register is too large for this address space'
120
-    exit(1)
121
-
122
-
123
-print 'Segment register information:'
124
-print ''
125
-print '  Segment 0 base  (grows positive) : 0x%08x (decimal %d)' % (base0, base0)
126
-print '  Segment 0 limit                  : %d' % (len0)
127
-print ''
128
-print '  Segment 1 base  (grows negative) : 0x%08x (decimal %d)' % (base1+len1, base1+len1)
129
-print '  Segment 1 limit                  : %d' % (len1)
130
-print ''
131
-nbase1  = base1 + len1
132
-
133
-if (len0 + base0) > (base1) and (base1 > base0):
134
-    print 'Error: segments overlap in physical memory'
135
-    exit(1)
136
-
137
-
138
-addrList = []
139
-if addresses == '-1':
140
-    # need to generate addresses
141
-    for i in range(0, options.num):
142
-        n = int(asize * random.random())
143
-        addrList.append(n)
144
-else:
145
-    addrList = addresses.split(',')
146
-
147
-#
148
-# now, need to generate virtual address trace
149
-#
150
-print 'Virtual Address Trace'
151
-i = 0
152
-for vStr in addrList:
153
-    # vaddr = int(asize * random.random())
154
-    vaddr = int(vStr)
155
-    if vaddr < 0 or vaddr >= asize:
156
-        print 'Error: virtual address %d cannot be generated in an address space of size %d' % (vaddr, asize)
157
-        exit(1)
158
-    if options.solve == False:
159
-        print '  VA %2d: 0x%08x (decimal: %4d) --> PA or segmentation violation?' % (i, vaddr, vaddr)
160
-    else:
161
-        paddr = 0
162
-        if (vaddr >= (asize / 2)):
163
-            # seg 1
164
-            paddr = nbase1 + (vaddr - asize)
165
-            if paddr < base1:
166
-                print '  VA %2d: 0x%08x (decimal: %4d) --> SEGMENTATION VIOLATION (SEG1)' % (i, vaddr, vaddr)
167
-            else:
168
-                print '  VA %2d: 0x%08x (decimal: %4d) --> VALID in SEG1: 0x%08x (decimal: %4d)' % (i, vaddr, vaddr, paddr, paddr)
169
-        else:
170
-            # seg 0
171
-            if (vaddr >= len0):
172
-                print '  VA %2d: 0x%08x (decimal: %4d) --> SEGMENTATION VIOLATION (SEG0)' % (i, vaddr, vaddr)
173
-            else:
174
-                paddr = vaddr + base0
175
-                print '  VA %2d: 0x%08x (decimal: %4d) --> VALID in SEG0: 0x%08x (decimal: %4d)' % (i, vaddr, vaddr, paddr, paddr)
176
-    i += 1
177
-
178
-print ''
179
-
180
-if options.solve == False:
181
-    print 'For each virtual address, either write down the physical address it translates to'
182
-    print 'OR write down that it is an out-of-bounds address (a segmentation violation). For'
183
-    print 'this problem, you should assume a simple address space with two segments: the top'
184
-    print 'bit of the virtual address can thus be used to check whether the virtual address'
185
-    print 'is in segment 0 (topbit=0) or segment 1 (topbit=1). Note that the base/limit pairs'
186
-    print 'given to you grow in different directions, depending on the segment, i.e., segment 0'
187
-    print 'grows in the positive direction, whereas segment 1 in the negative. '
188
-    print ''
189
-
190
-
191
-
192
-
193
-

+ 0
- 111
hw3/simu3/ANSWERS.md 查看文件

@@ -1,111 +0,0 @@
1
-# Warmup
2
-
3
-Die Entwicklung des Speichers nach ausführen von `./malloc.py -n 10 -H 0 -p BEST -s` 
4
-
5
-```
6
- --------------- 1000
7
- |             |
8
- |             |
9
- |-------------| 1100
10
-```
11
-
12
-```
13
- --------------- 1000
14
- |   alloc'd   |
15
- |-------------| 1003
16
- |             |
17
- |             |
18
- |    FREE     |
19
- |             |
20
- |             |
21
- |-------------| 1100
22
-```
23
-
24
-```
25
- --------------- 1000
26
- |    FREE     |
27
- |-------------| 1003
28
- |             |
29
- |             |
30
- |    FREE     |
31
- |             |
32
- |             |
33
- |-------------| 1100
34
-```
35
-
36
-```
37
- --------------- 1000
38
- |    FREE     |
39
- |-------------| 1003
40
- |   alloc'd   |
41
- |-------------| 1008
42
- |             |
43
- |    FREE     |
44
- |             |
45
- |-------------| 1100
46
-```
47
-```
48
- --------------- 1000
49
- |    FREE     |
50
- |-------------| 1003
51
- |    FREE     |
52
- |-------------| 1008
53
- |             |
54
- |    FREE     |
55
- |             |
56
- |-------------| 1100
57
-```
58
-```
59
- --------------- 1000
60
- |    FREE     |
61
- |-------------| 1003
62
- |    FREE     |
63
- |-------------| 1008
64
- |   alloc'd   |
65
- |-------------| 1016
66
- |    FREE     |
67
- |-------------| 1100
68
-```
69
-```
70
- --------------- 1000
71
- |    FREE     |
72
- |-------------| 1002
73
- |   alloc'd   |
74
- |-------------| 1003
75
- |    FREE     |
76
- |-------------| 1008
77
- |    FREE     |
78
- |-------------| 1016
79
- |    FREE     |
80
- |-------------| 1100
81
-```
82
-```
83
- --------------- 1000
84
- |    FREE     |
85
- |-------------| 1002
86
- |   alloc'd   |
87
- |-------------| 1003
88
- |    FREE     |
89
- |-------------| 1008
90
- |   alloc'd   |
91
- |-------------| 1015
92
- |    FREE     |
93
- |-------------| 1016
94
- |    FREE     |
95
- |-------------| 1100
96
-```
97
-
98
-Wie man sieht hat die Fragmentierung des Speichers bzw. der Free-Liste zugenommen.
99
-
100
-# Antworten
101
-
102
-1. Wenn zwei mal ein gleich großes Speicherstück alloziiert wird, dann wird nicht das wieder freigewordene Fragment genutzt, sondern ein neues reserviert. Auch Alloziierungen von kleineren Stücken bekommen keine Teile von wieder freigegebenem Platz. Also ensteht im allgemeinen eine höhere Fragmentierung als mit **BEST**.
103
-2. Die Struktur der Free-Liste ändert sich nicht, aber es werden weniger Elemente (Speicherblöcke) gesucht, bevor die Adresse zurückgeliefert wird. Je größer die Free-Liste, desto länger dauert es, diese zu durchsuchen. Das Flag **FIRST** verkürzt also die Suchzeit und somit auch die insgesamte alloc-Zeit.
104
-3. Die verschiedenen Sortiermechanismen:
105
-   - **ADDRSORT** sortiert die Liste mit dem freien Speicher nach der höhe der Adresse. Es verändert sich nichts zu vorher mit anderen Policies.
106
-   - Bei **SIZESORT+** sind die kleinsten *Stücke* vorne in der Liste. Bei **BEST** ist dann oft der Verschnitt, also 1-Byte-Blöcke am Anfang. 
107
-   - Bei **SIZESORT-** wird die Speicherliste absteigend nach der Größe der Blöcke sortiert. Diese Sortierung ist vorteilhaft für die Policy **FIRST**, da große Blöcke direkt am Anfang gefunden werden die sehr häufig für den angeforderten Speicher ausreichen. 
108
-4. Bei größeren Speicheranforderungen schlägt malloc fehl, mit dem Rückgabewert `-1` und die Free-Liste ist sehr groß. Wenn man nun die Verschmelzung von freiem Speicher mit `-C`  aktiviert, dann schlägt keine Allozierung mehr fehl und die Liste des freien Speichers ist kleiner. Die Sortierung der Liste spielt keine Rolle, da keine Fragmente über andere Adressen hinweg miteinander verschmolzen werden können.
109
-5. Wenn ein Faktor von über 50% erlaubt wird, dann bleibt die Liste klein, da der Speicher nicht wieder freigegeben wird. Bei Werten bis zu 100% kommt es definitiv zu einem Fehler bei der Alloziierung, da nicht genug freier Speicher vorhanden ist. Bei Werten, die gegen 0 gehen wird nach jedem **alloc** ein **free** aufgerufen und es ist immer wieder freier Speicher vorhanden.
110
-6. ​In dem man bei jedem **alloc** ein Byte mehr Speicher als davor anfordert, muss immer ein neuer "Block" angefangen werden. Dabei hilft die Policy BEST auch nichts mehr, da die neuen Allozierungen nie in die wieder frei gewordene kleinere Speicherstücke passt.
111
-

+ 0
- 41
hw3/simu3/QUESTIONS.md 查看文件

@@ -1,41 +0,0 @@
1
-# Questions 17-FreeSpace-Management
2
-
3
-The program, `malloc.py`, lets you explore the behavior of a simple free-space
4
-allocator as described in the chapter. See the README for details of its basic
5
-operation.
6
-
7
-## Warm-up
8
-
9
-First run with the flags `-n 10 -H 0 -p BEST -s 0` to generate a few random
10
-allocations and frees. Can you predict what *alloc()*/*free()* will return? Can
11
-you guess the state of the free list after each request? What do you notice
12
-about the free list over time?
13
-
14
-## Questions
15
-
16
-1. How are the results different when using a WORST fit policy to search the
17
-   free list (`-p WORST`) from warm-up? What changes (Explanation)?
18
-
19
-1. What about when using FIRST fit (`-p FIRST`)? What speeds up when you use
20
-   first fit (Explanation)?
21
-
22
-1. For the above questions, how the list is kept ordered can affect the time it
23
-   takes to find a free location for some of the policies. Use the different
24
-   free list orderings (`-l ADDRSORT, -l SIZESORT+, -l SIZESORT-`) to see how
25
-   the policies and the list orderings interact. What are your observations?
26
-
27
-1. Coalescing of a free list can be quite important. Increase the number of
28
-   random allocations (say to `-n 1000`). What happens to larger allocation
29
-   requests over time? Run with and without coalescing (i.e., without and with
30
-   the `-C` flag). What differences in outcome do you see? How big is the free
31
-   list over time in each case? Does the ordering of the list matter in this
32
-   case? Comment your results!
33
-
34
-1. What happens when you change the percent allocated fraction `-P` to higher
35
-   than 50? What happens to allocations as it nears 100? What about as it nears
36
-   0? Please give an explanation to your observations.
37
-
38
-1. What kind of specific requests can you make to generate a highly-fragmented
39
-   free space? Use the `-A` flag to create fragmented free lists, and see how
40
-   different policies and options change the organization of the free list.
41
-   Explain your results.

+ 0
- 164
hw3/simu3/README-malloc.md 查看文件

@@ -1,164 +0,0 @@
1
-# README malloc
2
-
3
-This program, `malloc.py`, allows you to see how a simple memory allocator works.
4
-Here are the options that you have at your disposal:
5
-
6
-```text
7
-  -h, --help            show this help message and exit
8
-  -s SEED, --seed=SEED  the random seed
9
-  -S HEAPSIZE, --size=HEAPSIZE
10
-                        size of the heap
11
-  -b BASEADDR, --baseAddr=BASEADDR
12
-                        base address of heap
13
-  -H HEADERSIZE, --headerSize=HEADERSIZE
14
-                        size of the header
15
-  -a ALIGNMENT, --alignment=ALIGNMENT
16
-                        align allocated units to size; -1->no align
17
-  -p POLICY, --policy=POLICY
18
-                        list search (BEST, WORST, FIRST)
19
-  -l ORDER, --listOrder=ORDER
20
-                        list order (ADDRSORT, SIZESORT+, SIZESORT-, INSERT-FRONT, INSERT-BACK)
21
-  -C, --coalesce        coalesce the free list?
22
-  -n OPSNUM, --numOps=OPSNUM
23
-                        number of random ops to generate
24
-  -r OPSRANGE, --range=OPSRANGE
25
-                        max alloc size
26
-  -P OPSPALLOC, --percentAlloc=OPSPALLOC
27
-                        percent of ops that are allocs
28
-  -A OPSLIST, --allocList=OPSLIST
29
-                        instead of random, list of ops (+10,-0,etc)
30
-  -c, --compute         compute answers for me
31
-```
32
-
33
-One way to use it is to have the program generate some random allocation/free
34
-operations and for you to see if you can figure out what the free list would
35
-look like, as well as the success or failure of each operation.
36
-
37
-Here is a simple example:
38
-
39
-```text
40
-prompt> ./malloc.py -S 100 -b 1000 -H 4 -a 4 -l ADDRSORT -p BEST -n 5
41
-
42
-ptr[0] = Alloc(3)  returned ?
43
-List?
44
-
45
-Free(ptr[0]) returned ?
46
-List?
47
-
48
-ptr[1] = Alloc(5)  returned ?
49
-List?
50
-
51
-Free(ptr[1]) returned ?
52
-List?
53
-
54
-ptr[2] = Alloc(8)  returned ?
55
-List?
56
-```
57
-
58
-In this example, we specify a heap of size 100 bytes (-S 100), starting at
59
-address 1000 (-b 1000). We specify an additional 4 bytes of header per allocated
60
-block (-H 4), and make sure each allocated space rounds up to the nearest 4-byte
61
-free chunk in size (-a 4). We specify that the free list be kept ordered by
62
-address (increasing). Finally, we specify a "best fit" free-list searching
63
-policy (-p BEST), and ask for 5 random operations to be generated (-n 5). The
64
-results of running this are above; your job is to figure out what each
65
-allocation/free operation returns, as well as the state of the free list after
66
-each operation.
67
-
68
-Here we look at the results by using the -c option.
69
-
70
-```text
71
-prompt> ./malloc.py -S 100 -b 1000 -H 4 -a 4 -l ADDRSORT -p BEST -n 5 -c
72
-
73
-ptr[0] = Alloc(3)  returned 1004 (searched 1 elements)
74
-Free List [ Size 1 ]:  [ addr:1008 sz:92 ]
75
-
76
-Free(ptr[0]) returned 0
77
-Free List [ Size 2 ]:  [ addr:1000 sz:8 ] [ addr:1008 sz:92 ]
78
-
79
-ptr[1] = Alloc(5)  returned 1012 (searched 2 elements)
80
-Free List [ Size 2 ]:  [ addr:1000 sz:8 ] [ addr:1020 sz:80 ]
81
-
82
-Free(ptr[1]) returned 0
83
-Free List [ Size 3 ]:  [ addr:1000 sz:8 ] [ addr:1008 sz:12 ] [ addr:1020 sz:80 ]
84
-
85
-ptr[2] = Alloc(8)  returned 1012 (searched 3 elements)
86
-Free List [ Size 2 ]:  [ addr:1000 sz:8 ] [ addr:1020 sz:80 ]
87
-```
88
-
89
-As you can see, the first allocation operation (an allocation) returns the
90
-following information:
91
-
92
-```text
93
-ptr[0] = Alloc(3)  returned 1004 (searched 1 elements)
94
-Free List [ Size 1 ]:  [ addr:1008 sz:92 ]
95
-```
96
-
97
-Because the initial state of the free list is just one large element, it is easy
98
-to guess that the Alloc(3) request will succeed. Further, it will just return
99
-the first chunk of memory and make the remainder into a free list. The pointer
100
-returned will be just beyond the header (address:1004), and the allocated space
101
-is rounded up to 4 bytes, leaving the free list with 92 bytes starting at 1008.
102
-
103
-The next operation is a Free, of "ptr[0]" which is what stores the results of
104
-the previous allocation request. As you can expect, this free will succeed (thus
105
-returning "0"), and the free list now looks a little more complicated:
106
-
107
-```text
108
-Free(ptr[0]) returned 0
109
-Free List [ Size 2 ]:  [ addr:1000 sz:8 ] [ addr:1008 sz:92 ]
110
-```
111
-
112
-Indeed, because we are NOT coalescing the free list, we now have two elements on
113
-it, the first being 8 bytes large and holding the just-returned space, and the
114
-second being the 92-byte chunk.
115
-
116
-We can indeed turn on coalescing via the -C flag, and the result is:
117
-
118
-```text
119
-prompt> ./malloc.py -S 100 -b 1000 -H 4 -a 4 -l ADDRSORT -p BEST -n 5 -c -C
120
-ptr[0] = Alloc(3)  returned 1004 (searched 1 elements)
121
-Free List [ Size 1 ]:  [ addr:1008 sz:92 ]
122
-
123
-Free(ptr[0]) returned 0
124
-Free List [ Size 1 ]:  [ addr:1000 sz:100 ]
125
-
126
-ptr[1] = Alloc(5)  returned 1004 (searched 1 elements)
127
-Free List [ Size 1 ]:  [ addr:1012 sz:88 ]
128
-
129
-Free(ptr[1]) returned 0
130
-Free List [ Size 1 ]:  [ addr:1000 sz:100 ]
131
-
132
-ptr[2] = Alloc(8)  returned 1004 (searched 1 elements)
133
-Free List [ Size 1 ]:  [ addr:1012 sz:88 ]
134
-```
135
-
136
-You can see that when the Free operations take place, the free list is coalesced
137
-as expected.
138
-
139
-There are some other interesting options to explore:
140
-
141
-* -p (BEST, WORST, FIRST)
142
-
143
-  This option lets you use these three different strategies to look for a chunk
144
-  of memory to use during an allocation request
145
-
146
-* -l (ADDRSORT, SIZESORT+, SIZESORT-, INSERT-FRONT, INSERT-BACK)
147
-
148
-  This option lets you keep the free list in a particular order, say sorted by
149
-  address of the free chunk, size of free chunk (either increasing with a + or
150
-  decreasing with a -), or simply returning free chunks to the front
151
-  (INSERT-FRONT) or back (INSERT-BACK) of the free list.
152
-
153
-* -A (list of ops)
154
-
155
-  This option lets you specify an exact series of requests instead of
156
-  randomly-generated ones.
157
-
158
-  For example, running with the flag "-A +10,+10,+10,-0,-2" will allocate three
159
-  chunks of size 10 bytes (plus header), and then free the first one ("-0") and
160
-  then free the third one ("-2"). What will the free list look like then?
161
-
162
-Those are the basics. Use the questions from the book chapter to explore more,
163
-or create new and interesting questions yourself to better understand how
164
-allocators function.

+ 0
- 253
hw3/simu3/malloc.py 查看文件

@@ -1,253 +0,0 @@
1
-#! /usr/bin/env python
2
-
3
-import random
4
-from optparse import OptionParser
5
-
6
-class malloc:
7
-    def __init__(self, size, start, headerSize, policy, order, coalesce, align):
8
-        # size of space
9
-        self.size        = size
10
-        
11
-        # info about pretend headers
12
-        self.headerSize  = headerSize
13
-
14
-        # init free list
15
-        self.freelist    = []
16
-        self.freelist.append((start, size))
17
-
18
-        # keep track of ptr to size mappings
19
-        self.sizemap     = {}
20
-
21
-        # policy
22
-        self.policy       = policy
23
-        assert(self.policy in ['FIRST', 'BEST', 'WORST'])
24
-
25
-        # list ordering
26
-        self.returnPolicy = order
27
-        assert(self.returnPolicy in ['ADDRSORT', 'SIZESORT+', 'SIZESORT-', 'INSERT-FRONT', 'INSERT-BACK'])
28
-
29
-        # this does a ridiculous full-list coalesce, but that is ok
30
-        self.coalesce     = coalesce
31
-
32
-        # alignment (-1 if no alignment)
33
-        self.align        = align
34
-        assert(self.align == -1 or self.align > 0)
35
-
36
-    def addToMap(self, addr, size):
37
-        assert(addr not in self.sizemap)
38
-        self.sizemap[addr] = size
39
-        # print 'adding', addr, 'to map of size', size
40
-        
41
-    def malloc(self, size):
42
-        if self.align != -1:
43
-            left = size % self.align
44
-            if left != 0:
45
-                diff = self.align - left
46
-            else:
47
-                diff = 0
48
-            # print 'aligning: adding %d to %d' % (diff, size)
49
-            size += diff
50
-
51
-        size += self.headerSize
52
-
53
-        bestIdx  = -1
54
-        if self.policy == 'BEST':
55
-            bestSize = self.size + 1
56
-        elif self.policy == 'WORST' or self.policy == 'FIRST':
57
-            bestSize = -1
58
-
59
-        count = 0
60
-            
61
-        for i in range(len(self.freelist)):
62
-            eaddr, esize = self.freelist[i][0], self.freelist[i][1]
63
-            count   += 1
64
-            if esize >= size and ((self.policy == 'BEST'  and esize < bestSize) or
65
-                                  (self.policy == 'WORST' and esize > bestSize) or
66
-                                  (self.policy == 'FIRST')):
67
-                bestAddr = eaddr
68
-                bestSize = esize
69
-                bestIdx  = i
70
-                if self.policy == 'FIRST':
71
-                    break
72
-
73
-        if bestIdx != -1:
74
-            if bestSize > size:
75
-                # print 'SPLIT', bestAddr, size
76
-                self.freelist[bestIdx] = (bestAddr + size, bestSize - size)
77
-                self.addToMap(bestAddr, size)
78
-            elif bestSize == size:
79
-                # print 'PERFECT MATCH (no split)', bestAddr, size
80
-                self.freelist.pop(bestIdx)
81
-                self.addToMap(bestAddr, size)
82
-            else:
83
-                abort('should never get here')
84
-            return (bestAddr, count)
85
-
86
-        # print '*** FAILED TO FIND A SPOT', size
87
-        return (-1, count)
88
-
89
-    def free(self, addr):
90
-        # simple back on end of list, no coalesce
91
-        if addr not in self.sizemap:
92
-            return -1
93
-            
94
-        size = self.sizemap[addr]
95
-        if self.returnPolicy == 'INSERT-BACK':
96
-            self.freelist.append((addr, size))
97
-        elif self.returnPolicy == 'INSERT-FRONT':
98
-            self.freelist.insert(0, (addr, size))
99
-        elif self.returnPolicy == 'ADDRSORT':
100
-            self.freelist.append((addr, size))
101
-            self.freelist = sorted(self.freelist, key=lambda e: e[0])
102
-        elif self.returnPolicy == 'SIZESORT+':
103
-            self.freelist.append((addr, size))
104
-            self.freelist = sorted(self.freelist, key=lambda e: e[1], reverse=False)
105
-        elif self.returnPolicy == 'SIZESORT-':
106
-            self.freelist.append((addr, size))
107
-            self.freelist = sorted(self.freelist, key=lambda e: e[1], reverse=True)
108
-
109
-        # not meant to be an efficient or realistic coalescing...
110
-        if self.coalesce == True:
111
-            self.newlist = []
112
-            self.curr    = self.freelist[0]
113
-            for i in range(1, len(self.freelist)):
114
-                eaddr, esize = self.freelist[i]
115
-                if eaddr == (self.curr[0] + self.curr[1]):
116
-                    self.curr = (self.curr[0], self.curr[1] + esize)
117
-                else:
118
-                    self.newlist.append(self.curr)
119
-                    self.curr = eaddr, esize
120
-            self.newlist.append(self.curr)
121
-            self.freelist = self.newlist
122
-            
123
-        del self.sizemap[addr]
124
-        return 0
125
-
126
-    def dump(self):
127
-        print 'Free List [ Size %d ]: ' % len(self.freelist), 
128
-        for e in self.freelist:
129
-            print '[ addr:%d sz:%d ]' % (e[0], e[1]),
130
-        print ''
131
-
132
-
133
-#
134
-# main program
135
-#
136
-parser = OptionParser()
137
-
138
-parser.add_option('-s', '--seed',        default=0,          help='the random seed',                             action='store', type='int',    dest='seed')
139
-parser.add_option('-S', '--size',        default=100,        help='size of the heap',                            action='store', type='int',    dest='heapSize') 
140
-parser.add_option('-b', '--baseAddr',    default=1000,       help='base address of heap',                        action='store', type='int',    dest='baseAddr') 
141
-parser.add_option('-H', '--headerSize',  default=0,          help='size of the header',                          action='store', type='int',    dest='headerSize')
142
-parser.add_option('-a', '--alignment',   default=-1,         help='align allocated units to size; -1->no align', action='store', type='int',    dest='alignment')
143
-parser.add_option('-p', '--policy',      default='BEST',     help='list search (BEST, WORST, FIRST)',            action='store', type='string', dest='policy') 
144
-parser.add_option('-l', '--listOrder',   default='ADDRSORT', help='list order (ADDRSORT, SIZESORT+, SIZESORT-, INSERT-FRONT, INSERT-BACK)', action='store', type='string', dest='order') 
145
-parser.add_option('-C', '--coalesce',    default=False,      help='coalesce the free list?',                     action='store_true',           dest='coalesce')
146
-parser.add_option('-n', '--numOps',      default=10,         help='number of random ops to generate',            action='store', type='int',    dest='opsNum')
147
-parser.add_option('-r', '--range',       default=10,         help='max alloc size',                              action='store', type='int',    dest='opsRange')
148
-parser.add_option('-P', '--percentAlloc',default=50,         help='percent of ops that are allocs',              action='store', type='int',    dest='opsPAlloc')
149
-parser.add_option('-A', '--allocList',   default='',         help='instead of random, list of ops (+10,-0,etc)', action='store', type='string', dest='opsList')
150
-parser.add_option('-c', '--compute',     default=False,      help='compute answers for me',                      action='store_true',           dest='solve')
151
-
152
-(options, args) = parser.parse_args()
153
-
154
-m = malloc(int(options.heapSize), int(options.baseAddr), int(options.headerSize),
155
-           options.policy, options.order, options.coalesce, options.alignment)
156
-
157
-print 'seed', options.seed
158
-print 'size', options.heapSize
159
-print 'baseAddr', options.baseAddr
160
-print 'headerSize', options.headerSize
161
-print 'alignment', options.alignment
162
-print 'policy', options.policy
163
-print 'listOrder', options.order
164
-print 'coalesce', options.coalesce
165
-print 'numOps', options.opsNum
166
-print 'range', options.opsRange
167
-print 'percentAlloc', options.opsPAlloc
168
-print 'allocList', options.opsList
169
-print 'compute', options.solve
170
-print ''
171
-
172
-percent = int(options.opsPAlloc) / 100.0
173
-
174
-random.seed(int(options.seed))
175
-p = {}
176
-L = []
177
-assert(percent > 0)
178
-
179
-if options.opsList == '':
180
-    c = 0
181
-    j = 0
182
-    while j < int(options.opsNum):
183
-        pr = False
184
-        if random.random() < percent:
185
-            size     = int(random.random() * int(options.opsRange)) + 1
186
-            ptr, cnt = m.malloc(size)
187
-            if ptr != -1:
188
-                p[c] = ptr
189
-                L.append(c)
190
-            print 'ptr[%d] = Alloc(%d)' % (c, size),
191
-            if options.solve == True:
192
-                print ' returned %d (searched %d elements)' % (ptr + options.headerSize, cnt)
193
-            else:
194
-                print ' returned ?'
195
-            c += 1
196
-            j += 1
197
-            pr = True
198
-        else:
199
-            if len(p) > 0:
200
-                # pick random one to delete
201
-                d = int(random.random() * len(L))
202
-                rc = m.free(p[L[d]])
203
-                print 'Free(ptr[%d])' % L[d], 
204
-                if options.solve == True:
205
-                    print 'returned %d' % rc
206
-                else:
207
-                    print 'returned ?'
208
-                del p[L[d]]
209
-                del L[d]
210
-                # print 'DEBUG p', p
211
-                # print 'DEBUG L', L
212
-                pr = True
213
-                j += 1
214
-        if pr:
215
-            if options.solve == True:
216
-                m.dump()
217
-            else:
218
-                print 'List? '
219
-            print ''
220
-else:
221
-    c = 0
222
-    for op in options.opsList.split(','):
223
-        if op[0] == '+':
224
-            # allocation!
225
-            size     = int(op.split('+')[1])
226
-            ptr, cnt = m.malloc(size)
227
-            if ptr != -1:
228
-                p[c] = ptr
229
-            print 'ptr[%d] = Alloc(%d)' % (c, size),
230
-            if options.solve == True:
231
-                print ' returned %d (searched %d elements)' % (ptr, cnt)
232
-            else:
233
-                print ' returned ?'
234
-            c += 1
235
-        elif op[0] == '-':
236
-            # free
237
-            index = int(op.split('-')[1])
238
-            if index >= len(p):
239
-                print 'Invalid Free: Skipping'
240
-                continue
241
-            print 'Free(ptr[%d])' % index, 
242
-            rc = m.free(p[index])
243
-            if options.solve == True:
244
-                print 'returned %d' % rc
245
-            else:
246
-                print 'returned ?'
247
-        else:
248
-            abort('badly specified operand: must be +Size or -Index')
249
-        if options.solve == True:
250
-            m.dump()
251
-        else:
252
-            print 'List?'
253
-        print ''

+ 0
- 14
hw3/simu4/ANSWERS.md 查看文件

@@ -1,14 +0,0 @@
1
-# Simulation 4 - Antworten
2
-
3
-1.1. Die Tabellengröße kann mit folgender Gleichung beschrieben werden: `T = a/P` mit `T` = Tabellengröße, `a` = Adressraumgröße und `P` = Seitengröße.
4
-
5
-1.2. Aus obiger Formel lässt sich schließen: Mit wachsendem Adressraum sollte die Tabellengröße mit gleichem Faktor wachsen, mit wachsender Seitengröße sollte die Tabellengröße mit gleichem Faktor sinken.
6
-
7
-1.3. Bei einem Kontextwechsel muss bei großer Seitengröße mehr geladen werden. Das benötigt Zeit.
8
-
9
-2. Je größer der Anteil der zum Adressraum zugeordneten Seiten wird, desto weniger Segmentation-Fehler treten auf.
10
-
11
-3. Der Parameter `-P 1m -a 256m -p 512m -v -s 3` ist unrealistisch, da eine Seitengröße von 1MB Größe viel zu groß ist, um praktikabel zu sein.
12
-
13
-4. Wenn der Adressraum größer als der physikalische Speicher ist, gibt das Programm eine Fehlermeldung aus.
14
-Weitere Fehler können manuell provoziert werden, wenn zum Beispiel eine negative Seitengröße (`math domain error`) oder die Seitengröße mit 0 angegeben werden (`float division by 0`). Auch beim angeben eines leeren Adressraums tritt ein Fehler auf (`must specify a non-zero address-space size`), genauso auch bei der physikalischen Speichergröße. Außerdem bekommt man einen Index-Fehler (`array index out of bounds`), wenn man eine sehr große (z.B. `2^31`) Seitengröße verwendet.

+ 0
- 69
hw3/simu4/QUESTIONS.md 查看文件

@@ -1,69 +0,0 @@
1
-# Questions 18-Paging-Linear-Translate
2
-
3
-In this simulation task, you will use a simple program, which is known as
4
-`paging-linear-translate.py`, to see if you understand how simple
5
-virtual-to-physical address translation works with linear page tables. See the
6
-README for details.
7
-
8
-## Questions
9
-
10
-1. Before doing any translations, let’s use the simulator to study how linear
11
-   page tables change size given different parameters. Compute the size of
12
-   linear page tables as different parameters change. Some suggested inputs are
13
-   below; by using the `-v` flag, you can see how many page-table entries are
14
-   filled.
15
-
16
-   First, to understand how linear page table size changes as the address space
17
-   grows:
18
-
19
-   ```text
20
-      paging-linear-translate.py -P 1k -a 1m -p 512m -v -n 0
21
-      paging-linear-translate.py -P 1k -a 2m -p 512m -v -n 0
22
-      paging-linear-translate.py -P 1k -a 4m -p 512m -v -n 0
23
-   ```
24
-
25
-   Then, to understand how linear page table size changes as page size grows:
26
-
27
-   ```text
28
-      paging-linear-translate.py -P 1k -a 1m -p 512m -v -n 0
29
-      paging-linear-translate.py -P 2k -a 1m -p 512m -v -n 0
30
-      paging-linear-translate.py -P 4k -a 1m -p 512m -v -n 0
31
-   ```
32
-
33
-   Before running any of these, try to think about the expected trends.
34
-
35
-    1.1. How can the page table size governed in equations? Give the equations to show, which parameters govern the page table size.
36
-
37
-    1.2. How should page-table size change as the address space grows? As the page size grows?
38
-
39
-    1.3. Why shouldn’t we just use really big pages in general?
40
-
41
-1. Now let’s do some translations. Start with some small examples, and change
42
-   the number of pages that are allocated to the address space with the `-u`
43
-   flag. For example:
44
-
45
-   ```text
46
-      paging-linear-translate.py -P 1k -a 16k -p 32k -v -u 0
47
-      paging-linear-translate.py -P 1k -a 16k -p 32k -v -u 25
48
-      paging-linear-translate.py -P 1k -a 16k -p 32k -v -u 50
49
-      paging-linear-translate.py -P 1k -a 16k -p 32k -v -u 75
50
-      paging-linear-translate.py -P 1k -a 16k -p 32k -v -u 100
51
-   ```
52
-
53
-   What happens as you increase the percentage of pages that are allocated in
54
-   each address space?
55
-
56
-1. Now let’s try some different random seeds, and some different (and sometimes
57
-   quite crazy) address-space parameters, for variety:
58
-
59
-   ```text
60
-      paging-linear-translate.py -P 8  -a 32   -p 1024 -v -s 1
61
-      paging-linear-translate.py -P 8k -a 32k  -p 1m   -v -s 2
62
-      paging-linear-translate.py -P 1m -a 256m -p 512m -v -s 3
63
-   ```
64
-
65
-   Which of these parameter combinations are unrealistic? Why?
66
-
67
-1. Use the program to try out some other problems. Can you find the limits of
68
-   where the program doesn’t work anymore? For example, what happens if the
69
-   address-space size is bigger than physical memory?

+ 0
- 135
hw3/simu4/README-paging-linear-translate.md 查看文件

@@ -1,135 +0,0 @@
1
-# README Paging: Linear-Translation
2
-
3
-In this homework, you will use a simple program, which is known as
4
-**paging-linear-translate.py**, to see if you understand how simple
5
-virtual-to-physical address translation works with linear page tables. To run
6
-the program, remember to either type just the name of the program
7
-(`./paging-linear-translate.py`) or possibly this (`python
8
-paging-linear-translate.py`). When you run it with the -h (help) flag, you see:
9
-
10
-```text
11
-Usage: paging-linear-translate.py [options]
12
-
13
-Options:
14
--h, --help              show this help message and exit
15
--s SEED, --seed=SEED    the random seed
16
--a ASIZE, --asize=ASIZE
17
-                        address space size (e.g., 16, 64k, ...)
18
--p PSIZE, --physmem=PSIZE
19
-                        physical memory size (e.g., 16, 64k, ...)
20
--P PAGESIZE, --pagesize=PAGESIZE
21
-                        page size (e.g., 4k, 8k, ...)
22
--n NUM, --addresses=NUM number of virtual addresses to generate
23
--u USED, --used=USED    percent of address space that is used
24
--v                      verbose mode
25
--c                      compute answers for me
26
-```
27
-
28
-First, run the program without any arguments:
29
-
30
-```text
31
-ARG seed 0
32
-ARG address space size 16k
33
-ARG phys mem size 64k
34
-ARG page size 4k
35
-ARG verbose False
36
-
37
-The format of the page table is simple:
38
-The high-order (left-most) bit is the VALID bit.
39
-  If the bit is 1, the rest of the entry is the PFN.
40
-  If the bit is 0, the page is not valid.
41
-Use verbose mode (-v) if you want to print the VPN # by
42
-each entry of the page table.
43
-
44
-Page Table (from entry 0 down to the max size)
45
-   0x8000000c
46
-   0x00000000
47
-   0x00000000
48
-   0x80000006
49
-
50
-Virtual Address Trace
51
-  VA  0: 0x00003229 (decimal:    12841) --> PA or invalid?
52
-  VA  1: 0x00001369 (decimal:     4969) --> PA or invalid?
53
-  VA  2: 0x00001e80 (decimal:     7808) --> PA or invalid?
54
-  VA  3: 0x00002556 (decimal:     9558) --> PA or invalid?
55
-  VA  4: 0x00003a1e (decimal:    14878) --> PA or invalid?
56
-
57
-For each virtual address, write down the physical address it
58
-translates to OR write down that it is an out-of-bounds
59
-address (e.g., a segmentation fault).
60
-```
61
-
62
-As you can see, what the program provides for you is a page table for a
63
-particular process (remember, in a real system with linear page tables, there is
64
-one page table per process; here we just focus on one process, its address
65
-space, and thus a single page table). The page table tells you, for each virtual
66
-page number (VPN) of the address space, that the virtual page is mapped to a
67
-particular physical frame number (PFN) and thus valid, or not valid.
68
-
69
-The format of the page-table entry is simple: the left-most (high-order) bit is
70
-the valid bit; the remaining bits, if valid is 1, is the PFN.
71
-
72
-In the example above, the page table maps VPN 0 to PFN 0xc (decimal 12), VPN 3
73
-to PFN 0x6 (decimal 6), and leaves the other two virtual pages, 1 and 2, as not
74
-valid.
75
-
76
-Because the page table is a linear array, what is printed above is a replica of
77
-what you would see in memory if you looked at the bits yourself. However, it is
78
-sometimes easier to use this simulator if you run with the verbose flag (-v);
79
-this flag also prints out the VPN (index) into the page table. From the example
80
-above, run with the -v flag:
81
-
82
-```text
83
-Page Table (from entry 0 down to the max size)
84
-  [       0]   0x8000000c
85
-  [       1]   0x00000000
86
-  [       2]   0x00000000
87
-  [       3]   0x80000006
88
-```
89
-
90
-Your job, then, is to use this page table to translate the virtual addresses
91
-given to you in the trace to physical addresses. Let's look at the first one: VA
92
-0x3229. To translate this virtual address into a physical address, we first have
93
-to break it up into its constituent components: a virtual page number and an
94
-offset. We do this by noting down the size of the address space and the page
95
-size. In this example, the address space is set to 16KB (a very small address
96
-space) and the page size is 4KB. Thus, we know that there are 14 bits in the
97
-virtual address, and that the offset is 12 bits, leaving 2 bits for the VPN.
98
-Thus, with our address 0x3229, which is binary 11 0010 0010 1001, we know the
99
-top two bits specify the VPN. Thus, 0x3229 is on virtual page 3 with an offset
100
-of 0x229.
101
-
102
-We next look in the page table to see if VPN 3 is valid and mapped to some
103
-physical frame or invalid, and we see that it is indeed valid (the high bit is 1
104
-) and mapped to physical page 6. Thus, we can form our final physical address by
105
-taking the physical page 6 and adding it onto the offset, as follows: 0x6000
106
-(the physical page, shifted into the proper spot) OR 0x0229 (the offset),
107
-yielding the final physical address: 0x6229. Thus, we can see that virtual
108
-address 0x3229 translates to physical address 0x6229 in this example.
109
-
110
-To see the rest of the solutions (after you have computed them yourself!), just
111
-run with the -c flag (as always):
112
-
113
-```text
114
-...
115
-VA  0: 00003229 (decimal: 12841) --> 00006229 (25129) [VPN 3]
116
-VA  1: 00001369 (decimal:  4969) --> Invalid (VPN 1 not valid)
117
-VA  2: 00001e80 (decimal:  7808) --> Invalid (VPN 1 not valid)
118
-VA  3: 00002556 (decimal:  9558) --> Invalid (VPN 2 not valid)
119
-VA  4: 00003a1e (decimal: 14878) --> 00006a1e (27166) [VPN 3]
120
-```
121
-
122
-Of course, you can change many of these parameters to make more interesting
123
-problems. Run the program with the -h flag to see what options there are:
124
-
125
-- The -s flag changes the random seed and thus generates different page table
126
-  values as well as different virtual addresses to translate.
127
-- The -a flag changes the size of the address space.
128
-- The -p flag changes the size of physical memory.
129
-- The -P flag changes the size of a page.
130
-- The -n flag can be used to generate more addresses to translate (instead of
131
-  the default 5).
132
-- The -u flag changes the fraction of mappings that are valid, from 0% (-u 0) up
133
-  to 100% (-u 100). The default is 50, which means that roughly 1/2 of the pages
134
-  in the virtual address space will be valid.
135
-- The -v flag prints out the VPN numbers to make your life easier.

+ 0
- 192
hw3/simu4/paging-linear-translate.py 查看文件

@@ -1,192 +0,0 @@
1
-#! /usr/bin/env python
2
-
3
-import sys
4
-from optparse import OptionParser
5
-import random
6
-import math
7
-
8
-def mustbepowerof2(bits, size, msg):
9
-    if math.pow(2,bits) != size:
10
-        print 'Error in argument: %s' % msg
11
-        sys.exit(1)
12
-
13
-def mustbemultipleof(bignum, num, msg):
14
-    if (int(float(bignum)/float(num)) != (int(bignum) / int(num))):
15
-        print 'Error in argument: %s' % msg
16
-        sys.exit(1)
17
-
18
-def convert(size):
19
-    length = len(size)
20
-    lastchar = size[length-1]
21
-    if (lastchar == 'k') or (lastchar == 'K'):
22
-        m = 1024
23
-        nsize = int(size[0:length-1]) * m
24
-    elif (lastchar == 'm') or (lastchar == 'M'):
25
-        m = 1024*1024
26
-        nsize = int(size[0:length-1]) * m
27
-    elif (lastchar == 'g') or (lastchar == 'G'):
28
-        m = 1024*1024*1024
29
-        nsize = int(size[0:length-1]) * m
30
-    else:
31
-        nsize = int(size)
32
-    return nsize
33
-
34
-
35
-#
36
-# main program
37
-#
38
-parser = OptionParser()
39
-parser.add_option('-A', '--addresses', default='-1',
40
-                  help='a set of comma-separated pages to access; -1 means randomly generate', 
41
-                  action='store', type='string', dest='addresses')
42
-parser.add_option('-s', '--seed',    default=0,     help='the random seed',                               action='store', type='int', dest='seed')
43
-parser.add_option('-a', '--asize',   default='16k', help='address space size (e.g., 16, 64k, 32m, 1g)',   action='store', type='string', dest='asize')
44
-parser.add_option('-p', '--physmem', default='64k', help='physical memory size (e.g., 16, 64k, 32m, 1g)', action='store', type='string', dest='psize')
45
-parser.add_option('-P', '--pagesize', default='4k', help='page size (e.g., 4k, 8k, whatever)',            action='store', type='string', dest='pagesize')
46
-parser.add_option('-n', '--numaddrs',  default=5,  help='number of virtual addresses to generate',       action='store', type='int', dest='num')
47
-parser.add_option('-u', '--used',       default=50, help='percent of virtual address space that is used', action='store', type='int', dest='used')
48
-parser.add_option('-v',                             help='verbose mode',                                  action='store_true', default=False, dest='verbose')
49
-parser.add_option('-c',                             help='compute answers for me',                        action='store_true', default=False, dest='solve')
50
-
51
-
52
-(options, args) = parser.parse_args()
53
-
54
-print 'ARG seed',               options.seed
55
-print 'ARG address space size', options.asize
56
-print 'ARG phys mem size',      options.psize
57
-print 'ARG page size',          options.pagesize
58
-print 'ARG verbose',            options.verbose
59
-print 'ARG addresses',          options.addresses
60
-print ''
61
-
62
-random.seed(options.seed)
63
-
64
-asize    = convert(options.asize)
65
-psize    = convert(options.psize)
66
-pagesize = convert(options.pagesize)
67
-addresses = str(options.addresses)
68
-
69
-if psize <= 1:
70
-    print 'Error: must specify a non-zero physical memory size.'
71
-    exit(1)
72
-
73
-if asize < 1:
74
-    print 'Error: must specify a non-zero address-space size.'
75
-    exit(1)
76
-
77
-if psize <= asize:
78
-    print 'Error: physical memory size must be GREATER than address space size (for this simulation)'
79
-    exit(1)
80
-
81
-if psize >= convert('1g') or asize >= convert('1g'):
82
-    print 'Error: must use smaller sizes (less than 1 GB) for this simulation.'
83
-    exit(1)
84
-
85
-mustbemultipleof(asize, pagesize, 'address space must be a multiple of the pagesize')
86
-mustbemultipleof(psize, pagesize, 'physical memory must be a multiple of the pagesize')
87
-
88
-# print some useful info, like the darn page table 
89
-pages = psize / pagesize;
90
-import array
91
-used = array.array('i')
92
-pt   = array.array('i')
93
-for i in range(0,pages):
94
-    used.insert(i,0)
95
-vpages = asize / pagesize
96
-
97
-# now, assign some pages of the VA
98
-vabits   = int(math.log(float(asize))/math.log(2.0))
99
-mustbepowerof2(vabits, asize, 'address space must be a power of 2')
100
-pagebits = int(math.log(float(pagesize))/math.log(2.0))
101
-mustbepowerof2(pagebits, pagesize, 'page size must be a power of 2')
102
-vpnbits  = vabits - pagebits
103
-pagemask = (1 << pagebits) - 1
104
-
105
-# import ctypes
106
-# vpnmask  = ctypes.c_uint32(~pagemask).value
107
-vpnmask = 0xFFFFFFFF & ~pagemask
108
-#if vpnmask2 != vpnmask:
109
-#    print 'ERROR'
110
-#    exit(1)
111
-# print 'va:%d page:%d vpn:%d -- %08x %08x' % (vabits, pagebits, vpnbits, vpnmask, pagemask)
112
-
113
-print ''
114
-print 'The format of the page table is simple:'
115
-print 'The high-order (left-most) bit is the VALID bit.'
116
-print '  If the bit is 1, the rest of the entry is the PFN.'
117
-print '  If the bit is 0, the page is not valid.'
118
-print 'Use verbose mode (-v) if you want to print the VPN # by'
119
-print 'each entry of the page table.'
120
-print ''
121
-
122
-print 'Page Table (from entry 0 down to the max size)'
123
-for v in range(0,vpages):
124
-    done = 0
125
-    while done == 0:
126
-        if ((random.random() * 100.0) > (100.0 - float(options.used))):
127
-            u = int(pages * random.random())
128
-            if used[u] == 0:
129
-                done = 1
130
-                # print '%8d - %d' % (v, u)
131
-                if options.verbose == True:
132
-                    print '  [%8d]  ' % v,
133
-                else:
134
-                    print '  ',
135
-                print '0x%08x' % (0x80000000 | u)
136
-                pt.insert(v,u)
137
-        else:
138
-            # print '%8d - not valid' % v
139
-            if options.verbose == True:
140
-                print '  [%8d]  ' % v,
141
-            else:
142
-                print '  ',
143
-            print '0x%08x' % 0
144
-            pt.insert(v,-1)
145
-            done = 1
146
-print ''            
147
-
148
-
149
-#
150
-# now, need to generate virtual address trace
151
-#
152
-
153
-addrList = []
154
-if addresses == '-1':
155
-    # need to generate addresses
156
-    for i in range(0, options.num):
157
-        n = int(asize * random.random())
158
-        addrList.append(n)
159
-else:
160
-    addrList = addresses.split(',')
161
-
162
-
163
-print 'Virtual Address Trace'
164
-for vStr in addrList:
165
-    # vaddr = int(asize * random.random())
166
-    vaddr = int(vStr)
167
-    if options.solve == False:
168
-        print '  VA 0x%08x (decimal: %8d) --> PA or invalid address?' % (vaddr, vaddr)
169
-    else:
170
-        paddr = 0
171
-        # split vaddr into VPN | offset
172
-        vpn = (vaddr & vpnmask) >> pagebits
173
-        if pt[vpn] < 0:
174
-            print '  VA 0x%08x (decimal: %8d) -->  Invalid (VPN %d not valid)' % (vaddr, vaddr, vpn)
175
-        else:
176
-            pfn    = pt[vpn]
177
-            offset = vaddr & pagemask
178
-            paddr  = (pfn << pagebits) | offset
179
-            print '  VA 0x%08x (decimal: %8d) --> %08x (decimal %8d) [VPN %d]' % (vaddr, vaddr, paddr, paddr, vpn)
180
-print ''
181
-
182
-if options.solve == False:
183
-    print 'For each virtual address, write down the physical address it translates to'
184
-    print 'OR write down that it is an out-of-bounds address (e.g., segfault).'
185
-    print ''
186
-
187
-
188
-
189
-
190
-
191
-
192
-

+ 0
- 28
hw4/README.md 查看文件

@@ -1,28 +0,0 @@
1
-# hw4
2
-
3
-To fulfill **hw4** you have to solve:
4
-
5
-- task1
6
-- simu1
7
-- simu2
8
-- simu3
9
-
10
-Optional are (bonus +2P):
11
-
12
-- task2 (Homework in OSTEP Chapter 19 in **Rust**)
13
-
14
-## Pull-Reuest
15
-
16
-Please merge any accepted reviews into your branch. If you are ready with the homework, all tests run, please create a pull request named **hw4**.
17
-
18
-## Credits for hw4
19
-
20
-| Task     | max. Credits | Comment |
21
-| -------- | ------------ | ------- |
22
-| task1    | 2            |         |
23
-| simu1    | 0.5          |         |
24
-| simu2    | 1            |         |
25
-| simu3    | 0.5          |         |
26
-| task2    | +2           |         |
27
-| Deadline | +1           |         |
28
-| =        | 7            |         |

+ 0
- 39
hw4/simu1/ANSWERS.md 查看文件

@@ -1,39 +0,0 @@
1
-# hw4 - Simulation 1 - Lösungen
2
-
3
-### Warmup
4
-
5
-`0x611c` =>
6
-
7
-`0110 0001 0001 1100` =>
8
-
9
-| Valid | PDE | PTE | Offset |
10
-|-------|-----|-----|--------|
11
-|0      |11000|01000|11100   |
12
-| False | 24  | 8   | 28     |
13
-
14
-PDE at index 24:
15
-
16
-> page 108: 83 [...] e9 **a1** e8 [...] ff
17
-
18
-
19
-
20
-`0xa1` => `1010 0001` => `1 | 0100001` => Valid | 33
21
-
22
-PTE at index 8 in page 33 (found in PDE):
23
-
24
-> page 33: 7f [...] 7f **b5** 7f [...] 7f
25
-
26
-
27
-`0xb5` => `1011 0101` => `1 | 0110101` => Valid | 53
28
-
29
-Final Value is in page `0xb5` (53) with offset 28 => 0x08 (8).
30
-
31
-
32
-
33
-### Aufgaben
34
-
35
-1. Für eine zweistufige Seitentabelle benötigt man ein Register, für eine dreistufige Seitentabelle bräuchte man ein zweites PDBR.
36
-
37
-2. Da es sich bei dieser Simulation um eine zweistufige Seitentabelle handelt, gibt es eine Referenz für den PDE, eine für den PTE und schlussendlich noch eine dritte Referenz, in der das Endergebnis steht.
38
-
39
-3. Da der Cache nicht im Voraus weiß, auf welche Adresse nach der Übersetzung des PDE bzw. PTE zugegriffen wird, müssen danach erst wieder Daten in den Cache geladen werden. Dies führt zu einer Reihe von Cache Misses.

+ 0
- 12
hw4/simu1/QUESTIONS.md 查看文件

@@ -1,12 +0,0 @@
1
-# Questions 20-paging-multilevel-translate
2
-
3
-This fun little homework tests if you understand how a multi-level page table works. And yes, there is some debate over the use of the term “fun” in the previous sentence. The program is called, perhaps unsurprisingly: `paging-multilevel-translate.py`; see the README for details.
4
-Questions
5
-
6
-## Questions
7
-
8
-1. With a linear page table, you need a single register to locate the page table, assuming that hardware does the lookup upon a TLB miss. How many registers do you need to locate a two-level page table? A three-level table?
9
-
10
-1. Use the simulator to perform translations given random seeds 0, 1, and 2, and check your answers using the -c flag. How many memory references are needed to perform each lookup?
11
-
12
-1. Given your understanding of how cache memory works, how do you think memory references to the page table will behave in the cache? Will they lead to lots of cache hits (and thus fast accesses?) Or lots of misses (and thus slow accesses)? Explain your answer in detail!

+ 0
- 80
hw4/simu1/README-paging-multilevel-translate.md 查看文件

@@ -1,80 +0,0 @@
1
-# README Paging: Multilevel Translate
2
-
3
-This fun little homework tests if you understand how a multi-level page table
4
-works. And yes, there is some debate over the use of the term fun in the
5
-previous sentence. The program is called: `paging-multilevel-translate.py`
6
-
7
-Some basic assumptions:
8
-
9
-- The page size is an unrealistically-small 32 bytes
10
-- The virtual address space for the process in question (assume there is only
11
-  one) is 1024 pages, or 32 KB
12
-- physical memory consists of 128 pages
13
-
14
-Thus, a virtual address needs 15 bits (5 for the offset, 10 for the VPN). A
15
-physical address requires 12 bits (5 offset, 7 for the PFN).
16
-
17
-The system assumes a multi-level page table. Thus, the upper five bits of a
18
-virtual address are used to index into a page directory; the page directory
19
-entry (PDE), if valid, points to a page of the page table. Each page table page
20
-holds 32 page-table entries (PTEs). Each PTE, if valid, holds the desired
21
-translation (physical frame number, or PFN) of the virtual page in question.
22
-
23
-The format of a PTE is thus:
24
-
25
-```text
26
-  VALID | PFN6 ... PFN0
27
-```
28
-
29
-and is thus 8 bits or 1 byte.
30
-
31
-The format of a PDE is essentially identical:
32
-
33
-```text
34
-  VALID | PT6 ... PT0
35
-```
36
-
37
-You are given two pieces of information to begin with.
38
-
39
-First, you are given the value of the page directory base register (PDBR), which
40
-tells you which page the page directory is located upon.
41
-
42
-Second, you are given a complete dump of each page of memory. A page dump looks
43
-like this:
44
-
45
-```text
46
-    page 0: 08 00 01 15 11 1d 1d 1c 01 17 15 14 16 1b 13 0b ...
47
-    page 1: 19 05 1e 13 02 16 1e 0c 15 09 06 16 00 19 10 03 ...
48
-    page 2: 1d 07 11 1b 12 05 07 1e 09 1a 18 17 16 18 1a 01 ...
49
-    ...
50
-```
51
-
52
-which shows the 32 bytes found on pages 0, 1, 2, and so forth. The first byte
53
-(0th byte) on page 0 has the value 0x08, the second is 0x00, the third 0x01, and
54
-so forth.
55
-
56
-You are then given a list of virtual addresses to translate.
57
-
58
-Use the PDBR to find the relevant page table entries for this virtual page. Then
59
-find if it is valid. If so, use the translation to form a final physical
60
-address. Using this address, you can find the VALUE that the memory reference is
61
-looking for.
62
-
63
-Of course, the virtual address may not be valid and thus generate a fault.
64
-
65
-Some useful options:
66
-
67
-- Change the seed to get different problems, as always:
68
-  ```text
69
-    -s SEED, --seed=SEED       the random seed
70
-  ```
71
-
72
-- Change the number of virtual addresses generated to do more translations for a given memory dump.
73
-  ```text
74
-    -n NUM, --addresses=NUM    number of virtual addresses to generate
75
-  ```
76
-
77
-- Use -c (or --solve) to show the solutions.
78
-  ```text
79
-    -c, --solve                compute answers for me
80
-  ```

+ 0
- 265
hw4/simu1/paging-multilevel-translate.py 查看文件

@@ -1,265 +0,0 @@
1
-#! /usr/bin/env python
2
-
3
-import sys
4
-from optparse import OptionParser
5
-import random
6
-import math
7
-
8
-def convert(size):
9
-    length = len(size)
10
-    lastchar = size[length-1]
11
-    if (lastchar == 'k') or (lastchar == 'K'):
12
-        m = 1024
13
-        nsize = int(size[0:length-1]) * m
14
-    elif (lastchar == 'm') or (lastchar == 'M'):
15
-        m = 1024*1024
16
-        nsize = int(size[0:length-1]) * m
17
-    elif (lastchar == 'g') or (lastchar == 'G'):
18
-        m = 1024*1024*1024
19
-        nsize = int(size[0:length-1]) * m
20
-    else:
21
-        nsize = int(size)
22
-    return nsize
23
-
24
-def roundup(size):
25
-    value = 1.0
26
-    while value < size:
27
-        value = value * 2.0
28
-    return value
29
-
30
-    
31
-class OS:
32
-    def __init__(self):
33
-        # 4k phys memory (128 pages)
34
-        self.pageSize  = 32
35
-        self.physPages = 128
36
-        self.physMem   = self.pageSize * self.physPages
37
-        self.vaPages   = 1024
38
-        self.vaSize    = self.pageSize * self.vaPages
39
-        self.pteSize   = 1
40
-        self.pageBits  = 5 # log of page size
41
-
42
-        # os tracks
43
-        self.usedPages      = []
44
-        self.usedPagesCount = 0
45
-        self.maxPageCount   = self.physMem / self.pageSize
46
-
47
-        # no pages used (yet)
48
-        for i in range(0, self.maxPageCount):
49
-            self.usedPages.append(0)
50
-
51
-        # set contents of memory to 0, too
52
-        self.memory = []
53
-        for i in range(0, self.physMem):
54
-            self.memory.append(0)
55
-
56
-        # associative array of pdbr's (indexed by PID)
57
-        self.pdbr = {}
58
-
59
-        # mask is 11111 00000 00000 --> 0111 1100 0000 0000 
60
-        self.PDE_MASK    = 0x7c00
61
-        self.PDE_SHIFT   = 10
62
-
63
-        # 00000 11111 00000 -> 000 0011 1110 0000
64
-        self.PTE_MASK    = 0x03e0
65
-        self.PTE_SHIFT   = 5
66
-
67
-        self.VPN_MASK    = self.PDE_MASK | self.PTE_MASK
68
-        self.VPN_SHIFT   = self.PTE_SHIFT
69
-
70
-        # grabs the last five bits of a virtual address
71
-        self.OFFSET_MASK = 0x1f
72
-
73
-    def findFree(self):
74
-        assert(self.usedPagesCount < self.maxPageCount)
75
-        look = int(random.random() * self.maxPageCount)
76
-        while self.usedPages[look] == 1:
77
-            look = int(random.random() * self.maxPageCount)
78
-        self.usedPagesCount = self.usedPagesCount + 1
79
-        self.usedPages[look] = 1
80
-        return look
81
-
82
-    def initPageDir(self, whichPage):
83
-        whichByte = whichPage << self.pageBits
84
-        for i in range(whichByte, whichByte + self.pageSize):
85
-            self.memory[i] = 0x7f
86
-
87
-    def initPageTablePage(self, whichPage):
88
-        self.initPageDir(whichPage)
89
-
90
-    def getPageTableEntry(self, virtualAddr, ptePage, printStuff):
91
-        pteBits = (virtualAddr & self.PTE_MASK) >> self.PTE_SHIFT
92
-        pteAddr = (ptePage << self.pageBits) | pteBits
93
-        pte     = self.memory[pteAddr]
94
-        valid   = (pte & 0x80) >> 7
95
-        pfn     = (pte & 0x7f)
96
-        if printStuff == True:
97
-            print '    --> pte index:0x%x [decimal %d] pte contents:0x%x (valid %d, pfn 0x%02x [decimal %d])' % \
98
-                  (pteBits, pteBits, pte, valid, pfn, pfn)
99
-        return (valid, pfn, pteAddr)
100
-
101
-    def getPageDirEntry(self, pid, virtualAddr, printStuff):
102
-        pageDir = self.pdbr[pid]
103
-        pdeBits = (virtualAddr & self.PDE_MASK) >> self.PDE_SHIFT
104
-        pdeAddr = (pageDir << self.pageBits) | pdeBits
105
-        pde     = self.memory[pdeAddr]
106
-        valid   = (pde & 0x80) >> 7
107
-        ptPtr   = (pde & 0x7f)
108
-        if printStuff == True:
109
-            print '  --> pde index:0x%x [decimal %d] pde contents:0x%x (valid %d, pfn 0x%02x [decimal %d])' % \
110
-                  (pdeBits, pdeBits, pde, valid, ptPtr, ptPtr)
111
-        return (valid, ptPtr, pdeAddr)
112
-
113
-    def setPageTableEntry(self, pteAddr, physicalPage):
114
-        self.memory[pteAddr] = 0x80 | physicalPage
115
-
116
-    def setPageDirEntry(self, pdeAddr, physicalPage):
117
-        self.memory[pdeAddr] = 0x80 | physicalPage
118
-        
119
-    def allocVirtualPage(self, pid, virtualPage, physicalPage):
120
-        # make it into a virtual address, as everything uses this (and not VPN)
121
-        virtualAddr = virtualPage << self.pageBits
122
-        (valid, ptPtr, pdeAddr) = self.getPageDirEntry(pid, virtualAddr, False)
123
-        if valid == 0:
124
-            # must allocate a page of the page table now, and have the PD point to it
125
-            assert(ptPtr == 127)
126
-            ptePage = self.findFree()
127
-            self.setPageDirEntry(pdeAddr, ptePage)
128
-            self.initPageTablePage(ptePage)
129
-        else:
130
-            # otherwise, just extract page number of page table page
131
-            ptePage = ptPtr
132
-        # now, look up page table entry too, and mark it valid and fill in translation
133
-        (valid, pfn, pteAddr) = self.getPageTableEntry(virtualAddr, ptePage, False)
134
-        assert(valid == 0)
135
-        assert(pfn == 127)
136
-        self.setPageTableEntry(pteAddr, physicalPage)
137
-
138
-    # -2 -> PTE fault, -1 means PDE fault
139
-    def translate(self, pid, virtualAddr):
140
-        (valid, ptPtr, pdeAddr) = self.getPageDirEntry(pid, virtualAddr, True)
141
-        if valid == 1:
142
-            ptePage = ptPtr
143
-            (valid, pfn, pteAddr) = self.getPageTableEntry(virtualAddr, ptePage, True)
144
-            if valid == 1:
145
-                offset = (virtualAddr & self.OFFSET_MASK)
146
-                paddr  = (pfn << self.pageBits) | offset
147
-		# print '     --> pfn: %02x  offset: %x' % (pfn, offset)
148
-                return paddr
149
-            else:
150
-                return -2
151
-        return -1
152
-
153
-    def fillPage(self, whichPage):
154
-        for j in range(0, self.pageSize):
155
-            self.memory[(whichPage * self.pageSize) + j] = int(random.random() * 31)
156
-
157
-    def procAlloc(self, pid, numPages):
158
-        # need a PDBR: find one somewhere in memory
159
-        pageDir = self.findFree()
160
-        # print '**ALLOCATE** page dir', pageDir
161
-        self.pdbr[pid] = pageDir
162
-        self.initPageDir(pageDir)
163
-
164
-        used = {}
165
-        for vp in range(0, self.vaPages):
166
-            used[vp] = 0
167
-        allocatedVPs = []
168
-        
169
-        for vp in range(0, numPages):
170
-            vp = int(random.random() * self.vaPages)
171
-            while used[vp] == 1:
172
-                vp = int(random.random() * self.vaPages)
173
-            assert(used[vp] == 0)
174
-            used[vp] = 1
175
-            allocatedVPs.append(vp)
176
-            pp = self.findFree()
177
-            # print '**ALLOCATE** page', pp
178
-            # print '  trying to map vp:%08x to pp:%08x' % (vp, pp)
179
-            self.allocVirtualPage(pid, vp, pp)
180
-            self.fillPage(pp)
181
-        return allocatedVPs
182
-
183
-    def dumpPage(self, whichPage):
184
-        i = whichPage
185
-        for j in range(0, self.pageSize):
186
-            print self.memory[(i * self.pageSize) + j],
187
-        print ''
188
-
189
-    def memoryDump(self):
190
-        for i in range(0, self.physMem / self.pageSize):
191
-            print 'page %3d:' %  i, 
192
-            for j in range(0, self.pageSize):
193
-                print '%02x' % self.memory[(i * self.pageSize) + j],
194
-            print ''
195
-
196
-    def getPDBR(self, pid):
197
-        return self.pdbr[pid]
198
-
199
-    def getValue(self, addr):
200
-        return self.memory[addr]
201
-
202
-# allocate some processes in memory
203
-# allocate some multi-level page tables in memory
204
-# make a bit of a mystery:
205
-# can examine PDBR (PFN of current proc's page directory)
206
-# can examine contents of any page
207
-# fill pages with values too
208
-# ask: when given
209
-#   LOAD VA, R1
210
-# what will final value will be loaded into R1?
211
-
212
-#
213
-# main program
214
-#
215
-parser = OptionParser()
216
-parser.add_option('-s', '--seed', default=0, help='the random seed', action='store', type='int', dest='seed')
217
-parser.add_option('-a', '--allocated', default=64, help='number of virtual pages allocated',
218
-                  action='store', type='int', dest='allocated')
219
-parser.add_option('-n', '--addresses', default=10, help='number of virtual addresses to generate',
220
-                  action='store', type='int', dest='num')
221
-parser.add_option('-c', '--solve', help='compute answers for me', action='store_true', default=False, dest='solve')
222
-
223
-
224
-(options, args) = parser.parse_args()
225
-
226
-print 'ARG seed', options.seed
227
-print 'ARG allocated',  options.allocated
228
-print 'ARG num',  options.num
229
-print ""
230
-
231
-random.seed(options.seed)
232
-
233
-# do the work now
234
-os = OS()
235
-used = os.procAlloc(1, options.allocated)
236
-
237
-os.memoryDump()
238
-
239
-print '\nPDBR:', os.getPDBR(1), ' (decimal) [This means the page directory is held in this page]\n'
240
-
241
-for i in range(0, options.num):
242
-    if (random.random() * 100) > 50.0 or i >= len(used):
243
-        vaddr = int(random.random() * 1024 * 32)
244
-    else:
245
-        vaddr = (used[i] << 5) | int(random.random() * 32)
246
-    if options.solve == True:
247
-        print 'Virtual Address %04x:' % vaddr
248
-        r = os.translate(1, vaddr)
249
-        if r > -1:
250
-            print '      --> Translates to Physical Address 0x%03x --> Value: %02x' % (r, os.getValue(r))
251
-        elif r == -1:
252
-            print '      --> Fault (page directory entry not valid)'
253
-        else:
254
-            print '      --> Fault (page table entry not valid)'
255
-    else:
256
-        print 'Virtual Address %04x: Translates To What Physical Address (And Fetches what Value)? Or Fault?' % vaddr
257
-
258
-print ''
259
-
260
-exit(0)
261
-
262
-
263
-
264
-
265
-

+ 0
- 31
hw4/simu2/ANSWERS.md 查看文件

@@ -1,31 +0,0 @@
1
-
2
-# Simulation 2 - Antworten
3
-
4
-Diese Simulation wurde auf einem Laptop mit 8GB RAM, einer 8GB swapfile und 4 Prozessorkernen ausgeführt.
5
-
6
-
7
-1. Wenn man *mem* mit auch nur mit 1 MB Speicher aufruft, dann geht die CPU Auslastung eines Kerns auf 100%. Im Idle Zustand war die user-time bei ~1%. Bei nur einem laufenden mem-Programm betrug die user-time ~25%. Bei 3 laufenden Instanzen waren es ~80% und bei 4 ~99% user-time.
8
-
9
-   Das klingt absolut logisch, da der Prozessor des Systems 4 Kerne hat. Denn wenn auf jedem Kern ein mem-Programm läuft, dann hat das Bertriessystem keinen eigenen Kern und die prozentuale sys-time wird winzig.
10
-
11
-2. Direkt nach dem Ausführen von ./mem 1024 hat sich der freie Speicher um ~1.050.000 Byte verringert und die Spalte swpd hat sich nicht verändert, sondern blieb auf 0. Sobald wir das mem-Programm (mit Ctrl-C) beendet haben, ist der freie Speicher (free) fast wieder auf den Urprungswert gesprungen.
12
-
13
-   Es fehlten ~250 Byte. Der freie Speicher hat sich danach also verkleinert. Auf der Workstation wurde bereits bei 1024 Byte *geswapped* und der freie Speicher war nach dem Beenden des Programms größer.
14
-
15
-3. Bei ./mem 4000 gab es auf dem Rechner (mit 8GB RAM) absolut kein swap-in / swap-out. Es sei denn, der freie Speicher von den gesamten 8GB war kleiner als die ~4GB. Unter normaler Last war erst bei ./mem 7000 ein deutlicher swap-in und -out sichtbar.
16
-
17
-   Bei jedem der Werte war jedoch der erste *loop* immer langsamer. Durschnittlich war er oft ~50% langsamer. Im ersten Loop werden 6x durchschnittlich 244.000 Byte in den Swap geschrieben (swap-out). Das ergibt die ~1.700.000 bei (swpd). Es werden bei ./mem 7000 ~5.400.000 Bytes in den physikalischen Speicher ausgelagert und insgesamt ~1.700.000 in den Swap. Das sind zusammen ungefähr die angeforderten 7 GB.
18
-   
19
-   In den folgenden Loops fand kaum noch ein swap-out statt (durchschnittlich ~0 Byte), dafür aber Rückschrieb von Swap in den RAM (swap-in).
20
-
21
-4. Die CPU Auslastung durch das mem-Programm ist immens. Wenn man es auf dem Laptop ausführt, drehen direkt die Lüfter hoch. Doch wie zu erwarten und im Quellcode zu sehen, ist das C-Programm nicht *multi-threaded*. In einem beliebigen System Monitor (z.B. htop) sieht man, dass nur ein Kern ausgelastet ist.
22
-
23
-   Im ersten Loop entsprechen die Werte von **swap-out** ungefähr den den Werten von **block-out**, aber es finden auch **block-in**s im ähnlichen Werteberich statt.
24
-
25
-5. Bei 4000 Byte braucht der erste loop 1070 ms und alle restlichen 745ms
26
-
27
-   Da bereits beim Aufruf von ./mem 8192 ein Segmentation Fault auftritt, war es nicht möglich über die Grenze des physikalischen 8GB Speichers (8192 kByte) zu gehen. Der Rest dieser Aufgabe ist also nicht wirklich beantwortbar.
28
-
29
-   Bei ./mem 8191 muss allerdings auch schon massiv *geswapped* werden. Der erste Loop braucht 6 Sekunden und die folgenden mehr als 60 Sekunden. Die Bandbreite in Loop 0 war noch bei 1317 MB/s in Loop 1 schon 128 MB/s und in den folgenden Loops ~110 MB/s. Man merkt dass nun die Festplatte der *bottleneck* ist, da das Programm kaum noch CPU Leistung benötigt.
30
-
31
-6. Bei 14584 schlägt die Speicheralloziierung fehl.

+ 0
- 6
hw4/simu2/Makefile 查看文件

@@ -1,6 +0,0 @@
1
-
2
-all: mem
3
-
4
-mem: mem.c
5
-	gcc -o mem mem.c -Wall -O
6
-

+ 0
- 21
hw4/simu2/QUESTIONS.md 查看文件

@@ -1,21 +0,0 @@
1
-# Questions 21-Physical-Memory-Mechanisms
2
-
3
-This homework introduces you to a new tool, **vmstat**, and how it can be used to get a sense of what your computer is doing with regards to memory, CPU, and I/O usage (with a focus on memory and swapping).
4
-
5
-Read the associated README and examine the code in mem.c before proceeding to the exercises and questions below.
6
-
7
-## Questions
8
-
9
-1. First, open two separate terminal connections to the same machine, so that you can easily run something in one window and the other. Now, in one window, run `vmstat 1`, which shows statistics about machine usage every second. Read the man page, the associated README, and any other information you need so that you can understand its output. Leave this window running **vmstat** for the rest of the exercises below.
10
-
11
-   Now, we will run the program `mem.c` but with very little memory usage. This can be accomplished by typing `./mem 1` (which uses only 1 MB of memory). How do the CPU usage statistics change when running mem? Do the numbers in the user time column make sense? How does this change when running more than one instance of mem at once?
12
-
13
-2. Let’s now start looking at some of the memory statistics while running mem. We’ll focus on two columns: swpd (the amount of virtual memory used) and free (the amount of idle memory). Run `./mem 1024` (which allocates 1024 MB) and watch how these values change. Then kill the running program (by typing control-c) and watch again how the values change. What do you notice about the values? In particular, how does the free column change when the program exits? Does the amount of free memory increase by the expected amount when mem exits?
14
-
15
-3. We’ll next look at the swap columns (si and so), which indicate how much swapping is taking place to and from the disk. Of course, to activate these, you’ll need to run mem with large amounts of memory. First, examine how much free memory is on your Linux system (for example, by typing cat `/proc/meminfo`; type **man proc** for details on the */proc* file system and the types of information you can find there). One of the first entries in `/proc/meminfo` is the total amount of memory in your system. Let’s assume it’s something like 8 GB of memory; if so, start by running mem 4000 (about 4 GB) and watching the swap in/out columns. Do they ever give non-zero values? Then, try with 5000, 6000, etc. What happens to these values as the program enters the second loop (and beyond), as compared to the first loop? How much data (total) are swapped in and out during the second, third, and subsequent loops? (do the numbers make sense?)
16
-
17
-4. Do the same experiments as above, but now watch the other statistics (such as CPU utilization, and block I/O statistics). How do they change when mem is running?
18
-
19
-5. Now let’s examine performance. Pick an input for mem that comfortably fits in memory (say 4000 if the amount of memory on the system is 8 GB). How long does loop 0 take (and subsequent loops 1, 2, etc.)? Now pick a size comfortably beyond the size of memory (say 12000 again assuming 8 GB of memory). How long do the loops take here? How do the bandwidth numbers compare? How different is performance when constantly swapping versus fitting everything comfortably in memory? Can you make a graph, with the size of memory used by mem on the x-axis, and the bandwidth of accessing said memory on the y-axis? Finally, how does the performance of the first loop compare to that of subsequent loops, for both the case where everything fits in memory and where it doesn’t?
20
-
21
-6. Swap space isn’t infinite. You can use the tool **/sbin/swapon** with the -s flag to see how much swap space is available. What happens if you try to run mem with increasingly large values, beyond what seems to be available in swap? At what point does the memory allocation fail?

+ 0
- 92
hw4/simu2/README-mem-vmstat.md 查看文件

@@ -1,92 +0,0 @@
1
-# README
2
-
3
-In this homework, you'll be investigating swap performance with a simple
4
-program found in `mem.c. The program is really simple: it just allocates an
5
-array of integers of a certain size, and then proceeds to loop through it
6
-(repeatedly), incrementing each value in the array.
7
-
8
-Type "make" to build it (and look at the file Makefile for details about how
9
-the build works).
10
-
11
-Then, type "./mem" followed by a number to run it. The number is the size (in
12
-MB) of the array. Thus, to run with a small array (size 1 MB):
13
-
14
-```text
15
-prompt> ./mem 1
16
-```
17
-
18
-and to run with a larger array (size 1 GB):
19
-
20
-```text
21
-prompt> ./mem 1024
22
-```
23
-
24
-The program prints out the time it takes to go through each loop as well as
25
-the bandwidth (in MB/s). Bandwidth is particularly interesting to know as it
26
-gives you a sense of how fast the system you're using can move through data;
27
-on modern systems, this is likely in the GB/s range.
28
-
29
-Here is what the output looks like for a typical run:
30
-
31
-```text
32
-prompt> ./mem 1000
33
-allocating 1048576000 bytes (1000.00 MB)
34
-  number of integers in array: 262144000
35
-loop 0 in 448.11 ms (bandwidth: 2231.61 MB/s)
36
-loop 1 in 345.38 ms (bandwidth: 2895.38 MB/s)
37
-loop 2 in 345.18 ms (bandwidth: 2897.07 MB/s)
38
-loop 3 in 345.23 ms (bandwidth: 2896.61 MB/s)
39
-^C
40
-prompt>
41
-```
42
-
43
-The program first tells you how much memory it allocated (in bytes, MB, and in
44
-the number of integers), and then starts looping through the array. The first
45
-loop (in the example above) took 448 milliseconds; because the program
46
-accessed the 1000 MB in just under half a second, the computed bandwidth is
47
-(not surprisingly) just over 2000 MB/s.
48
-
49
-The program continues by doing the same thing over and over, for loops 1, 2,
50
-etc.
51
-
52
-Important: to stop the program, you must kill it. This task is accomplished on
53
-Linux (and all Unix-based systems) by typing control-C (^C) as shown above.
54
-
55
-Note that when you run with small array sizes, each loop's performance numbers
56
-won't be printed. For example:
57
-
58
-```text
59
-prompt>  ./mem 1
60
-allocating 1048576 bytes (1.00 MB)
61
-  number of integers in array: 262144
62
-loop 0 in 0.71 ms (bandwidth: 1414.61 MB/s)
63
-loop 607 in 0.33 ms (bandwidth: 3039.35 MB/s)
64
-loop 1215 in 0.33 ms (bandwidth: 3030.57 MB/s)
65
-loop 1823 in 0.33 ms (bandwidth: 3039.35 MB/s)
66
-^C
67
-prompt>
68
-```
69
-
70
-In this case, the program only prints out a sample of outputs, so as not to
71
-flood the screen with too much output.
72
-
73
-The code itself is simple to understand. The first important part is a memory
74
-allocation:
75
-
76
-```c
77
-    // the big memory allocation happens here
78
-    int *x = malloc(size_in_bytes);
79
-```
80
-
81
-Then, the main loop begins:
82
-
83
-```c
84
-    while (1) {
85
-	x[i++] += 1; // main work of loop done here.
86
-```
87
-
88
-The rest is just timing and printing out information. See mem.c for details.
89
-
90
-Much of the homework revolves around using the tool vmstat to monitor what is
91
-happening with the system. Read the vmstat man page (type "man vmstat") for
92
-details on how it works, and what each column of output means.

+ 0
- 67
hw4/simu2/mem.c 查看文件

@@ -1,67 +0,0 @@
1
-#include <stdio.h>
2
-#include <stdlib.h>
3
-#include <string.h>
4
-#include <assert.h>
5
-#include <sys/time.h>
6
-
7
-// Simple routine to return absolute time (in seconds).
8
-double Time_GetSeconds() {
9
-    struct timeval t;
10
-    int rc = gettimeofday(&t, NULL);
11
-    assert(rc == 0);
12
-    return (double) ((double)t.tv_sec + (double)t.tv_usec / 1e6);
13
-}
14
-
15
-// Program that allocates an array of ints of certain size,
16
-// and then proceeeds to update each int in a loop, forever.
17
-int main(int argc, char *argv[]) {
18
-    if (argc != 2) {
19
-	fprintf(stderr, "usage: spin <memory (MB)>\n");
20
-	exit(1);
21
-    }
22
-    long long int size = (long long int) atoi(argv[1]);
23
-    long long int size_in_bytes = size * 1024 * 1024;
24
-
25
-    printf("allocating %lld bytes (%.2f MB)\n", 
26
-	   size_in_bytes, size_in_bytes / (1024 * 1024.0));
27
-
28
-    // the big memory allocation happens here
29
-    int *x = malloc(size_in_bytes);
30
-    if (x == NULL) {
31
-	fprintf(stderr, "memory allocation failed\n");
32
-	exit(1);
33
-    }
34
-
35
-    long long int num_ints = size_in_bytes / sizeof(int);
36
-    printf("  number of integers in array: %lld\n", num_ints);
37
-
38
-    // now the main loop: each time through, touch each integer
39
-    // (and increment its value by 1).
40
-    int i = 0;
41
-    double time_since_last_print = 2.0; 
42
-    double t = Time_GetSeconds();
43
-    int loop_count = 0;
44
-    while (1) {
45
-	x[i++] += 1; // main work of loop done here.
46
-
47
-	// if we've gone through the whole loop, reset a bunch of stuff
48
-	// and then (perhaps) print out some statistics. 
49
-	if (i == num_ints) {
50
-	    double delta_time = Time_GetSeconds() - t;
51
-	    time_since_last_print += delta_time;
52
-	    if (time_since_last_print >= 0.2) { // only print every .2 seconds
53
-		printf("loop %d in %.2f ms (bandwidth: %.2f MB/s)\n", 
54
-		       loop_count, 1000 * delta_time, 
55
-		       size_in_bytes / (1024.0*1024.0*delta_time));
56
-		time_since_last_print = 0;
57
-	    }
58
-
59
-	    i = 0;
60
-	    t = Time_GetSeconds();
61
-	    loop_count++;
62
-	}
63
-    }
64
-
65
-    return 0;
66
-}
67
-

+ 0
- 18
hw4/simu3/ANSWERS.md 查看文件

@@ -1,18 +0,0 @@
1
-# hw4 - Simulation 3 - Antworten
2
-
3
-1.
4
-    1. FIFO: Da immer das älteste Element aus dem Cache geworfen wird, verursacht `1,2,3,4,5,6,1,2,...` ausschließlich Cache-Misses.
5
-    2. LRU: Nun wird immer das am längsten nicht getroffene Element aus dem Cache geworfen. Die Strategie bei FIFO funktioniert auch hier.
6
-    3. MRU: Hier funktioniert die bisher verwendete Folge nicht mehr. Da immer das zuletzt verwendete Element aus dem Cache entfernt wird, ist `1,2,3,4,5,6,5,6,...` eine Möglichkeit, um ausschließlich Cache-Misses zu provozieren. Die Folge `1-6` dient dabei dazu, den Cache zuerst aufzufüllen.
7
-    4. Für unseren Fall (eine Abfolge von 6 verschiedenen Zugriffen) braucht der Cache eine minimale Größe von 6, um sehr viel mehr Cache-Hits zu erreichen. Um genau zu sein, sind dann immer alle Einträge im Cache vorhanden, und nach der anfänglichen Auffüllphase (in der nur Misses auftreten) ist jeder Zugriff ein Hit.
8
-
9
-2. Für unser Programm, siehe `randomtrace.c`.
10
-    1. Wir erwarten, dass sich die verschiedenen Policies entsprechend dem, wie wir es in der Vorlesung besprochen hatten, verhalten.
11
-
12
-3. *Traces* mit *locality*:
13
-
14
-    i. Um räumliche Lokalität (spatial locality) herzustellen darf man die TLB Abdeckung nicht überschreiten bzw. müssen Zahlen gewählt werden, die in der Nähe von einander liegen. Zusätzlich kann man zeitliche Lokalität erzeugen, in dem sich Zahlen wiederholen (temporal locality). Das bedeutet 1,2,2,3,2,3,2,3,2,3,2,2,2,2 ist von räumlicher und zeitlicher Lokalität.
15
-
16
-    ii. LRU hatte beim Auruf mit solchen traces eine Hitrate von ca. 80%
17
-
18
-    iii. Mit der Policy RAND gab es trotzdem immer die selbe Hitrate wie mit LRU...

+ 0
- 19
hw4/simu3/QUESTIONS.md 查看文件

@@ -1,19 +0,0 @@
1
-# Questions 20-paging-multilevel-translate
2
-
3
-This simulator, paging-policy.py, allows you to play around with different page-replacement policies. See the README for details.
4
-
5
-## Warmup
6
-
7
-Generate random addresses with the following arguments: -s 0 -n 10, -s 1 -n 10, and -s 2 -n 10. Change the policy from FIFO,to LRU, to OPT. Compute whether each access in said address traces are hits or misses.
8
-
9
-## Questions
10
-
11
-1. For a cache of size 5, generate worst-case address reference streams for each of the following policies: FIFO, LRU, and MRU (worst-case reference streams cause the most misses possible. For the worst case reference streams, how much bigger of a cache is needed to improve performance dramatically and approach OPT?
12
-
13
-1. Generate a random trace (use python or c or rust (single file, no project).
14
-    1. How would you expect the different policies to perform on such a trace?
15
-1. Now generate a trace with some locality.
16
-    1. How can you generate such a trace?
17
-    1. How does LRU perform on it?
18
-    1. How much better than RAND is LRU?
19
-    1. How does CLOCK do? How about CLOCK with different numbers of clock bits?

+ 0
- 128
hw4/simu3/README-paging-policy.md 查看文件

@@ -1,128 +0,0 @@
1
-# README Paging: Policy
2
-
3
-This simulator, paging-policy.py, allows you to play around with different
4
-page-replacement policies. For example, let's examine how LRU performs with a
5
-series of page references with a cache of size 3:
6
-
7
-```text
8
-  0 1 2 0 1 3 0 3 1 2 1
9
-```
10
-
11
-To do so, run the simulator as follows:
12
-
13
-```text
14
-prompt> ./paging-policy.py --addresses=0,1,2,0,1,3,0,3,1,2,1
15
-                           --policy=LRU --cachesize=3 -c
16
-```text
17
-
18
-And what you would see is:
19
-
20
-```text
21
-ARG addresses 0,1,2,0,1,3,0,3,1,2,1
22
-ARG numaddrs 10
23
-ARG policy LRU
24
-ARG cachesize 3
25
-ARG maxpage 10
26
-ARG seed 0
27
-
28
-Solving...
29
-
30
-Access: 0 MISS LRU->      [br 0]<-MRU Replace:- [br Hits:0 Misses:1]
31
-Access: 1 MISS LRU->   [br 0, 1]<-MRU Replace:- [br Hits:0 Misses:2]
32
-Access: 2 MISS LRU->[br 0, 1, 2]<-MRU Replace:- [br Hits:0 Misses:3]
33
-Access: 0 HIT  LRU->[br 1, 2, 0]<-MRU Replace:- [br Hits:1 Misses:3]
34
-Access: 1 HIT  LRU->[br 2, 0, 1]<-MRU Replace:- [br Hits:2 Misses:3]
35
-Access: 3 MISS LRU->[br 0, 1, 3]<-MRU Replace:2 [br Hits:2 Misses:4]
36
-Access: 0 HIT  LRU->[br 1, 3, 0]<-MRU Replace:2 [br Hits:3 Misses:4]
37
-Access: 3 HIT  LRU->[br 1, 0, 3]<-MRU Replace:2 [br Hits:4 Misses:4]
38
-Access: 1 HIT  LRU->[br 0, 3, 1]<-MRU Replace:2 [br Hits:5 Misses:4]
39
-Access: 2 MISS LRU->[br 3, 1, 2]<-MRU Replace:0 [br Hits:5 Misses:5]
40
-Access: 1 HIT  LRU->[br 3, 2, 1]<-MRU Replace:0 [br Hits:6 Misses:5]
41
-```
42
-
43
-The complete set of possible arguments for paging-policy is listed on the
44
-following page, and includes a number of options for varying the policy, how
45
-addresses are specified/generated, and other important parameters such as the
46
-size of the cache.
47
-
48
-```text
49
-prompt> ./paging-policy.py --help
50
-Usage: paging-policy.py [options]
51
-
52
-Options:
53
--h, --help      show this help message and exit
54
--a ADDRESSES, --addresses=ADDRESSES
55
-                a set of comma-separated pages to access;
56
-                -1 means randomly generate
57
--f ADDRESSFILE, --addressfile=ADDRESSFILE
58
-                a file with a bunch of addresses in it
59
--n NUMADDRS, --numaddrs=NUMADDRS
60
-                if -a (--addresses) is -1, this is the
61
-                number of addrs to generate
62
--p POLICY, --policy=POLICY
63
-                replacement policy: FIFO, LRU, LFU, OPT,
64
-                                    UNOPT, RAND, CLOCK
65
--b CLOCKBITS, --clockbits=CLOCKBITS
66
-                for CLOCK policy, how many clock bits to use
67
--C CACHESIZE, --cachesize=CACHESIZE
68
-                size of the page cache, in pages
69
--m MAXPAGE, --maxpage=MAXPAGE
70
-                if randomly generating page accesses,
71
-                this is the max page number
72
--s SEED, --seed=SEED  random number seed
73
--N, --notrace   do not print out a detailed trace
74
--c, --compute   compute answers for me
75
-```
76
-
77
-As usual, "-c" is used to solve a particular problem, whereas without it, the
78
-accesses are just listed (and the program does not tell you whether or not a
79
-particular access is a hit or miss).
80
-
81
-To generate a random problem, instead of using "-a/--addresses" to pass in
82
-some page references, you can instead pass in "-n/--numaddrs" as the number of
83
-addresses the program should randomly generate, with "-s/--seed" used to
84
-specify a different random seed. For example:
85
-
86
-```text
87
-prompt> ./paging-policy.py -s 10 -n 3
88
-.. .
89
-
90
-Assuming a replacement policy of FIFO, and a cache of size 3 pages,
91
-figure out whether each of the following page references hit or miss
92
-in the page cache.
93
-
94
-Access: 5  Hit/Miss?  State of Memory?
95
-Access: 4  Hit/Miss?  State of Memory?
96
-Access: 5  Hit/Miss?  State of Memory?
97
-```
98
-
99
-As you can see, in this example, we specify "-n 3" which means the program
100
-should generate 3 random page references, which it does: 5, 7, and 5. The
101
-random seed is also specified (10), which is what gets us those particular
102
-numbers. After working this out yourself, have the program solve the problem
103
-for you by passing in the same arguments but with "-c" (showing just the
104
-relevant part here):
105
-
106
-```text
107
-prompt> ./paging-policy.py -s 10 -n 3 -c
108
-...
109
-Solving...
110
-
111
-Access: 5 MISS FirstIn->   [br 5] <-Lastin Replace:- [br Hits:0 Misses:1]
112
-Access: 4 MISS FirstIn->[br 5, 4] <-Lastin Replace:- [br Hits:0 Misses:2]
113
-Access: 5 HIT  FirstIn->[br 5, 4] <-Lastin Replace:- [br Hits:1 Misses:2]
114
-```
115
-
116
-The default policy is FIFO, though others are available, including LRU, MRU,
117
-OPT (the optimal replacement policy, which peeks into the future to see what
118
-is best to replace), UNOPT (which is the pessimal replacement), RAND (which
119
-does random replacement), and CLOCK (which does the clock algorithm). The
120
-CLOCK algorithm also takes another argument (-b), which states how many bits
121
-should be kept per page; the more clock bits there are, the better the
122
-algorithm should be at determining which pages to keep in memory.
123
-
124
-Other options include: "-C/--cachesize" which changes the size of the page
125
-cache; "-m/--maxpage" which is the largest page number that will be used if
126
-the simulator is generating references for you; and "-f/--addressfile" which
127
-lets you specify a file with addresses in them, in case you wish to get traces
128
-from a real application or otherwise use a long trace as input.

+ 0
- 275
hw4/simu3/paging-policy.py 查看文件

@@ -1,275 +0,0 @@
1
-#! /usr/bin/env python
2
-
3
-import sys
4
-from optparse import OptionParser
5
-import random
6
-import math
7
-
8
-def convert(size):
9
-    length = len(size)
10
-    lastchar = size[length-1]
11
-    if (lastchar == 'k') or (lastchar == 'K'):
12
-        m = 1024
13
-        nsize = int(size[0:length-1]) * m
14
-    elif (lastchar == 'm') or (lastchar == 'M'):
15
-        m = 1024*1024
16
-        nsize = int(size[0:length-1]) * m
17
-    elif (lastchar == 'g') or (lastchar == 'G'):
18
-        m = 1024*1024*1024
19
-        nsize = int(size[0:length-1]) * m
20
-    else:
21
-        nsize = int(size)
22
-    return nsize
23
-
24
-def hfunc(index):
25
-    if index == -1:
26
-        return 'MISS'
27
-    else:
28
-        return 'HIT '
29
-
30
-def vfunc(victim):
31
-    if victim == -1:
32
-        return '-'
33
-    else:
34
-        return str(victim)
35
-
36
-#
37
-# main program
38
-#
39
-parser = OptionParser()
40
-parser.add_option('-a', '--addresses', default='-1',   help='a set of comma-separated pages to access; -1 means randomly generate',  action='store', type='string', dest='addresses')
41
-parser.add_option('-f', '--addressfile', default='',   help='a file with a bunch of addresses in it',                                action='store', type='string', dest='addressfile')
42
-parser.add_option('-n', '--numaddrs', default='10',    help='if -a (--addresses) is -1, this is the number of addrs to generate',    action='store', type='string', dest='numaddrs')
43
-parser.add_option('-p', '--policy', default='FIFO',    help='replacement policy: FIFO, LRU, OPT, UNOPT, RAND, CLOCK',                action='store', type='string', dest='policy')
44
-parser.add_option('-b', '--clockbits', default=2,      help='for CLOCK policy, how many clock bits to use',                          action='store', type='int', dest='clockbits')
45
-parser.add_option('-C', '--cachesize', default='3',    help='size of the page cache, in pages',                                      action='store', type='string', dest='cachesize')
46
-parser.add_option('-m', '--maxpage', default='10',     help='if randomly generating page accesses, this is the max page number',     action='store', type='string', dest='maxpage')
47
-parser.add_option('-s', '--seed', default='0',         help='random number seed',                                                    action='store', type='string', dest='seed')
48
-parser.add_option('-N', '--notrace', default=False,    help='do not print out a detailed trace',                                     action='store_true', dest='notrace')
49
-parser.add_option('-c', '--compute', default=False,    help='compute answers for me',                                                action='store_true', dest='solve')
50
-
51
-(options, args) = parser.parse_args()
52
-
53
-print 'ARG addresses', options.addresses
54
-print 'ARG addressfile', options.addressfile
55
-print 'ARG numaddrs', options.numaddrs
56
-print 'ARG policy', options.policy
57
-print 'ARG clockbits', options.clockbits
58
-print 'ARG cachesize', options.cachesize
59
-print 'ARG maxpage', options.maxpage
60
-print 'ARG seed', options.seed
61
-print 'ARG notrace', options.notrace
62
-print ''
63
-
64
-addresses   = str(options.addresses)
65
-addressFile = str(options.addressfile)
66
-numaddrs    = int(options.numaddrs)
67
-cachesize   = int(options.cachesize)
68
-seed        = int(options.seed)
69
-maxpage     = int(options.maxpage)
70
-policy      = str(options.policy)
71
-notrace     = options.notrace
72
-clockbits   = int(options.clockbits)
73
-
74
-random.seed(seed)
75
-
76
-addrList = []
77
-if addressFile != '':
78
-    fd = open(addressFile)
79
-    for line in fd:
80
-        addrList.append(int(line))
81
-    fd.close()
82
-else:
83
-    if addresses == '-1':
84
-        # need to generate addresses
85
-        for i in range(0,numaddrs):
86
-            n = int(maxpage * random.random())
87
-            addrList.append(n)
88
-    else:
89
-        addrList = addresses.split(',')
90
-
91
-if options.solve == False:
92
-    print 'Assuming a replacement policy of %s, and a cache of size %d pages,' % (policy, cachesize)
93
-    print 'figure out whether each of the following page references hit or miss'
94
-    print 'in the page cache.\n'
95
-
96
-    for n in addrList:
97
-        print 'Access: %d  Hit/Miss?  State of Memory?' % int(n)
98
-    print ''
99
-
100
-else:
101
-    if notrace == False:
102
-        print 'Solving...\n'
103
-
104
-    # init memory structure
105
-    count = 0
106
-    memory = []
107
-    hits = 0
108
-    miss = 0
109
-
110
-    if policy == 'FIFO':
111
-        leftStr = 'FirstIn'
112
-        riteStr = 'Lastin '
113
-    elif policy == 'LRU':
114
-        leftStr = 'LRU'
115
-        riteStr = 'MRU'
116
-    elif policy == 'MRU':
117
-        leftStr = 'LRU'
118
-        riteStr = 'MRU'
119
-    elif policy == 'OPT' or policy == 'RAND' or policy == 'UNOPT' or policy == 'CLOCK':
120
-        leftStr = 'Left '
121
-        riteStr = 'Right'
122
-    else:
123
-        print 'Policy %s is not yet implemented' % policy
124
-        exit(1)
125
-
126
-    # track reference bits for clock
127
-    ref   = {}
128
-
129
-    cdebug = False
130
-
131
-    # need to generate addresses
132
-    addrIndex = 0
133
-    for nStr in addrList:
134
-        # first, lookup
135
-        n = int(nStr)
136
-        try:
137
-            idx = memory.index(n)
138
-            hits = hits + 1
139
-            if policy == 'LRU' or policy == 'MRU':
140
-                update = memory.remove(n)
141
-                memory.append(n) # puts it on MRU side
142
-        except:
143
-            idx = -1
144
-            miss = miss + 1
145
-
146
-        victim = -1        
147
-        if idx == -1:
148
-            # miss, replace?
149
-            # print 'BUG count, cachesize:', count, cachesize
150
-            if count == cachesize:
151
-                # must replace
152
-                if policy == 'FIFO' or policy == 'LRU':
153
-                    victim = memory.pop(0)
154
-                elif policy == 'MRU':
155
-                    victim = memory.pop(count-1)
156
-                elif policy == 'RAND':
157
-                    victim = memory.pop(int(random.random() * count))
158
-                elif policy == 'CLOCK':
159
-                    if cdebug:
160
-                        print 'REFERENCE TO PAGE', n
161
-                        print 'MEMORY ', memory
162
-                        print 'REF (b)', ref
163
-
164
-                    # hack: for now, do random
165
-                    # victim = memory.pop(int(random.random() * count))
166
-                    victim = -1
167
-                    while victim == -1:
168
-                        page = memory[int(random.random() * count)]
169
-                        if cdebug:
170
-                            print '  scan page:', page, ref[page]
171
-                        if ref[page] >= 1:
172
-                            ref[page] -= 1
173
-                        else:
174
-                            # this is our victim
175
-                            victim = page
176
-                            memory.remove(page)
177
-                            break
178
-
179
-                    # remove old page's ref count
180
-                    if page in memory:
181
-                        assert('BROKEN')
182
-                    del ref[victim]
183
-                    if cdebug:
184
-                        print 'VICTIM', page
185
-                        print 'LEN', len(memory)
186
-                        print 'MEM', memory
187
-                        print 'REF (a)', ref
188
-
189
-                elif policy == 'OPT':
190
-                    maxReplace  = -1
191
-                    replaceIdx  = -1
192
-                    replacePage = -1
193
-                    # print 'OPT: access %d, memory %s' % (n, memory) 
194
-                    # print 'OPT: replace from FUTURE (%s)' % addrList[addrIndex+1:]
195
-                    for pageIndex in range(0,count):
196
-                        page = memory[pageIndex]
197
-                        # now, have page 'page' at index 'pageIndex' in memory
198
-                        whenReferenced = len(addrList)
199
-                        # whenReferenced tells us when, in the future, this was referenced
200
-                        for futureIdx in range(addrIndex+1,len(addrList)):
201
-                            futurePage = int(addrList[futureIdx])
202
-                            if page == futurePage:
203
-                                whenReferenced = futureIdx
204
-                                break
205
-                        # print 'OPT: page %d is referenced at %d' % (page, whenReferenced)
206
-                        if whenReferenced >= maxReplace:
207
-                            # print 'OPT: ??? updating maxReplace (%d %d %d)' % (replaceIdx, replacePage, maxReplace)
208
-                            replaceIdx  = pageIndex
209
-                            replacePage = page
210
-                            maxReplace  = whenReferenced
211
-                            # print 'OPT: --> updating maxReplace (%d %d %d)' % (replaceIdx, replacePage, maxReplace)
212
-                    victim = memory.pop(replaceIdx)
213
-                    # print 'OPT: replacing page %d (idx:%d) because I saw it in future at %d' % (victim, replaceIdx, whenReferenced)
214
-                elif policy == 'UNOPT':
215
-                    minReplace  = len(addrList) + 1
216
-                    replaceIdx  = -1
217
-                    replacePage = -1
218
-                    for pageIndex in range(0,count):
219
-                        page = memory[pageIndex]
220
-                        # now, have page 'page' at index 'pageIndex' in memory
221
-                        whenReferenced = len(addrList)
222
-                        # whenReferenced tells us when, in the future, this was referenced
223
-                        for futureIdx in range(addrIndex+1,len(addrList)):
224
-                            futurePage = int(addrList[futureIdx])
225
-                            if page == futurePage:
226
-                                whenReferenced = futureIdx
227
-                                break
228
-                        if whenReferenced < minReplace:
229
-                            replaceIdx  = pageIndex
230
-                            replacePage = page
231
-                            minReplace  = whenReferenced
232
-                    victim = memory.pop(replaceIdx)
233
-            else:
234
-                # miss, but no replacement needed (cache not full)
235
-                victim = -1
236
-                count = count + 1
237
-
238
-            # now add to memory
239
-            memory.append(n)
240
-            if cdebug:
241
-                print 'LEN (a)', len(memory)
242
-            if victim != -1:
243
-                assert(victim not in memory)
244
-
245
-        # after miss processing, update reference bit
246
-        if n not in ref:
247
-            ref[n] = 1
248
-        else:
249
-            ref[n] += 1
250
-            if ref[n] > clockbits:
251
-                ref[n] = clockbits
252
-        
253
-        if cdebug:
254
-            print 'REF (a)', ref
255
-
256
-        if notrace == False:
257
-            print 'Access: %d  %s %s -> %12s <- %s Replaced:%s [Hits:%d Misses:%d]' % (n, hfunc(idx), leftStr, memory, riteStr, vfunc(victim), hits, miss)
258
-        addrIndex = addrIndex + 1
259
-        
260
-    print ''
261
-    print 'FINALSTATS hits %d   misses %d   hitrate %.2f' % (hits, miss, (100.0*float(hits))/(float(hits)+float(miss)))
262
-    print ''
263
-
264
-
265
-
266
-    
267
-    
268
-    
269
-
270
-
271
-
272
-
273
-
274
-
275
-

+ 0
- 25
hw4/simu3/randomtrace.c 查看文件

@@ -1,25 +0,0 @@
1
-#include <stdio.h>
2
-#include <stdlib.h>
3
-#include <time.h>
4
-
5
-int main(int argc, char* argv[]) {
6
-  srand(time(NULL));
7
-
8
-  if (argc != 3) {
9
-    fprintf(stderr, "Usage: ./randomtrace <count> <size>\n");
10
-    return -1;
11
-  }
12
-
13
-  int i, r, s, t;
14
-  s = atoi(argv[1]);
15
-  t = atoi(argv[2]);
16
-  for (i = 0; i < s; i++) {
17
-    r = (int) (rand() % t);
18
-    if (i != s - 1) {
19
-      printf("%d,", r);
20
-    } else {
21
-      printf("%d", r);
22
-    }
23
-  }
24
-  printf("\n");
25
-}

+ 0
- 8
hw4/task1/Cargo.toml 查看文件

@@ -1,8 +0,0 @@
1
-[package]
2
-name = "task1"
3
-version = "0.1.0"
4
-authors = ["Lorenz Bung & Joshua Rutschmann"]
5
-
6
-[dependencies]
7
-procinfo = "^0.4.2"
8
-libc = "^0.2"

+ 0
- 277
hw4/task1/README.md 查看文件

@@ -1,277 +0,0 @@
1
-# Homework hw4 task1
2
-
3
-- [Überblick](#%C3%BCberblick)
4
-- [Daten aus dem /proc Verzeichnis lesen](#daten-aus-dem-proc-verzeichnis-lesen)
5
-- [Externe Crate nutzen](#externe-crate-nutzen)
6
-- [Optionalen Parameter parsen](#optionalen-parameter-parsen)
7
-- [Aufgaben](#aufgaben)
8
-    - [Externe Crate in Dependencies eintragen](#externe-crate-in-dependencies-eintragen)
9
-    - [`readproc.rs`: Eigene Prozessinformationen auslesen](#readprocrs-eigene-prozessinformationen-auslesen)
10
-    - [`pstree.rs`: Prozesskette ausgeben](#pstreers-prozesskette-ausgeben)
11
-- [Kontrolle Ihres Repositories](#kontrolle-ihres-repositories)
12
-
13
-## Überblick
14
-
15
-Ziel dieser Aufgabe ist es, mittels des externen Crates `procinfo` einige
16
-Prozessverwaltungs-Informationen kennen zu lernen, die das Betriebssystem beim
17
-Ausführen der Prozesse verwaltet. Fertige Programme wie **ps**, **htop** oder
18
-**pmap** verwenden diese Informationen, um über das System und Tasks Auskunft zu
19
-geben.
20
-
21
-Die Funktionalität der Programms wird auf die 3 Module aufgeteilt:
22
-
23
-- `main.rs`: die Funktion `main()
24
-- `readproc.rs`: Handling der Funktionen, die angefragte Informationen aus dem
25
-  `proc/` Verzeichnis zu Verfügung stellen.
26
-- `pstree.rs`: Struct und Methoden, um einen 'pstree' darzustellen
27
-
28
-## Daten aus dem /proc Verzeichnis lesen
29
-
30
-"Das `/proc`-Verzeichnis ist kein wirkliches Dateisystem, sondern eine
31
-Schnittstelle zum Kernel. Die Dateien, die in diesem Verzeichnis liegen,
32
-benutzen keinen Speicherplatz auf der Platte, sind aber trotzdem les- und in
33
-manchen Fällen auch beschreibbar.
34
-
35
-Seinen Namen trägt dieses Verzeichnis daher, dass es für jeden laufenden Prozess
36
-ein Unterverzeichnis bereithält, das Informationen über diesen Prozess zur
37
-Verfügung stellt. Das Unterverzeichnis trägt als Namen die ProzessID (PID) des
38
-jeweiligen Prozesses. Es enthält unter anderem folgende Dateien:
39
-
40
-- `cmdline` Die Kommandozeile, mit der der Prozess gestartet wurde, mit allen
41
-  verwendeten Parametern.
42
-- `cwd` (current working directory) Ein symbolischer Link auf das Verzeichnis,
43
-  das beim Aufruf des Prozesses das aktuelle Arbeitsverzeichnis war.
44
-- `environ` Die komplette Umgebung des Prozesses (Variablen, Funktionen usw.)
45
-  sofern er eine Umgebung hat.
46
-- `exe` Ein symbolischer Link auf das aufgerufene Programm, dass den Prozess
47
-  ausmacht.
48
-- `root` Ein symbolischer Link auf das Verzeichnis, das für den Prozess das
49
-  Wurzelverzeichnis darstellt.
50
-
51
-Daneben finden sich weitere Informationen zu den verwendeten Ressourcen
52
-(Speicher, Libraries) und ein Unterverzeichnis **fd**, das die File-Descriptoren
53
-aller vom Prozess verwendeten Dateien enthält.
54
-
55
-Diese Information wird beispielsweise von den Programmen verwertet, die
56
-Prozess-Informationen ausgeben." (aus [Referenz][])
57
-
58
-Das `/proc` Verzeichnis steht nur unter Linux zu Verfügung. Daher müssen
59
-Programme, die auf `/proc` zugreifen auch auf einem Linux System erstellt und
60
-getestet werden.
61
-
62
-## Externe Crate nutzen
63
-
64
-Um nicht selbst im Programm auf die nötigen Dateien per File E/A im ´/proc´
65
-zugreifen zu müssen, wird zum Auslesen eine externe Crate benutzt. Die Crate
66
-*[procinfo][]* stellt dazu die nötigen Funktionen zu Verfügung. Die Funktionen
67
-liefern in einem Result eine Datenstruktur, aus der wir die benötigten
68
-Informationen komfortabel auslesen können. Verwenden Sie in Ihrem Programm
69
-soweit wie möglich die Funktionen des externen Crates *procinfo*, auch wenn in
70
-der Standard-Bibliothek ebenfalls Funktionen für einzelne Aufgaben zu Verfügung
71
-stehen.
72
-
73
-## Optionalen Parameter parsen
74
-
75
-Der Optionale Parameter PID (u32) entscheidet darüber, ob Ihr Programm die
76
-Funktionen des Moduls `readproc.rs` oder `pstree.rs` verwendet. Wird kein
77
-Parameter angegeben, so werden die Funktionen des Moduls `readproc.rs` benutzt.
78
-
79
-## Aufgaben
80
-
81
-### Externe Crate in Dependencies eintragen
82
-
83
-- Benutzen Sie für die folgenden Aufgaben das *[procinfo][]* Crate.
84
-- Fügen Sie dazu den notwendigen Eintrag unter `[dependencies]` in
85
-  **Cargo.toml** hinzu.
86
-- Um auf die nötige Funktionen des Crate zugreifen zu können schreiben Sie NUR
87
-  in **main.rs** bitte folgenden Zeilen an den Beginn der Datei:
88
-
89
- ```Rust
90
- extern crate procinfo;
91
- ```
92
-
93
-Benutzen Sie in Ihren Modulen `readproc.rs` und `pstree.rs` die `use` Anweisung
94
-geeignet, um auf die nötigen Funktionen des Crate *procinfo* in den Modulen
95
-zugreifen zu können.
96
-
97
-In der Crate *procinfo* wird als Return ein Result Typ mit nur dem OK Typ
98
-benutzt. Der Err Typ ist scheinbar nicht im Result enthalten. Wenn man
99
-allerdings die Info der Standardbibliothek zu [io::Result][] liest, erfährt man,
100
-dass es sich hier um einen Alias handelt, der komfortableres Arbeiten mit Errors
101
-erlaubt. Dazu kommen wir aber erst in späteren Kapiteln, wenn wir uns dem `?`
102
-Makro nähern. Daher bitte hier in der Aufgabe noch keine Makros wie `try` und
103
-`?` benutzen.
104
-
105
-### `readproc.rs`: Eigene Prozessinformationen auslesen
106
-
107
-Ziel dieser Teilaufgabe ist es das Crate *procinfo* kennen zu lernen und sich
108
-noch ein wenig mit dem Return Typ 'Result' und der Fehlerbehandlung zu üben.
109
-
110
-Die folgenden Funktionen werden im Modul `readproc.rs` implementiert. Alle
111
-Funktionen reichen mögliche Fehler über einen Result zurück zur aufrufenden
112
-Funktion. Keine der Funktionen darf im Fehlerfall einen Programmabbruch
113
-erzwingen.
114
-
115
-1. Schreiben Sie die Funktion `fn self_pids() -> Result<(i32, i32), &'static
116
-   str>`, die die eigene PID und die PPID in einem Tupel (PID,PPID) Im
117
-   Erfolgsfall zurückgibt.
118
-
119
-   > Hinweis: Überlegen Sie sich, ob `stat()` und der `stat_self()` die
120
-   > geeignetere Funktion im *procinfo* Crate für diesen Fall ist.
121
-
122
-1. Schreiben Sie die Funktion `fn get_pid_command(pid: i32) -> Result<String,
123
-   &'static str>`, die den Command Namen zu einer PID zurück liefert. Wird die
124
-   PID nicht gefunden im System, so soll die Funktion den String "PID not alive:
125
-   no command name found" zurück geben.
126
-
127
-1. Schreiben Sie die Funktion `fn get_last_created_command() -> Result<String,
128
-   &'static str>`, die den Command Namen des zuletzt erzeugten Prozesses im
129
-   System zurück gibt. Wird die PID nicht gefunden im System, so soll die
130
-   Funktion den String "No last command via PID found" zurück geben.
131
-
132
-   > Tip: `loadavg()` Funktion.
133
-
134
-1. Schreiben Sie die Funktion `fn get_thread_count(pid: i32) -> Result<u32,
135
-   &'static str>`, die die Anzahl der Threads pro PID zurückliefert. Wird die
136
-   PID nicht gefunden im System, so soll die Funktion den String "PID not alive:
137
-   no threads counted" zurück geben.
138
-
139
-1. Benutzen Sie nun Ihre Funktionen geeignet, um in Ihrer `main()` Funktion
140
-   folgende Ausgaben zu produzieren:
141
-
142
-   ```text
143
-    My PID : 31894 - process1 running 4 threads
144
-    My PPID: 27952 - process2 running 2 threads
145
-    Last process created in system was: process3
146
-   ```
147
-
148
-   > Hinweis: Die Nummer und Command Namen sind bei Ihnen verschieden. Wenn Sie
149
-   > Probleme beim Aufruf Ihres Programms über **cargo run** haben lesen Sie
150
-   > unbedingt die nächste Frage!
151
-
152
-1. Sie können Ihr Programm über:
153
-
154
-   - **cargo run** oder
155
-   - **./target/debug/task1** starten.
156
-
157
-   Überlegen Sie sich, wie es zu den unterschiedlichen Ausgaben und
158
-   Programmverhalten kommt.
159
-
160
-1. Schreiben Sie die Funktion `fn get_task_total() -> Result<u32, &'static
161
-   str>`, die die Gesamtmenge aller Tasks im System zurück liefert. Wird die
162
-   Gesamtmenge nicht gefunden, so soll die Funktion den String "No total count
163
-   of tasks in system found" zurück geben.
164
-
165
-   > Warum z.B. zeigt Ihnen das Programm **htop** eine andere Anzahl von
166
-   > Prozessen als Ihre ausgelesene Funktion?
167
-
168
-1. Schreiben Sie die Funktion `fn get_ownprocess_mem() ->
169
-   Result<(usize,usize,usize), &'static str>`, die in einem Tuple die Werte für:
170
-
171
-   - vsize
172
-   - code und
173
-   - data
174
-
175
-   zurück liefert.
176
-
177
-1. Im Modul `main.rs` produzieren Sie die Ausgabe für die Kommandozeile und
178
-   kümmern sich um evtl. Fehler. Bei korrektem Programmablauf ergibt sich
179
-   folgende Ausgabe (genau 5 Zeilen!):
180
-
181
-   ```text
182
-   My PID : 31894 - process1 running 4 threads
183
-   My PPID: 27952 - process2 running 2 threads
184
-   My mem : 3560 (vspace), 208 (code), 588 (data)
185
-   Last process created in system was: process3
186
-   Total number of tasks: 145
187
-   ```
188
-
189
-### `pstree.rs`: Prozesskette ausgeben
190
-
191
-1. Auf Basis des Crate *procinfo* sollen Sie bei Aufruf des Programms mit einer
192
-   PID, ausgehend von dieser PID der Tree bis zum aktuellen Programm ausgegeben
193
-   werden. Wird somit als Argument eine `1` angegeben, wird eine Funktionalität
194
-   des Kommandozeilen Programms **pstree / pstree.x11** nachgebildet. Wenn Sie sich z.B. mit
195
-   dem Kommando **ps** die PID Ihrer aktuellen Shell anzeigen lassen, können Sie
196
-   sich durch Aufruf von **pstree.x11 -p -s <pid>** die Kette aller Prozesse
197
-   anzeigen lassen, in denen die <pid> enthalten ist.
198
-
199
-   ```text
200
-   systemd(1)---sshd(1264)---sshd(7161)---sshd(7198)---zsh(7199)---pstree.x11(47200)
201
-   ```
202
-
203
-   Genau diese Ausgabe soll nun Ihr Programm erzeugen bei der Option '1', wobei
204
-   natürlich das Ende der Kette nicht mehr `pstree.x11` ist sondern Ihr Programm.
205
-
206
-   Geben Sie im obigen Beispiel die PID 7161 als Parameter an, so soll Ihr Programm
207
-   nur den Teil-Tree ausgegeben, startend vom Prozess mit PID 7161.
208
-
209
-   ```text
210
-   sshd(7161)---sshd(7198)---zsh(7199)---task1(47200)
211
-   ```
212
-
213
-   Ausgehend von der eigenen pid sollen alle Elternpid bis zum übergebenen PID
214
-   (z.B. 1 für init Prozess, hier `systemd`) angezeigt werden. Der Init Prozess
215
-   (hier systemd) hat immer die PID 1 in UNIX Systemen, aber unterschiedliche Namen.
216
-
217
-1. Nutzen Sie zum parsen der PID im Argument die `parse()` Funktion. Behandeln
218
-   Sie folgende Fehler:
219
-
220
-   - Parameter ist keine Zahl
221
-   - Parameter ist keine Elternpid
222
-   - Mehr als 2 Parameter werden bei Aufruf mit angegeben.
223
-
224
-   Geben Sie im Fehlerfall eine entsprechende Meldung in einer(1!) Zeile aus und
225
-   beenden Sie das Programm mit dem Exitcode 1. Eine möglich Ausgabe:
226
-
227
-   ```text
228
-   $ ./task1 2 3
229
-   Correct usage: no param or param PID
230
-   ```
231
-
232
-   >Wichtig: Im Fehlerfall beenden Sie das Programm kontrolliert mit exit(1).
233
-   >Den Fehlercode '1' überprüfen die Tests in tests/output.bats!
234
-
235
-1. Erstellen Sie eine eigene Datenstruktur und Methoden um die Aufgabe zu lösen.
236
-   Verwenden Sie nur die externe Crate *procinfo* dazu. Die Ausgabe beim Aufruf
237
-   Ihres Programms muss folgender Beispielformatierung entsprechen:
238
-
239
-    ```text
240
-    systemd(1)---sshd(1264)---sshd(7161)---sshd(7198)---zsh(7199)---task1(47151)
241
-    ```
242
-   > Je nachdem wie Sie Ihr Programm aufrufen wird es natürlich andere Ausgaben
243
-   > produzieren. Durch das Kommandozeilen-Tool **pstree.x11** können Sie Ihre
244
-   > Ausgabe kontrollieren!
245
-
246
-1. Schreiben Sie eine eigene unit Test Datei `unit_test_pstree.rs`, die Ihre
247
-   Funktionen im Modul `pstree.rs` geeignet testet und beim Aufruf von **cargo
248
-   test** die Tests ausführt.
249
-
250
-1. Schreiben Sie ausreichend Kommentare, um Ihre Implementierung in `pstree.rs`
251
-   über die per **cargo doc** erstellten Dokumentation nachvollziehen zu können.
252
-
253
-## Kontrolle Ihres Repositories
254
-
255
-Haben Sie die Aufgaben komplett bearbeitet, so sollten sich folgende Dateien in
256
-Ihrem Projekt-Verzeichnis befinden:
257
-
258
-```text
259
-.
260
-├── Cargo.lock
261
-├── Cargo.toml
262
-├── README.md
263
-├── src
264
-│   ├── main.rs
265
-│   ├── pstree.rs
266
-│   ├── readproc.rs
267
-│   ├── unit_test_pstree.rs
268
-│   └── unit_test_readproc.rs
269
-└── tests
270
-    └── output.bats
271
-
272
-2 directories, 9 files
273
-```
274
-
275
-[Referenz]: http://www.linux-praxis.de/lpic1/lpi101/proc.html
276
-[procinfo]: https://docs.rs/procinfo/
277
-[io::Result]: https://doc.rust-lang.org/std/io/type.Result.html

+ 0
- 95
hw4/task1/src/main.rs 查看文件

@@ -1,95 +0,0 @@
1
-extern crate procinfo;
2
-
3
-use std::env;
4
-use std::process;
5
-
6
-mod readproc;
7
-mod pstree;
8
-
9
-mod unit_test_pstree;
10
-mod unit_test_readproc;
11
-
12
-/// Mainfunction
13
-fn main() {
14
-
15
-    let args: Vec<String> = env::args().collect();
16
-
17
-    match args.len() {
18
-        1 => {
19
-            if let Ok(pid_tuple) = readproc::self_pids() {
20
-                let pid = pid_tuple.0;
21
-                let ppid = pid_tuple.1;
22
-
23
-                // Commands & Threads for PID
24
-                if let Ok(pid_command) = readproc::get_pid_command(pid) {
25
-                    if let Ok(pid_threads) = readproc::get_thread_count(pid) {
26
-                        println!(
27
-                            "My PID : {} - {} running {} threads",
28
-                            pid,
29
-                            pid_command,
30
-                            pid_threads
31
-                        );
32
-                    }
33
-                }
34
-
35
-                // Commands & Threads for Parent-PID
36
-                if let Ok(ppid_command) = readproc::get_pid_command(ppid) {
37
-                    if let Ok(ppid_threads) = readproc::get_thread_count(ppid) {
38
-                        println!(
39
-                            "My PPID: {} - {} running {} threads",
40
-                            ppid,
41
-                            ppid_command,
42
-                            ppid_threads
43
-                        );
44
-                    }
45
-                }
46
-
47
-            }
48
-
49
-
50
-            if let Ok(size_tuple) = readproc::get_ownprocess_mem() {
51
-                // Memory
52
-                let vspace = size_tuple.0;
53
-                let code = size_tuple.1;
54
-                let data = size_tuple.2;
55
-
56
-                println!(
57
-                    "My mem : {} (vspace), {} (code), {} (data)",
58
-                    vspace,
59
-                    code,
60
-                    data
61
-                );
62
-            }
63
-
64
-            if let Ok(last_command) = readproc::get_last_created_command() {
65
-                // Last Process
66
-                println!("Last process created in system was: {}", last_command);
67
-            }
68
-
69
-
70
-            if let Ok(task_total) = readproc::get_task_total() {
71
-                // Number of tasks
72
-                println!("Total number of tasks: {}", task_total);
73
-            }
74
-        }
75
-
76
-        2 => {
77
-            match args[1].parse::<i32>() {
78
-                Ok(pid) => {
79
-                    if !pstree::print(pid) {
80
-                        process::exit(1);
81
-                    }
82
-                }
83
-                Err(_) => {
84
-                    println!("Error while parsing PID");
85
-                    process::exit(1);
86
-                }
87
-            }
88
-        }
89
-
90
-        _ => {
91
-            println!("Correct usage: no param or param PID");
92
-            process::exit(1);
93
-        }
94
-    }
95
-}

+ 0
- 95
hw4/task1/src/pstree.rs 查看文件

@@ -1,95 +0,0 @@
1
-extern crate libc;
2
-
3
-use procinfo::pid;
4
-use self::libc::pid_t;
5
-
6
-/// Datenstruktur für einen Prozess.
7
-pub struct Process {
8
-    name: String,
9
-    pid: pid_t,
10
-    ppid: pid_t,
11
-}
12
-
13
-impl Process {
14
-    /// Erstellt eine Prozess-Datenstruktur aus procinfo::Stat.
15
-    pub fn new(with_pid: pid_t) -> Self {
16
-        if let Ok(stat) = pid::stat(with_pid) {
17
-            Process {
18
-                name: stat.command,
19
-                pid: stat.pid,
20
-                ppid: stat.ppid,
21
-            }
22
-        } else {
23
-            panic!("Internal Error: Process not found")
24
-        }
25
-    }
26
-
27
-    /// Erstellt eine Prozess-Datenstruktur aus procinfo::Stat.
28
-    pub fn me() -> Self {
29
-        if let Ok(my_pid) = pid::stat_self() {
30
-            Process::new(my_pid.pid)
31
-        } else {
32
-            panic!("Internal Error: I don't have a PID but I am running.")
33
-        }
34
-    }
35
-
36
-    /// Prüft ob das Prozess-Struct ein Elternprozess besitzt.
37
-    pub fn has_parent(&self) -> bool {
38
-        self.ppid != 0
39
-    }
40
-
41
-    /// Gibt den Elternprozess zurück.
42
-    pub fn parent(&self) -> Self {
43
-        Process::new(self.ppid)
44
-    }
45
-
46
-    /// Prüft ob das Prozess-Struct einen (entfernten) Elternprozess mit dem übergebenen pid hat.
47
-    pub fn has_parent_with_pid(&self, pid: pid_t) -> bool {
48
-        if self.pid == pid {
49
-            return true;
50
-        }
51
-
52
-        if self.has_parent() {
53
-            return self.parent().has_parent_with_pid(pid);
54
-        }
55
-
56
-        false
57
-    }
58
-
59
-    /// Gibt über Rekursion über die Eltern eine Prozesskette aus.
60
-    pub fn print_recursive(&self, to_pid: pid_t, output: &mut String) {
61
-
62
-        if output.len() == 0 {
63
-            *output = format!("{}({}){}", self.name, self.pid, output);
64
-        } else {
65
-            *output = format!("{}({})---{}", self.name, self.pid, output);
66
-        }
67
-
68
-        if self.has_parent() && self.pid != to_pid {
69
-            self.parent().print_recursive(to_pid, output);
70
-        }
71
-    }
72
-}
73
-
74
-/// Geht von eigenem Prozess aus und gibt die Prozesskette bis zum übergebenem PID aus
75
-/// und fängt mögliche Fehler ab.
76
-pub fn print(pid: pid_t) -> bool {
77
-
78
-    if let Err(_) = pid::stat(pid) {
79
-        println!("Invalid PID");
80
-        return false;
81
-    }
82
-
83
-    let my_proc = Process::me();
84
-
85
-    if !my_proc.has_parent_with_pid(pid) {
86
-        println!("This Process has no parent {}", pid);
87
-        return false;
88
-    }
89
-
90
-    let mut output = String::new();
91
-    my_proc.print_recursive(pid, &mut output);
92
-    println!("{}", output);
93
-
94
-    true
95
-}

+ 0
- 66
hw4/task1/src/readproc.rs 查看文件

@@ -1,66 +0,0 @@
1
-use procinfo::pid;
2
-use procinfo::loadavg;
3
-
4
-/// Returns the PID and PPID of the current process.
5
-/// Throws an error if the current process doesn't exist (should never occur).
6
-pub fn self_pids() -> Result<(i32, i32), &'static str> {
7
-    match pid::stat_self() {
8
-        Ok(stat) => Ok((stat.pid, stat.ppid)),
9
-        Err(_) => Err("PID not alive: PID and PPID not found"),
10
-    }
11
-}
12
-
13
-/// Returns the command (string) belonging to the given PID.
14
-/// Throws an error if the given PID doesn't exist.
15
-pub fn get_pid_command(pid: i32) -> Result<String, &'static str> {
16
-    match pid::stat(pid) {
17
-        Ok(stat) => Ok(stat.command),
18
-        Err(_) => Err("PID not alive: no command name found"),
19
-    }
20
-}
21
-
22
-/// Returns the last created command (string) of the system.
23
-/// Throws an error if there is no last Command.
24
-pub fn get_last_created_command() -> Result<String, &'static str> {
25
-    match loadavg() {
26
-        Ok(stat) => {
27
-            let last_pid = stat.last_created_pid;
28
-            match pid::stat(last_pid) {
29
-                Ok(st) => Ok(st.command),
30
-                Err(_) => Err("No last command via PID found"),
31
-            }
32
-        }
33
-        Err(_) => Err("No last command found"),
34
-    }
35
-}
36
-
37
-/// Returns the number of threads belonging to the given PID.
38
-/// Throws an error if the given PID doesn't exist.
39
-pub fn get_thread_count(pid: i32) -> Result<u32, &'static str> {
40
-    match pid::stat(pid) {
41
-        Ok(stat) => Ok(stat.num_threads as u32),
42
-        Err(_) => Err("PID not alive: no threads counted"),
43
-    }
44
-}
45
-
46
-/// Returns the number of total tasks running in the system.
47
-/// Throws an error if the total number of tasks doesn't exist.
48
-pub fn get_task_total() -> Result<u32, &'static str> {
49
-    match loadavg() {
50
-        Ok(stat) => Ok(stat.tasks_total),
51
-        Err(_) => Err("No total count of tasks in system found"),
52
-    }
53
-}
54
-
55
-/// Returns the size of the virtual, code and data memory size of the current process.
56
-/// Throws an error if the current process doesn't exist (should never occur).
57
-pub fn get_ownprocess_mem() -> Result<(usize, usize, usize), &'static str> {
58
-    match pid::stat_self() {
59
-        Ok(stat) => {
60
-            let csize = stat.end_code - stat.start_code;
61
-            let dsize = stat.end_data - stat.start_data;
62
-            Ok((stat.vsize, csize, dsize))
63
-        }
64
-        Err(_) => Err("PID not alive: no memory found"),
65
-    }
66
-}

+ 0
- 57
hw4/task1/src/unit_test_pstree.rs 查看文件

@@ -1,57 +0,0 @@
1
-#[cfg(test)]
2
-mod tests {
3
-    use pstree::Process;
4
-    use pstree::print;
5
-
6
-    #[test]
7
-    #[should_panic]
8
-    fn new_invalid_pid() {
9
-        Process::new(-1000);
10
-    }
11
-
12
-    #[test]
13
-    fn new_valid_pid() {
14
-        Process::new(1);
15
-    }
16
-
17
-    #[test]
18
-    fn hasparent_no() {
19
-        assert_eq!(false, Process::has_parent(&Process::new(1)));
20
-    }
21
-
22
-    #[test]
23
-    fn hasparent_yes() {
24
-        assert_eq!(true, Process::has_parent(&Process::me()));
25
-    }
26
-
27
-    #[test]
28
-    #[should_panic]
29
-    fn parent_not_existing() {
30
-        Process::parent(&Process::new(1));
31
-    }
32
-
33
-    #[test]
34
-    fn parent_existing() {
35
-        Process::parent(&Process::me());
36
-    }
37
-
38
-    #[test]
39
-    fn hasparent_with_pid_not_existing() {
40
-        assert_eq!(false, Process::has_parent_with_pid(&Process::me(), -1000));
41
-    }
42
-
43
-    #[test]
44
-    fn hasparent_with_pid_existing() {
45
-        assert_eq!(true, Process::me().has_parent_with_pid(1));
46
-    }
47
-
48
-    #[test]
49
-    fn print_not_existing() {
50
-        assert_eq!(false, print(-1000));
51
-    }
52
-
53
-    #[test]
54
-    fn print_existing() {
55
-        assert_eq!(true, print(1));
56
-    }
57
-}

+ 0
- 63
hw4/task1/src/unit_test_readproc.rs 查看文件

@@ -1,63 +0,0 @@
1
-#[cfg(test)]
2
-mod tests {
3
-    use procinfo::pid::{status, status_self};
4
-    use readproc::{get_ownprocess_mem, get_pid_command, get_task_total, get_thread_count,
5
-                   self_pids};
6
-
7
-    fn sol_self_pids() -> (i32, i32) {
8
-        match status_self() {
9
-            Ok(status) => (status.pid, status.ppid),
10
-            Err(_) => panic!(),
11
-        }
12
-    }
13
-
14
-    fn name_of_init() -> String {
15
-        status(1).unwrap().command
16
-    }
17
-
18
-    #[test]
19
-    fn test_name_of_init() {
20
-        let status = status(1).unwrap();
21
-        assert_eq!(name_of_init(), status.command);
22
-    }
23
-
24
-    #[test]
25
-    fn test0_ppid() {
26
-        assert_eq!(sol_self_pids(), self_pids().unwrap());
27
-    }
28
-
29
-    #[test]
30
-    fn test1_command() {
31
-        assert_eq!(
32
-            Err("PID not alive: no command name found"),
33
-            get_pid_command(0)
34
-        );
35
-    }
36
-
37
-    #[test]
38
-    fn test2_command() {
39
-        assert_eq!(Ok(name_of_init()), get_pid_command(1));
40
-    }
41
-
42
-
43
-    #[test]
44
-    fn test3_systemd_threads() {
45
-        let status = status(1).unwrap();
46
-        assert_eq!(get_thread_count(1), Ok(status.threads));
47
-    }
48
-
49
-    // Only check if fn is defined
50
-
51
-    #[test]
52
-    #[should_panic]
53
-    fn test8_mem() {
54
-        assert_eq!(Ok((0, 0, 0)), get_ownprocess_mem());
55
-    }
56
-
57
-    #[test]
58
-    #[should_panic]
59
-    fn test9_get_task_total() {
60
-        assert_eq!(Ok((0)), get_task_total());
61
-    }
62
-
63
-}

+ 0
- 45
hw4/task1/tests/output.bats 查看文件

@@ -1,45 +0,0 @@
1
-#!/usr/bin/env bats
2
-
3
-
4
-@test "task1: Check that we have a debug output" {
5
-    run stat "$BATS_TEST_DIRNAME/../target/debug/task1"
6
-    [ "$status" -eq 0 ]
7
-}
8
-
9
-
10
-# wc output with white spaces is trimmed by xargs
11
-@test "task1: Output with no param must be exact 5 line long" {
12
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1'  | wc -l | xargs"
13
-    [ "$output" = "5" ]
14
-}
15
-
16
-# wc output with white spaces is trimmed by xargs
17
-@test "task1: Output with to many paras must be exact 1 line long" {
18
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' 2 3 | wc -l | xargs"
19
-    [ "$output" = "1" ]
20
-
21
-}
22
-
23
-
24
-# wc output with white spaces is trimmed by xargs
25
-@test "task1: Output with wrong para must be exact 1 line long" {
26
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' b | wc -l | xargs"
27
-    [ "$output" = "1" ]
28
-}
29
-
30
-
31
-
32
-@test "task1: Output with wrong PID does not crash" {
33
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' 2 "
34
-    [ "$status" = 1 ]
35
-}
36
-
37
-@test "task1: Output with wrong PARAM does not crash" {
38
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' a "
39
-    [ "$status" = 1 ]
40
-}
41
-
42
-@test "task1: Output with to many para does not crash" {
43
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' 2 3 "
44
-    [ "$status" = 1 ]
45
-}

+ 0
- 30
hw5/README.md 查看文件

@@ -1,30 +0,0 @@
1
-# hw5
2
-
3
-## Tasks
4
-
5
-To fulfill **hw5** you have to solve:
6
-
7
-- task1
8
-- simu1
9
-- simu2
10
-
11
-## Files
12
-
13
-You find already or reuse some files for rust tasks. Please remember to use
14
-cargo to create the relevant projects for each task.
15
-
16
-## Pull-Reuest
17
-
18
-Please merge any accepted reviews into your branch. If you are ready with the
19
-homework, all tests run, please create a pull request named **hw5**.
20
-
21
-## Credits for hw5
22
-
23
-| Task     | max. Credits | Comment |
24
-| -------- | ------------ | ------- |
25
-| task1    | 2            |         |
26
-| task2    | +1           |         |
27
-| simu1    | 1            |         |
28
-| simu2    | 1            |         |
29
-| Deadline | +1           |         |
30
-| =        | 6            |         |

+ 0
- 22
hw5/simu1/QUESTIONS.md 查看文件

@@ -1,22 +0,0 @@
1
-# Questions 7-Scheduler-Intro
2
-
3
-This program, **scheduler.py**, allows you to see how different schedulers
4
-perform under scheduling metrics such as response time, turnaround time, and
5
-total wait time. See the README for details.
6
-
7
-## Questions
8
-
9
-1. Compute the average response time and average turnaround time when running
10
-   three jobs of length 200 with the SJF and FIFO schedulers.
11
-1. Now do the same but with jobs of different lengths: 300, 200, and 100.
12
-1. Now do the same (1.+2.), but also with the RR scheduler and a time-slice of
13
-   1.
14
-1. For what types of workloads does SJF deliver the same turnaround times as
15
-   FIFO?
16
-1. For what types of workloads and quantum lengths does SJF deliver the same
17
-   response times as RR?
18
-1. What happens to response time with SJF as job lengths increase? Can you use
19
-   the simulator to demonstrate the trend?
20
-1. What happens to response time with RR as quantum lengths increase? Can you
21
-   write an equation that gives the average worst-case response time, given N
22
-   jobs?

+ 0
- 129
hw5/simu1/README-scheduler.md 查看文件

@@ -1,129 +0,0 @@
1
-# README Scheduler
2
-
3
-This program, **scheduler.py**, allows you to see how different schedulers
4
-perform under scheduling metrics such as response time, turnaround time, and
5
-total wait time. Three schedulers are "implemented": FIFO, SJF, and RR.
6
-
7
-There are two steps to running the program.
8
-
9
-First, run without the -c flag: this shows you what problem to solve without
10
-revealing the answers. For example, if you want to compute response, turnaround,
11
-and wait for three jobs using the FIFO policy, run this:
12
-
13
-```text
14
-  ./scheduler.py -p FIFO -j 3 -s 100
15
-```
16
-
17
-If that doesn't work, try this:
18
-
19
-```text
20
-  python ./scheduler.py -p FIFO -j 3 -s 100
21
-```
22
-
23
-This specifies the FIFO policy with three jobs, and, importantly, a specific
24
-random seed of 100. If you want to see the solution for this exact problem, you
25
-have to specify this exact same random seed again. Let's run it and see what
26
-happens. This is what you should see:
27
-
28
-```text
29
-prompt> ./scheduler.py -p FIFO -j 3 -s 100
30
-ARG policy FIFO
31
-ARG jobs 3
32
-ARG maxlen 10
33
-ARG seed 100
34
-
35
-Here is the job list, with the run time of each job:
36
-  Job 0 (length = 1)
37
-  Job 1 (length = 4)
38
-  Job 2 (length = 7)
39
-
40
-Compute the turnaround time, response time, and wait time for each job.  When
41
-you are done, run this program again, with the same arguments, but with -c,
42
-which will thus provide you with the answers. You can use -s <somenumber> or
43
-your own job list (-l 10,15,20 for example) to generate different problems for
44
-yourself.
45
-```
46
-
47
-As you can see from this example, three jobs are generated: job 0 of length 1,
48
-job 1 of length 4, and job 2 of length 7. As the program states, you can now use
49
-this to compute some statistics and see if you have a grip on the basic
50
-concepts.
51
-
52
-Once you are done, you can use the same program to "solve" the problem and see
53
-if you did your work correctly. To do so, use the "-c" flag. The output:
54
-
55
-```text
56
-prompt> ./scheduler.py -p FIFO -j 3 -s 100 -c
57
-ARG policy FIFO
58
-ARG jobs 3
59
-ARG maxlen 10
60
-ARG seed 100
61
-
62
-Here is the job list, with the run time of each job:
63
-  Job 0 (length = 1)
64
-  Job 1 (length = 4)
65
-  Job 2 (length = 7)
66
-
67
-** Solutions **
68
-
69
-Execution trace:
70
-  [time   0] Run job 0 for 1.00 secs (DONE)
71
-  [time   1] Run job 1 for 4.00 secs (DONE)
72
-  [time   5] Run job 2 for 7.00 secs (DONE)
73
-
74
-Final statistics:
75
-  Job   0 -- Response: 0.00  Turnaround 1.00  Wait 0.00
76
-  Job   1 -- Response: 1.00  Turnaround 5.00  Wait 1.00
77
-  Job   2 -- Response: 5.00  Turnaround 12.00  Wait 5.00
78
-
79
-  Average -- Response: 2.00  Turnaround 6.00  Wait 2.00
80
-```
81
-
82
-As you can see from the figure, the -c flag shows you what happened. Job 0 ran
83
-first for 1 second, Job 1 ran second for 4, and then Job 2 ran for 7 seconds.
84
-Not too hard; it is FIFO, after all! The execution trace shows these results.
85
-
86
-The final statistics are useful too: they compute the "response time" (the time
87
-a job spends waiting after arrival before first running), the "turnaround time"
88
-(the time it took to complete the job since first arrival), and the total "wait
89
-time" (any time spent ready but not running). The stats are shown per job and
90
-then as an average across all jobs. Of course, you should have computed these
91
-things all before running with the "-c" flag!
92
-
93
-If you want to try the same type of problem but with different inputs, try
94
-changing the number of jobs or the random seed or both. Different random seeds
95
-basically give you a way to generate an infinite number of different problems
96
-for yourself, and the "-c" flag lets you check your own work. Keep doing this
97
-until you feel like you really understand the concepts.
98
-
99
-One other useful flag is "-l" (that's a lower-case L), which lets you specify
100
-the exact jobs you wish to see scheduled. For example, if you want to find out
101
-how SJF would perform with three jobs of lengths 5, 10, and 15, you can run:
102
-
103
-```text
104
-prompt> ./scheduler.py -p SJF -l 5,10,15
105
-ARG policy SJF
106
-ARG jlist 5,10,15
107
-
108
-Here is the job list, with the run time of each job:
109
-  Job 0 (length = 5.0)
110
-  Job 1 (length = 10.0)
111
-  Job 2 (length = 15.0)
112
-...
113
-```
114
-
115
-And then you can use -c to solve it again. Note that when you specify the exact
116
-jobs, there is no need to specify a random seed or the number of jobs: the jobs
117
-lengths are taken from your comma-separated list.
118
-
119
-Of course, more interesting things happen when you use SJF (shortest-job first)
120
-or even RR (round robin) schedulers. Try them and see!
121
-
122
-And you can always run
123
-
124
-```text
125
-  ./scheduler.py -h
126
-```
127
-
128
-to get a complete list of flags and options (including options such as setting
129
-the time quantum for the RR scheduler).

+ 0
- 155
hw5/simu1/scheduler.py 查看文件

@@ -1,155 +0,0 @@
1
-#! /usr/bin/env python
2
-
3
-import sys
4
-from optparse import OptionParser
5
-import random
6
-
7
-parser = OptionParser()
8
-parser.add_option("-s", "--seed", default=0, help="the random seed", 
9
-                  action="store", type="int", dest="seed")
10
-parser.add_option("-j", "--jobs", default=3, help="number of jobs in the system",
11
-                  action="store", type="int", dest="jobs")
12
-parser.add_option("-l", "--jlist", default="", help="instead of random jobs, provide a comma-separated list of run times",
13
-                  action="store", type="string", dest="jlist")
14
-parser.add_option("-m", "--maxlen", default=10, help="max length of job",
15
-                  action="store", type="int", dest="maxlen")
16
-parser.add_option("-p", "--policy", default="FIFO", help="sched policy to use: SJF, FIFO, RR",
17
-                  action="store", type="string", dest="policy")
18
-parser.add_option("-q", "--quantum", help="length of time slice for RR policy", default=1, 
19
-                  action="store", type="int", dest="quantum")
20
-parser.add_option("-c", help="compute answers for me", action="store_true", default=False, dest="solve")
21
-
22
-(options, args) = parser.parse_args()
23
-
24
-random.seed(options.seed)
25
-
26
-print 'ARG policy', options.policy
27
-if options.jlist == '':
28
-    print 'ARG jobs', options.jobs
29
-    print 'ARG maxlen', options.maxlen
30
-    print 'ARG seed', options.seed
31
-else:
32
-    print 'ARG jlist', options.jlist
33
-
34
-print ''
35
-
36
-print 'Here is the job list, with the run time of each job: '
37
-
38
-import operator
39
-
40
-joblist = []
41
-if options.jlist == '':
42
-    for jobnum in range(0,options.jobs):
43
-        runtime = int(options.maxlen * random.random()) + 1
44
-        joblist.append([jobnum, runtime])
45
-        print '  Job', jobnum, '( length = ' + str(runtime) + ' )'
46
-else:
47
-    jobnum = 0
48
-    for runtime in options.jlist.split(','):
49
-        joblist.append([jobnum, float(runtime)])
50
-        jobnum += 1
51
-    for job in joblist:
52
-        print '  Job', job[0], '( length = ' + str(job[1]) + ' )'
53
-print '\n'
54
-
55
-if options.solve == True:
56
-    print '** Solutions **\n'
57
-    if options.policy == 'SJF':
58
-        joblist = sorted(joblist, key=operator.itemgetter(1))
59
-        options.policy = 'FIFO'
60
-    
61
-    if options.policy == 'FIFO':
62
-        thetime = 0
63
-        print 'Execution trace:'
64
-        for job in joblist:
65
-            print '  [ time %3d ] Run job %d for %.2f secs ( DONE at %.2f )' % (thetime, job[0], job[1], thetime + job[1])
66
-            thetime += job[1]
67
-
68
-        print '\nFinal statistics:'
69
-        t     = 0.0
70
-        count = 0
71
-        turnaroundSum = 0.0
72
-        waitSum       = 0.0
73
-        responseSum   = 0.0
74
-        for tmp in joblist:
75
-            jobnum  = tmp[0]
76
-            runtime = tmp[1]
77
-            
78
-            response   = t
79
-            turnaround = t + runtime
80
-            wait       = t
81
-            print '  Job %3d -- Response: %3.2f  Turnaround %3.2f  Wait %3.2f' % (jobnum, response, turnaround, wait)
82
-            responseSum   += response
83
-            turnaroundSum += turnaround
84
-            waitSum       += wait
85
-            t += runtime
86
-            count = count + 1
87
-        print '\n  Average -- Response: %3.2f  Turnaround %3.2f  Wait %3.2f\n' % (responseSum/count, turnaroundSum/count, waitSum/count)
88
-                     
89
-    if options.policy == 'RR':
90
-        print 'Execution trace:'
91
-        turnaround = {}
92
-        response = {}
93
-        lastran = {}
94
-        wait = {}
95
-        quantum  = float(options.quantum)
96
-        jobcount = len(joblist)
97
-        for i in range(0,jobcount):
98
-            lastran[i] = 0.0
99
-            wait[i] = 0.0
100
-            turnaround[i] = 0.0
101
-            response[i] = -1
102
-
103
-        runlist = []
104
-        for e in joblist:
105
-            runlist.append(e)
106
-
107
-        thetime  = 0.0
108
-        while jobcount > 0:
109
-            # print '%d jobs remaining' % jobcount
110
-            job = runlist.pop(0)
111
-            jobnum  = job[0]
112
-            runtime = float(job[1])
113
-            if response[jobnum] == -1:
114
-                response[jobnum] = thetime
115
-            currwait = thetime - lastran[jobnum]
116
-            wait[jobnum] += currwait
117
-            if runtime > quantum:
118
-                runtime -= quantum
119
-                ranfor = quantum
120
-                print '  [ time %3d ] Run job %3d for %.2f secs' % (thetime, jobnum, ranfor)
121
-                runlist.append([jobnum, runtime])
122
-            else:
123
-                ranfor = runtime;
124
-                print '  [ time %3d ] Run job %3d for %.2f secs ( DONE at %.2f )' % (thetime, jobnum, ranfor, thetime + ranfor)
125
-                turnaround[jobnum] = thetime + ranfor
126
-                jobcount -= 1
127
-            thetime += ranfor
128
-            lastran[jobnum] = thetime
129
-
130
-        print '\nFinal statistics:'
131
-        turnaroundSum = 0.0
132
-        waitSum       = 0.0
133
-        responseSum   = 0.0
134
-        for i in range(0,len(joblist)):
135
-            turnaroundSum += turnaround[i]
136
-            responseSum += response[i]
137
-            waitSum += wait[i]
138
-            print '  Job %3d -- Response: %3.2f  Turnaround %3.2f  Wait %3.2f' % (i, response[i], turnaround[i], wait[i])
139
-        count = len(joblist)
140
-        
141
-        print '\n  Average -- Response: %3.2f  Turnaround %3.2f  Wait %3.2f\n' % (responseSum/count, turnaroundSum/count, waitSum/count)
142
-
143
-    if options.policy != 'FIFO' and options.policy != 'SJF' and options.policy != 'RR': 
144
-        print 'Error: Policy', options.policy, 'is not available.'
145
-        sys.exit(0)
146
-else:
147
-    print 'Compute the turnaround time, response time, and wait time for each job.'
148
-    print 'When you are done, run this program again, with the same arguments,'
149
-    print 'but with -c, which will thus provide you with the answers. You can use'
150
-    print '-s <somenumber> or your own job list (-l 10,15,20 for example)'
151
-    print 'to generate different problems for yourself.'
152
-    print ''
153
-
154
-
155
-

+ 0
- 27
hw5/simu2/QUESTIONS.md 查看文件

@@ -1,27 +0,0 @@
1
-# Questions: 8-Scheduler-MLFQ
2
-
3
-This program, **mlfq.py**, allows you to see how the MLFQ scheduler presented in
4
-this chapter behaves. See the README for details.
5
-
6
-Run a few randomly-generated problems with just two jobs and two queues; compute
7
-the MLFQ execution trace for each. Make your life easier by limiting the length
8
-of each job and turning off I/Os.
9
-
10
-## Questions
11
-
12
-1. How would you run the scheduler to reproduce each of the examples in the
13
-   chapter? Give to each figure number of the PDF chapter the corresponding
14
-   simulator call.
15
-1. How would you configure the scheduler parameters to behave just like a
16
-   round-robin scheduler?
17
-1. Craft a workload with two jobs and scheduler parameters so that one job takes
18
-   advantage of the older Rules 4a and 4b (turned on with the -S flag) to game
19
-   the scheduler and obtain 99% of the CPU over a particular time interval.
20
-1. Given a system with a quantum length of 10ms in its highest queue, how often
21
-   would you have to boost jobs back to the highest priority level (with the -B
22
-   flag) in order to guarantee that a single long-running (and
23
-   potentially-starving) job gets at least 5% of the CPU?
24
-1. One question that arises in scheduling is which end of a queue to add a job
25
-   that just finished I/O; the -I flag changes this behavior for this scheduling
26
-   simulator. Play around with some workloads and see if you can see the effect
27
-   of this flag.

+ 0
- 184
hw5/simu2/README-mlfq.md 查看文件

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

+ 0
- 338
hw5/simu2/mlfq.py 查看文件

@@ -1,338 +0,0 @@
1
-#! /usr/bin/env python
2
-
3
-import sys
4
-from optparse import OptionParser
5
-import random
6
-
7
-# finds the highest nonempty queue
8
-# -1 if they are all empty
9
-def FindQueue():
10
-    q = hiQueue
11
-    while q > 0:
12
-        if len(queue[q]) > 0:
13
-            return q
14
-        q -= 1
15
-    if len(queue[0]) > 0:
16
-        return 0
17
-    return -1
18
-
19
-def LowerQueue(currJob, currQueue, issuedIO):
20
-    if currQueue > 0:
21
-        # in this case, have to change the priority of the job
22
-        job[currJob]['currPri'] = currQueue - 1
23
-        if issuedIO == False:
24
-            queue[currQueue-1].append(currJob)
25
-        job[currJob]['ticksLeft'] = quantum[currQueue-1]
26
-    else:
27
-        if issuedIO == False:
28
-            queue[currQueue].append(currJob)
29
-        job[currJob]['ticksLeft'] = quantum[currQueue]
30
-
31
-def Abort(str):
32
-    sys.stderr.write(str + '\n')
33
-    exit(1)
34
-
35
-
36
-#
37
-# PARSE ARGUMENTS
38
-#
39
-
40
-parser = OptionParser()
41
-parser.add_option('-s', '--seed', help='the random seed', 
42
-                  default=0, action='store', type='int', dest='seed')
43
-parser.add_option('-n', '--numQueues',
44
-                  help='number of queues in MLFQ (if not using -Q)', 
45
-                  default=3, action='store', type='int', dest='numQueues')
46
-parser.add_option('-q', '--quantum', help='length of time slice (if not using -Q)',
47
-                  default=10, action='store', type='int', dest='quantum')
48
-parser.add_option('-Q', '--quantumList',
49
-                  help='length of time slice per queue level, specified as ' + \
50
-                  'x,y,z,... where x is the quantum length for the highest ' + \
51
-                  'priority queue, y the next highest, and so forth', 
52
-                  default='', action='store', type='string', dest='quantumList')
53
-parser.add_option('-j', '--numJobs', default=3, help='number of jobs in the system',
54
-                  action='store', type='int', dest='numJobs')
55
-parser.add_option('-m', '--maxlen', default=100, help='max run-time of a job ' +
56
-                  '(if randomly generating)', action='store', type='int',
57
-                  dest='maxlen')
58
-parser.add_option('-M', '--maxio', default=10,
59
-                  help='max I/O frequency of a job (if randomly generating)',
60
-                  action='store', type='int', dest='maxio')
61
-parser.add_option('-B', '--boost', default=0,
62
-                  help='how often to boost the priority of all jobs back to ' +
63
-                  'high priority', action='store', type='int', dest='boost')
64
-parser.add_option('-i', '--iotime', default=5,
65
-                  help='how long an I/O should last (fixed constant)',
66
-                  action='store', type='int', dest='ioTime')
67
-parser.add_option('-S', '--stay', default=False,
68
-                  help='reset and stay at same priority level when issuing I/O',
69
-                  action='store_true', dest='stay')
70
-parser.add_option('-I', '--iobump', default=False,
71
-                  help='if specified, jobs that finished I/O move immediately ' + \
72
-                  'to front of current queue',
73
-                  action='store_true', dest='iobump')
74
-parser.add_option('-l', '--jlist', default='',
75
-                  help='a comma-separated list of jobs to run, in the form ' + \
76
-                  'x1,y1,z1:x2,y2,z2:... where x is start time, y is run ' + \
77
-                  'time, and z is how often the job issues an I/O request',
78
-                  action='store', type='string', dest='jlist')
79
-parser.add_option('-c', help='compute answers for me', action='store_true',
80
-                  default=False, dest='solve')
81
-
82
-(options, args) = parser.parse_args()
83
-
84
-random.seed(options.seed)
85
-
86
-
87
-# MLFQ: How Many Queues
88
-numQueues = options.numQueues
89
-
90
-quantum = {}
91
-if options.quantumList != '':
92
-    # instead, extract number of queues and their time slic
93
-    quantumLengths = options.quantumList.split(',')
94
-    numQueues = len(quantumLengths)
95
-    qc = numQueues - 1
96
-    for i in range(numQueues):
97
-        quantum[qc] = int(quantumLengths[i])
98
-        qc -= 1
99
-else:
100
-    for i in range(numQueues):
101
-        quantum[i] = int(options.quantum)
102
-
103
-hiQueue = numQueues - 1
104
-
105
-# MLFQ: I/O Model
106
-# the time for each IO: not great to have a single fixed time but...
107
-ioTime = int(options.ioTime)
108
-
109
-# This tracks when IOs and other interrupts are complete
110
-ioDone = {}
111
-
112
-# This stores all info about the jobs
113
-job = {}
114
-
115
-# seed the random generator
116
-random.seed(options.seed)
117
-
118
-# jlist 'startTime,runTime,ioFreq:startTime,runTime,ioFreq:...'
119
-jobCnt = 0
120
-if options.jlist != '':
121
-    allJobs = options.jlist.split(':')
122
-    for j in allJobs:
123
-        jobInfo = j.split(',')
124
-        if len(jobInfo) != 3:
125
-            sys.stderr.write('Badly formatted job string. Should be x1,y1,z1:x2,y2,z2:...\n')
126
-            sys.stderr.write('where x is the startTime, y is the runTime, and z is the I/O frequency.\n')
127
-            exit(1)
128
-        assert(len(jobInfo) == 3)
129
-        startTime = int(jobInfo[0])
130
-        runTime   = int(jobInfo[1])
131
-        ioFreq    = int(jobInfo[2])
132
-        job[jobCnt] = {'currPri':hiQueue, 'ticksLeft':quantum[hiQueue], 'startTime':startTime,
133
-                       'runTime':runTime, 'timeLeft':runTime, 'ioFreq':ioFreq, 'doingIO':False,
134
-                       'firstRun':-1}
135
-        if startTime not in ioDone:
136
-            ioDone[startTime] = []
137
-        ioDone[startTime].append((jobCnt, 'JOB BEGINS'))
138
-        jobCnt += 1
139
-else:
140
-    # do something random
141
-    for j in range(options.numJobs):
142
-        startTime = 0
143
-        # runTime   = int(random.random() * options.maxlen)
144
-        # ioFreq    = int(random.random() * options.maxio)
145
-        runTime   = int(random.random() * (options.maxlen - 1) + 1)
146
-        ioFreq    = int(random.random() * (options.maxio - 1) + 1)
147
-        
148
-        job[jobCnt] = {'currPri':hiQueue, 'ticksLeft':quantum[hiQueue], 'startTime':startTime,
149
-                       'runTime':runTime, 'timeLeft':runTime, 'ioFreq':ioFreq, 'doingIO':False,
150
-                       'firstRun':-1}
151
-        if startTime not in ioDone:
152
-            ioDone[startTime] = []
153
-        ioDone[startTime].append((jobCnt, 'JOB BEGINS'))
154
-        jobCnt += 1
155
-
156
-
157
-numJobs = len(job)
158
-
159
-print 'Here is the list of inputs:'
160
-print 'OPTIONS jobs',            numJobs
161
-print 'OPTIONS queues',          numQueues
162
-for i in range(len(quantum)-1,-1,-1):
163
-    print 'OPTIONS quantum length for queue %2d is %3d' % (i, quantum[i])
164
-print 'OPTIONS boost',           options.boost
165
-print 'OPTIONS ioTime',          options.ioTime
166
-print 'OPTIONS stayAfterIO',     options.stay
167
-print 'OPTIONS iobump',          options.iobump
168
-
169
-print '\n'
170
-print 'For each job, three defining characteristics are given:'
171
-print '  startTime : at what time does the job enter the system'
172
-print '  runTime   : the total CPU time needed by the job to finish'
173
-print '  ioFreq    : every ioFreq time units, the job issues an I/O'
174
-print '              (the I/O takes ioTime units to complete)\n'
175
-
176
-print 'Job List:'
177
-for i in range(numJobs):
178
-    print '  Job %2d: startTime %3d - runTime %3d - ioFreq %3d' % (i, job[i]['startTime'],
179
-                                                                   job[i]['runTime'], job[i]['ioFreq'])
180
-print ''
181
-
182
-if options.solve == False:
183
-    print 'Compute the execution trace for the given workloads.'
184
-    print 'If you would like, also compute the response and turnaround'
185
-    print 'times for each of the jobs.'
186
-    print ''
187
-    print 'Use the -c flag to get the exact results when you are finished.\n'
188
-    exit(0)
189
-
190
-# initialize the MLFQ queues
191
-queue = {}
192
-for q in range(numQueues):
193
-    queue[q] = []
194
-
195
-# TIME IS CENTRAL
196
-currTime = 0
197
-
198
-# use these to know when we're finished
199
-totalJobs    = len(job)
200
-finishedJobs = 0
201
-
202
-print '\nExecution Trace:\n'
203
-
204
-while finishedJobs < totalJobs:
205
-    # find highest priority job
206
-    # run it until either
207
-    # (a) the job uses up its time quantum
208
-    # (b) the job performs an I/O
209
-
210
-    # check for priority boost
211
-    if options.boost > 0 and currTime != 0:
212
-        if currTime % options.boost == 0:
213
-            print '[ time %d ] BOOST ( every %d )' % (currTime, options.boost)
214
-            # remove all jobs from queues (except high queue)
215
-            for q in range(numQueues-1):
216
-                for j in queue[q]:
217
-                    if job[j]['doingIO'] == False:
218
-                        queue[hiQueue].append(j)
219
-                queue[q] = []
220
-            # print 'BOOST: QUEUES look like:', queue
221
-
222
-            # change priority to high priority
223
-            # reset number of ticks left for all jobs (XXX just for lower jobs?)
224
-            # add to highest run queue (if not doing I/O)
225
-            for j in range(numJobs):
226
-                # print '-> Boost %d (timeLeft %d)' % (j, job[j]['timeLeft'])
227
-                if job[j]['timeLeft'] > 0:
228
-                    # print '-> FinalBoost %d (timeLeft %d)' % (j, job[j]['timeLeft'])
229
-                    job[j]['currPri']   = hiQueue
230
-                    job[j]['ticksLeft'] = quantum[hiQueue]
231
-            # print 'BOOST END: QUEUES look like:', queue
232
-
233
-    # check for any I/Os done
234
-    if currTime in ioDone:
235
-        for (j, type) in ioDone[currTime]:
236
-            q = job[j]['currPri']
237
-            job[j]['doingIO'] = False
238
-            print '[ time %d ] %s by JOB %d' % (currTime, type, j)
239
-            if options.iobump == False or type == 'JOB BEGINS':
240
-                queue[q].append(j)
241
-            else:
242
-                queue[q].insert(0, j)
243
-
244
-    # now find the highest priority job
245
-    currQueue = FindQueue()
246
-    if currQueue == -1:
247
-        print '[ time %d ] IDLE' % (currTime)
248
-        currTime += 1
249
-        continue
250
-    #print 'FOUND QUEUE: %d' % currQueue
251
-    #print 'ALL QUEUES:', queue
252
-            
253
-    # there was at least one runnable job, and hence ...
254
-    currJob = queue[currQueue][0]
255
-    if job[currJob]['currPri'] != currQueue:
256
-        Abort('currPri[%d] does not match currQueue[%d]' % (job[currJob]['currPri'], currQueue))
257
-
258
-    job[currJob]['timeLeft']  -= 1
259
-    job[currJob]['ticksLeft'] -= 1
260
-
261
-    if job[currJob]['firstRun'] == -1:
262
-        job[currJob]['firstRun'] = currTime
263
-
264
-    runTime   = job[currJob]['runTime']
265
-    ioFreq    = job[currJob]['ioFreq']
266
-    ticksLeft = job[currJob]['ticksLeft']
267
-    timeLeft  = job[currJob]['timeLeft']
268
-
269
-    print '[ time %d ] Run JOB %d at PRIORITY %d [ TICKSLEFT %d RUNTIME %d TIMELEFT %d ]' % \
270
-          (currTime, currJob, currQueue, ticksLeft, runTime, timeLeft)
271
-
272
-    if timeLeft < 0:
273
-        Abort('Error: should never have less than 0 time left to run')
274
-
275
-
276
-    # UPDATE TIME
277
-    currTime += 1
278
-
279
-    # CHECK FOR JOB ENDING
280
-    if timeLeft == 0:
281
-        print '[ time %d ] FINISHED JOB %d' % (currTime, currJob)
282
-        finishedJobs += 1
283
-        job[currJob]['endTime'] = currTime
284
-        # print 'BEFORE POP', queue
285
-        done = queue[currQueue].pop(0)
286
-        # print 'AFTER POP', queue
287
-        assert(done == currJob)
288
-        continue
289
-
290
-    # CHECK FOR IO
291
-    issuedIO = False
292
-    if ioFreq > 0 and (((runTime - timeLeft) % ioFreq) == 0):
293
-        # time for an IO!
294
-        print '[ time %d ] IO_START by JOB %d' % (currTime, currJob)
295
-        issuedIO = True
296
-        desched = queue[currQueue].pop(0)
297
-        assert(desched == currJob)
298
-        job[currJob]['doingIO'] = True
299
-        # this does the bad rule -- reset your tick counter if you stay at the same level
300
-        if options.stay == True:
301
-            job[currJob]['ticksLeft'] = quantum[currQueue]
302
-        # add to IO Queue: but which queue?
303
-        futureTime = currTime + ioTime
304
-        if futureTime not in ioDone:
305
-            ioDone[futureTime] = []
306
-        print 'IO DONE'
307
-        ioDone[futureTime].append((currJob, 'IO_DONE'))
308
-        # print 'NEW IO EVENT at ', futureTime, ' is ', ioDone[futureTime]
309
-        
310
-    # CHECK FOR QUANTUM ENDING AT THIS LEVEL
311
-    if ticksLeft == 0:
312
-        # print '--> DESCHEDULE %d' % currJob
313
-        if issuedIO == False:
314
-            # print '--> BUT IO HAS NOT BEEN ISSUED (therefor pop from queue)'
315
-            desched = queue[currQueue].pop(0)
316
-        assert(desched == currJob)
317
-        # move down one queue! (unless lowest queue)
318
-        LowerQueue(currJob, currQueue, issuedIO)
319
-
320
-
321
-# print out statistics
322
-print ''
323
-print 'Final statistics:'
324
-responseSum   = 0
325
-turnaroundSum = 0
326
-for i in range(numJobs):
327
-    response   = job[i]['firstRun'] - job[i]['startTime']
328
-    turnaround = job[i]['endTime'] - job[i]['startTime']
329
-    print '  Job %2d: startTime %3d - response %3d - turnaround %3d' % (i, job[i]['startTime'],
330
-                                                                        response, turnaround)
331
-    responseSum   += response
332
-    turnaroundSum += turnaround
333
-
334
-print '\n  Avg %2d: startTime n/a - response %.2f - turnaround %.2f' % (i, 
335
-                                                                        float(responseSum)/numJobs,
336
-                                                                        float(turnaroundSum)/numJobs)
337
-
338
-print '\n'

+ 0
- 243
hw5/task1/README.md 查看文件

@@ -1,243 +0,0 @@
1
-# Homework hw5 task1
2
-
3
-- [1.1. Ziel](#11-ziel)
4
-- [1.2. Externe Crate nutzen](#12-externe-crate-nutzen)
5
-    - [1.2.1. Versionen der externen Crates](#121-versionen-der-externen-crates)
6
-- [1.3. Aufgaben](#13-aufgaben)
7
-    - [1.3.1. Optionale Parameter](#131-optionale-parameter)
8
-    - [1.3.2. Externe Crate in Dependencies eintragen](#132-externe-crate-in-dependencies-eintragen)
9
-    - [1.3.3. Die Funktion `pub fn run_zombie()`](#133-die-funktion-pub-fn-runzombie)
10
-    - [1.3.4. Die Funktion `pub fn run_childs(start_pid: i32, arg: &str) -> Result<(), String>`](#134-die-funktion-pub-fn-runchildsstartpid-i32-arg-str---result-string)
11
-- [1.4. Tests](#14-tests)
12
-- [1.5. Dokumentation](#15-dokumentation)
13
-- [1.6. Kontrolle Ihres Repositories](#16-kontrolle-ihres-repositories)
14
-
15
-## 1.1. Ziel
16
-
17
-Ziel dieser Aufgabe ist es, mittels des externen Crates *nix* einige systemnahe
18
-Funktionen zur Prozesserzeugung und -synchronisierung kennen zu lernen.
19
-
20
-Über optionale Aufrufparameter werden die verschiedenen Verhaltensweisen Ihres
21
-Programms getrickert.
22
-
23
-## 1.2. Externe Crate nutzen
24
-
25
-Um möglichst direkt die Systemfunktionen zu nutzen, stellt das *[nix Crate][]*
26
-eine einheitliche Schnittstelle dar. Insbesondere der Umgang mit der
27
-Fehlerbehandlung ist unter Rust und der nix Crate um einiges komfortabler und
28
-sicherer. Dazu stellt die nix Crate über den Result Typ die Informationen über
29
-den aufgerufenen Systemcall zur Verfügung. Rust Datentypen werden in der nix
30
-Crate überall dort benutzt wo dies Sinn macht. So werden z.B. Slices als
31
-Standard benutzt, wenn Bereiche eines Puffers weitergegeben werden müssen.
32
-Dieser Standard soll nun wiederum in C++ im C++17 Standard einfließen.
33
-
34
-In dieser Aufgabe interessieren wir uns vor allem für das *nix* Modul
35
-`nix::unistd` und `nix::sys::wait`. Darüber hinaus werden auch weitere Rust
36
-Standard-Library Methoden benutzt, sowie die externe Crate *procinfo*
37
-eingebunden.
38
-
39
-### 1.2.1. Versionen der externen Crates
40
-
41
-- *nix*: 0.9.0
42
-- *procinfo*: 0.4.2
43
-
44
-In Ihrer Lösung dürfen nur diese beiden externen Crates eingebunden werden.
45
-
46
-## 1.3. Aufgaben
47
-
48
-### 1.3.1. Optionale Parameter
49
-
50
-Ihr Programm wird sich entsprechend der übergebenen Optionen unterschiedlich
51
-verhalten:
52
-
53
-- ohne Parameter: Aufruf der Funktion `pub fn run_zombie()`
54
-- ein Parameter: Aufruf der Funktion `pub fn run_childs(start_pid: i32, arg:
55
-  &str) -> Result<(), String>`
56
-
57
-Details zu den einzelnen Funktionen erhalten Sie bei den entsprechenden Aufgaben
58
-dazu.
59
-
60
-### 1.3.2. Externe Crate in Dependencies eintragen
61
-
62
-- Benutzen Sie für die folgenden Aufgaben das *[nix Crate][]*.
63
-- Fügen Sie dazu den notwendigen Eintrag unter `[dependencies]` in
64
-  **Cargo.toml** hinzu und benutzen in Ihrem Root Modul `main.rs` die
65
-  entsprechende extern Anweisung.
66
-
67
-### 1.3.3. Die Funktion `pub fn run_zombie()`
68
-
69
-Wird das Programm ohne einen Parameter aufgerufen, erstellen wir als 'Belohnung'
70
-für diesen 'müden' Programmaufruf einen Zombie! Dies geschieht im Modul
71
-*zombie/mod.rs* über die dortige Funktion `pub fn run_zombie()`. Innerhalb
72
-dieser Funktion behandeln Sie evtl. auftretende Fehler direkt mit
73
-Programmabbruch. Dies gilt jedoch nur für diesen Aufgabenpunkt!
74
-
75
-Was ist ein Zombieprozess?
76
-
77
->"Wenn ein Prozess einen neuen Prozess startet (mittels Forking), wird der alte
78
->'Elternprozess' und der neue 'Kindprozess' genannt. Wenn der Kindprozess
79
->beendet wird, kann der Elternprozess vom Betriebssystem erfragen, auf welche
80
->Art der Kindprozess beendet wurde: erfolgreich, mit Fehler, abgestürzt,
81
->abgebrochen, etc.
82
->
83
->Um diese Abfrage zu ermöglichen, bleibt ein Prozess, selbst nachdem er beendet
84
->wurde, in der Prozesstabelle stehen, bis der Elternprozess diese Abfrage
85
->durchführt – egal ob diese Information gebraucht wird oder nicht. Bis dahin hat
86
->der Kindprozess den Zustand Zombie. In diesem Zustand belegt der Prozess selbst
87
->keinen Arbeitsspeicher mehr (bis auf den platzmäßig vernachlässigbaren Eintrag
88
->in der Prozesstabelle des Kernels) und verbraucht auch keine Rechenzeit, jedoch
89
->behält er seine PID, die (noch) nicht für andere Prozesse wiederverwendet
90
->werden kann." ([Quelle Wikipedia][])
91
-
92
-Die Funktion `run_zombie()` erstellen Sie im Modul *zombie/mod.rs*. Wenn Sie Ihr
93
-Programm ohne Parameter aufrufen, erhalten Sie bei korrekter Zombie
94
-'Generierung' folgende Ausgabe:
95
-
96
-```text
97
-PID   TTY      STAT   TIME COMMAND
98
-27524 pts/1    Ss     0:00 -bash
99
-27531 pts/1    S      0:00 zsh
100
-27935 pts/1    S+     0:00 cargo run
101
-27936 pts/1    S+     0:00 target/debug/task1
102
-27962 pts/1    Z+     0:00 [task1] \<defunct\>
103
-27963 pts/1    R+     0:00 ps t
104
-```
105
-
106
-Diese Ausgabe wird über das Programm **ps t** generiert, welches in Ihrem
107
-Programm dann geschickterweise aufgerufen wird, wenn Sie den im vorherigen Text
108
-beschriebenen Zustand durch Ihr Programm selbst hergestellt haben. Den
109
-Zombizustand bekommen Sie als Z dargestellt, siehe auch [man ps][].
110
-
111
->Tipp: Um Ihr Programm einen Moment 'schlafen' zu lassen, stellt Ihnen Rust die
112
->Funktion [thread::sleep][] zur Verfügung. Ein Prozess besteht aus mindestens
113
->einem Thread (Main-Thread). Und da Sie keine weiteren Threads erstellen, lässt
114
->diese Funktion Ihren Prozess (bestehend aus einem Main-Thread) schlafen.
115
-
116
-Um ein anderes Programm aus Ihrem Programm heraus starten zu lassen stellen
117
-Ihnen die *nix* Crate und die `std Bibliothek verschiedene Funktionen` bereit:
118
-
119
-- [Module nix::unistd][] der *nix* Crate: die Funktion execv(), execve() und
120
-   execvp()
121
-
122
-- [Module std::process][] der Standardbibliothek: Machen Sie sich mit der
123
-   Benutzung von [Module std::process][] grob vertraut, insbesondere die
124
-   Methoden des Typs [Command][]:
125
-
126
-  - new
127
-  - arg
128
-  - spawn
129
-  - output
130
-  - status
131
-
132
-Je nachdem für welche Bibliothek Sie sich entscheiden, experimentieren Sie zu
133
-Beginn ein wenig mit den Code Beispielen der Dokumentation.
134
-
135
->Tipp: Das Command Interface der Standardbibliothek ist einfacher zu verwenden.
136
-
137
-### 1.3.4. Die Funktion `pub fn run_childs(start_pid: i32, arg: &str) -> Result<(), String>`
138
-
139
-Wird ein Parameter (`arg`) beim Aufruf Ihres Programms mit angegeben,
140
-spezifiziert dieser Parameter die Anzahl der zu erzeugenden Kindprozesse.
141
-Wichtig dabei ist, dass alle zu erstellenden Kindprozesse voneinander abhängen.
142
-Rufen Sie im letzten erstellten Kindprozess Ihre bereits erstellte `pstree()`
143
-Funktion mit der übergebenen PID des 1. Elternprozesses (`start_pid`) auf, so
144
-können Sie aufgrund der ausgegebenen Liste erkennen, ob alle Kindprozess
145
-voneinander abhängen. Ihr *pstree* Modul stellen Sie in *child/pstree.rs*
146
-bereit, da dieses nur im Modul *child/mod.rs* benutzt werden muss.
147
-
148
-> Die Pid aus dem **nix Crate** ist vom Typ `Pid`, welches ein Alias ist. Lesen
149
-> Sie dazu die Dokumentation des nix Crates und benutzen Sie eine geeignete Rust
150
-> Funktion (einer Trait), um diesen Typ als i32 an Ihre Funktion `run_childs()`
151
-> weiterzugeben. Sie müssen in der **pstree Funktion** dazu nichts anpassen!
152
-
153
-```text
154
-> ./target/debug/task1 4
155
-...
156
-task1(28207)---task1(28233)---task1(28234)---task1(28235)---task1(28236)
157
-...
158
-```
159
-
160
-Implementieren Sie die Funktion `pub fn run_childs(start_pid: i32, arg: &str) ->
161
-Result<(), String>` im Modul *child/mod.rs*. Alle dazu nötigen Hilfsfunktionen
162
-werden entweder in *child/mod.rs* oder entsprechenden Modulen im *child/*
163
-Verzeichnis zur Verfügung gestellt. Evtl. auftretende Fehler werden an das Root
164
-Modul (*main.rs*) zurückgegeben und dort behandelt. Bei dieser Teilaufgabe
165
-müssen alle auftretenden Fehler entsprechend an das Root-Modul zurückgegeben
166
-werden. Treten Fehler auf, so darf die Fehlermeldung, generiert im Root-Modul,
167
-dazu max. 1 Zeile lang sein und der Exit-Code des Programms muss '1' sein.
168
-
169
-Parsen Sie den übergebenen Parameter mit der `parse()` Funktion in einen `u8`
170
-Typ! Es ist wichtig, dass Sie im weiteren die Anzahl der Kindprozesse über eine
171
-`u8` Variable steuern!
172
-
173
-Jedes Child soll eine Ausgabe machen, sowie jeder Parent, wenn sich der Child
174
-beendet hat:
175
-
176
-- Child: hello, I am child (\<pid\>)
177
-- Eltern: I am \<pid\> and my child is \<child\>.  After I waited for
178
-  \<waitstatuspid\>, it sent me status \<status\>
179
-
180
-  - \<pid\> via getpid()
181
-  - \<child\> = child pid
182
-  - \<waitstatuspid\> = see Ok of waitpid()
183
-  - \<status\> = see Ok of waitpid()
184
-
185
-```text
186
-> ./target/debug/task1 4
187
-hello, I am child (pid:28233)
188
-hello, I am child (pid:28234)
189
-hello, I am child (pid:28235)
190
-hello, I am child (pid:28236)
191
-
192
-task1(28207)---task1(28233)---task1(28234)---task1(28235)---task1(28236)
193
-I am 28235 and my child is 28236.  After I waited for 28236, it sent me status 0
194
-I am 28234 and my child is 28235.  After I waited for 28235, it sent me status 0
195
-I am 28233 and my child is 28234.  After I waited for 28234, it sent me status 0
196
-I am 28207 and my child is 28233.  After I waited for 28233, it sent me status 0
197
-```
198
-
199
->Leerzeile wichtig nach der Ausgabe aller Kinder!
200
-
201
-## 1.4. Tests
202
-
203
-Für das *tests/* Verzeichnis steht wieder eine *output.bats* Datei zur
204
-Verfügung. Ausserdem erstellen Sie bitte eigene Unit Tests in einer eigenen zu
205
-erstellenden *unit_tests.rs* Datei in Ihrem Crate Root Verzeichnis (*src/*).
206
-
207
-## 1.5. Dokumentation
208
-
209
-Erstellen Sie für alle Module und Funktionen eine kurze aber aussagekräftige
210
-Dokumentation, und vergessen Sie nicht wichtige Passagen auch im Code zu
211
-kommentieren. Als Tutoren sollte es uns möglich sein, schnell Ihre genialen
212
-Lösungen nachvollziehen zu können.
213
-
214
-## 1.6. Kontrolle Ihres Repositories
215
-
216
-Haben Sie die Aufgaben komplett bearbeitet, so sollten sich folgende Dateien in
217
-Ihrem HW (Homework) Verzeichnis befinden:
218
-
219
-```text
220
-.
221
-├── Cargo.lock
222
-├── Cargo.toml
223
-├── README.md
224
-├── src
225
-│   ├── child
226
-│   │   ├── mod.rs
227
-│   │   └── pstree.rs
228
-│   ├── main.rs
229
-│   └── zombie
230
-│       └── mod.rs
231
-└── tests
232
-    └── output.bats
233
-
234
-4 directories, 8 files
235
-```
236
-
237
-[nix Crate]: https://docs.rs/nix/0.8.1/nix/
238
-[Module nix::unistd]: https://docs.rs/nix/0.8.1/nix/unistd/index.html
239
-[Module std::process]: https://doc.rust-lang.org/std/process/
240
-[Command]: https://doc.rust-lang.org/std/process/struct.Command.html
241
-[Quelle Wikipedia]: https://de.wikipedia.org/wiki/Zombie-Prozess
242
-[thread::sleep]: https://doc.rust-lang.org/std/thread/fn.sleep.html
243
-[man ps]: http://man7.org/linux/man-pages/man1/ps.1.html

+ 0
- 104
hw5/task1/tests/output.bats 查看文件

@@ -1,104 +0,0 @@
1
-#!/usr/bin/env bats
2
-
3
-
4
-@test "task1: Check that we have a debug output" {
5
-    run stat "$BATS_TEST_DIRNAME/../target/debug/task1"
6
-    [ "$status" -eq 0 ]
7
-}
8
-
9
-# Check lines of output
10
-
11
-# wc output with white spaces is trimmed by xargs
12
-@test "task1: Output with Zombie must at least 4 Lines long" {
13
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' | wc -l | xargs"
14
-    [ "$output" -gt 4 ]
15
-
16
-}
17
-
18
-# wc output with white spaces is trimmed by xargs
19
-@test "task1: Output with to many paras must be exact 1 line long" {
20
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' 2 3 4 | wc -l | xargs"
21
-    [ "$output" = "1" ]
22
-
23
-}
24
-
25
-
26
-# wc output with white spaces is trimmed by xargs
27
-@test "task1: Output with wrong para must be exact 1 line long" {
28
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' y | wc -l | xargs"
29
-    [ "$output" = "1" ]
30
-}
31
-
32
-# wc output with white spaces is trimmed by xargs
33
-@test "task1: Output with wrong para must be exact 1 line long" {
34
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' -1 | wc -l | xargs"
35
-    [ "$output" = "1" ]
36
-}
37
-
38
-# wc output with white spaces is trimmed by xargs
39
-@test "task1: Output with para 0 must be exact 0 line long" {
40
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' 0 | wc -l | xargs"
41
-    [ "$output" = "0" ]
42
-}
43
-
44
-# wc output with white spaces is trimmed by xargs
45
-@test "task1: Output with para 256 must be exact 1 line long" {
46
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' 256 | wc -l | xargs"
47
-    [ "$output" = "1" ]
48
-}
49
-
50
-# wc output with white spaces is trimmed by xargs
51
-@test "task1: Output with para 1 must be exact 4 line long" {
52
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' 1 | wc -l | xargs"
53
-    [ "$output" = "4" ]
54
-}
55
-
56
-# wc output with white spaces is trimmed by xargs
57
-@test "task1: Output with para 16 must be exact 34 line long" {
58
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' 16 | wc -l | xargs"
59
-    [ "$output" = "34" ]
60
-}
61
-
62
-# wc output with white spaces is trimmed by xargs
63
-@test "task1: Output with para 255 must be exact 512 line long" {
64
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' 255 | wc -l | xargs"
65
-    [ "$output" = "512" ]
66
-}
67
-
68
-# Status checks
69
-@test "task1: Output with wrong CHILD_NUMBERS does not crash" {
70
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' 0 "
71
-    [ "$status" = 1 ]
72
-}
73
-
74
-@test "task1: Output with wrong CHILD_NUMBERS does not crash" {
75
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' 256 "
76
-    [ "$status" = 1 ]
77
-}
78
-
79
-@test "task1: Output with wrong PARAM does not crash" {
80
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' a "
81
-    [ "$status" = 1 ]
82
-}
83
-
84
-@test "task1: Output with to many para does not crash" {
85
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' 2 3 4 "
86
-    [ "$status" = 1 ]
87
-}
88
-
89
-@test "task1: Output with standard CHILD_NUMBERS exits with 0" {
90
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' 4 "
91
-    [ "$status" = 0 ]
92
-}
93
-
94
-@test "task1: Output with MIN CHILD_NUMBERS exits with 0" {
95
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' 1 "
96
-    [ "$status" = 0 ]
97
-}
98
-
99
-@test "task1: Output with MAX CHILD_NUMBERS exits with 0" {
100
-    run bash -c "'$BATS_TEST_DIRNAME/../target/debug/task1' 255 "
101
-    [ "$status" = 0 ]
102
-}
103
-
104
-

+ 0
- 0
hw5/task2/README.md 查看文件


部分文件因为文件数量过多而无法显示

正在加载...
取消
保存