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

+ 0
- 15
.gitignore 查看文件

@@ -1,15 +0,0 @@
1
-# Generated by Cargo
2
-# will have compiled files and executables
3
-*/*/target/
4
-
5
-# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
6
-# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
7
-Cargo.lock
8
-
9
-# These are backup files generated by rustfmt
10
-**/*.rs.bk
11
-
12
-*.swp
13
-
14
-# Files generated by IntelliJ IDEA
15
-*.idea

+ 48
- 0
GRADING.md 查看文件

@@ -1 +1,49 @@
1 1
 # Grading
2
+
3
+### hw1 (kein PR gestellt)
4
+
5
+| Task | Credits | Comment |
6
+|---|---|---|
7
+| simu1 | 0 | |
8
+| task1 | 0 | |
9
+| task2 | 0 | |
10
+| task3 | 0 | |
11
+| task4 | 0 | |
12
+| simu2 | 0 | |
13
+| task5 | 0 | |
14
+| Deadline | 0 | |
15
+| = | 0 | |
16
+
17
+### hw2
18
+
19
+| Task | Credits | Comment |
20
+|---|---|---|
21
+| task1 | 1 | |
22
+| task2 | 2 | |
23
+| task3 | 1 | |
24
+| simu1 | 0,7 | Frage 5 und 7 nicht beantwortet|
25
+| Deadline | 1 | |
26
+| = | 5,7 | |
27
+
28
+### hw3
29
+
30
+| Task | Credits | Comment |
31
+| --- | --- | --- |
32
+| simu1    | 1 |  |
33
+| simu2    | 0,8 | Anteiliger Abzug (1) |
34
+| simu3    | 0,7 | Anteiliger Abzug für (4,6) |
35
+| simu4    | 0,9 | Anteiliger Abzug für (1.3) |
36
+| Deadline | 0,9 | Anteiliger Abzug |
37
+| = | 4,3 | |
38
+
39
+### hw4
40
+
41
+| Task     | Credits | Comment |
42
+| -------- | ------- | ------- |
43
+| task1    | 2        |         |
44
+| simu1    | 0,08        | Anteilige Abzüge(1,2,3)        |
45
+| simu2    | 1       |         |
46
+| simu3    | 0,33        | Anteilige Abzüge(2,3)       |
47
+| task2    | 0       | nicht bearbeitet         |
48
+| Deadline | 0,9       |         |
49
+| =        | 4,31       |         |

+ 6
- 4
README.md 查看文件

@@ -20,7 +20,9 @@
20 20
 
21 21
 In diesem Ordner werden die Aufgaben (Homework,`hw`) veröffentlicht, die bearbeitet werden müssen, um den Schein in BSYS zu bekommen.
22 22
 
23
-Eine Homework besteht aus einer oder mehreren Tasks. Sie finden somit die zu einer Homework gehörenden Aufgaben in den `README.md`, Dateien der zughörigen `hwN/taskN/` Ordner. `N` steht als Platzhalter für die entsprechende Homework bzw. Tasknummer.
23
+Eine Homework besteht aus einer oder mehreren Tasks. Sie finden somit die zu einer Homework gehörenden Aufgaben in den `README.md`, Dateien der zughörigen `hwN/taskN/` Ordner.
24
+
25
+> `N` steht als Platzhalter für die entsprechende Homework bzw. Tasknummer.
24 26
 
25 27
 ## Vorbereitung
26 28
 Die folgenden Befehle demonstrieren den prinzipiellen technischen Ablauf um die Aufgaben vorzubereiten.
@@ -33,13 +35,13 @@ Nach der Vorbereitung haben beide Gruppenmitglieder eine lokale Kopie des Git-Re
33 35
 > Wer UserA und UserB ist, ist nicht wichtig, darf aber während des gesamten Ablaufs nicht verändert werden!
34 36
 
35 37
 ### User A and User B @ Github:
36
-* Visit invitation link and join _grp$N_
38
+* Visit invitation link and join _grpN_
37 39
 
38 40
 ## Git and GitHub Preparations
39 41
 
40 42
 ### User A @ GitHub
41
-* *htwg-syslab-bsys-ws17/bsys-ws17-grp$N* -> fork -> *UserA/bsys-ws17-grp$N*
42
-* Add _UserB_ as collaborator to *UserA/bsys-ws17-grp$N*
43
+* *htwg-syslab-bsys-ws17/bsys-ws17-grpN* -> fork -> *UserA/bsys-ws17-grpN*
44
+* Add _UserB_ as collaborator to *UserA/bsys-ws17-grpN*
43 45
 
44 46
 ### User A @ Container:
45 47
 

+ 34
- 0
files/hw1.txt 查看文件

