Subject: [PATCH] net: solve a NAPI race

博客详细描述了一个在Linux内核中关于NAPI(New API)的竞态条件bug,该bug导致某些网络包接收延迟约200毫秒。此问题在2017年被Eric Dumazet发现并修复,主要原因是NAPI驱动程序在重新启用IRQ前未能正确处理NAPI_STATE_SCHED标志。修复方案引入了一个新的NAPI_STATE_MISSED标志,确保不会错过任何网络包。

包括我在内很多人认为Linux已经很成熟了,不应该有什么不可思议的bug。最近发现有个bug在2017年才fix。

From 39e6c8208d7b6fb9d2047850fb3327db567b564b Mon Sep 17 00:00:00 2001
From: Eric Dumazet <edumazet@google.com>
Date: Tue, 28 Feb 2017 10:34:50 -0800
Subject: [PATCH] net: solve a NAPI race

While playing with mlx4 hardware timestamping of RX packets, I found
that some packets were received by TCP stack with a ~200 ms delay...

Since the timestamp was provided by the NIC, and my probe was added
in tcp_v4_rcv() while in BH handler, I was confident it was not
a sender issue, or a drop in the network.

This would happen with a very low probability, but hurting RPC
workloads.

A NAPI driver normally arms the IRQ after the napi_complete_done(),
after NAPI_STATE_SCHED is cleared, so that the hard irq handler can grab
it.

Problem is that if another point in the stack grabs NAPI_STATE_SCHED bit
while IRQ are not disabled, we might have later an IRQ firing and
finding this bit set, right before napi_complete_done() clears it.

This can happen with busy polling users, or if gro_flush_timeout is
used. But some other uses of napi_schedule() in drivers can cause this
as well.

thread 1                                 thread 2 (could be on same cpu, or not)

// busy polling or napi_watchdog()
napi_schedule();
...
napi->poll()

device polling:
read 2 packets from ring buffer
                                          Additional 3rd packet is
available.
                                          device hard irq

                                          // does nothing because
NAPI_STATE_SCHED bit is owned by thread 1
                                          napi_schedule();

napi_complete_done(napi, 2);
rearm_irq();

Note that rearm_irq() will not force the device to send an additional
IRQ for the packet it already signaled (3rd packet in my example)

This patch adds a new NAPI_STATE_MISSED bit, that napi_schedule_prep()
can set if it could not grab NAPI_STATE_SCHED

Then napi_complete_done() properly reschedules the napi to make sure
we do not miss something.

Since we manipulate multiple bits at once, use cmpxchg() like in
sk_busy_loop() to provide proper transactions.

 

mlx5_core相关的函数调用关系如下:


alloc_comp_eqs
        mlx5_create_map_eq
                request_irq(mlx5_eq_int)

mlx5_eq_int   # hard irq handler
        mlx5_eq_cq_completion
                cq->comp        ->      mlx5e_completion_event
                        napi_schedule
                                napi_schedule_prep
                                        set NAPIF_STATE_SCHED
                                        if NAPIF_STATE_SCHED is already set
                                                set NAPIF_STATE_MISSED
                                __napi_schedule
                                        ____napi_schedule
                                                __raise_softirq_irqoff(NET_RX_SOFTIRQ)

mlx5e_napi_poll   # softirq handler
        mlx5e_poll_tx_cq
        mlx5e_poll_rx_cq
        napi_complete_done
                clear NAPIF_STATE_SCHED
                if NAPIF_STATE_MISSED is set
                        __napi_schedule
        mlx5e_cq_arm
 

