You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

内核传感器驱动轮询优化:高负载下维持200Hz事件输出

传感器驱动轮询稳定性优化问题

我有一个传感器驱动,未采用中断处理方式,而是借助workqueue每5ms轮询陀螺仪和加速度计。驱动核心轮询代码如下:

static void  sensor_delaywork_func(struct work_struct *work)
{
        struct delayed_work *delaywork = container_of(work, struct delayed_work, work);
        struct sensor_private_data *sensor = container_of(delaywork, struct sensor_private_data, delaywork);
        struct i2c_client *client = sensor->client;
        int result;

        mutex_lock(&sensor->sensor_mutex);
        result = sensor->ops->report(client);
        if (result < 0)
                dev_err(&client->dev, "%s: Get data failed\n", __func__);
        mutex_unlock(&sensor->sensor_mutex);

        if ((!sensor->pdata->irq_enable) && (sensor->stop_work == 0))
                schedule_delayed_work(&sensor->delaywork, msecs_to_jiffies(sensor->pdata->poll_delay_ms));
}

当前问题:高负载下kworker/*线程会被抢占、CPU分配减少,导致生成的输入事件从每秒200个降至170-180个。使用chrt工具为kworker/*线程设置更高(实时)优先级可缓解此问题,但希望在内核层面正确改造驱动,确保任何情况下都能稳定输出200个事件/秒。已知高优先级tasklet无法睡眠不适用,自定义高优先级内核线程被视为hack方案,寻求合理优化建议。


可行优化方案

1. 创建实时优先级的自定义工作队列

内核允许创建带特定调度属性的工作队列,替代默认系统队列,让轮询任务运行在高优先级kworker线程中,避免被普通任务抢占。

实现步骤:

  • 驱动初始化时,通过alloc_workqueue_attrs设置调度策略为SCHED_FIFO或SCHED_RR,并指定合理的实时优先级(如50,避免过高影响系统关键进程)。
  • 调用alloc_workqueue创建带WQ_HIGHPRI | WQ_RESCUER标志的工作队列,绑定上述属性。
  • 将延迟工作提交到该自定义队列,而非默认队列。
  • 驱动卸载时销毁队列。

示例代码片段:

struct workqueue_struct *sensor_wq;
struct workqueue_attrs *attrs;

// 初始化工作队列属性
attrs = alloc_workqueue_attrs();
if (!attrs) {
    // 错误处理
}
attrs->sched_policy = SCHED_FIFO;
attrs->sched_priority = 50;

// 创建实时工作队列
sensor_wq = alloc_workqueue("sensor_poll_wq", WQ_HIGHPRI | WQ_RESCUER, 1, attrs);
free_workqueue_attrs(attrs);
if (!sensor_wq) {
    // 错误处理
}

// 提交延迟工作到自定义队列
queue_delayed_work(sensor_wq, &sensor->delaywork, msecs_to_jiffies(5));

2. 加入轮询时间补偿逻辑

即使使用高优先级队列,极端情况仍可能出现微小延迟,可通过计算实际耗时动态调整下一次延迟,弥补误差:

修改原函数的调度部分:

unsigned long actual_delay;
ktime_t start, end;

start = ktime_get();
// 原有数据采集逻辑
mutex_lock(&sensor->sensor_mutex);
result = sensor->ops->report(client);
if (result < 0)
        dev_err(&client->dev, "%s: Get data failed\n", __func__);
mutex_unlock(&sensor->sensor_mutex);
end = ktime_get();

// 计算实际耗时,用目标5ms减去实际耗时得到下一次延迟
actual_delay = msecs_to_jiffies(5) - ktime_to_jiffies(ktime_sub(end, start));
// 确保延迟不为负
actual_delay = max(actual_delay, 0UL);

if ((!sensor->pdata->irq_enable) && (sensor->stop_work == 0))
    // 指定当前CPU运行,减少跨CPU调度开销
    schedule_delayed_work_on(smp_processor_id(), &sensor->delaywork, actual_delay);

3. 优化数据采集路径耗时

检查sensor->ops->report函数的执行效率,减少不必要的延迟:

  • 缩短临界区持有时间,将非核心逻辑移出mutex_lock/mutex_unlock范围。
  • 若传感器支持批量读取,调整I2C传输方式,减少单次操作耗时。
  • 移除高负载下不必要的调试打印或冗余逻辑。

4. 高精度定时器(hrtimer)替代delayed_work

对时间精度要求极高时,hrtimer比delayed_work提供更精准的定时。由于hrtimer回调运行在软中断上下文,若需睡眠(如I2C操作),可在回调中调度高优先级工作队列任务:

示例思路:

static enum hrtimer_restart sensor_hrtimer_handler(struct hrtimer *timer)
{
    struct sensor_private_data *sensor = container_of(timer, struct sensor_private_data, hrtimer);
    ktime_t now = ktime_get();

    // 调度高优先级工作队列执行数据采集
    queue_work(sensor_wq, &sensor->work);

    // 调整定时器,确保5ms间隔
    hrtimer_forward(timer, now, ms_to_ktime(5));
    return HRTIMER_RESTART;
}

// 初始化时启动高精度定时器
hrtimer_init(&sensor->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
sensor->hrtimer.function = sensor_hrtimer_handler;
hrtimer_start(&sensor->hrtimer, ms_to_ktime(5), HRTIMER_MODE_REL);

方案优先级推荐

  1. 自定义实时工作队列:实现简单、兼容性好,是解决抢占问题的核心方案,优先采用。
  2. 时间补偿逻辑:作为辅助优化,进一步提升极端负载下的稳定性。
  3. 高精度定时器:仅在对时间精度有极致要求的场景下使用。

内容的提问来源于stack exchange,提问作者pulse

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 07:45:29