色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

深度剖析基于塊層的組成“request層”

Linux閱碼場 ? 2018-02-03 16:29 ? 次閱讀

Linux 塊層向上為文件系統和塊設備提交接口,使得上層能夠以統一的方式訪問各種類型的后端存儲設備。同時,它也向下為設備驅動提供接口,讓驅動層能夠以一致的方式來接受請求。一些驅動如上一篇文章中提到的DRBD和RBD設備,只使用bio層提供的一些接口,對bio請求進行處理。其它的驅動則可以從IO請求plugging機制,各種請求排序和請求合并中受益。為了給驅動層提供服務,塊層做了不少事情,我且稱之為"request層"。

現在,"request層"并存著兩種模型:單隊列(single-queue) 和 多隊列(multi-queue)。多隊列的出現也就是近幾年的事情,也許總有一天會完全取代單隊列的,但是目前來看兩者在內核的使用都相當活躍。有了這兩種不同的排隊方法(queuing approach)做參考,我們就可以兩相對比來學習學習,所以我們將花點時間都看看,分析他們如何把請求呈現給驅動層的。首先,我們來看看兩者的共同之處,分析這兩個關鍵的結構體是個不錯的入手點: struct request_queue 和 struct request。

請求隊列和請求

struct request_queue之于struct request的關系,非常像struct gendisk之于struct bio的關系:一個代表具體的設備,一個代表IO請求。需要注意的是,每個gendisk都有一個關聯的request_queue結構體,但是只有那些使用了"request層"的設備才會分配request結構體。按理說,適用于所有塊設備的域,比如struct queue_limits,都應該放到gendisk結構體里面,而對于一些僅適用于"request層"隊列管理的域,其實只應當分配給那些使用了"request層"的設備。現在來看,這些結構體里有些域的安排可能就是歷史巧合,也不值得去糾正了。各種隊列相關的域,都可以在/sys/block/*/queue/目錄下查看。

request結構體代表單個IO請求,最終要傳遞到底層設備。一個request包含一個或多個代表連續IO請求的bio,一些跟蹤總體狀態的信息(比如時間戳,哪個CPU發來的請求),和一些用來鏈入更大數據結構的“錨點”,比如用struct list_head queuelist鏈入一個簡單的隊列結構,用struct hlist_node hash鏈入一個哈希表(用來查找與新bio相鄰的請求),用struct rb_node rb_node來把請求放在一棵紅黑樹上。在分配一個request結構體的時候,有時候要分配一些額外的空間來給底層驅動保存一些額外的信息。有時候這些空間用來保存命令頭部,以便發送給底層設備,比如 SCSI command descriptor block,驅動可以自由地決定如何使用這塊空間。

相應的make_request_fn()函數 (單隊列是blk_queue_bio,多隊列是blk_mq_make_request())為IO請求創建一個request結構體,然后把交給IO調度器, 也叫電梯算法"elevator", 這個名字來自電梯算法( elevator algorithm),電梯算法曾是磁盤IO調度一個里程碑式的成就。我們將快速看一下單隊列的實現,然后再對比地去看多隊列。

深度剖析基于塊層的組成“request層”

單隊列上的請求調度

過去,大多存儲設備都是機械硬盤,要通過磁頭尋道,盤片旋轉來定位數據。機械盤一次只能處理一個請求,從盤片上一個位置挪動到下一個位置代價很大。單隊列的實現就是為這種類型的設備而生的,然后漸漸地也能支持其它快速設備,然而單隊列整體結構依然反映了旋轉類型存儲設備的需求。

單隊列調度器主要有三個任務:

積聚代表連續IO操作的多個bio,合并成更大的IO請求,充分發揮硬件性能,但是請求不能太大超高硬件設備的限制;

把請求進行排序來減少尋道時間,但是又要保證重要的請求得到及時處理。不斷尋求較優方案,來解決這個問題,是這一部分代碼復雜度的根源。一般很難知道這兩點:一個請求有多重要,和一個請求需要多少尋道時間,我們只能依賴啟發式方法來判斷怎樣排序比較好,然而啟發式方法絕不是完美的;

把經過整理的請求列表交給底層驅動,讓驅動從隊列取下請求去處理,同時提供一個通知機制來告訴上層請求處理的結果。

最后一個任務很直接了當。驅動會通過blk_init_queue_node()來注冊一個request_fn()策略例程,只要隊列上有新請求已經準備好,策略例程被調用去處理這個請求。驅動負責用blk_peek_request()來從隊列上取下請求,然后進行處理。當請求處理完畢 [有些設備可以并行處理多個請求],驅動會從隊列上摘下另一個請求來處理,而不用再去調用request_fn() [因為request_fn()一次拿到了整個列表上的所有request]。請求一旦處理完畢,就可調用blk_finish_request()來通知上層。

第一個任務有部分是用elv_attempt_insert_merge()完成的,它會快速地檢查隊列,看是否可以找到一個已經存在的request,把新的bio合并進入。如果成功,調度器就會允許合并,如果失敗,調度器還有一次機會嘗試在調度器內部進行一次合并。如果沒有機會合并,就分配一個新的請求,然后交給調度器。稍后一會,如果某個請求因合并而長大,使得它與該請求變成了連續的,調度器就可以再次嘗試合并操作。

第二個任務可能是最復雜的。如何把請求按照"適當"順序排隊非常依賴我們如何來解釋"適當"的含義。這三種不同的單隊列調度器: noop, deadline和cfq,對“適當”的解釋就非常不一樣。

"noop"會對請求做一些簡單的排序,不允許把讀請求挪到寫請求之前,反之亦然;依據電梯算法,一個同類型的請求可以插入到另一個之前。除了elv_dispatch_sort()所做簡單排序,"noop"就是一個FIFO隊列。

“deadline”會把提交時間相近的請求放在一批。在同一批中,請求會被排序。當一批請求達到了大小上限或著定時器超時,這批請求就會提交到設備隊列上去。這個算法嘗試給每一個請求都設置一個延遲時間上限,同時盡量聚集比較大的一批請求。

"cfq"即"Complete Fairness Queuing",相比其它幾個調度器要復雜很多,目的是在不同進程或進程組間保證IO資源使用的公平性。cfq調度器內部維護了多個隊列,每一個進程都有一個隊列來保存來自該進程的同步請求(通常是讀),而對于異步請求(通常是寫),每一個優先級都有一個隊列,所有請求不論來自哪個進程都按照優先級放到相應的隊列上。在提交請求時,按照優先級每個隊列都有機會得到調度。每個隊列都有一定的時間片,在時間片內才能提交一定數量的請求。當一個同步隊列中的請求不足一定數量時,這個設備可以空閑一會,即使其它隊列里可能有請求等待處理。通常,同步請求之間在磁盤上的物理位置是連續的,所以讓磁盤稍等一會來接收更多連續的請求,這樣做可以提高吞吐量。以上對CFQ的描述僅僅是點皮毛。內核文檔(Documentation/block/cfq-iosched.txt)講的更詳細點,還列出了所有參數,通過調整這些參數能夠適應各種不同的場景。

之前提到過,一些高端點的設備可以一次處理多個請求,即在一個請求還沒有處理完成之前,就能夠處理新的請求。通常,這個要用到"tagging"功能,給每一個請求加一個標簽,這樣請求完成通知就能和原來的請求正確的對應起來。單隊列的"request層"可以對任意深度的設備提供"tagging"功能。

一個設備內部可以通過真正地并行處理請求,來支持被標記的命令,比如通過訪問一個內存緩存,通過設計多模塊而每個模塊都能處理一個請求,或者通過其內部隊列,這樣的隊列比"request層"更加了解設備。

多隊列和多CPU

多隊列的另一個動機就是減少鎖的開銷,因為我們的系統處理器越來越多,而請求從多個處理器放到一個隊列中時需要加鎖,鎖的開銷變得越來越大。"plugging"機制能幫得上一些忙,但是不夠理想。如果我們能夠分配更多隊列:每個NUMA節點一個隊列,或者一個CPU一個隊列,那么把請求放到隊列的鎖開銷就會減少很多。如果硬件支持并行處理多個請求,那么這樣做的優勢就更大了。如果硬件只支持一次提交一個請求,那么多個per-CPU隊列仍然需要合并。如果他們比"plugging"機制批處理的效果更好,那么這樣做也是有益處的。假如不能提高批處理的效果,寫程序的時候小心點應該也能夠保證,至少不會有什么損失。

之前說過,cfq調度器內部已經有多個隊列,但是它們跟multi-queue的目的完全不一樣,它們把請求與進程和優先級關聯起來,而multi-queue的隊列是跟硬件密切相關的。multi-queue "request層"維護著兩組硬件相關的隊列:軟件的"staging"隊列和硬件的"dispatch"隊列。

軟件staging隊列(struct blk_mq_ctx)是依CPU硬件情況而分配的,每個CPU分配一個,或每個NUMA節點分配一個。當塊層的"plugging"機制拔開"塞子"時(blk_mq_flush_plug_list()),request請求在一個spinlock的保護下被添加到隊列上,鎖競爭應該很少。multi-queue的隊列可以選擇由某一個multi-queue調度器來管理, 現在有三種multi-queue調度器:bfq, kyber和mq-deadline.

硬件dispatch隊列是基于目標硬件塊設備進行分配的,所以有可能只有一個,也有可能多達2048個隊列 (或與硬件支持的中斷源個數一樣)。"request層"為每一個硬件隊列(或"硬件上下文")分配一個數據結構struct blk_mq_hw_ctx,維護著一個CPU和隊列之間的映射表,而隊列本身就是為底層驅動而服務的。“request 層”時不時地把硬件隊列中的請求傳遞給底層驅動。接下來,請求就全由驅動處理了,通常情況下,又會很快按照接收的順序交給硬件。

與single-queue相比有另一個重要區別,multi-queue使用的request結構體都是預分配的。每個request結構體都關聯著一個不同tag number,這個tag number會隨著請求傳遞到硬件,再隨著請求完成通知傳遞回來。早點為一個請求分配tag number,在時機到來的時候,request 層可隨時向底層發送請求。

single-queue只需要一個request_fn()就可以了,但是multi-queue需要底層驅動提供一個struct blk_mq_ops結構體,包含了多達11個函數。其中,最核心的一個函數是queue_rq(),其它的函數實現了超時,請求完成輪詢,請求初始化,等類似操作。

一旦請求就緒,并且調度器不想再把請求保持在隊列上來排序或擴展,調度器就會調用queue_rq()函數。single-queue把收集請求的責任交給了驅動層,與之不同,multi-queue卻把這個責任交給了"request層"。queue_rq()有個參數代表的是硬件上下文,通常會把請求放在內部FIFO隊列上,也有可能會直接處理。queue_rq()可以拒絕一個請求,然后返回BLK_STS_RESOURCE,讓請求繼續在staging隊列上等待。除了BLK_STS_RESOURCE和BLK_STS_OK,其它返回值都被視為IO錯誤。

多隊列調度

multi-queue不是必須要配置一個調度器,如果不指定的話,那么就會用類似單隊列中的“noop”調度器。連續的bio會被合并到一個請求,而不連續的bio各成為一個獨立的請求。這些請求以FIFO的順序被放到staging隊列中,盡管有多個submission隊列,默認的調度器會嘗試直接提交新請求,僅僅在收到BLK_STS_RESOURCE返回值時才會使用staging隊列。當塊設備上的plugging機制拔開“塞子”時,調度器會調用blk_mq_run_hw_queue()或blk_mq_delay_run_hw_queue()把軟件隊列傳遞給驅動層處理。

可插拔的multi-queue調度器有22個入口點,其中有兩個函數,一個是insert_requests()把一組請求添加到軟件staging隊列中,另一個是dispatch_request()會選擇一個請求然后傳遞給硬件設備。如果沒有實現insert_request()函數,請求就會被簡單的插入到列表末尾。如果沒有提供dispatch_request()函數,就會從staging隊列里取下請求,然后以任意順序傳遞到相應的硬件隊列。This "collect everything" step is the main point of cross-CPU locking and can hurt performance, so it is best if a device with a single hardware queue accepts all the requests it is given.[最后一句我理解不到那個點,大致理解是說staging隊列有多個,硬件隊列只有一個的情況,那么多個軟件隊列上的請求最終要收集到這個硬件隊列上來,那么必然要加鎖,會比較影響性能]

mq-deadline調度器跟單隊列的deadline調度器發揮的功能很相似。它有個insert_request()函數,不會使用多個staging隊列,而是把請求放到兩個全局的基于時間的隊列中 - 一個放讀請求,一個放寫請求,先嘗試把該新請求與已經存在的請求合并,如果合并不了,則把這個新請求放到隊列尾部。dispatch_request()函數會從這些隊列中返回第一個請求:基于時間的隊列,基于請求批大小,以及避免寫饑餓的隊列。

bfq調度器,即Budget Fair Queueing, 一定程度上是借鑒cfq實現的。內核里有介紹bfq的文檔(Documentation/block/bfq-iosched.txt),幾年前lwn上有篇講bfq的文章(https://lwn.net/Articles/601799/),后來又出了一篇文章(https://lwn.net/Articles/709202/),跟進了bfq被吸納進multi-queue的情況。bfq有一點比較像mq-deadline,沒有使用多個per-CPU staging隊列。bfq有多個隊列,每一個隊列由一把自旋鎖保護。

與mq-deadline和bfq不一樣,kyber IO調度器,在這篇文章中(https://lwn.net/Articles/720675/)有簡單介紹,它使用了per-CPU的staging隊列,也沒有實現自己的insert_request()函數,而用的是默認行為。dispatch_request()函數為每一個硬件上下文都維護著各種內部隊列,如果這些隊列是空的,它就會從給定的硬件上下文所對應的所有staging隊列來收集請求,然后在內部將請求做個分布,如果硬件隊列不是空的,它就直接從對應的內部隊列里下發請求。關于kyber調度器的這幾個方面內核沒有相應的注釋和文檔:策略解釋,請求分布,以及處理順序。

單隊列要壽終正寢了?

在塊層中,并存兩套不同的隊列系統,兩套調度器和兩套不同的驅動接口很明顯是不理想的。我們可以期待single-queue的代碼很快被移除掉嗎?multi-queue到底又有多好呢?

不幸的是,這些問題的回答需要在不同的硬件上做很多測試,而筆者只是個做軟件的。從軟件的角度來說,很清楚,在支持多隊列并行提交請求的硬件上,multi-queue應該能帶來很多好處。當用在單隊列硬件上時,multi-queue至少應該和單隊列旗鼓相當,但是不要期望一夜之間就能達到旗鼓相當的水平,因為任何新事物都不是完美的。

說到不完美,舉個例子,最近一個補丁集進了Linux 4.15。這些補丁對mq-deadline調度器做了一些修改來解決redhat在內部存儲系統測試中發現的性能問題。假如切換到multi-queue, 存儲領域的各家廠商很有可能在測試中發現類似的性能回退。在未來幾個月里,這些被發現的問題很有希望得到修復。2017可能不會成為multi-queue-ony Linux的一年,但是這樣的一天不會太遠。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • cpu
    cpu
    +關注

    關注

    68

    文章

    10854

    瀏覽量

    211587
  • Linux
    +關注

    關注

    87

    文章

    11292

    瀏覽量

    209331
  • 隊列
    +關注

    關注

    1

    文章

    46

    瀏覽量

    10893

原文標題:塊層介紹 第二篇: request層

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    c語言深度剖析

    c語言深度剖析
    發表于 04-02 09:12

    【資料分享】C語言深度剖析

    C語言深度剖析
    發表于 10-16 15:16

    C語言深度剖析

    C語言深度剖析
    發表于 08-25 09:08

    C語言深度剖析

    C語言深度剖析[完整版].pdfC語言深度剖析[完整版].pdf (919.58 KB )
    發表于 03-19 05:11

    AUTOSAR基礎軟件是由哪些部分組成

    基礎軟件主要是用于提供基礎軟件服務,包括標準化的系統功能以及功能接口,并且由一系列的基礎服務軟件組成,包括系統服務、內存服務、通信服務等。一、基礎軟件模塊按照類型可以分為驅動模塊、接口模塊、處理模塊以及管理器。驅動模塊:包含
    發表于 02-17 08:00

    EPA功能及用戶技術研究

    EPA功能及用戶技術研究 Research on EPA Functional Block and User Layer Technology
    發表于 03-17 09:14 ?16次下載

    基于組成“bio”的詳細解析

    在深挖bio之前,很有必要先了解點背景知識,看看之上的天地。這里“之上”意思是靠近用戶空間(the top),遠離硬件(the bottom),包括所有使用
    的頭像 發表于 02-03 16:23 ?4116次閱讀
    基于<b class='flag-5'>塊</b><b class='flag-5'>層</b>的<b class='flag-5'>組成</b>“bio<b class='flag-5'>層</b>”的詳細解析

    Linux通用之deadline簡介及通用調度器框架

    接口很簡單,首先判斷request的IO方向,根據IO方向通過deadline_add_rq_rb將request添加到讀/寫紅黑樹中,request在紅黑樹中以請求的起始扇區作為節點的key value,可以直接認為紅黑樹中的
    的頭像 發表于 04-29 16:40 ?5697次閱讀
    Linux通用<b class='flag-5'>塊</b><b class='flag-5'>層</b>之deadline簡介及通用<b class='flag-5'>塊</b><b class='flag-5'>層</b>調度器框架

    硬化深度檢測的技術規定以及檢測方法

    一、范圍 1、滲碳和碳氮共滲有效化深度大于0.3mm的零件 2、經熱處理至最終硬度值后,離表面二倍有效硬化處硬度小于450hv的零件 不能滿足上述條件的鋼件,經協議可另行確定有效硬化
    發表于 06-29 15:24 ?1.3w次閱讀

    電纜外護的結構組成是怎樣的,它的作用是什么

    外護是包覆在電纜護套(內護)外面的保護覆蓋層,主要起機械加強和防腐蝕的作用。常用電纜有內護為金屬護的外護和內護
    發表于 07-27 09:48 ?4752次閱讀

    pcb板各層畫什么?絲印 機械 阻焊 助焊 信號 鉆孔數據作用詳解

    pcb板在畫圖的時候大家都知道,電路板會有很多層,那么首先我們要知道都是PCB板子的哪些。通過對PCB的各個圖層的詳細解答,希望能夠對大家進一步了解一PCB的組成與設計有幫助。下面我們多以
    的頭像 發表于 08-17 11:25 ?2.1w次閱讀

    如何去理解CNN卷積與池化計算?

    概述 深度學習中CNN網絡是核心,對CNN網絡來說卷積與池化的計算至關重要,不同的步長、填充方式、卷積核大小、
    的頭像 發表于 04-06 15:13 ?2753次閱讀
    如何去理解CNN卷積<b class='flag-5'>層</b>與池化<b class='flag-5'>層</b>計算?

    Linux架構介紹 IO流程與IO調度器詳解

    之前一直跟大家聊文件系統,文件系統提供一文件到物理的映射轉換。這邏輯可能非常復雜,依賴于文件系統的實現。今天則跟大家聊聊
    的頭像 發表于 05-16 12:12 ?2386次閱讀

    PCB阻焊與助焊的區別

    標準的印刷電路板 (PCB) 通常需要兩種不同類型的,即“罩 (mask)”。
    發表于 06-01 16:58 ?2864次閱讀
    PCB阻焊<b class='flag-5'>層</b>與助焊<b class='flag-5'>層</b>的區別

    神經網絡中的卷積、池化與全連接

    深度學習中,卷積神經網絡(Convolutional Neural Network, CNN)是一種特別適用于處理圖像數據的神經網絡結構。它通過卷積、池化和全連接的組合,實現了
    的頭像 發表于 07-11 14:18 ?5450次閱讀
    主站蜘蛛池模板: 曰本少妇高潮久久久久久| 欧美一区二区日韩一区二区| 国产51麻豆二区精品AV视频| 91精品国产色综合久久| 一边亲着一面膜下奶韩剧免费 | 国产电影一区二区三区| 被黑人做的白浆直流| sm主人调教揉花蒂H| DASD-700美谷朱里| H厨房灌草莓| voyeurhit农村夫妻偷拍| black大战chinese周晓琳| www黄色大片| 趁老师睡着吃她的奶水| 成人手机在线| 国产高清亚洲日韩字幕一区| 国产69精品久久久久乱码韩国| 成人片免费看| 国产精品久久久久久熟妇吹潮软件 | 老牛天天晚上夜噜噜噜| 久久免费特黄毛片| 美女与男人对肌免费网站| 内射气质御姐视频在线播放| 男女车车的车车网站W98免费 | 国产69精品久久久熟女| 国产成人在线网站| 国产一卡 二卡三卡四卡无卡乱码视频 | 中文在线观看永久免费| 70岁妇女牲交色牲片| tube日本护士| 国产成人在线视频播放| 精品久久伊人| 免费毛片在线播放| 色悠悠电影网| 亚洲精品第一页| 3344永久在线观看视频免费| qq快播电影网| 国产免费播放一区二区三区 | 东北足疗店妓女在线观看| 国产精品久久免费视频| 精品免费久久久久久成人影院|