林建寬
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # 2025q1 Homework1 (lab0) contributed by < `kurtislin` > ## Reviewed by BennyWang1007 1. 倉庫應使用 rebase 而不是直接 merge,如 commit `221c30e`、`4b811c7`等。 2. Commit 連結皆指向不屬於任何分支的 commit,例如 [3066919](https://github.com/sysprog21/lab0-c/commit/3066919ac0617bb76fa6680f5539b3a8f3ea6d47),或許是 rebase 之類的操作導致。 3. 最後一部分應該為 `q_delete_dup`,標題錯誤。 4. `q_delete_dup` 可考慮改成只使用一層迴圈走訪鏈結串列,將與 `curr_elem` 重複的節點釋放,最後再將 `curr_elem` 釋放(若有重複),即可避免字串的複製,也不會產生懸空指標。 5. 注意排版以及句尾的句號。 6. Commit message 可以再更詳盡,例如 `q_reverseK`。 7. 缺乏的部分如 tiny web server 等,有空可以慢慢補上。 {%hackmd NrmQUGbRQWemgwPfhzXj6g %} ## 開發環境 ```shell $gcc --version gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0 $lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Address sizes: 46 bits physical, 48 bits virtual Byte Order: Little Endian CPU(s): 24 On-line CPU(s) list: 0-23 Vendor ID: GenuineIntel Model name: 13th Gen Intel(R) Core(TM) i7-13700 CPU family: 6 Model: 183 Thread(s) per core: 2 Core(s) per socket: 16 Socket(s): 1 Stepping: 1 CPU(s) scaling MHz: 55% CPU max MHz: 5200.0000 CPU min MHz: 800.0000 BogoMIPS: 4224.00 ``` ## 用linked list實做queue ### q_new,q_free [Commit 732fa62](https://github.com/kurtislin/lab0-c/commit/732fa6268fcaec33fa0a854a34b82b344461d512) `new` 和 `free` 是密切相關的操作 `q_new` 建立新的鍊結串列的節點 回傳初始化完成的queue `q_free` 遍歷鍊結串列 釋放所有節點 最後還要釋放head ### q_insert_head , q_insert_tail [Commit aab9360](https://github.com/kurtislin/lab0-c/commit/aab93606010b3fe58c8fc874b6ed48a817722327) `q_insert_head` 在佇列的頭部插入新元素 `q_insert_tail` 在佇列的尾部插入新元素 * 首先檢查輸入參數的有效性 * 為新元素分配記憶體 * 為字串值創建一個副本 * 使用 `list.h` 中定義的 `list_add` 函數將節點添加到頭部 * 返回操作結果 ### q_size,q_remove_head,q_remove_tail [Commit 3066919](https://github.com/kurtislin/lab0-c/commit/3066919ac0617bb76fa6680f5539b3a8f3ea6d47) `q_size` 在計算佇列裡的元素數量 `q_remove_head`,`q_remove_tail` 在移除佇列的頭部元素和尾部元素 在實作 `q_remove_head` 和 `q_remove_tail` 函數時,我們採用輸出參數模式,透過 sp 緩衝區參數和返回值同時提供元素指針與元素內容。這種設計讓單一函數調用能夠返回多種資訊,提升了函數的靈活性,使調用者可根據需求選擇獲取所需的資料形式。 ### q_reverse [Commit c04198f](https://github.com/kurtislin/lab0-c/commit/c04198f5af66efa42886378fc6845161f9c46e49) `q_reverse`將佇列所有元素反轉 ### q_swap [Commit a46fa1d](https://github.com/kurtislin/lab0-c/commit/a46fa1d96caec6600d0eb6a452cf42be63dc44b1) `q_swap` 將相鄰的節點交換 ### q_delete_mid q_reverseK [Commit d3a52e3](https://github.com/kurtislin/lab0-c/commit/d3a52e3ce7b88315fb6d54977c970a591907aa02) `q_delete_mid` 利用快慢指標實現 `q_reverseK` 利用`temporary list` 實現,在`q_reverseK` 函數中,我使用了 `struct list_head temp_head` 而不是指標 `struct list_head *temp_head` 來宣告臨時頭節點,主要有以下原因: #### 堆疊(Stack)分配 vs. 堆(Heap)分配: 直接宣告 `struct list_head temp_head` 會在函數的堆疊上分配記憶體 使用指標 `struct list_head *temp_head` 則需要使用 `malloc` 從堆中分配記憶體,並在使用完後需要 `free` 堆疊分配更快速,也不需要擔心記憶體洩漏 ### q_delete_dup [Commit a290040](https://github.com/kurtislin/lab0-c/commit/a29004075c0c873749788b72e1ba990cb751aee7) ```c bool q_delete_dup(struct list_head *head) { if (!head || list_empty(head)) return false; bool removed = false; struct list_head *node = head->next; while (node != head && node->next != head) { element_t *curr_elem = list_entry(node, element_t, list); element_t *next_elem = list_entry(node->next, element_t, list); if (!strcmp(curr_elem->value, next_elem->value)) { removed = true; char *dup_val = curr_elem->value; while (node != head) { element_t *check_elem = list_entry(node, element_t, list); if (!strcmp(check_elem->value, dup_val)) { struct list_head *tmp = node->next; list_del(node); q_release_element(check_elem); node = tmp; } else break; } } else node = node->next; } return removed; } ``` 以上是我一開始的代碼但是不管怎麼測試都會剩下一個元素 測試資料中沒有要刪除的元素時也會有以下問題 ```shell l = [1 2 3 4] cmd> dedup ERROR: Calling delete duplicate on null queue ``` 之後發現問題是出現在執行`q_release_element(check_elem)`時,釋放了元素的記憶體,包括 `check_elem->value`。但是`dup_val` 指針是指向 `curr_elem->value`,所以造成懸空指標,之後改成`char *dup_val = strdup(curr_elem->value);`就可以了 ### q_sort 和 merge sort 實作 [Commit f32ba44](https://github.com/kurtislin/lab0-c/commit/f32ba44ca9fa33a7143a0b43b7286328e80b18f3) `q_sort` 使用 merge sort 演算法來排序,整個實作分成三個主要的 helper functions: #### merge_sort() 遞迴式的 merge sort 主體,採用分治法的概念。先把鏈結串列切成兩半,各自排序後再合併。時間複雜度是 O(n log n),對鏈結串列來說效率不錯。 #### split_list() 用快慢指標的技巧把鏈結串列分成兩半。慢指標走一步,快指標走兩步,當快指標到底時慢指標就在中間位置。這樣可以在一次遍歷中找到分割點。 #### merge_lists() 把兩個已排序的鏈結串列合併成一個。比較兩個串列的頭部元素,選較小(或較大)的放到結果中,重複到其中一個串列空了為止,剩下的直接接上去。 整個 merge sort 的設計很適合鏈結串列,因為不需要額外的記憶體空間,只要重新連接指標就行了。 ### q_ascend, q_descend, q_merge [Commit 9c0d6d0](https://github.com/kurtislin/lab0-c/commit/9c0d6d03513683f5f66c08e2efb97a7cb6b74045) **q_ascend()** 和 **q_descend()** 都用了單調棧的概念,從尾部開始往前掃描,只保留符合條件的節點。ascend 會移除右邊有更小值的節點,descend 則相反。 **q_merge()** 把多個佇列合併成一個,先把所有元素收集到第一個佇列裡,最後用 q_sort 排序。實作上比較直觀,就是先合併再排序。 ## Valgrind 記憶體分析 使用 `make valgrind` 進行動態記憶體分析 ### 測試結果 ``` --- TOTAL 100/100 ``` ## 研讀 lib/list_sort.c 並比較實作的sort ### 閱讀 [list_sort.c](https://github.com/torvalds/linux/blob/master/lib/list_sort.c) [Linux核心的鏈接串列排序](https://hackmd.io/@sysprog/linux2025-lab0/%2F%40sysprog%2Flinux2025-lab0-e) **發現**: 1. 使用 bottom-up merge sort 而非 recursive 2. Power-of-two 合併策略:確保每次合併都是 2:1 平衡的 可避免極端情況 例如 1024個已排序好的元素 再去合併4個元素 3. 使用位元運算追蹤合併狀態 4. 設計考慮 cache-friendly 的合併順序 ```c=226 if (likely(bits)) { struct list_head *a = *tail, *b = a->prev; a = merge(priv, cmp, b, a); /* Install the merged result in place of the inputs */ a->prev = b->prev; *tail = a; } ``` `likely()` 是一個編譯器優化提示,用於分支預測優化。 `likely(bits)` 告訴編譯器這個條件很可能為真,從而進行以下優化: 1. **分支預測**:CPU 會傾向於預測條件為真,減少管線停頓 2. **程式碼布局**:將 `if` 區塊放在較近的記憶體位置,提高快取命中率 3. **管線優化**:減少分支預測錯誤時的效能懲罰 這種優化在高頻執行的程式碼路徑中特別有效。 ### 比較原本的sort 和 list_sort.c #### 在queue.c加入切換機制 [Commit 83a61cb](https://github.com/kurtislin/lab0-c/commit/83a61cbca932253cfe90a966d003c99414b3f471) **實作內容**: 1. **新增 ksort 命令**:切換排序演算法 - `ksort 0`: 原版 merge sort - `ksort 1`: Linux kernel list_sort 2. **新增 benchmark 命令**: - 支援多種資料分布:random, sorted, reverse, partial - 使用 `clock_gettime(CLOCK_MONOTONIC)` - 自動計算加速比並報告結果 3. **修改檔案**: - `queue.c`: 加入 `q_set_kernel_sort()` 和比較函數 - `qtest.c`: 實作 `do_ksort()` 和 `do_benchmark()` 命令 - `Makefile`: 加入 `list_sort.o` 編譯目標 - 新增 `list_sort.c/h`: Linux kernel 排序實作 ### benchmark 命令使用範例 #### 基本語法 ```bash ./qtest > benchmark <size> [distribution_type] ``` #### 使用範例 ```bash # 測試 1000 個隨機元素 > benchmark 1000 random # 測試 5000 個已排序元素 > benchmark 5000 sorted # 測試 10000 個反向排序元素 > benchmark 10000 reverse # 測試 2000 個部分排序元素(80% 已排序 + 20% 隨機) > benchmark 2000 partial ``` #### 支援的分布類型 - `random` (預設): 隨機生成的元素 - `sorted`: 預先排序好的元素(升序) - `reverse`: 反向排序的元素(降序) - `partial`: 部分排序的元素(80% 已排序 + 20% 隨機) #### 範例輸出 ``` Benchmarking with 10000 elements (random distribution) Original merge sort: 2.45 ms Linux kernel list_sort: 1.89 ms Speedup: 1.30x (Linux kernel is 29.6% faster) ``` #### 切換排序演算法 ```bash # 使用原版 merge sort > ksort 0 # 使用 Linux kernel list_sort > ksort 1 # 確認當前使用的演算法 > help ksort ``` 這個commit我是用clock_gettime 去取得時間 但是執行 benchmark 10000 random 幾次後 發現每次的結果差異都不小(包含效能提升比例) #### 測試結果 以下是用10000個測試資料的時候的結果 結果都是kernel sort更快 差異最小的是1.26倍 差異最大的是1.5倍 後續數量改為500k 和100k 的結果也差不多 ```bash cmd> benchmark 10000 random === Benchmark Results === Data size: 10000 elements Distribution: random Original merge sort: 7.343 ms Linux kernel list_sort: 5.837 ms Kernel sort is 1.26 times faster cmd> benchmark 10000 random === Benchmark Results === Data size: 10000 elements Distribution: random Original merge sort: 8.219 ms Linux kernel list_sort: 5.483 ms Kernel sort is 1.50 times faster ```

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully