---
# System prepended metadata

title: 台大 110 硬體
tags: [NTU, 硬體, '110']

---

# 台大 110 硬體
###### tags: `NTU` `110` `硬體`
1. (a) C (or B)
    :::info
    不知道它問的是 kernel 的 memory management subsystem 還是 heap allocator。不過 (b) 是 B，這題感覺應該要選 C
    :::

    (b) B
    \(c\) A
    (d) A

2. DABC
3. 懶得寫
4. baseline 的程式碼:

```c=
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

#define SIZE (1LL << 31)

char data[SIZE];

int main() {
  int fd = open("big_file", O_WRONLY);
  write(fd, data, SIZE);
  return 0;
}

```
測試結果：
```bash=
$ perf stat -e cycles ./test  -F 63500 --repeat 5
    1.780873839 seconds time elapsed

       0.000000000 seconds user
       0.718827000 seconds sys
```
(a) B
:::info
fsync 會強制把資料寫進 disk 裡，所以...整體時間理論上要比較慢
```bash=
$ perf stat -e cycles ./test  -F 63500 --repeat 5
22.463485995 seconds time elapsed

       0.000000000 seconds user
       1.022562000 seconds sys
```
一如預期
:::
(b) C ?
猜測：因為是 unbuffered I/O，所以在 user space 的時間基本上不會有太大的波動

不過我不知道要怎麼改 disk cache size (連該怎麼查都不知道)，所以沒有實驗

\(c\) ?
:::info
我不太懂 "line-at-a-time" 是什麼意思
:::
(d) B
:::info
程式碼:
```c=
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#define SIZE (1LL << 31)

int main() {
  int line = 128;
  char data[line];
  for (int i = 0; i < line - 1; i++) data[i] = 'a';
  data[line - 1] = '\0';

  for (int i = 0; i < SIZE / line; i++) {
    puts(data);
  }
  return 0;
}
```
因為是 buffered I/O，留在 user space 的時間應該要比較長。

測試結果：
```bash=
$ perf stat -e cycles ./test 1>./big_file -F 63500 --repeat 5

 Performance counter stats for './test -F 63500 --repeat 5':

     7,357,129,797      cycles                                                      

       2.422631297 seconds time elapsed

       0.444117000 seconds user
       1.944515000 seconds sys
```
一如預期
:::
(e) B
:::info
fflush() 會把 buffer 裡的資料全掃進 kernel，fsync 又會把資料再掃進 disk 裡，應該要更慢？

但 puts 是接到 std I/O，fsync 在這裡到底要幹嘛我也不清楚

```bash=
$ perf stat -e cycles ./test 1>./big_file -F 63500 --repeat

 Performance counter stats for './test -F 63500 --repeat':

     1,847,542,983      cycles                                                      

     526.039486192 seconds time elapsed

       0.079181000 seconds user
       1.411285000 seconds sys
```
可以觀察到 user space 時間變短了些，在 kernel 的時間則是變長。
:::

5. (a) 43
    (b) B
    \(c\) B
    (d) 63
    (e)  ?
:::info
逐行解說：
17: 針對 `SIGUSR1` 設 signal 處理函式 `sigHandling`
19: 針對 `SIGUSR2` 設 signal 處理函式 `sigHandling`
21: 針對 `SIGINT`  設 signal 處理函式 `sigHandling`

24: 將 `waitmask` 清空
25: 將 `SIGUSR1` 加進 `waitmask`
26: 將 `newmask` 清空
27: 將 `SIGINT` 加進 `newmask`

32: 將 `newmask` 加進 process 的 signal mask
在這一步之後，`newmask` 裡的所有信號(也就是 `SIGINT`)都會被擋下來

43: 將 process 停下來，並將目前的 signal mask 換成 `waitmask`
在這一步之後，process 會被 blocked，直到`waitmask` 裡(也就是 `SIGUSR1`)**以外**的信號(`SIGUSR2` or `SIGINT` 或其他會把 process terminated 掉的信號)發生。

51: 將 signal mask 換回原本的
:::
:::warning
關於 (e)，signal 跟 sigaction 的差別在於：signal 會「重置」，所以信號被觸發之後，signal action 會被重置。但我不清楚 mask 是不是也會被重置。所以做了點實驗，答案是：不會
測試環境
```
Linux desktop 5.11.0-44-generic #48~20.04.2-Ubuntu SMP Tue Dec 14 15:36:44 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
```
程式碼：
```c=
#define _POSIX_C_SOURCE 1

#include <signal.h>
#include <stdio.h>

int hi = 0;

void sighandler(int num) {
  hi = 1;
}


int main() {
  signal(SIGINT, sighandler);
  sigset_t newmask, oldmask;

  sigemptyset(&newmask);
  sigaddset(&newmask, SIGTSTP);
  if (sigprocmask(SIG_BLOCK, &newmask, &oldmask)) {
    printf("error\n");
    return -1;
  }

  while(1) {
    if (hi) {
      printf("hi\n");
      hi = 0;
    }
  }
}
```
可以先按 Ctrl-Z，確定這個信號真的被擋住
然後再按 Ctrl-C，你會看到他在跟你打招呼 (ﾉ>ω<)ﾉ
再按 Ctrl-C，他不會理你-`д´-，代表信號處理函式真的被重置了。
再按 Ctrl-Z，程式還是沒停下來，代表Ctrl-Z還是被擋住，signal mask 沒有被重置

所以他會保留原本的 signal mask，也就是 `SIGINT`
但這裡沒這個選項？幹我也不知道 (╯°Д°)╯ ┻━┻ ，去問出題的。
:::
6. (a) 20
    (b) NO
    :::info
    在地址有衝突時，增加 set-associativity 才有用。A，B，C 分別是起始於 0xA000, 0xA4B0, 0xA960，index 分別為 0, 4B, 96，沒有衝突。
    :::
    \(c\) 0 / 0
    :::info
    兩個 CPU 計算的資料區塊剛好錯開
    :::
    (d) 7 / 6
    :::info
    - P0 第一次存取 => compulsory miss
    - P1 第一次存取 => coherence miss
    - P0 第二次存取 => coherence miss, false sharing
    - P1 第二次存取 => coherence miss, false sharing
    總共 7 次 coherence miss，有 6 次 false sharing，應該吧。
    :::

7. 累了