# 2020q1 Homework2 (quiz2) contributed by < [simpson0114](https://github.com/simpson0114/quiz2) > ###### tags: `linux2020` ## 測試環境 ```shell $ cat /etc/os-release NAME="Ubuntu" VERSION="18.04.4 LTS (Bionic Beaver)" ID=ubuntu ID_LIKE=debian PRETTY_NAME="Ubuntu 18.04.4 LTS" VERSION_ID="18.04" HOME_URL="https://www.ubuntu.com/" SUPPORT_URL="https://help.ubuntu.com/" BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" VERSION_CODENAME=bionic UBUNTU_CODENAME=bionic $ cat /proc/version Linux version 5.3.0-42-generic (buildd@lcy01-amd64-019) (gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #34~18.04.1-Ubuntu SMP Fri Feb 28 13:42:26 UTC 2020 ``` ## 作業要求 - [x]重新回答第 2 周測驗題 - [ ]解釋上述程式碼運作原理,並提出改進方案,可善用 GDB 追蹤和分析 - [ ]以上述程式碼為基礎,提供字串複製 (應考慮到 CoW) 和類似 strtok 功能的函式實作 - [ ]設計實驗,確認上述字串處理最佳化 (針對空間效率) 帶來的效益,應考慮到 locality of reference - [ ]在 Linux 核心原始程式碼中,找出類似手法的 SSO 或 CoW 案例並解說 ## 測驗題分析 ### 第一題 本題所在位置為 `xs.c:xs_new` 函式中 ```cpp xs *xs_new(xs *x, const void *p) { *x = xs_literal_empty(); size_t len = strlen(p) + 1; if (len > AAA) { x->capacity = ilog2(len) + 1; x->size = len - 1; x->is_ptr = true; x->ptr = malloc((size_t) 1 << x->capacity); memcpy(x->ptr, p, len); } else { memcpy(x->data, p, len); x->space_left = 15 - (len - 1); } return x; } ``` 這個函式用途為初始化 `xs` 結構的設定,因此可以先觀察 `xs` 的結構 ```cpp typedef union { /* allow strings up to 15 bytes to stay on the stack * use the last byte as a null terminator and to store flags */ char data[16]; struct { uint8_t filler[15], /* how many free bytes in this stack allocated string * same idea as fbstring */ space_left : 4, /* if it is on heap, set to 1 */ is_ptr : 1, flag1 : 1, flag2 : 1, flag3 : 1; }; /* heap allocated */ struct { char *ptr; /* supports strings up to 2^54 - 1 bytes */ size_t size : 54, /* capacity is always a power of 2 (unsigned)-1 */ capacity : 6; /* the last 4 bits are important flags */ }; } xs; ``` 因此我們可以知道 `len` 所代表的就是 `p` 的字元數,而由結構可以看到`data` 的陣列大小為16,因此就可以判斷 `AAA` 的答案為16。 ### 第二題、第三題 此兩題所在位置為 `xs.c:xs_trim` 函式中 ```cpp xs *xs_trim(xs *x, const char *trimset) { if (!trimset[0]) return x; char *dataptr = xs_data(x), *orig = dataptr; /* similar to strspn/strpbrk but it operates on binary data */ uint8_t mask[BBB] = {0}; #define check_bit(byte) (mask[(uint8_t) byte / 8] CCC 1 << (uint8_t) byte % 8) #define set_bit(byte) (mask[(uint8_t) byte / 8] |= 1 << (uint8_t) byte % 8) size_t i, slen = xs_size(x), trimlen = strlen(trimset); for (i = 0; i < trimlen; i++) set_bit(trimset[i]); for (i = 0; i < slen; i++) if (!check_bit(dataptr[i])) break; for (; slen > 0; slen--) if (!check_bit(dataptr[slen - 1])) break; ``` 觀察 `set_bit(byte)` 這個函式主要的功能是將字元的數值放進 `mask` 裡面的一個位元中,所以考慮所有字元都能存入 $256 / 8 = 32$ ,因此 BBB 為 $32$。 而根據 `check_bit(byte)` 的用途,可以得知他是要確認字元是否該修剪,所以運算後應該得到的數值是 - 非 `0` : 該字元是 `trimset` 中所出現的字元 - `0` : 該字元不是 `trimset` 中所出現的字元 而因為該字元所對應到 `mask` 的位置就是 `1 << (uint8_t) byte % 8)` 的位置,所以 CCC 的答案應該是 `&`。