<think>好的,我现在需要回答用户关于OpenCV中cv::solve和fisheye::solve的原理区别和应用场景的问题。首先,我得回忆一下这两个函数的基本信息,然后深入它们的实现原理。首先,cv::solve是OpenCV中的通用线性系统求解函数,用于解决形如Ax =B的方程。用户可能知道,它支持多种分解方法,比如LU分解、QR分解等。而fisheye::solve属于fisheye模块,专门用于鱼眼相机的标定,可能涉及非线性优化问题,因为鱼眼镜头通常有较大的畸变,标定过程需要更复杂的模型,比如多项式畸变模型。接下来,我需要明确两者的原理差异。cv::solve处理的是线性问题,可能使用数值线性代数中的标准方法。而fisheye::solve可能针对鱼眼相机的非线性畸变参数进行优化,比如使用Levenberg-Marquardt算法这样的非线性最小二乘法。这里需要确认OpenCV文档中fisheye::solve的具体实现,是否确实如此。然后,应用场景方面,cv::solve适用于一般的线性系统求解,比如计算单应性矩阵、相机姿态估计中的PnP问题等。而fisheye::solve则专用于鱼眼相机的标定过程,估计相机内参和畸变系数。这里需要区分普通相机标定和鱼眼标定的不同,鱼眼通常需要更高阶的畸变模型,比如使用4个畸变参数而不是普通的径向切向模型。 可能还需要考虑两者的输入参数和输出结果的不同。比如,cv::solve的输入是矩阵A和B,输出是解向量x,而fisheye::solve可能需要输入的是多个标定图像的点对应,输出相机矩阵和畸变参数。 另外,需要注意OpenCV中普通相机标定和鱼眼标定的模块不同,普通标定可能使用calib3d模块,而鱼眼标定在fisheye模块中。两者的标定函数可能分别是calibrateCamera和fisheye::calibrate,而solve函数可能是在标定过程中被调用的优化方法。 还要思考用户可能的深层需求,比如他们可能在处理鱼眼相机的标定问题,遇到精度或速度上的挑战,想知道该选择哪个函数,或者如何优化标定结果。因此,在回答中需要明确两者的适用场景,帮助用户做出正确选择。最后,生成相关问题时,需要考虑用户可能进一步想知道如何选择这两个函数,或者鱼眼标定的具体步骤,以及如何处理标定中的常见问题。比如,标定板的选择、参数初始化的方法,或者如何评估标定结果的准确性。总结一下,回答的结构应该先分点说明原理差异,包括问题类型、算法、参数模型,然后讨论应用场景,最后给出示例代码(如果有的话)和相关问题。需要确保使用正确的中文术语,并且LaTeX公式符合要求,比如变量用$符号包裹,独立公式用$$。</think>### OpenCV中cv::solve与fisheye::solve的原理差异 #### 1. **数学问题类型** - **cv::solve**: 用于求解线性方程组$Ax = B$,支持LU、QR、Cholesky等矩阵分解方法[^1]。例如: $$ A = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix},\quad B = \begin{bmatrix} 5 \\ 6 \end{bmatrix} $$ - **fisheye::solve**: 针对鱼眼相机标定的**非线性优化问题**,需最小化重投影误差,通常使用Levenberg-Marquardt算法[^2]。目标函数为: $$ \min_{\theta} \sum_{i} \| \pi(K, D, X_i) - x_i \|^2 $$ 其中$K$为内参,$D$为畸变系数,$\pi$为鱼眼投影模型。 #### 2. **参数模型差异** - **cv::solve**: 输入为矩阵$A$和向量$B$,输出直接解$x$。 - **fisheye::solve**: 输入为标定板的3D-2D点对应关系,输出包含: - 内参矩阵$K = \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix}$ - 畸变系数$D = [k_1, k_2, k_3, k_4]$ #### 3. **算法实现** - **cv::solve**: 基于数值线性代数库(如LAPACK),直接调用`cv::decompose`函数。 - **fisheye::solve**: 通过迭代优化更新参数,每次迭代计算雅可比矩阵$J$并求解增量$\Delta \theta$: $$ (J^T J + \lambda I) \Delta \theta = J^T e $$ ### 应用场景对比 | **场景** | **cv::solve** | **fisheye::solve** | |------------------------|---------------|--------------------------| | 普通相机标定 | ✓ (PnP问题) | ✗ | | 鱼眼相机标定 | ✗ | ✓ (支持大畸变模型) | | 实时姿态估计 | ✓ (低延迟) | ✗ | | 广角镜头标定 | ✗ | ✓ (需4阶畸变参数补偿) | ### 代码示例 ```cpp // 使用cv::solve求解线性系统 cv::Mat A, B, x; cv::solve(A, B, x, cv::DECOMP_QR); // 使用fisheye::solve进行标定 std::vector<cv::Mat> objectPoints, imagePoints; cv::Mat K, D; cv::fisheye::calibrate(objectPoints, imagePoints, imageSize, K, D); ```
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值