fio是如何運行的?

来源:https://www.cnblogs.com/mmmmmmmelody/archive/2019/02/23/10424958.html
-Advertisement-
Play Games

本文主要介紹fio是如何運行的,並且以單線程、單job為例 fio的入口在fio.c中的main函數,下麵列出了main函數,此處只出示了一些調用的關鍵函數 在main函數中主要調用了兩個關鍵函數,parse_options,顧名思義,就是分析options,也就是fio的參數,而fio_backe ...


本文主要介紹fio是如何運行的,並且以單線程、單job為例

fio的入口在fio.c中的main函數,下麵列出了main函數,此處只出示了一些調用的關鍵函數

1 int main(int argc, char *argv[], char *envp[])
2 {
3     parse_options(argc, argv);
4     fio_backend();
5 }

在main函數中主要調用了兩個關鍵函數,parse_options,顧名思義,就是分析options,也就是fio的參數,而fio_backend()函數則是fio進程的入口

fio_backend()函數在backend.c文件中

1 int fio_backend(void)
2 {
3     ......
4     run_threads();
5     ......
6 }

在fio_backend()函數中,初始化一些數據結構之後,調用了run_threads()(backend.c)函數,該函數是fio用來創建譬如I/O, verify線程等。

 

 1 /*
 2  * Main function for kicking off and reaping jobs, as needed.
 3  */
 4 static void run_threads(void)
 5 {
 6     ......
 7     todo = thread_number;
 8     ......
 9     while (todo) {
10         if (td->o.use_thread) {
11             ......
12             ret = pthread_create(&td->thread, NULL,thread_main, td);
13             ret = pthread_detach(td->thread);
14             ......
15     }
16     ......
17 }

在這個函數中,創建了thread_main線程(backend.c),這個線程功能是,生成I/O,發送並完成I/O,記錄數據等。

 1 /*
 2  * Entry point for the thread based jobs. The process based jobs end up
 3  * here as well, after a little setup.
 4  */
 5 static void *thread_main(void *data)
 6 {
 7     ........
 8      /*
 9       * May alter parameters that init_io_u() will use, so we need to
10       * do this first.
11       * 下麵兩個函數的主要功能是生成讀寫的參數,offset,len
12        */
13     if (init_iolog(td))
14         goto err;
15 
16     if (init_io_u(td))
17         goto err;
18     ......
19     while (keep_running(td)) {
20         do_io(td);
21         do_verify(td, verify_bytes);//如果需要verification的話
22     }
23 }

如果不考慮verify的話,下麵主要看do_io(backend.c)函數。

 1 /*
 2  * Main IO worker function. It retrieves io_u's to process and queues
 3  * and reaps them, checking for rate and errors along the way.
 4  *
 5  * Returns number of bytes written and trimmed.
 6  */
 7 static uint64_t do_io(struct thread_data *td)
 8 {
 9     ......
10     //下麵是do_io的主迴圈,判斷條件是,io_log里有生成的pos信息,而且已經iuuse的數據小於總數據,
11     while ((td->o.read_iolog_file && !flist_empty(&td->io_log_list)) ||
12               (!flist_empty(&td->trim_list)) || !io_bytes_exceeded(td) ||
13               td->o.time_based) {
14         ......
15         io_u = get_io_u(td);// io_u,是一個io unit,是根據參數生成的io unit
16         ......
17         ret = td_io_queue(td, io_u); //將io_u提交到隊列中
18         switch (ret) {
19         case FIO_Q_COMPLETED: //處理錯誤,以及同步的操作
20         ......
21         case FIO_Q_QUEUED://成功入隊
22             bytes_issued += io_u->xfer_buflen;
23         case FIO_Q_BUSY: //隊伍滿了,重新入隊
24         .......
25     /*
26          * See if we need to complete some commands. Note that we
27          * can get BUSY even without IO queued, if the system is
28          * resource starved.
29          */
30         full = queue_full(td) || (ret == FIO_Q_BUSY && td->cur_depth);
31         if (full || !td->o.iodepth_batch_complete) {
32         min_evts = min(td->o.iodepth_batch_complete,td->cur_depth);
33         /*
34          * if the queue is full, we MUST reap at least 1 event
35          */
36         if (full && !min_evts)
37             min_evts = 1;
38         do {
39             ret = io_u_queued_complete(td, min_evts, bytes_done);
40         } while (full && (td->cur_depth > td->o.iodepth_low));
41     }
42 }

上面do_io函數的關鍵入隊函數td_io_queue(ioengines.c)

 1 int td_io_queue(struct thread_data *td, struct io_u *io_u)
 2 {
 3     ......
 4     ret = td->io_ops->queue(td, io_u);
 5     ......
 6     else if (ret == FIO_Q_QUEUED) {
 7         int r;
 8         if (ddir_rw(io_u->ddir)) {
 9             td->io_u_queued++;
10             td->ts.total_io_u[io_u->ddir]++;
11         }
12          if (td->io_u_queued >= td->o.iodepth_batch) {
13              r = td_io_commit(td);
14              if (r < 0)
15                  return r;
16          }
17     }
18 }
19 int td_io_commit(struct thread_data *td)
20 {
21     ......
22     int ret;
23     if (td->io_ops->commit) {
24         ret = td->io_ops->commit(td);
25     }
26     ......
27     return 0;
28 }

對於td->iops,它是在各個engines中定義了,以libaio(/engines/libaio.c)為例,調用的函數就是相應engines里對應的函數

 1 static struct ioengine_ops ioengine = {
 2     .name            = "libaio",
 3     .version        = FIO_IOOPS_VERSION,
 4     .init            = fio_libaio_init,
 5     .prep            = fio_libaio_prep,
 6     .queue            = fio_libaio_queue,
 7     .commit            = fio_libaio_commit,
 8     .cancel            = fio_libaio_cancel,
 9     .getevents        = fio_libaio_getevents,
10     .event            = fio_libaio_event,
11     .cleanup        = fio_libaio_cleanup,
12     .open_file        = generic_open_file,
13     .close_file        = generic_close_file,
14     .get_file_size        = generic_get_file_size,
15     .options        = options,
16     .option_struct_size    = sizeof(struct libaio_options),
17 };

對於reap流程里的io_u_queued_complete(io_u.c)函數

 1 /*
 2  * Called to complete min_events number of io for the async engines.
 3  */
 4 int io_u_queued_complete(struct thread_data *td, int min_evts,
 5              uint64_t *bytes)
 6 {
 7     ......
 8 
 9     ret = td_io_getevents(td, min_evts, td->o.iodepth_batch_complete, tvp);
10     ......
11 }
12 
13 int td_io_getevents(struct thread_data *td, unsigned int min, unsigned int max,
14             struct timespec *t)
15 {
16     int r = 0;
17 
18     if (min > 0 && td->io_ops->commit) {
19         r = td->io_ops->commit(td);
20         if (r < 0)
21             goto out;
22     }
23     if (max > td->cur_depth)
24         max = td->cur_depth;
25     if (min > max)
26         max = min;
27 
28     r = 0;
29     if (max && td->io_ops->getevents)
30         r = td->io_ops->getevents(td, min, max, t);
31 out:
32     ......
33     return r;
34 }    
這裡調用的getevents也是各個engines里定義的函數



您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在ES6中有了繼承,使用extends關鍵字就能實現。但這裡講的講的不是這種,而是ES6之前的幾種實現繼承的方式。 (一)原型繼承 ECMAScript中將原型鏈作為實現繼承的主要方法。其基本思想是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法。 例如: (二)借用構造函數 在解決原型中包含引 ...
  • 如今,Fetch API已經成為現在瀏覽器非同步網路請求的標準方法,但Fetch也是有弊端的,比如: Fetch還沒有方法終止一個請求,而且Fetch無法檢測上傳進度 現在我們可以通過 AbortController 和 AbortSignal 來終止,代碼如下: const controller = ...
  • JavaScript 原生提供兩個 Base64 相關的方法: btoa():任意值轉為 Base64 編碼 atob():Base64 編碼轉為原來的值 encodeURIComponent() 該方法會轉碼除了語義字元之外的所有字元,即元字元也會被轉碼。 decodeURIComponent() ...
  • 首先,不論是在Windows、Linux還是Mac上,Webassembly的編譯都是主要依賴於Emscripten SDK這個工具的。但是,在這裡必須要吐槽一下,不論是WebAssembly官網、WebAssembly中文網還是Emscriptem官網安裝文檔上給出的安裝方式基本都是這樣的(中文網 ...
  • 本文是抽屜組件在PC端滾動滑鼠中鍵、手機端滑動時,滾動數據列表實現方法,沒有使用iscroll等第三方插件,支持火狐,谷歌,IE等瀏覽器。演示在:www.jgui.com Github地址:https://github.com/zhaogaojian/JGUI覺得好的給個star,謝謝! 源碼未壓縮 ...
  • 一、服務註冊中心介紹 分散式服務框架部署在多台不同的機器上。例如服務A是訂單相關的處理服務,服務B是訂單的客戶的相關信息服務。此時有個需求需要在服務A中獲取訂單客戶的信息。如下圖: 此時就面臨以下幾個問題: 1、集群A中的服務調用者如何發現集群B中的服務提供者。 2、集群A中的服務調用者如何選擇集群 ...
  • 一個成熟的大型分散式系統,並不是在其開始時,就設計為這樣,而是在之後的不斷優化,迭代而不斷的進化成熟的。 在一個系統剛開始運行時,可能用戶數,業務處理等都還比較簡單,因此由一臺伺服器就能支撐起其正常的業務處理。其系統架構模型可能如下所示: 1,單應用架構 其應用服務和資料庫服務,都部署在同一臺伺服器 ...
  • 前言:這段時間項目組正在加班加點的進行基於現有單體應用的微服務架構改造。微服務是一種架構概念,這個概念是2012年出現的,作為加快Web和移動應用程式開發進程的一種方法,2014年開始受到各方的關註,而2015年,可以說是微服務的元年;越來越多的論壇、社區、blog以及互聯網行業巨頭開始對微服務進行 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...