跳到主要內容

發表文章

【Linux 排程機制】從 CFS 到 EEVDF:虛擬截止時間如何給 Linux 排程帶來延遲保證 / [Linux Scheduling] From CFS to EEVDF: How Earliest Eligible Virtual Deadline First Brings Latency Guarantees to Linux

你有沒有遇過這種情況:開著幾個重度應用,滑鼠游標明明沒動,系統卻突然停頓半秒,播放的影片掉幀、遊戲瞬間卡住?這往往不是記憶體不足,而是「排程延遲」——核心決定哪個進程下次使用 CPU 的時間點,沒有給即時工作負載足夠的保證。舊版 Linux 預設排程器 CFS(完全公平排程)追求整體公平,但對「這個任務必須在多久內執行」的延遲上限,缺乏明確承諾。 Have you ever experienced this: several heavy applications running, the mouse cursor sits still, yet the system suddenly freezes for half a second, video stutters, or a game hitches? This is often not memory exhaustion, but "scheduling latency" — the kernel's decision of which process gets the CPU next fails to guarantee timing for latency-sensitive workloads. The default Linux scheduler CFS (Completely Fair Scheduler) pursues overall fairness, but lacks a clear upper-bound commitment on "this task must run within how long." struct sched_entity (排程實體) Linux 6.18.55 · kernel/sched/fair.c · include/linux/sched.h EEVDF 決策欄位 load struct load_weight — 加權負載,決定分攤時間比例 run_node struct rb_node — 掛在 CFS 紅黑樹 tasks_timeline 上的節點 vrun...
最近的文章

【Android 底層篇】Binder IPC 內部機制拆解:一次拷貝背後的 mmap 記憶體映射黑魔法與執行緒池調度 / [Android Internals] Demystifying Binder IPC: The "Single-Copy" mmap Black Magic and Thread Pool Scheduling

只要開發過 Android 應用程式,你幾乎肯定遇過令人抓狂的 TransactionTooLargeException 。當你試圖在 Intent、Bundle 或 AIDL 介面塞入一張稍微清晰的高解析圖片或龐大資料列表時,應用程式便無情崩潰。為什麼在動輒配備 16 GB 記憶體的旗艦手機上,一次跨行程通訊只要超過區區 1 MB 就會引發系統報警? If you have ever developed an Android application, you have almost certainly encountered the notorious TransactionTooLargeException . When attempting to pass a high-resolution bitmap or an extensive serialized dataset across an Intent, Bundle, or AIDL interface, the application abruptly terminates. Why does an inter-process transaction exceeding a mere 1 MB trigger immediate system panic on a flagship smartphone packing 16 GB of physical RAM? 要徹底解開這個謎題,我們必須告別抽象的 Java 介面,穿透 Android Runtime(ART),直接潛入 Linux 核心驅動 drivers/android/binder.c 。Binder 作為 Android 系統的血脈神經,憑藉著「僅需一次記憶體拷貝」的精巧設計,支撐起整座作業系統的骨架。今天我們就來深度拆解 Binder 的核心映射機制、執行緒池調度與工程師除錯指南。 To unravel this puzzle completely, we must look beyond abstract Java interfaces, bypass the Android Runtime (ART), and dive directly into the Linux kernel driver at driver...

【Linux 核心 x Android AI 篇】DMA-BUF 零拷貝機制深度拆解:Linux 核心如何讓 NPU 與相機/模型共享記憶體?直擊 dma_buf.c 核心原始碼與 Android AI 推論加速原理 / [Linux Kernel x Android AI] DMA-BUF Zero-Copy Teardown: How the Kernel Shares Buffers Across Cameras, NPU, and On-Device Models via dma_buf.c

在當前智慧型手機與邊緣裝置全面邁向「生成式 AI 與即時神經網路推論」的時代,你是否曾思考過:當手機鏡頭開啟 4K 60FPS 即時串流,相機影像要如何在短短幾毫秒內送進 NPU(神經網路處理單元)執行物體偵測或語義分割,而手機卻不會在幾分鐘內發燙降頻? In an era where smartphones and edge devices rapidly converge toward generative AI and real-time neural network inference, have you ever wondered: When your camera streams 4K 60FPS video, how are raw image frames routed into the NPU (Neural Processing Unit) within milliseconds for object detection or segmentation without turning your handset into a scalding thermal furnace? 如果你曾試著在 Android 應用層呼叫傳統的 read() 或位元組陣列搬運影像,很快就會發現系統陷入嚴重的快取洗刷(Cache Thrashing)與卡頓。要解開即時 AI 高吞吐量的秘密,關鍵鑰匙就深藏在 Linux 核心的 dma-buf (Direct Memory Access Buffer)子系統。今天我們直接深入 Linux 6.18 核心原始碼,剖析 Linux 與 Android 如何透過 DMA-BUF 打造零拷貝(Zero-Copy)的高速資料通道。 If you have ever tried pulling raw camera frames into an application buffer using conventional read() calls or byte arrays, you inevitably observed severe cache thrashing, latency spikes, and frame drops. The definitive solution for real-time ...

【Git 協同篇】三方合併(Three-Way Merge)揭秘:Git 到底如何尋找共同祖先(Merge Base)與判定每一行衝突? / [Git Three-Way Merge Internals] How Git Finds the Merge Base and Determines Line-by-Line Conflicts

