歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux資訊 >> 更多Linux >> Linux高級應用CpuMemSets在Linux中的實現

Linux高級應用CpuMemSets在Linux中的實現

日期:2017/2/27 9:45:55   编辑:更多Linux
  一、 前言  非一致性內存訪問(Non-Uniform Memory Access)結構是分布式共享內存(Distributed Shared Memory)體系結構的主要分支,它通過結合分布式內存技術和單一系統映像(SSI)技術,實現了SMP 系統的易編程性和 MPP系統的易擴展性的折中,已成為當今高性能服務器的主流體系結構之一。目前國外著名的服務器廠商都先後推出了基於 NUMA 架構的高性能服務器,如HP的Superdome、SGI 的 Altix 3000、Origin 3000、IBM 的 x440、NEC 的 TX7、AMD 的Opteron 等。    隨著NUMA架構的高性能服務器被逐漸推廣,系統軟件針對這種分布式共享內存架構的特點,在調度器、存儲管理和用戶級接口等方面進行了大量的優化工作。例如,SGI的Origin 3000 ccNUMA系統在許多領域得到了廣泛應用,是個非常成功的系統,為了優化Origin 3000的性能,SGI的IRIX操作系統在其上實現了CpuMemSets,通過將應用與處理器和內存的綁定,充分發揮NUMA系統本地訪存的優勢。Linux社區在自己的NUMA項目中也實現了CpuMemSets,並且在SGI的Altix 3000的服務器中得到實際應用。    本文將以 SGI 的 ProPack v2.2 為研究對象,分析 CpuMemSets 在Linux-2.4.20 中的具體實現。CpuMemSets 是 SGI 進行的一個開放源碼項目,由針對 Linux2.4 內核的補丁、用戶庫、python 模塊和 runon 等命令共四部分組成,以實現處理器和內存塊的分區為目標,控制系統資源(處理器、內存塊)面向內核、任務以及虛擬存儲區的分配,為 dplace、RunOn 等 NUMA 工具提供支持,最終優化 Linux 系統的 NUMA 性能。    二、 相關工作  分區技術(Partition)最初出現在大型機(MainFrame)上,如今被廣泛應用到服務器領域,支持在單個服務器上運行一個操作系統的多個實例或者多個操作系統的多個實例,主要特點是"機器獨立、屏障可靠、單點管理"。在分區技術支持下,當前多台服務器運行的多個操作系統就可以在同一地點的一台服務器上同時運行,優於在一個組織中四處分散用多個服務器來支持不同的操作系統,從而有效地實現了服務器整合。支持分區技術的服務器可以當作應用服務器,運行Windows平台供市場部門使用;同時還可以運行Linux系統供工程部門使用。還可以在大多數用戶運行windows 2000 Advanced Server系統的同時,在另一個分區中為發展組測試其它操作系統;或者所有節點都應用在一個操作系統環境下。各種分區實現技術的主要差別體現在分區故障隔離手段(硬件或軟件)、分區資源粒度、分區資源靈活性以、虛擬分區資源以及對動態分區重構的支持等方面。典型的有IBM的LPAR和DLAPAR(AIX 5L 5.1)、HP的nPartitions和vPartitions(HP-UX 11i)、SUN的Dynamic Domains(Solaris 8)、以及Compaq的Alpha Servers(Tru64 Unix 5.1)。但是,針對NUMA系統采用的分區技術與NUMA系統本身具有的單系統映像優勢是矛盾的。    從用戶的角度來看,NUMA系統提供了對本地主存和遠程主存訪問的透明性;但是,從性能的角度來看,由於存儲模塊物理上分布在不同的節點引起的存儲訪問延遲不一致現象,對系統的性能也帶來了較大的影響。在這類系統中,一個節點對遠程節點存儲訪問的延遲通常比本地訪問延遲高1到2個數量級。頁遷移與頁復制是對數據進行動態局部性優化的主要方法之一。其實質是一種預測技術,根據收集到的信息預測將來對頁面的訪問情況,然後作出遷移或復制頁面的決策。采用適當的頁復制與頁遷移策略可以減小cache容量和沖突失效,平衡遠程和本地訪問延遲的不一致,達到優化NUMA系統性能的目的。但是現有的頁遷移與頁復制策略大都過分依賴於體系結構和特殊的硬件支持,開銷比較大,通用性也不好。    在NUMA結構的多處理器系統中,一個任務可以在任何一個處理器上運行,然而任務在各種情況的執行會被中斷;被中斷的任務在恢復執行的時候,如果選擇恢復在另外一個處理器上執行,就會導致它失去原有的處理器cache數據。我們知道,訪問cache數據只需要幾個納秒,而訪問主存需要大約50納秒。這時處理器運行的速度處在訪問主存的級別上,直到任務運行了足夠的時間,任務運行所需要的數據重新充滿該處理器的cache為止。為解決這個問題,系統可以采用處理器親近調度策略調度每個節點上的任務:系統記錄下最後執行這個任務的處理器並維持這種關系,在恢復執行被中斷的任務時,盡量恢復在最後執行這個任務的處理器上執行。但是,由於應用程序的特點各有不同,而且工作集具有動態屬性,處理器親近調度的作用是有限的。    用戶是系統的使用者,也是性能的評判者,他們最清楚應用對系統的需求和評價指標。在一個大的NUMA系統中,用戶往往希望控制一部分處理器和內存給某些特殊的應用。CpuMemSets允許用戶更加靈活的控制(它可以重疊、劃分系統的處理器和內存),允許多個進程將系統看成一個單系統映像,並且不需要重啟系統,保障某些處理器和內存資源在不同的時間分配給指定的應用;也是對分區技術、頁遷移和親近調度策略的有益補充。    三、 系統實現  在介紹CpuMemSets在Linux-2.4.20中的具體實現之前,我們首先說明CpuMemSets涉及的幾個基本概念,包括:    處理器:指承載任務調度的物理處理器,但是不包括DMA設備、向量處理器等專用處理器;  內存塊:在SMP、UP系統中,所有的內存塊與所有處理器的距離相等,因此不存在差別;但是在NUMA系統中,可以按照與處理器的距離對內存塊劃分等價類。此外,CpuMemSets不考慮具有速度差異的特殊存儲器,如輸入輸出設備緩存、幀緩存等。    任務:一個任務,在任一時刻,或者等待事件、資源,或者被中斷,或者在處理器上運行。  虛擬存儲區:內核為每個任務維護的多個虛擬地址區域,可為多個任務共享。位於虛擬存儲區內的頁,或者沒有分配,或者已分配但被換出,或者已分配且在內存中。可以指定允許分配給某個虛擬存儲區的內存塊以及分配順序。    CpuMemSets為Linux提供了將系統服務和應用綁定在指定的處理器上進行調度、在指定的結點上分配內存的機制。CpuMemSets在已有的Linux調度和內存分配代碼基礎上增加了cpumemmap(cmm)和cpumemset(cms)兩層結構,底層的cpumemmap層提供一個簡單的映射對,實現系統的處理器號與應用的處理器號、系統的內存塊號與應用的內存塊號的映射。這種映射不一定是單射,一個系統號可以對應多個應用號。上層的cpumemset層負責說明允許把任務調度到哪些應用處理器號所對應的處理器上運行、可以從哪些應用內存塊號所對應的內存塊中為相應的內核或虛擬存儲區分配內存頁,也就是說,指定可供內核、任務、虛擬存儲區使用的資源集合。在這種兩層結構中,資源的系統號供內核執行調度和內存分配時使用;而資源的應用號供用戶進程指定本應用的資源集合時使用。系統號在啟動期間全系統范圍內有效,而應用號僅僅相對於共享同一個cmm的所有用戶進程有效。而且,由於負載平衡和熱插拔引發的資源物理編號的變化對應用號是不可見的。    Linux的進程調度和內存分配在保持現有代碼正常運轉的基礎上,添加了對CpuMemSets的支持,使用"系統處理器號"和"系統內存塊號"以及其他數據結構如cpus_allowed和mems_allowed等實現資源的分區。此外,CpuMemSets的API提供了對cpusets、dplace、runon、psets、MPI、OpenMP、nodesets的支持,並且提供/proc接口以顯示cmm和 cms的結構、設置以及與任務、虛擬存儲區、內核的連接關系、系統資源號和應用資源號等信息。下面我們分別對cpumemmap和cpumemset、進程調度和內存分配、以及API這三個部分進行詳細分析:    3.1 cmm&cms  3.1.1 數據結構    cpumemmap和cpumemset的數據結構如下所示,具體定義在include/linux/cpumemset.h中。Cpumemmap中的scpus和smems域分別指向一組系統處理器號和一組系統內存塊號,實現應用的資源號(數組下標)與系統的資源號(數組元素值)的映射。Cpumemset中的acpus域指向一組應用處理器號,而amems域指向一組cms_memory_list_t類型的內存塊列表。每個內存塊列表描述了一組應用內存塊號(mems)以及享有該列表的一組應用處理器號(cpus)。內存塊分配策略由cpumemset中的policy域決定,缺省使用本地優先方式。Cpumemset通過cmm域與相應的cpumemmap建立關聯。兩個數據結構中的counter域的作用將在後文介紹。    【include/linux/cpumemset.h】  84 typedef strUCt cpumemmap {  85     int nr_cpus;       /* number of cpus in map */  86     int nr_mems;       /* number of mems in map */  87     cms_scpu_t *cpus;    /* array maps application to system cpu num */  88     cms_smem_t *mems;    /* array maps application to system mem num */  89     atomic_t counter;    /* reference counter */  90    } cpumemmap_t;    92 typedef struct cpumemset {  93     cms_setpol_t policy;  /* CMS_* policy flag :Memory allocation policy */  94     int nr_cpus;        /* Number of cpus in this CpuMemSet */  95     int nr_mems;        /* Number of Memory Lists in this CpuMemSet */  96     cms_acpu_t *cpus;    /* The 'nr_cpus' app cpu nums in this set */  97     cms_memory_list_t *mems;     /* Array 'nr_mems' Memory Lists */  98     unsigned long mems_allowed;   /* memory_allowed vector used by vmas */  99     cpumemmap_t *cmm;    /* associated cpumemmap */  100    atomic_t counter;    /* reference counter */




Copyright © Linux教程網 All Rights Reserved