per-cpu是2.6核心中引入的,訪問per-cpu變數幾乎不需要鎖,每個處理器都在其自己的副本上工作。這些副本是如何生成的呢?本文嘗試解答這個問題。
靜態per-cpu結構設計思路大體可以分為兩個階段:編譯階段和執行時階段
在編譯階段,實際上只生成了乙個cpu原本。系統中所有per-cpu結構都放到了乙個叫做"data.percpu"的section中,在ld.s鏈結指令碼有如下內容:
. = align(32);
__per_cpu_start = .;
.data.percpu :
__per_cpu_end = .;
. = align(4096);
__init_end = .;
由這個鏈結指令碼知道,
.data.percpu section是處於init資料段的,在系統初始化結束後將被**。那麼,系統如何維持per-cpu資料呢?這個任務在執行時完成。在系統初始化階段有乙個函式會分配 nr_cpu * (
__per_cpu_end -
__per_cpu_start)大小的記憶體,然後將 data.percpu段中的cpu原本拷貝nr_cpu份到這塊記憶體中。從此以後系統通過get_cpu_var訪問per-cpu變數的時候就會根據自己的cpu_id找到對應的拷貝。
可見,靜態per-cpu變數的locality非常好,cpu之間在cache級都不彼此干擾。對於靜態生成的per-cpu變數需要使用get_cpu_var來訪問。
在講述動態per-cpu結構之前不妨思考下,如何能把動態per-cpu的locality設計得跟靜態的一樣呢? 由於不知道系統中將會有多少動態結構出現,所以不宜採用預留記憶體的方式,這為我們的設計帶來了很大挑戰。實際上,linux也沒有完全解決這個問題,但還是做了最大程度的優化,手法也比較贊。考慮到per-cpu變數的訪問模式,效率應該和靜態方式不相上下。下面看看linux的處理方式。
int node = cpu_to_node(cpu); bug_on(pdata->ptrs[cpu]); if (node_online(node)) pdata->ptrs[cpu] = kmalloc_node(size, gfp|__gfp_zero, node); else pdata->ptrs[cpu] = kzalloc(size, gfp);
對於動態生成的per-cpu變數需要用per_cpu_ptr來訪問。
ref:
ref:
kernel中的per cpu變數
per cpu 變數的引入有效的解決了smp系統中處理器對鎖得競爭,每個cpu只需訪問自己的本地變數。本文闡述了per cpu變數在2.6核心上的實現和相關操作。在系統編譯階段我們就手工的定義了乙份所有的per cpu變數,這些變數的定義是通過巨集define per cpu實現的 11 defin...
靜態變數和動態變數
首先,變數的儲存型別可分為四類 自動型別 auto 暫存器型別 register 靜態型別 static 外部型別 extern 動態變數 自動型別 auto 暫存器型別 register 靜態變數 靜態型別 static 外部型別 extern 屬於動態全域性變數,可以省略auto識別符號,因此,...
靜態儲存 動態儲存 靜態變數與動態變數
動態變數 int a 靜態變數 static int a 靜態變數,全域性動態變數都是靜態儲存,儲存在全域性資料區,在變數定義時就分定儲存單元並一直保持不變,直至整個程式結束。靜態儲存變數是一直存在的,只會初始化一次。區域性動態變數是動態儲存,動態儲存變數是在程式執行過程中,使用它時才分配儲存單元,...