Net DIM - 通用網路動態中斷調節

作者:

Tal Gilboa <talgi@mellanox.com>

假設

本文件假設讀者具備網路驅動程式和通用中斷調節的基礎知識。

介紹

動態中斷調節(DIM)(在網路中)指的是更改通道的中斷調節配置,以最佳化資料包處理。該機制包括一種演算法,該演算法決定是否以及如何更改通道的調節引數,通常是透過對從系統取樣的執行時資料執行分析來實現的。Net DIM就是這樣一種機制。在演算法的每次迭代中,它都會分析給定的資料樣本,將其與先前的樣本進行比較,如果需要,它可以決定更改某些中斷調節配置欄位。資料樣本由資料頻寬、資料包數量和事件數量組成。還測量了樣本之間的時間。Net DIM比較當前資料和先前資料,並返回調整後的中斷調節配置物件。在某些情況下,該演算法可能會決定不進行任何更改。配置欄位是事件之間允許的最小持續時間(微秒)和每個事件所需的最大資料包數量。Net DIM演算法將增加頻寬的重要性置於降低中斷速率之上。

Net DIM演算法

Net DIM演算法的每次迭代都遵循以下步驟

  1. 計算新的資料樣本。

  2. 將其與先前的樣本進行比較。

  3. 做出決定 - 建議中斷調節配置欄位。

  4. 應用計劃的工作函式,該函式應用建議的配置。

前兩個步驟很簡單,新資料和先前資料都由註冊到Net DIM的驅動程式提供。先前資料是提供給先前迭代的新資料。比較步驟檢查新資料和先前資料之間的差異,並決定最後一步的結果。如果頻寬增加,則結果為“更好”,如果頻寬減少,則結果為“更差”。如果頻寬沒有變化,則以類似的方式比較資料包速率 - 增加 == “更好”,減少 == “更差”。如果資料包速率也沒有變化,則比較中斷速率。在這裡,該演算法嘗試最佳化為較低的中斷速率,因此中斷速率的增加被認為是“更差”,而減少被認為是“更好”。步驟2對避免錯誤結果進行了最佳化:僅當樣本之間的差異大於某個百分比時,才將其視為有效。此外,由於Net DIM本身不測量任何東西,因此它假設驅動程式提供的資料是有效的。

步驟3根據步驟2的結果和演算法的內部狀態決定建議的配置。這些狀態反映了演算法的“方向”:是向左(減少調節),向右(增加調節)還是靜止不動。另一個最佳化是,如果多次做出靜止不動的決定,則演算法迭代之間的間隔會增加,以減少計算開銷。此外,在“停靠”在最左或最右的決策之一後,該演算法可能會決定透過朝另一個方向邁出一步來驗證此決策。這樣做是為了避免陷入“深度睡眠”場景。做出決定後,將從預定義的配置檔案中選擇中斷調節配置。

最後一步是通知註冊的驅動程式,它應該應用建議的配置。這是透過排程一個工作函式來完成的,該函式由Net DIM API定義並由註冊的驅動程式提供。

如您所見,Net DIM本身不會主動與系統互動。如果向其提供了錯誤的資料,它將難以做出正確的決策,並且如果工作函式未應用建議的配置,它將毫無用處。但是,這確實允許註冊的驅動程式有一定的操作空間,因為它可能會提供部分資料或在某些情況下忽略演算法建議。

將網路設備註冊到DIM

Net DIM API公開了主要函式net_dim()。此函式是Net DIM演算法的入口點,並且每次驅動程式想要檢查是否應該更改中斷調節引數時都必須呼叫。驅動程式應提供兩個資料結構:struct dimstruct dim_samplestruct dim描述了DIM針對特定物件(RX佇列、TX佇列、其他佇列等)的狀態。這包括當前選擇的配置檔案、先前的資料樣本、驅動程式提供的回撥函式等。struct dim_sample描述了一個數據樣本,該樣本將與struct dim中儲存的資料樣本進行比較,以決定演算法的下一步。該樣本應包括驅動程式測量的位元組數、資料包數和中斷數。