@@ -0,0 +1,34 @@
1
+./hw1/README.md
2
+./hw1/simu1/README-process-run.md
3
+./hw1/simu1/ANSWERS.md
4
+./hw1/simu1/QUESTIONS.md
5
+./hw1/simu1/process-run.py
6
+
7
+
8
+./hw1/simu2/QUESTIONS.md
9
+?./hw1/simu2/ANSWERS.md
10
+
11
+./hw1/task1/Cargo.toml
12
+./hw1/task1/src/lib.rs
13
+./hw1/task1/tests/task1.rs
14
+
15
+
16
+./hw1/task2/Cargo.toml
17
+./hw1/task2/src/lib.rs
18
+./hw1/task2/tests/task2.rs
19
+
20
+
21
+./hw1/task3/Cargo.toml
22
+./hw1/task3/src/lib.rs
23
+./hw1/task3/tests/task3.rs
24
+
25
+
26
+./hw1/task4/Cargo.toml
27
+./hw1/task4/src/lib.rs
28
+./hw1/task4/tests/task4.rs
29
+
30
+./hw1/task5/Cargo.toml
31
+./hw1/task5/Cargo.lock
32
+./hw1/task5/src/main.rs
33
+./hw1/task5/tests/output.bats
34
+

+ 21
- 0
files/hw2.txt 查看文件

@@ -0,0 +1,21 @@
1
+./hw2/README.md
2
+./hw2/simu1/ANSWERS.md
3
+./hw2/simu1/QUESTIONS.md
4
+./hw2/simu1/null.c
5
+
6
+./hw2/task1/README.md
7
+./hw2/task1/Cargo.toml
8
+./hw2/task1/tests/task1.rs
9
+./hw2/task1/src/lib.rs
10
+
11
+./hw2/task2/README.md
12
+./hw2/task2/Cargo.toml
13
+./hw2/task2/Cargo.lock
14
+./hw2/task2/tests/task2.rs
15
+./hw2/task2/src/lib.rs
16
+./hw2/task2/src/main.rs
17
+
18
+?./hw2/task3/README.md
19
+?./hw2/task3/Cargo.toml
20
+?./hw2/task3/tests/task3.rs
21
+?./hw2/task3/src/lib.rs

+ 22
- 0
files/hw3.txt 查看文件

@@ -0,0 +1,22 @@
1
+./hw3/README.md
2
+
3
+./hw3/simu1/QUESTIONS.md
4
+./hw3/simu1/README-relocation.md
5
+./hw3/simu1/relocation.py
6
+./hw3/simu1/ANSWERS.md
7
+
8
+./hw3/simu2/QUESTIONS.md
9
+./hw3/simu2/README-segmentation.md
10
+./hw3/simu2/segmentation.py
11
+./hw3/simu2/ANSWERS.md
12
+
13
+./hw3/simu3/QUESTIONS.md
14
+./hw3/simu3/README-malloc.md
15
+./hw3/simu3/malloc.py
16
+./hw3/simu3/ANSWERS.md
17
+
18
+./hw3/simu4/QUESTIONS.md
19
+./hw3/simu4/README-paging-linear-translate.md
20
+./hw3/simu4/paging-linear-translate.py
21
+./hw3/simu4/ANSWERS.md
22
+

+ 27
- 0
files/hw4.txt 查看文件

@@ -0,0 +1,27 @@
1
+./hw4/README.md
2
+
3
+./hw4/simu1/ANSWERS.md
4
+./hw4/simu1/QUESTIONS.md
5
+./hw4/simu1/paging-multilevel-translate.py
6
+./hw4/simu1/README-paging-multilevel-translate.md
7
+
8
+./hw4/simu2/ANSWERS.md
9
+./hw4/simu2/QUESTIONS.md
10
+./hw4/simu2/Makefile
11
+./hw4/simu2/mem.c
12
+./hw4/simu2/README-mem-vmstat.md
13
+
14
+./hw4/simu3/ANSWERS.md
15
+./hw4/simu3/QUESTIONS.md
16
+./hw4/simu3/README-paging-policy.md
17
+./hw4/simu3/paging-policy.py
18
+
19
+./hw4/task1/Cargo.lock
20
+./hw4/task1/Cargo.toml
21
+./hw4/task1/src/main.rs
22
+./hw4/task1/src/pstree.rs
23
+./hw4/task1/src/readproc.rs
24
+./hw4/task1/src/unit_test_readproc.rs
25
+./hw4/task1/src/unit_test_pstree.rs
26
+./hw4/task1/tests/output.bats
27
+

+ 20
- 0
files/hw5.txt 查看文件

@@ -0,0 +1,20 @@
1
+./hw5/README.md
2
+
3
+./hw5/task1/Cargo.lock
4
+./hw5/task1/Cargo.toml
5
+./hw5/task1/src/main.rs
6
+./hw5/task1/src/zombie/mod.rs
7
+./hw5/task1/src/child/mod.rs
8
+./hw5/task1/src/child/pstree.rs
9
+./hw5/task1/src/unit_tests.rs
10
+./hw5/task1/tests/output.bats
11
+
12
+./hw5/simu1/ANSWERS.md
13
+./hw5/simu1/QUESTIONS.md
14
+./hw5/simu1/README-scheduler.md
15
+./hw5/simu1/scheduler.py
16
+
17
+./hw5/simu2/ANSWERS.md
18
+./hw5/simu2/QUESTIONS.md
19
+./hw5/simu2/README-mlfq.md
20
+./hw5/simu2/mlfq.py

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


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


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


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