在多名工程師協同開發大型系統時,「合併代碼」幾乎是每天都會執行的核心動作。當你在終端機下達 git merge feature ,看到終端機回傳「Merge made by the 'ort' strategy.」並且幾十個檔案順暢無阻地合為一體時,你是否曾好奇:Git 究竟是憑藉什麼魔法,能精準知道哪一行是誰新增的、哪一行是誰刪除的?又是依據什麼規則,在雙方改動重疊時精準拋出衝突? When multiple engineers collaborate on large-scale systems, merging branches is an indispensable daily routine. When you run git merge feature and watch the console announce "Merge made by the 'ort' strategy" while dozens of files seamlessly combine, have you ever wondered: What mathematical mechanics allow Git to discern exactly who added or removed each line? By what underlying rules does it flag conflicts when edits overlap? 承接我們上一篇深入探討的 Git Rebase 補丁重播與雜湊移植機制,今天我們將焦點轉向分支整合的另一大基石——「三方合併」(Three-Way Merge)。許多開發者以為合併只是把兩個分支的最新快照拿來互相比對,然而單純的「雙方比對」在數學邏輯上根本無法判定檔案到底是新增還是刪除。要解開這個謎題,必須深入探究 Git 如何在有向無環圖中尋找「共同祖先」(Merge Base),以及 Diff3 演算法如何在每一行代碼中進行裁決。 Continuing our previous deep dive into Git Rebase patch replay and hash recomputation, today we pivot to the other fou...

【Git 變基篇】git rebase 與 merge 底層拆解:為什麼變基會產生全新 SHA?Commit 移植機制與無痛衝突解決 / [Git Rebase vs Merge Internals] Why Rebase Generates New SHAs: Commit Replay Mechanism and Conflict Resolution

在團隊協同開發時,許多工程師都曾遇過這樣的困惑:明明只是把功能分支對齊最新主幹,執行了 git rebase main 之後,原本好端端的提交雜湊碼(Commit SHA)居然全數換成了一組完全陌生的新代碼;要是有人不小心在共用分支上執行變基並強制推送,全團隊的 git pull 更會瞬間陷入雙倍歷史與衝突地獄。 During team collaboration, many developers stumble upon this puzzle: simply wanting to align a feature branch with the latest main via git rebase main unexpectedly rewrites every single commit SHA into completely unfamiliar hashes; if someone accidentally rebases a shared branch and force-pushes, teammates' subsequent pulls instantly turn into a nightmare of duplicated history and merge conflicts. 承接我們在上一篇探討的 Git 底層物件模型與指標移動,今天我們將視野推進到分支整合的核心戰場。究竟 git rebase 在底層做了什麼?它與傳統的 git merge 拓撲有何根本不同?為什麼變基一定會產生新雜湊?搞懂這些機制,你就能徹底擺脫對變基的恐懼,自信寫出乾淨俐落的線性版本歷史。 Building on our previous exploration of Git object stores and pointer movements, today we advance to the central arena of branch integration. What does git rebase actually execute under the hood? How does its direct acyclic graph differ fundamentally from traditional git mer...

【Git 救援篇】不小心 git reset --hard?別慌:用 reflog 與底層物件找回丟失的 Commit / [Git Recovery Guide] Accidentally Ran git reset --hard? Rescuing Commits with Git Reflog

在終端機按下 Enter 的瞬間,許多工程師都曾有過心臟漏跳半拍的經歷:原本只想清除暫存,手指卻下意識敲出 git reset --hard HEAD~1 ,剛剛花了一下午寫完並提交的功能代碼,瞬間在編輯器視窗裡消失得無影無蹤。 The moment Enter is pressed, many developers experience that stomach-dropping panic: intending only to clear staged files, fingers muscle-memory typed git reset --hard HEAD~1 , instantly wiping an entire afternoon of newly committed code from editor buffers. 請先深吸一口氣,停下鍵盤上的所有強制寫入指令。Git 的底層設計並不是像磁碟碎紙機一樣立即覆寫資料;事實上,只要那個修改曾經被 git commit 記錄過,你的程式碼絕大多數時候都依然毫髮無傷地躺在硬碟的物件資料庫裡。 Take a deep breath and immediately step away from destructive write commands. Git's underlying architecture is not a shredder that overwrites disk blocks immediately; if your work was committed even once, the files almost certainly remain intact inside the local object store. 圖一|reset --hard 僅後移分支與 HEAD 指標,Commit 物件仍完整保留於物件庫中(原創架構示意圖,非產品截圖) Figure 1 | reset --hard only moves branch and HEAD pointers; the commit object remains intact in the object database (Original architecture ...

Git 顯示 detached HEAD,不是壞掉:先替實驗提交留一個分支 / Detached HEAD Is Not Broken: Name the Commit You Want to Keep

現象:看到 detached,不代表壞掉 / Detached does not mean broken 假設你為了查看舊版本,執行 git switch --detach HEAD~1,終端機卻跳出 detached HEAD。畫面裡的「detached」很像檔案壞了,其實 Git 只是告訴你:現在的 HEAD 沒有掛在任何分支名稱上。你仍能查看檔案、修改內容,甚至提交;真正要留意的是,新提交暫時沒有分支名稱替它保留位置。 Suppose you inspect an older revision with git switch --detach HEAD~1 and the terminal reports a detached HEAD. “Detached” sounds like something broke, but Git is only saying that HEAD is not attached to a branch name. You may still inspect files, edit, and commit. The part that needs attention is that a new commit is not yet retained by a branch name. HEAD 與分支原本怎麼連 / How HEAD normally follows a branch 平常在 main 上工作時,HEAD 是符號參照,也就是它先指向 refs/heads/main,而 main 再指向某個提交。建立新提交後,Git 會把 main 移到新提交,HEAD 因為跟著 main,也間接移動。官方資料模型則把 detached HEAD 定義成另一種合法狀態:HEAD 直接保存提交 ID,沒有目前分支。[1][2] While working on main, HEAD is normally a symbolic reference: it points to refs/heads/main, and main points to a commit. Creating a commit moves main to the new commit, so HEAD follows indirectly. Git’s off...