為了從網路驅動程式中使用Net DIM,驅動程式需要呼叫主要的net_dim()函式。推薦的方法是在每次中斷時呼叫net_dim()。由於Net DIM具有內建的調節功能,並且它可能會在某些情況下決定跳過迭代,因此無需對net_dim()呼叫進行調節。如上所述,驅動程式需要向net_dim()函式呼叫提供struct dim型別的物件。建議每個使用Net DIM的實體都將struct dim作為其資料結構的一部分,並將其用作主要的Net DIM API物件。struct dim_sample應儲存最新的位元組數、資料包數和中斷數。無需執行任何計算,只需包含原始資料。

net_dim()呼叫本身不返回任何內容。相反,Net DIM依賴於驅動程式來提供回撥函式,當演算法決定更改中斷調節引數時會呼叫該函式。此回撥將被排程並在單獨的執行緒中執行,以避免增加資料流的開銷。完成工作後,需要將Net DIM演算法設定為正確的狀態,以便進行下一次迭代。

示例

以下程式碼演示瞭如何將驅動程式註冊到Net DIM。實際用法並不完整,但它應該清楚地說明了用法的輪廓。

#include <linux/dim.h>

/* Callback for net DIM to schedule on a decision to change moderation */
void my_driver_do_dim_work(struct work_struct *work)
{
      /* Get struct dim from struct work_struct */
      struct dim *dim = container_of(work, struct dim,
                                     work);
      /* Do interrupt moderation related stuff */
      ...

      /* Signal net DIM work is done and it should move to next iteration */
      dim->state = DIM_START_MEASURE;
}

/* My driver's interrupt handler */
int my_driver_handle_interrupt(struct my_driver_entity *my_entity, ...)
{
      ...
      /* A struct to hold current measured data */
      struct dim_sample dim_sample;
      ...
      /* Initiate data sample struct with current data */
      dim_update_sample(my_entity->events,
                        my_entity->packets,
                        my_entity->bytes,
                        &dim_sample);
      /* Call net DIM */
      net_dim(&my_entity->dim, &dim_sample);
      ...
}

/* My entity's initialization function (my_entity was already allocated) */
int my_driver_init_my_entity(struct my_driver_entity *my_entity, ...)
{
      ...
      /* Initiate struct work_struct with my driver's callback function */
      INIT_WORK(&my_entity->dim.work, my_driver_do_dim_work);
      ...
}

調優DIM

Net DIM服務於各種網路裝置,並提供出色的加速優勢。然而,已經觀察到DIM的某些預設配置可能無法與網路裝置的各種規格無縫對齊,並且這種差異已被確定為啟用DIM的網路裝置效能欠佳的一個因素,這與配置檔案中的不匹配有關。

為了解決這個問題,Net DIM引入了每個裝置的控制來修改和訪問裝置的rx-profiletx-profile引數:假設目標網路裝置名為ethx,並且ethx僅宣告支援RX配置檔案設定,並且支援修改usec欄位和pkts欄位(請參閱資料結構:struct dim_cq_moder)。

您可以使用ethtool來修改當前的RX DIM配置檔案,其中所有值為64

$ ethtool -C ethx rx-profile 1,1,n_2,2,n_3,n,n_n,4,n_n,n,n

n表示不修改此欄位,_分隔配置檔案陣列的結構元素。

使用以下命令查詢當前配置檔案

$ ethtool -c ethx
...
rx-profile:
{.usec =   1, .pkts =   1, .comps = n/a,},
{.usec =   2, .pkts =   2, .comps = n/a,},
{.usec =   3, .pkts =  64, .comps = n/a,},
{.usec =  64, .pkts =   4, .comps = n/a,},
{.usec =  64, .pkts =  64, .comps = n/a,}
tx-profile:   n/a

