YI-CHENG LI
    • 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
    • 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
    • Make a copy
    • 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 Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
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
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
  • 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
    1
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # 2026q1 Homework1 (warmup) contributed by < Lyciih > {%hackmd NrmQUGbRQWemgwPfhzXj6g %} [2026 年 Linux 核心設計課程作業 —— warmup](https://hackmd.io/@sysprog/linux2026-warmup) ## 細讀〈[資訊科技詞彙翻譯](https://hackmd.io/@sysprog/it-vocabulary)〉 ### 感想: 在[為什麼不該在台灣用「視頻」一詞?](https://matters.town/a/i35tafyix5o2)中,我發現了原來「視頻」中的「頻」是指頻率的意思,之前如果不把單個字拆開來研究的話其實沒有想過這件事。文中介紹到,此處的「頻」詳細來說是指「用來傳遞影像訊號或同步脈衝的訊號頻率」。 這讓我聯想到玩遊戲時常會聽到的「幀率」,也叫[「影格速率」](https://zh.wikipedia.org/zh-tw/%E5%B8%A7%E7%8E%87)、或「 FPS 」,用來描述遊戲畫面每秒重新繪製多少張,與視頻想表達的意思相近。不同的地方在於影像的來源跟產生的方式。 其他感想: - 原來「電鋸」並不是用電驅動的,以前只顧著看電影但沒有發現。 - 原來「緩存」是「緩衝存儲器」的意思。 - 原來「 render 」較精準的翻譯是「算繪」。由於我的碩士論文與圖學有關,在論文口試時也被校外委員問過渲染這個詞。後來經過討論後,折衷的做法是在論文中第一次出現「渲染」這個詞的地方說明了論文中提到的渲染指的是「 render 」。 ### 我的疑問: - 遍歷假設一開始我看不太懂,詢問GPT後,也只有一些模糊的概念。目前的理解是,不停的做某個實驗並統計實驗的結果,則各種結果佔全部結果的比例,會趨近所有可能結果在狀態空間中的比例?感覺有種蒙地卡羅的味道? - 下圖是我目前的理解。 ![圖片](https://hackmd.io/_uploads/Byk3kyPFbl.png) ### 作業問題回答: * "render" 在電腦圖學語境中為何應強調「如實呈現」?「渲染」一詞喪失什麼關鍵意涵?在 Linux 核心原始程式碼中,"render" 出現在哪些場景、語境又有哪些?翻閱詞典 (善用學校圖書館) 並考據詞源 * 說明 constant 與 immutable 的差異,並探討程式設計中的關鍵考量 * [constant](https://dictionary.cambridge.org/zht/%E8%A9%9E%E5%85%B8/%E8%8B%B1%E8%AA%9E-%E6%BC%A2%E8%AA%9E-%E7%B9%81%E9%AB%94/constant) 在劍橋辭典中的意思是:`經常發生的;連續發生的;連續不斷的` * [immutable](https://dictionary.cambridge.org/zht/%E8%A9%9E%E5%85%B8/%E8%8B%B1%E8%AA%9E-%E6%BC%A2%E8%AA%9E-%E7%B9%81%E9%AB%94/immutable) 在劍橋辭典中的意思是:`永恆的;不可改變的` * 在最新的 [C23](https://www.open-std.org/jtc1/sc22/wg14/) 規格書中 * 比較 concurrent 與 parallel 的語意差異,並說明為何「並行」較貼近 concurrent 的本意 * 當我們撰寫 Linux 核心文件,應如何區分 process, thread, task, job 等術語,才能避免跨領域誤解又省去過多的中英並陳? ## 細讀〈[GNU/Linux 開發工具](https://hackmd.io/@sysprog/gnu-linux-dev/https%3A%2F%2Fhackmd.io%2F%40sysprog%2Fr1Psrf0KW)〉 ### LaTeX 波函數的 LaTeX 語法: `$\psi(x)$` - $\psi(x)$ 密度矩陣的 LaTeX 語法: `$\rho$` - $\rho$ - 一般密度矩陣定義 $\rho = |\psi\rangle \langle \psi|$ ### git 以前我使用 git ,只會用 `git add .` + `git commit` + `git push` 這三種指令,不假思索的只用一個 branch 開發整個專案,根本沒有分支的概念。基本上只是搭配 github 當作備份而已,沒有完全發揮 git 被發明出來的用意,趁著這次機會總算能體驗到各種 git 提供的功能。 在關於 git 的教學中,有提供一個網站可以透過闖關遊戲的方式來學習 git 的各種指令,我覺得很好玩,花了一天把全部的關卡都解完。 ![image](https://hackmd.io/_uploads/HkuruH3KWx.png) ![image](https://hackmd.io/_uploads/BychXShY-x.png) ### perf 參考資料:[羅根學習筆記](https://zh-blog.logan.tw/2019/07/10/analyze-program-performance-with-perf-events/) #### 範例程式1: 計算圓周率 `perf_top_example.c` ```c #include <stdio.h> #include <unistd.h> double compute_pi_baseline(size_t N) { double pi = 0.0; double dt = 1.0 / N; for (size_t i = 0; i < N; i++) { double x = (double) i / N; pi += dt / (1.0 + x * x); } return pi * 4.0; } int main() { printf("pid: %d\n", getpid()); sleep(10); compute_pi_baseline(50000000); return 0; } ``` #### 編譯 ``` $ gcc -std=c99 -g -o example perf_top_example.c` ``` #### 測量 ``` $ perf record -g ./example ``` #### 觀看報告 ``` $ perf report ``` ![圖片](https://hackmd.io/_uploads/HyatGnAtZg.png) 可以觀察到大部分的開銷都集中在 `compute_pi_baseline` #### 範例程式2: 矩陣相乘 `matrix-v1.c` :::spoiler 實驗環境 ```shell $ cat /etc/os-release NAME="Linux Mint" VERSION="21.3 (Virginia)" ID=linuxmint ID_LIKE="ubuntu debian" PRETTY_NAME="Linux Mint 21.3" VERSION_ID="21.3" HOME_URL="https://www.linuxmint.com/" SUPPORT_URL="https://forums.linuxmint.com/" BUG_REPORT_URL="http://linuxmint-troubleshooting-guide.readthedocs.io/en/latest/" PRIVACY_POLICY_URL="https://www.linuxmint.com/" VERSION_CODENAME=virginia UBUNTU_CODENAME=jammy $ lscpu 架構: x86_64 CPU 作業模式: 32-bit, 64-bit Address sizes: 39 bits physical, 48 bits virtual Byte Order: Little Endian CPU(s): 8 On-line CPU(s) list: 0-7 供應商識別號: GenuineIntel Model name: Intel(R) Xeon(R) CPU E3-1231 v3 @ 3.40GHz CPU 家族: 6 型號: 60 每核心執行緒數: 2 每通訊端核心數: 4 Socket(s): 1 製程: 3 CPU max MHz: 3800.0000 CPU min MHz: 800.0000 BogoMIPS: 6783.89 Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm cpuid_fault invpcid_single pti ssbd i brs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt dtherm ida arat pln pts md_clear flush_l1d ibpb_exit_to_user Virtualization features: 虛擬: VT-x Caches (sum of all): L1d: 128 KiB (4 instances) L1i: 128 KiB (4 instances) L2: 1 MiB (4 instances) L3: 8 MiB (1 instance) NUMA: NUMA 節點: 1 NUMA node0 CPU(s): 0-7 Vulnerabilities: Gather data sampling: Not affected Indirect target selection: Not affected Itlb multihit: KVM: Mitigation: VMX disabled L1tf: Mitigation; PTE Inversion; VMX conditional cache flushes, SMT vulnerable Mds: Mitigation; Clear CPU buffers; SMT vulnerable Meltdown: Mitigation; PTI Mmio stale data: Unknown: No mitigations Reg file data sampling: Not affected Retbleed: Not affected Spec rstack overflow: Not affected Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl and seccomp Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization Spectre v2: Mitigation; Retpolines; IBPB conditional; IBRS_FW; STIBP conditional; RSB filling; PBRSB-eIBRS Not affected; BHI Not affected Srbds: Mitigation; Microcode Tsa: Not affected Tsx async abort: Not affected Vmscape: Mitigation; IBPB before exit to userspace $ gcc --version gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0 ``` ::: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #define N 1024 #define NUM_ROUNDS 5 static int32_t a[N][N]; static int32_t b[N][N]; static int32_t c[N][N]; __attribute__((noinline)) static void load_matrix() { FILE *fp = fopen("input.dat", "rb"); if (!fp) { abort(); } if (fread(a, sizeof(a), 1, fp) != 1) { abort(); } if (fread(b, sizeof(b), 1, fp) != 1) { abort(); } fclose(fp); } __attribute__((noinline)) static void mult() { size_t i, j, k; for (i = 0; i < N; ++i) { for (j = 0; j < N; ++j) { for (k = 0; k < N; ++k) { c[i][j] += a[i][k] * b[k][j]; } } } } __attribute__((always_inline)) static inline void escape(void *p) { __asm__ volatile ("" : : "r"(p) : "memory"); } int main() { int r; load_matrix(); for (r = 0; r < NUM_ROUNDS; ++r) { memset(c, '\0', sizeof(c)); escape(c); mult(); escape(c); } return 0; } ``` #### 編譯 ``` $ gcc matrix-v1.c -o matrix-v1 -mno-sse2 -Wall -O2 -g -fno-omit-frame-pointer ``` #### 產生測試資料 ``` $ dd if=/dev/urandom of=input.dat bs=$((8 * 1024 * 1024)) count=1 ``` #### 以 perf stat 取得總體統計數據 ``` $ perf stat -e cycles,instructions ./matrix-v1 Performance counter stats for './matrix-v1': 95,785,073,294 cycles 37,686,138,060 instructions # 0.39 insn per cycle 26.543938341 seconds time elapsed 26.529436000 seconds user 0.011998000 seconds sys ``` #### 以 perf record -g 取樣 ``` $ sudo perf record -g ./matrix-v1 ``` #### 以 perf report 讀取報告 ``` $ sudo perf report -g graph,0.5,caller ``` ![圖片](https://hackmd.io/_uploads/Sy_B5hRFZe.png) 在 mult 欄按 a 觀看詳細內容 ![圖片](https://hackmd.io/_uploads/B1P55n0FWe.png) 可以發現 imul 佔用大量的執行時間,文章的作者猜測可能是 cache-miss ,於是想用 perf 針對 cache-miss 進行觀測。要觀測 cache-miss 需要找到相關的事件選項。 #### 以 perf list 查詢合適的事件種類 ``` $ perf list ``` 雖然跟文章作者使用不同的 CPU ,但一樣找到了同樣的觀測選項。 ![圖片](https://hackmd.io/_uploads/Sk64Tn0KZl.png) #### 重新使用 perf record 記錄 cycles、instructions 與 L1-dcache-load-miss 的事件次數 ``` $ sudo perf record -g -e cycles,instructions,L1-dcache-load-misses ./matrix-v1 ``` #### 再次以 perf report 讀取報告 ``` $ sudo perf report -g graph,0.5,caller ``` 這次觀察了三種選項,我們選擇觀看第三個選項的報告。 ![圖片](https://hackmd.io/_uploads/rk3XR20Kbg.png) 可以看到 cache-miss 都發生在 mult 函式中。 ![圖片](https://hackmd.io/_uploads/B1iBRhRYWg.png) 在 mult 的欄位上按下 a ,觀看更詳細的內容。 ![圖片](https://hackmd.io/_uploads/HyykJ6AY-g.png) #### 統計 matrix-v1 的 cache-miss 發生次數 | 指令 | 次數 | | ----------------- | ------------- | | imul (%rax), %edx | 112,544,952 | | add $0x1000, %rax | 5,017,847,773 | | add $0x4, %rcx | 198,762,201 | | add %edx, %esi | 6,586,141 | | cmp %rdi, %rax | 89,581,774 | | 總和 | 5,425,322,841 | | 平均 (除以 5 * 1024 * 1024 * 1024) | 101.05% | cache-miss 發生次數在迴圈中的佔比竟然超過100% !? ![圖片](https://hackmd.io/_uploads/HJI1MTCFWl.png) #### 範例程式2: 執行矩陣乘法之前先轉置矩陣 b `matrix-v2.c` ```c static int32_t bT[N][N]; __attribute__((noinline)) static void transpose() { size_t i, j; for (i = 0; i < N; ++i) { for (j = 0; j < N; ++j) { bT[i][j] = b[j][i]; } } } __attribute__((noinline)) static void mult() { size_t i, j, k; transpose(); for (i = 0; i < N; ++i) { for (j = 0; j < N; ++j) { for (k = 0; k < N; ++k) { c[i][j] += a[i][k] * bT[j][k]; } } } } ``` #### 用同樣的命令編譯 matrix-v2.c ``` $ gcc matrix-v2.c -o matrix-v2 -mno-sse2 -Wall -O2 -g -fno-omit-frame-pointer ``` #### 再次使用 perf stat 測量 matrix-v2 的總體統計數據 ``` $ sudo perf stat -e cycles,instructions,L1-dcache-load-misses ./matrix-v2 Performance counter stats for './matrix-v2': 10,204,459,433 cycles 32,302,151,961 instructions # 3.17 insn per cycle 343,137,247 L1-dcache-load-misses 2.837096672 seconds time elapsed 2.818573000 seconds user 0.007984000 seconds sys ``` #### 再次使用 perf record 記錄 cycles、instructions 與 L1-dcache-load-miss 的事件次數 ``` $ sudo perf record -g -e cycles,instructions,L1-dcache-load-misses ./matrix-v2 ``` ![圖片](https://hackmd.io/_uploads/r1mVUT0Y-g.png) #### 統計 matrix-v2 的 cache-miss 發生次數 | 指令 | 次數 | | ----------------- | ------------- | | imul (%rsi,%rax,4),%edx | 49,162,793 | | add $0x1,%rax | 103,876,222 | | add %edx,%ecx | 71,573,598 | | cmp $0x400,%rax | 79,379,898 | | 總和 | 303,992,511 | | 平均 (除以 5 * 1024 * 1024 * 1024) | 5.66% | #### 改良前後的比較 改良後的程式在效能上有大幅的改善。 | 項目 | matrix-v1 | matrix-v2 | 差異百分比 | | -------------------- | --------- | ----------- | ---------- | | Insn Per Cycle(個) | 0.39 | 3.17 | 712% | | L1 Data Cache Miss (次) | 5,425,322,841 | 303,992,511 | -95% | | 總花費時間(秒) | 26.54 | 2.83 | -90% | ### 簡介 perf_events 與 Call Graph #### 實際操作 1 範例程式:[callgraph.c](https://zh-blog.logan.tw/static/sourcecode/2019/10/06/callgraph.c) #### 編譯 ```shell $ gcc -g -O2 -fno-omit-frame-pointer callgraph.c -o callgraph ``` #### 測量 ```shell $ sudo perf record -g --call-graph fp -o callgraph.fp.perf.data ./callgraph $ sudo perf record -g --call-graph dwarf -o callgraph.dwarf.perf.data ./callgraph $ sudo perf record -g --call-graph lbr -o callgraph.lbr.perf.data ./callgraph ``` 三者的檔案大小不同 ![圖片](https://hackmd.io/_uploads/r1DFvy1qbe.png) #### 觀察記錄檔案的內容 ```shell $ sudo perf report --stdio -i [filename] ``` fp: ``` 99.99% 5.92% callgraph callgraph [.] main | |--94.08%--main | | | |--58.78%--A | | | | | |--23.49%--C | | | | | --23.47%--B | | | | | --11.74%--C | | | |--23.44%--B | | | | | --11.72%--C | | | --11.77%--C | --5.92%--__libc_start_call_main main ``` dwarf: ``` 99.98% 5.66% callgraph callgraph [.] main | |--94.33%--main | | | |--59.02%--A | | | | | |--23.96%--B | | | | | | | --11.71%--C | | | | | --23.34%--C | | | |--23.62%--B | | | | | --11.93%--C | | | --11.59%--C | --5.66%--_start __libc_start_main_impl (inlined) __libc_start_call_main main ``` lbr: ``` 99.99% 5.94% callgraph callgraph [.] main | |--94.05%--main | | | |--82.21%--A | | | | | |--35.20%--B | | | | | | | --11.69%--C | | | | | --11.80%--C | | | --11.74%--B | C | --5.94%--_start __libc_start_main@@GLIBC_2.34 __libc_start_call_main main ``` 可以看到 lbr 的結果與前兩者差異較大,並且有奇怪的 stack ,另外三張圖中都有跳過 A 呼叫 B 或 C 的情況。這些是因為 `Sibling Call Optimization` 造成的。 #### 使用 -fno-optimize-sibing-calls 重新編譯 ```shell $ gcc -g -O2 -fno-omit-frame-pointer -fno-optimize-sibling-calls callgraph.c -o callgraph ``` #### 重新測量 ```shell $ sudo perf record -g --call-graph fp -o callgraph.fp.perf.data ./callgraph $ sudo perf record -g --call-graph dwarf -o callgraph.dwarf.perf.data ./callgraph $ sudo perf record -g --call-graph lbr -o callgraph.lbr.perf.data ./callgraph ``` fp: ``` 99.99% 5.82% callgraph callgraph [.] main | |--94.17%--main | | | --94.14%--A | | | |--70.73%--B | | | | | --47.04%--C | | | --11.76%--C | --5.82%--__libc_start_call_main main ``` dwarf: ``` 99.98% 5.77% callgraph callgraph [.] main | |--94.21%--main | | | --94.17%--A | | | |--70.61%--B | | | | | --46.94%--C | | | --11.99%--C | --5.77%--_start __libc_start_main_impl (inlined) __libc_start_call_main main ``` lbr: ``` 99.99% 5.89% callgraph callgraph [.] main | |--94.10%--main | | | --94.03%--A | | | |--70.59%--B | | | | | --47.05%--C | | | --11.83%--C | --5.89%--_start __libc_start_main@@GLIBC_2.34 __libc_start_call_main main ``` 這次,三種測量的結果就很相近, stack 也符合預期。 ## 探討〈[linked list 和非連續記憶體](https://hackmd.io/@sysprog/c-linked-list)〉 文中的練習題,將函式原型改為 `void remove(list_entry_t head, int value)` ```clike void remove(list_entry_t **head, int value){ list_entry_t **dummy = head; while((*dummy)->value != value) dummy = &(*dummy)->next; *dummy = (*dummy)->next; } ``` 我的疑問: - 使用 indirect pointer 雖然變優雅了,但會不會多了解指標的開銷? - 在討論 [LeetCode 23. Merge k Sorted Lists](https://leetcode.com/problems/merge-k-sorted-lists/description/) 的段落中 - 長度相近的 linked list 合併真的會比不等長的快嗎?還是只是省了某部份的時間,卻多了另一部份的時間? 感想: 原來環狀的意義在於省去雙向鏈結佔用的空間(可以在 cache line 中多放一些)但又同時彌補反向查詢的功能。並且在嵌入式環境中,因為沒有 MMU ,所以 NULL 的位置其實可以使用,環狀的好處就是可以不去使用 NULL 當結尾,使 NULL 可以被其他需求利用。 - 案例探討: Leetcode 2095. Delete the Middle Node of a Linked List 中 利用快慢指標 - 檢查 linked list 是否有環 - 在環狀 linked list 找到中點 的方法很有趣,以前沒有想過。用不停檢查是否曾經走過的方法,會佔用很多空間。

    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