sysprog
      • 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
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners 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 No publishing access yet

      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.

      Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Explore these features while you wait
      Complete general settings
      Bookmark and like published notes
      Write a few more notes
      Complete general settings
      Write a few more notes
      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 New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Help
Menu
Options
Engagement control Make a copy 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
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners 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 No publishing access yet

    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.

    Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Explore these features while you wait
    Complete general settings
    Bookmark and like published notes
    Write a few more notes
    Complete general settings
    Write a few more notes
    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
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # 2026-05-12/14/21 問答簡記 ## 期末專題 > [專題列表](https://hackmd.io/@sysprog/linux2026-projects) > 課程規劃在 6 月 27 日舉辦[期末成果發表](https://hackmd.io/@sysprog/linux2026-projects),預計採用線上直播的模式 ## [Open Source Summit North America](https://events.linuxfoundation.org/open-source-summit-north-america/) ## 《Demystifying the Linux CPU Scheduler》 ## Krixi0828 condition variable broadcast fast userspace wake wait constract 持有資源者透過 condition variable 去通知其他 thread 沒等到的繼續 wait ,有等到的 wake ## ericlin1231 - RR : 以 timeslice 為單位排程任務 - 連續執行的假象 : 執行序執行 I/O 任務時可以交出 CPU 資源,此時 I/O 在執行,CPU 也被其他執行緒使用,所以看來有多任務在執行 - 問題 : 3 個執行緒已建立,期望執行緒 1, 2, 3 之間順序執行,如何搭配 mutex 使其可以達成 TSO (total store order) $\to$ [並行程式設計: Atomics 操作](https://hackmd.io/@sysprog/concurrency-atomics) x86/Intel 64 的 memory-ordering 規則是「軟體可見行為」的規格,不等於硬體內部真的完全禁止 OoOE;Intel 文件明確說硬體可以做任何最佳化,只要不違反可見順序,甚至同一個 memory access 可執行多次,最後可見結果正確即可。TSO 的簡化模型是每個處理器核有 FIFO store buffer,load 可繞過自己較早、不同位址的 store,因此表現出 Store→Load relaxation;但 Load→Load、Load→Store、Store→Store 在架構可見層面仍維持順序。Intel 的最佳化手冊也說,處理器核允許 load/store speculative、out-of-order issue,但即將執行完畢時要保證資料正確並符合 Intel 64/IA-32 ordering rules。 machine clear 不是每個 load 在 retire 前都固定發起 bus snooping;比較準確地說,它是投機執行或 memory disambiguation 判斷失敗後的回復機制。Intel performance event 文件列出 MACHINE_CLEARS.MEMORY_ORDERING 的來源包含 memory disambiguation、external snoop,以及 cross-SMT stores hitting load buffers;若頻繁發生,確實會有顯著效能衝擊。TSO 的硬體成本存在,包括 store buffer、load buffer、store-to-load forwarding、memory disambiguation、coherence snoop、false sharing 放大的 invalidation traffic,以及錯誤投機後的 pipeline clear。硬體平常積極 speculate 執行,只有在偵測到可能破壞架構記憶體模型時才 rollback。 Apple: [Accelerating the performance of Rosetta](https://developer.apple.com/documentation/virtualization/accelerating-the-performance-of-rosetta) ROB ## chuang0720 當每個 CPU 有自己的 runqueue 時,該如何決定誰要執行? 每個核的 runqueue 會對分配到的可執行任務追蹤並排程,而主動負載平衡會讓主排程器定期檢查整個系統的負載分佈,並在必要時重新分配任務。 核心引入 PELT (PerEntity Load Tracking)來追蹤任務所造成的負載 ## CHEN-YOU-0331 問題一:Linux 現代排程器如何挑選 per-CPU 的最佳 Task? 自 Linux v6.6 (2023 年底發布) 起,預設排程器已替換為 EEVDF (Earliest Eligible Virtual Deadline First)。 CFS 雖然公平,但在處理延遲敏感 (Latency-sensitive) 任務時表現不佳。EEVDF 引入了「截止時間 (Deadline)」的概念來解決這個問題。 * Eligibility (資格審查 - 延遲計算): 系統會計算一個任務的 Lag (落後時間),即「任務理應獲得的 CPU 時間」減去「實際獲得的 CPU 時間」。只有當 $Lag \ge 0$ 的任務,才會被標記為 Eligible (具備排程資格),這確保了沒有任務可以超支其應得的時間。 * Virtual Deadline (虛擬截止時間): 每個任務都會被賦予一個虛擬截止時間(與其所需的時間片大小有關)。 * 挑選最佳 Task: 在該 CPU 的 Runqueue 中,EEVDF 會在所有 具備資格 (Eligible) 的任務裡,挑選出 虛擬截止時間最早 (Earliest Virtual Deadline) 的任務來執行。 問題二:用 C 語言計算 $e^x - 1$ (不使用 math.h 與浮點數) ```c #include <stdio.h> #include <stdint.h> #define SCALE 1000000LL // 保留 6 位小數點的精確度 #define MAX_ITER 20 // 最大迭代次數 (x 越大,需要的次數越多) /* * 計算 e^x - 1 (x 為整數) * 回傳值為乘以 SCALE 後的定點數 */ int64_t exp_minus_one_int(int x) { // 雖然 x 是整數,但展開的結果會有小數 // 所以我們在第一項就把整數 x 轉換為定點數格式 (x * SCALE) int64_t term = (int64_t)x * SCALE; int64_t sum = 0; int n = 1; // 當項次不為 0,且未達到最大迭代次數時繼續累加 while (term != 0 && n < MAX_ITER) { sum += term; n++; // 核心簡化:因為 x 是純整數,直接乘 x 再除以 n 即可。 // 不需要像之前那樣再除以 SCALE 來校正! term = (term * x) / n; } return sum; } void print_fixed(int64_t val) { int64_t int_part = val / SCALE; int64_t frac_part = val % SCALE; if (frac_part < 0) { frac_part = -frac_part; if (int_part == 0) printf("-"); } printf("%lld.%06lld\n", (long long)int_part, (long long)frac_part); } int main() { // 測試案例: 輸入純整數 x = 1 (即 e^1 - 1) int x1 = 1; printf("計算 e^1 - 1: "); print_fixed(exp_minus_one_int(x1)); // 測試案例: 輸入純整數 x = 2 (即 e^2 - 1) int x2 = 2; printf("計算 e^2 - 1: "); print_fixed(exp_minus_one_int(x2)); return 0; } ``` :::danger 缺乏對於降低誤差的探討,詳閱 [歐拉數 e: 描述連續變化的基石](https://hackmd.io/@sysprog/euler-number) ::: * 定點數運算原理 因為不能用浮點數,我們將所有的數值放大一個常數倍數 (例如 SCALE = 1,000,000,代表保留 6 位小數)。 * 實數 $1.0$ 在程式中表示為整數 1000000。 * 兩個定點數相乘 $A \times B$ 在程式碼中必須寫成 (A * B) / SCALE,否則小數點會位移。 為什麼這段程式能用「整數」算出「小數」? 我們通常習慣用浮點數 (float) 來算 $0.5$、$1.718$ 這種小數。但在沒有浮點數的情況下,這個程式使用了「放大單位」的魔法。 舉個生活化的例子: 假設你要平分 $1.5$ 元。 如果系統規定只能用整數,你不能寫 $1.5 \div 2$。 但如果你把單位從「元」換成「分」呢? $1.5$ 元 = $150$ 分。 $150 \div 2 = 75$ 分。 用純整數算出了 $75$,這個 $75$ 其實就代表了 $0.75$ 元! 這支程式的原理完全一樣: 程式裡的 SCALE = 1000000,就是把所有的數字都放大一百萬倍,以此來保留 6 位小數點的精確度。 真實世界的 $1.0$,在程式裡被表示為 1000000。 :::danger 缺乏 ULP 的討論 ::: ## ascodeasice > 承上一位的計算 $e^x-1$,在單精度如何應用微積分的中央極限定理、夾擠定理估算最大值 TODO: 分析誤差 --- ## 校友交流 > [ReiFu Zhang](https://www.linkedin.com/in/chiwawa/) > 彰師資管倒數第三名 $\to$ 成大工科所 $\to$ Mediatek * 大學時因興趣開始探索 FPGA * 碩一時開始跟 jserv 做 FPGA 相關專案 * 血統不好怎麼辦?專攻有利基的領域如 [HPC](https://en.wikipedia.org/wiki/High-performance_computing) $\to$ [以 HPC 開發者的視角,搭配 RISC-V 來理解現代處理器架構](https://hackmd.io/2BD1rr8YTo6MfVGdxnDh9A) * 畢業前一年開始面試(六月開始),一個禮拜面兩次 * 發哥一面 二面 實體 處長找你談 準備 3 頁履歷(英文) 濃縮過往做的專案內容。會派題目,給兩個禮拜做準備,問裡面的技術細節 CPU/HW architecture ASIC 天璣 CPU 從 Arm 授權 -> 公司 GPU (Mali) 從 Arm 授權 -> 公司 (RTL) ARM Cortex-X2 大核 x1 3× Cortex-A710 @ 2.85 GHz 4× Cortex-A510 @ 1.8 GHz 大/中/小核的組合涉及到應用場景 gaming/AI I/O-bound, CPU-bound performance modeling -> CA, OS, digital IC / RTL CA: performance, CPU 的組成 (cache, uarch [microarch], memory, Network on Chip [NoC]) > https://fuse.wikichip.org/news/5006/the-mesh-network-for-next-generation-neoverse-chips/ Q: 現代 SoC 的 NoC 架構要留意哪些議題? Q: 功耗與面積限制決定 PPA,技術挑戰是什麼? Q: 如何評估 Linux 在最終處理器的表現? PPA https://old.chipsandcheese.com/2025/12/31/inside-nvidia-gb10s-memory-subsystem-from-the-cpu-side/ https://github.com/rigtorp/c2clat https://developer.arm.com/Processors/CoreLink%20CMN-600 NoC (Network-on-Chip)拓撲與延遲 ==> 最佳路徑 cadence palladium 業界普遍對新人不友善,但善用 AI 的新人仍有機會 Let AI model generates testbench (TB) CPU: I/O , memory bound, edge cases, benchmarking ALU spec -> RTL 不要外包思考: make decisions by yourself! GEMM 人掌握 spec formalized prompts 學得精 shared L2 -> dedicated L2 cache refine cache microarchitecture 思考 why (motivation/consideration),先於真的進行 DE: develop RTL, 不能只看 PPA, prototyping for system integration DMIPS speedup JD (job description): 找夠廣的題目 --- ## keep90ing vruntime (virtual runtime) CFS 的 weight function PELT Linux task_struct: tgid vs. pid getpid vs. gettid PID 重用攻擊 container_of --- concurrency: C11 atomics 有幾種 memory order? consume, acquire, release 適用場景? acquire vs. obtain vs. get ownership --- ## kevinjone25 sched_prio_to_weight 為何有 40 個單元? * 在 nice 的 man page 裡有提及 nice value range 是從 -20 - +19,再根據 man page sched (7) 的內容,是現代 Linux 系統中的範圍是 -20 - +19,早期的 Linux Kernel (2.0 以前) 是 -inf - +15 的 (根據 §POSIX.1-2008的 NZERO 所訂定) [sched (7)](https://man7.org/linux/man-pages/man7/sched.7.html) CFS 的 fairness Linux: linked list https://www.kernel.org/doc/html/v4.14/core-api/kernel-api.html 找出第 k 大的節點 (透過 List Sort API 寫出,不能排序) O(n) list_sort 空間複雜度 https://hackmd.io/@sysprog/it-vocabulary --- ## [panzhipop](https://github.com/panzhipop) ### Q1. vruntime (virtual runtime) 根據 CPU book P. 87, vruntime 指 a clock that measures how much CPU time a task `has consumed`, normalized by its priority. The key insight: if we always run the task with the smallest virtual runtime, we maintain fairness over time. 因為每次都是先執行最小的 vruntime ,變向達到了公平分配 CPU time 的目的。 ### Q2. O(1) 根據 CPU book P.86,明確指出 O(1) 排程器的四大缺點 : Heuristic failures 、 Gaming the system 、 Unpredictable behavior 、 Starvation risks。 在 CFS 排程器中,採用公平分配 CPU time 的想法,去避免 O(1) 中 Heuristic failures 一直猜錯造成的成本。 ### Q3. the ways to calcuate / algorithm ### Q5. fairness 根據 CPU book P. 41,fairness 意思為 the ability to give each process the same timeslices of the CPU。 根據 CPU book P.86 詳細解釋 fairness。在理想多工的 CPU 中,假設 CPU 可以真正地展現 parallel 的性質。舉例來說, CPU 現在有 n 個 task , 則每個 task 可以獲得連續 $\frac{1} {n}$ 的使用時間 (proportional share of CPU time)。 ### Q6. RT prio (為什麽有 100 個) ### Q7. normal prio (nice)? 40? ### Q8. 為什麽是這個公式 $\frac{1024} {1.25 ^ {nice}}$ ```c /* * Nice levels are multiplicative, with a gentle 10% change for every * nice level changed. I.e. when a CPU-bound task goes from nice 0 to * nice 1, it will get ~10% less CPU time than another CPU-bound task * that remained on nice 0. * * The "10% effect" is relative and cumulative: from _any_ nice level, * if you go up 1 level, it's -10% CPU usage, if you go down 1 level * it's +10% CPU usage. (to achieve that we use a multiplier of 1.25. * If a task goes up by ~10% and another task goes down by ~10% then * the relative distance between them is ~25%.) */ static const int prio_to_weight[40] = { /* -20 */ 88761, 71755, 56483, 46273, 36291, /* -15 */ 29154, 23254, 18705, 14949, 11916, /* -10 */ 9548, 7620, 6100, 4904, 3906, /* -5 */ 3121, 2501, 1991, 1586, 1277, /* 0 */ 1024, 820, 655, 526, 423, /* 5 */ 335, 272, 215, 172, 137, /* 10 */ 110, 87, 70, 56, 45, /* 15 */ 36, 29, 23, 18, 15, }; ``` 在 nice 值轉換到 weight 的公式中,因為相鄰 weight 的比值約為 1.25 倍。所以該公式以零為基準,即 nice 0 的權重 1024。當 nice 值往負數方向前進,$1024* 1.25^{abs(nice)}$,權重會變大;當 nice 值往正前進,$\frac{1024} {1.25^{abs(nice)}}$,權重會變小。 --- ## Kai5088 ```c /* File include/linux/kernel.h */ #define container_of(ptr, type, member) \ ({ \ void *__mptr = (void *)(ptr); \ ((type *)(__mptr - offsetof(type, member))); \ }) ``` 是否存在 UB? * 依 C99 §6.5.6 Additive operators,加減法的指標算術只對「指向完整物件型別(complete object type)」的指標有定義。而 C99 §6.2.5指出:The void type comprises an empty set of values; it is an incomplete type that cannot be completed.所以 void * 是指向 incomplete type 的指標,對它做 +/- 在標準 C 中是 constraint violation https://man7.org/linux/man-pages/man3/pthread_detach.3.html https://man7.org/linux/man-pages/man3/pthread_join.3.html ``` main + +---- T1 * pthread_join + +---- T2 * + +----- T3 * pthread_detach ``` pthread_join * 依據 man7.org 敘述,這個函式會等待由 thread 參數所指定的執行緒終止;若該執行緒已經終止,pthread_join() 會立即返回,而且由 thread 所指定的執行緒必須是 joinable 的,曾經被 pthread_detach 分離過、或建立時就已被設為 detached 的執行緒,不能拿來 join。pthread_join有三個功能,同步點(等待目標執行緒終止)、結果通道(取回 pthread_exit 的回傳值或 PTHREAD_CANCELED)、以及資源回收機制(釋放目標執行緒在 pthread 實作中佔用的內部資源,避免 zombie thread)。正確的多執行緒程式設計中,每一條 joinable 執行緒在程式結束前都應恰好被 join 一次,否則就應在建立時或建立後盡早 detach。 https://hackmd.io/@sysprog/unix-fork-exec 1960s fork-join * 依據〈UNIX 作業系統 fork/exec 系統呼叫的前世今生〉,1960 年代的 fork-join 並不是一個作業系統的具體機制,而是一個比 UNIX 早了整整六年提出的並行處理(concurrent processing)抽象模型。其意義不在於它是不是某個具體作業系統的某條系統呼叫,而在於它確立了並行運算最根本的兩個動作「分岔出獨立執行流」與「等待所有分支匯流」。Conway 把這對動作從多處理器硬體中抽象出來,讓人們得以脫離具體機器去談並行;Project Genie / BTSS 把它落實為可呼叫的原語;UNIX 則在 1969 年把它精簡為一個「無參數、雙回傳值、子行程完整繼承親代狀態」的 fork 系統呼叫,並用 exec、wait、exit 把整個生命週期補齊。現在C程式裡寫的 pthread_join 是由當時join而來。 寫程式測試觀察 * https://gist.github.com/Kai5088/b58df62df05da9de5e546eb71b99f2c1 此程式使用五個案例來測試pthread_join和detach: 1. 正常 join:pthread_create 之後 threads=2,worker 印出 pthread_exit(0xcafe0001) 後 1 ms,main thread 的 pthread_join 解除阻塞並收到完全相同的 retval,thread 數立刻回到 1。這驗證了 man page 兩件事:join 阻塞等待目標終止,以及 retval 就是目標 pthread_exit 傳出的值。 2. joinable 但不 join:創出 3 條後 threads=4,1 秒後 3 條都 pthread_exit 完畢,但你會看到 threads 並沒有立刻乾淨地降回 1——這就是 man page 警告的 zombie thread,雖然執行緒邏輯已結束,核心仍保留 task_struct 等待親代 join。情境結尾我補做 pthread_join 收尾,thread 數才回到基線。 3. detach:pthread_detach 回傳 0 表示成功,接著我故意對它 pthread_join 看會發生什麼——回傳 EINVAL (22) = "Invalid argument",印證 man page 的 EINVAL: thread is not a joinable thread。worker 在 5 秒處自然結束,thread 數自動回到 1,不需要任何手動回收。 4. 重複 join (UB):第一次 join 拿到 retval 0xcafe00c8;第二次對同一個 pthread_t 再 join,在我的 glibc 上得到 ESRCH (3) = "No such process"——但 man page 寫得很清楚這是 undefined behavior,意思是「換一台機器、換一個 libc、換一個版本,結果可能完全不一樣」,所以這個回傳值不能依賴,只是讓你看到「實作上 glibc 怎麼處理它」。 5. join 自己:回傳 EDEADLK (35) = "Resource deadlock avoided",完全對應 man page 的 EDEADLK: ... or thread specifies the calling thread。注意這個錯誤碼字面意思是「死結避免」——因為若真讓你 join 自己,呼叫端就會永久阻塞等自己終止,核心直接幫你擋掉。 ## tobiichi3227 重新閱讀 https://hackmd.io/@sysprog/linux-process 跟著作實驗 設計實驗在執行時期,判定 process vs. thread task_struct bpftrace Linux 核心用 TASK_RUNNING 來表示 ready 和 running 的狀態 透過實驗來確認陳述

    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
    Sign in via Google Sign in via Facebook Sign in via X(Twitter) Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    By signing in, you agree to our terms of service.

    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