如果網路裝置不支援DIM配置檔案的特定欄位,則將顯示相應的n/a。如果正在修改n/a欄位,則將報告錯誤訊息。

動態中斷調節(DIM)庫API

struct dim_cq_moder

CQ調節值的結構。用於DIM及其使用者之間的通訊。

定義:

struct dim_cq_moder {
    u16 usec;
    u16 pkts;
    u16 comps;
    u8 cq_period_mode;
    struct rcu_head rcu;
};

成員

usec

CQ計時器建議(由DIM提供)

pkts

CQ資料包計數器建議(由DIM提供)

comps

完成計數器

cq_period_mode

CQ週期計數模式(來自CQE/EQE)

rcu

用於非同步kfree_rcu

struct dim_irq_moder

用於irq調節資訊的結構。用於收集irq調節相關資訊。

定義:

struct dim_irq_moder {
    u8 profile_flags;
    u8 coal_flags;
    u8 dim_rx_mode;
    u8 dim_tx_mode;
    struct dim_cq_moder __rcu *rx_profile;
    struct dim_cq_moder __rcu *tx_profile;
    void (*rx_dim_work)(struct work_struct *work);
    void (*tx_dim_work)(struct work_struct *work);
};

成員

profile_flags

DIM_PROFILE_*

coal_flags

Rx和Tx的DIM_COALESCE_*

dim_rx_mode

Rx DIM週期計數模式:CQE或EQE

dim_tx_mode

Tx DIM週期計數模式:CQE或EQE

rx_profile

Rx的DIM配置檔案列表

tx_profile

Tx的DIM配置檔案列表

rx_dim_work

net_dim()排程的Rx DIM工作程式

tx_dim_work

net_dim()排程的Tx DIM工作程式

struct dim_sample

DIM樣本資料的結構。用於DIM及其使用者之間的通訊。

定義:

struct dim_sample {
    ktime_t time;
    u32 pkt_ctr;
    u32 byte_ctr;
    u16 event_ctr;
    u32 comp_ctr;
};

成員

time

樣本時間戳

pkt_ctr

資料包數量

byte_ctr

位元組數

event_ctr

事件數

comp_ctr

當前完成計數器

struct dim_stats

DIM統計資訊的結構。用於儲存當前測量的速率。

定義:

struct dim_stats {
    int ppms;
    int bpms;
    int epms;
    int cpms;
    int cpe_ratio;
};

成員

ppms

每毫秒的資料包數

bpms

每毫秒的位元組數

epms

每毫秒的事件數

cpms

每毫秒的完成數

cpe_ratio

完成數與事件數的比率

struct dim

動態中斷調節(DIM)的主要結構。用於儲存有關特定DIM例項的所有資訊。

定義:

struct dim {
    u8 state;
    struct dim_stats prev_stats;
    struct dim_sample start_sample;
    struct dim_sample measuring_sample;
    struct work_struct work;
    void *priv;
    u8 profile_ix;
    u8 mode;
    u8 tune_state;
    u8 steps_right;
    u8 steps_left;
    u8 tired;
};

成員

state

演算法狀態(見下文)

prev_stats

來自先前迭代的測量速率(用於比較)

start_sample

當前迭代開始時取樣的資料

measuring_sample

用於更新當前事件的dim_sample

work

需要在操作時執行的工作

priv

指向dim的struct的指標

profile_ix

當前調節配置檔案

mode

CQ週期計數模式

tune_state

演算法調優狀態(見下文)

steps_right

朝著更高調節級別邁出的步數

steps_left

朝著更低調節級別邁出的步數

tired

停靠深度計數器

enum dim_cq_period_mode

CQ週期計數模式

常量

DIM_CQ_PERIOD_MODE_START_FROM_EQE

從EQE開始計數