@@ -0,0 +1,37 @@
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
+```

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

@@ -0,0 +1,81 @@
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

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

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

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

@@ -0,0 +1,47 @@
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 | |

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

@@ -0,0 +1,35 @@
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/

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

@@ -0,0 +1,236 @@
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)

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

@@ -0,0 +1,325 @@
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 ''

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

@@ -0,0 +1,18 @@
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`?

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

@@ -0,0 +1,31 @@
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.

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

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

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

@@ -0,0 +1,25 @@
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
+}

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

@@ -0,0 +1,24 @@
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.

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

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

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

@@ -0,0 +1,41 @@
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
+}

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

@@ -0,0 +1,8 @@
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.

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

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

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

@@ -0,0 +1,45 @@
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
+}

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

@@ -0,0 +1,22 @@
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

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

@@ -0,0 +1,11 @@
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
+}

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

@@ -0,0 +1,31 @@
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
+}

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

@@ -0,0 +1,32 @@
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.

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

@@ -0,0 +1,40 @@
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
+}

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

@@ -0,0 +1,27 @@
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
+}

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

@@ -0,0 +1,40 @@
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            |         |

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

@@ -0,0 +1,9 @@
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
+

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

@@ -0,0 +1,11 @@
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 $@

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

@@ -0,0 +1,72 @@
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

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

@@ -0,0 +1,7 @@
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
+}

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

@@ -0,0 +1,7 @@
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
+}

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

@@ -0,0 +1,8 @@
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
+}

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

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

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

@@ -0,0 +1,12 @@
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
+}

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

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

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

@@ -0,0 +1,38 @@
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.

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

@@ -0,0 +1,22 @@
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
+}

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

@@ -0,0 +1,36 @@
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
+}

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

@@ -0,0 +1,10 @@
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"

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

@@ -0,0 +1,317 @@
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

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

@@ -0,0 +1,86 @@
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
+}

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

@@ -0,0 +1,28 @@
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
+}

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

@@ -0,0 +1,41 @@
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
+}

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

@@ -0,0 +1,95 @@
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
+}

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

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

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

@@ -0,0 +1,24 @@
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
+```

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

@@ -0,0 +1,45 @@
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
+}

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

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

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

@@ -0,0 +1,39 @@
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
+}

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

@@ -0,0 +1,51 @@
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            |         |

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

@@ -0,0 +1,21 @@
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

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

@@ -0,0 +1,53 @@
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
+    ```

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

@@ -0,0 +1,99 @@
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).

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

@@ -0,0 +1,118 @@
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
+

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

@@ -0,0 +1,82 @@
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.

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

@@ -0,0 +1,87 @@
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?

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

@@ -0,0 +1,183 @@
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!

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

@@ -0,0 +1,193 @@
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
+

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

@@ -0,0 +1,111 @@
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
+

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

@@ -0,0 +1,41 @@
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.

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

@@ -0,0 +1,164 @@
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.

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

@@ -0,0 +1,253 @@
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 ''

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

@@ -0,0 +1,14 @@
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.

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

@@ -0,0 +1,69 @@
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?

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

@@ -0,0 +1,135 @@
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.

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

@@ -0,0 +1,192 @@
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
+

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

@@ -0,0 +1,28 @@
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            |         |

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

@@ -0,0 +1,39 @@
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.

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

@@ -0,0 +1,12 @@
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!

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

@@ -0,0 +1,80 @@
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
+  ```

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

@@ -0,0 +1,265 @@
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
+

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

@@ -0,0 +1,31 @@
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.

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

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

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

@@ -0,0 +1,21 @@
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?

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

@@ -0,0 +1,92 @@
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.

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

@@ -0,0 +1,67 @@
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
+

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

@@ -0,0 +1,18 @@
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...

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

@@ -0,0 +1,19 @@
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?

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

@@ -0,0 +1,128 @@
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.

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

@@ -0,0 +1,275 @@
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
+

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

@@ -0,0 +1,25 @@
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
+}

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

@@ -0,0 +1,8 @@
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"

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

@@ -0,0 +1,277 @@
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

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

@@ -0,0 +1,95 @@
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
+}

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

@@ -0,0 +1,95 @@
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
+}

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

@@ -0,0 +1,66 @@
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
+}

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

@@ -0,0 +1,57 @@
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
+}

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

@@ -0,0 +1,63 @@
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
+}

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

@@ -0,0 +1,45 @@
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
+}

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

@@ -0,0 +1,30 @@
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
- 0
hw5/simu1/QUESTIONS.md 查看文件


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

正在加载...
取消
保存