Net DIM - 通用网络动态中断调节¶
- 作者:
Tal Gilboa <talgi@mellanox.com>
假设¶
本文档假设读者具备网络驱动程序和通用中断调节的基础知识。
介绍¶
动态中断调节(DIM)(在网络中)指的是更改通道的中断调节配置,以优化数据包处理。该机制包括一种算法,该算法决定是否以及如何更改通道的调节参数,通常是通过对从系统采样的运行时数据执行分析来实现的。Net DIM就是这样一种机制。在算法的每次迭代中,它都会分析给定的数据样本,将其与先前的样本进行比较,如果需要,它可以决定更改某些中断调节配置字段。数据样本由数据带宽、数据包数量和事件数量组成。还测量了样本之间的时间。Net DIM比较当前数据和先前数据,并返回调整后的中断调节配置对象。在某些情况下,该算法可能会决定不进行任何更改。配置字段是事件之间允许的最小持续时间(微秒)和每个事件所需的最大数据包数量。Net DIM算法将增加带宽的重要性置于降低中断速率之上。
Net DIM算法¶
Net DIM算法的每次迭代都遵循以下步骤
计算新的数据样本。
将其与先前的样本进行比较。
做出决定 - 建议中断调节配置字段。
应用计划的工作函数,该函数应用建议的配置。
前两个步骤很简单,新数据和先前数据都由注册到Net DIM的驱动程序提供。先前数据是提供给先前迭代的新数据。比较步骤检查新数据和先前数据之间的差异,并决定最后一步的结果。如果带宽增加,则结果为“更好”,如果带宽减少,则结果为“更差”。如果带宽没有变化,则以类似的方式比较数据包速率 - 增加 == “更好”,减少 == “更差”。如果数据包速率也没有变化,则比较中断速率。在这里,该算法尝试优化为较低的中断速率,因此中断速率的增加被认为是“更差”,而减少被认为是“更好”。步骤2对避免错误结果进行了优化:仅当样本之间的差异大于某个百分比时,才将其视为有效。此外,由于Net DIM本身不测量任何东西,因此它假设驱动程序提供的数据是有效的。
步骤3根据步骤2的结果和算法的内部状态决定建议的配置。这些状态反映了算法的“方向”:是向左(减少调节),向右(增加调节)还是静止不动。另一个优化是,如果多次做出静止不动的决定,则算法迭代之间的间隔会增加,以减少计算开销。此外,在“停靠”在最左或最右的决策之一后,该算法可能会决定通过朝另一个方向迈出一步来验证此决策。这样做是为了避免陷入“深度睡眠”场景。做出决定后,将从预定义的配置文件中选择中断调节配置。
最后一步是通知注册的驱动程序,它应该应用建议的配置。这是通过调度一个工作函数来完成的,该函数由Net DIM API定义并由注册的驱动程序提供。
如您所见,Net DIM本身不会主动与系统交互。如果向其提供了错误的数据,它将难以做出正确的决策,并且如果工作函数未应用建议的配置,它将毫无用处。但是,这确实允许注册的驱动程序有一定的操作空间,因为它可能会提供部分数据或在某些情况下忽略算法建议。
将网络设备注册到DIM¶
Net DIM API公开了主要函数net_dim()
。此函数是Net DIM算法的入口点,并且每次驱动程序想要检查是否应该更改中断调节参数时都必须调用。驱动程序应提供两个数据结构:struct dim
和struct dim_sample
。struct 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-profile
和tx-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);
};
成员
-
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方向
参数
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模式
参数
struct dim *dim
DIM上下文
描述
检查当前配置文件是否是停靠的好地方。这将导致降低DIM检查频率,因为我们假设除非流量模式发生变化,否则我们不应该更改配置文件。
参数
struct dim *dim
DIM上下文
描述
如果我们向右走,则向左走,反之亦然。如果当前停靠,则不执行任何操作。
参数
struct dim *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
当前数据测量
描述
由消费者调用。这是算法的主要逻辑,在此处理数据以决定下一个所需的动作。
参数
struct dim *dim
节制结构体。
u64 completions
在此轮中收集的完成数。
描述
每次调用rdma_dim都会获取最新收集的完成数量,并将其计数为一个新事件。一旦收集到足够的事件,该算法将决定一个新的节制级别。