DIM_CQ_PERIOD_MODE_START_FROM_CQE

從CQE開始計數(意味著計時器重置)

DIM_CQ_PERIOD_NUM_MODES

模式數量

enum dim_state

DIM演算法狀態

常量

DIM_START_MEASURE

這是第一次迭代(也是在應用新配置檔案之後)

DIM_MEASURE_IN_PROGRESS

演算法已經在進行中 - 檢查是否需要執行操作

DIM_APPLY_NEW_PROFILE

DIM使用者當前正在應用配置檔案 - 無需測量

描述

這些將確定演算法是否處於啟動迭代的有效狀態。

enum dim_tune_state

DIM演算法調優狀態

常量

DIM_PARKING_ON_TOP

演算法找到一個區域性最高點 - 在出現顯著差異時退出

DIM_PARKING_TIRED

演算法找到一個深度最高點 - 如果tired > 0,則不要退出

DIM_GOING_RIGHT

演算法當前正在嘗試更高的調節級別

DIM_GOING_LEFT

演算法當前正在嘗試更低的調節級別

描述

這些將確定演算法應執行哪個操作。

enum dim_stats_state

DIM演算法統計資訊狀態

常量

DIM_STATS_WORSE

當前迭代顯示比以前更差的效能

DIM_STATS_SAME

當前迭代顯示與以前相同的效能

DIM_STATS_BETTER

當前迭代顯示比以前更好的效能

描述

這些將確定當前迭代的判定結果。

enum dim_step_result

DIM演算法步驟結果

常量

DIM_STEPPED

執行了常規步驟

DIM_TOO_TIRED

多次完成了相同型別的步驟 - 應轉到tired parking

DIM_ON_EDGE

已步進到最左/最右的配置檔案

描述

這些描述了一個步驟的結果。

int net_dim_init_irq_moder(struct net_device *dev, u8 profile_flags, u8 coal_flags, u8 rx_mode, u8 tx_mode, void (*rx_dim_work)(struct work_struct *work), void (*tx_dim_work)(struct work_struct *work))

收集資訊以初始化irq調節

引數

struct net_device *dev

目標網路裝置

u8 profile_flags

Rx或Tx配置檔案修改能力

u8 coal_flags

irq調節引數標誌

u8 rx_mode

Rx的CQ週期模式

u8 tx_mode

Tx的CQ週期模式

void (*rx_dim_work)(struct work_struct *work)

在dim決策後呼叫的Rx工作程式

void (*tx_dim_work)(struct work_struct *work)

在dim決策後呼叫的Tx工作程式

返回

成功時為0,否則為負錯誤程式碼。

void net_dim_free_irq_moder(struct net_device *dev)

釋放irq調節的欄位

引數

struct net_device *dev

目標網路裝置

void net_dim_setting(struct net_device *dev, struct dim *dim, bool is_tx)

初始化DIM的cq模式並排程工作程式

引數

struct net_device *dev

目標網路裝置

struct dim *dim

DIM上下文

bool is_tx

true表示tx方向,false表示rx方向

void net_dim_work_cancel(struct dim *dim)

同步取消dim的工作程式

引數

struct dim *dim

DIM上下文

struct dim_cq_moder net_dim_get_rx_irq_moder(struct net_device *dev, struct dim *dim)

根據profile_ix獲取DIM rx結果

引數

struct net_device *dev

目標網路裝置

struct dim *dim

DIM上下文

返回

DIM irq調節

struct dim_cq_moder net_dim_get_tx_irq_moder(struct net_device *dev, struct dim *dim)

根據profile_ix獲取DIM tx結果

引數

struct net_device *dev

目標網路裝置

struct dim *dim

DIM上下文

返回

DIM irq調節

void net_dim_set_rx_mode(struct net_device *dev, u8 rx_mode)

設定DIM rx cq模式

引數

struct net_device *dev

目標網路裝置

u8 rx_mode

