Michael Mächtel 8 anos atrás
pai
commit
149ab5d427

+ 27
- 0
files/hw4.txt Ver arquivo

@@ -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
+

+ 28
- 0
hw4/README.md Ver arquivo

@@ -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 +1P):
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            |         |

+ 12
- 0
hw4/simu1/QUESTIONS.md Ver arquivo

@@ -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 Ver arquivo

@@ -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 Ver arquivo

@@ -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
+

+ 6
- 0
hw4/simu2/Makefile Ver arquivo

@@ -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 Ver arquivo

@@ -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 Ver arquivo

@@ -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 Ver arquivo

@@ -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
+

+ 19
- 0
hw4/simu3/QUESTIONS.md Ver arquivo

@@ -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 Ver arquivo

@@ -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 Ver arquivo

@@ -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
+

+ 197
- 0
hw4/task1/README.md Ver arquivo

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

+ 45
- 0
hw4/task1/output.bats Ver arquivo

@@ -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
+}

+ 57
- 0
hw4/task1/unit_test_readproc.rs Ver arquivo

@@ -0,0 +1,57 @@
1
+#[cfg(test)]
2
+mod tests {
3
+    use procinfo::pid::{status, status_self};
4
+    use {self_pids, get_pid_command, get_thread_count, get_ownprocess_mem, get_task_total};
5
+
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
+    #[test]
15
+    fn test0_ppid() {
16
+        assert_eq!(sol_self_pids(), self_pids().unwrap());
17
+    }
18
+
19
+    #[test]
20
+    fn test1_command() {
21
+        assert_eq!(Err("PID not alive: no command name found"),
22
+                   get_pid_command(0));
23
+    }
24
+
25
+    #[test]
26
+    fn test2_command() {
27
+        assert_eq!(Ok("systemd".to_string()), get_pid_command(1));
28
+    }
29
+
30
+
31
+    #[test]
32
+    fn test3_systemd_command() {
33
+        let status = status(1).unwrap();
34
+        assert_eq!("systemd".to_string(), status.command);
35
+    }
36
+
37
+    #[test]
38
+    fn test4_systemd_threads() {
39
+        let status = status(1).unwrap();
40
+        assert_eq!(get_thread_count(1), Ok(status.threads));
41
+    }
42
+
43
+    // Only check if fn is defined
44
+
45
+    #[test]
46
+    #[should_panic]
47
+    fn test8_mem() {
48
+        assert_eq!(Ok((0, 0, 0)), get_ownprocess_mem());
49
+    }
50
+
51
+    #[test]
52
+    #[should_panic]
53
+    fn test9_get_task_total() {
54
+        assert_eq!(Ok((0)), get_task_total());
55
+    }
56
+
57
+}

Carregando…
Cancelar
Salvar