目標rx cq模式

void net_dim_set_tx_mode(struct net_device *dev, u8 tx_mode)

設定DIM tx cq模式

引數

struct net_device *dev

目標網路裝置

u8 tx_mode

目標tx cq模式

bool dim_on_top(struct dim *dim)

檢查當前狀態是否是停止的好地方(最高位置)

引數

struct dim *dim

DIM上下文

描述

檢查當前配置檔案是否是停靠的好地方。這將導致降低DIM檢查頻率,因為我們假設除非流量模式發生變化,否則我們不應該更改配置檔案。

void dim_turn(struct dim *dim)

更改配置檔案更改方向

引數

struct dim *dim

DIM上下文

描述

如果我們向右走,則向左走,反之亦然。如果當前停靠,則不執行任何操作。

void dim_park_on_top(struct dim *dim)

在最高位置進入停靠狀態

引數

struct dim *dim

DIM上下文

描述

進入停靠狀態。清除所有移動歷史記錄。

void dim_park_tired(struct dim *dim)

進入疲勞停靠狀態

引數

struct dim *dim

DIM上下文

描述

進入停靠狀態。清除所有移動歷史記錄,並導致降低DIM檢查頻率。

bool dim_calc_stats(const struct dim_sample *start, const struct dim_sample *end, struct dim_stats *curr_stats)

計算兩個樣本之間的差

引數

const struct dim_sample *start

開始樣本

const struct dim_sample *end

結束樣本

struct dim_stats *curr_stats

樣本之間的增量

描述

計算兩個樣本之間的增量(以資料速率表示)。考慮計數器迴繞。返回的布林值指示curr_stats是否可靠。

void dim_update_sample(u16 event_ctr, u64 packets, u64 bytes, struct dim_sample *s)

使用給定值設定樣本的欄位

引數

u16 event_ctr

要設定的事件數

u64 packets

要設定的資料包數

u64 bytes

要設定的位元組數

struct dim_sample *s

DIM樣本

void dim_update_sample_with_comps(u16 event_ctr, u64 packets, u64 bytes, u64 comps, struct dim_sample *s)

使用給定值(包括完成引數)設定樣本的欄位

引數

u16 event_ctr

要設定的事件數

u64 packets

要設定的資料包數

u64 bytes

要設定的位元組數

u64 comps

要設定的完成數

struct dim_sample *s

DIM樣本

struct dim_cq_moder net_dim_get_rx_moderation(u8 cq_period_mode, int ix)

為給定的RX配置檔案提供一個CQ節制物件

引數

u8 cq_period_mode

CQ週期模式

int ix

配置檔案索引

struct dim_cq_moder net_dim_get_def_rx_moderation(u8 cq_period_mode)

提供預設的RX節制

引數

u8 cq_period_mode

CQ週期模式

struct dim_cq_moder net_dim_get_tx_moderation(u8 cq_period_mode, int ix)

為給定的TX配置檔案提供一個CQ節制物件

引數

u8 cq_period_mode

CQ週期模式

int ix

配置檔案索引

struct dim_cq_moder net_dim_get_def_tx_moderation(u8 cq_period_mode)

提供預設的TX節制

引數

u8 cq_period_mode

CQ週期模式

void net_dim(struct dim *dim, const struct dim_sample *end_sample)

主要的DIM演算法入口點

引數

struct dim *dim

DIM例項資訊

const struct dim_sample *end_sample

當前資料測量

描述

由消費者呼叫。這是演算法的主要邏輯,在此處理資料以決定下一個所需的動作。

void rdma_dim(struct dim *dim, u64 completions)

執行自適應節制。

引數

struct dim *dim

節制結構體。

u64 completions

在此輪中收集的完成數。

描述

每次呼叫rdma_dim都會獲取最新收集的完成數量,並將其計數為一個新事件。一旦收集到足夠的事件,該演算法將決定一個新的節制級別。