You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

内核模式音频驱动如何阻止CPU进入空闲C状态?

解决音频驱动中CPU C3状态导致的中断延迟问题

很高兴能帮你搞定这个音频驱动里的棘手问题!针对你提到的「不想用全局用户态设置、要驱动层面告知系统不要进入空闲C状态」的需求,我整理了几个内核态的实现方案,都是更适合驱动场景的做法:

一、内核态动态维护处理器空闲设置(避免被全局修改覆盖)

这种方式是在驱动层面接管处理器C状态的控制,并且监听系统电源设置的变化,一旦被用户或其他应用修改,驱动自动重新恢复设置:

核心思路

  1. 驱动加载时,读取当前处理器电源策略,禁用空闲C状态并保存原始设置;
  2. 注册电源设置回调,监听GUID_PROCESSOR_IDLE_DISABLE的变化;
  3. 一旦检测到C状态被重新启用,立刻再次禁用;
  4. 驱动卸载时恢复原始设置,避免影响系统后续运行。

代码示例

// 保存原始的空闲状态设置,用于卸载时恢复
BOOLEAN g_OriginalIdleDisable = FALSE;

NTSTATUS DisableProcessorIdle()
{
    PROCESSOR_POWER_POLICY powerPolicy;
    NTSTATUS status = PoGetPowerPolicy(NULL, sizeof(PROCESSOR_POWER_POLICY), &powerPolicy);
    if (!NT_SUCCESS(status))
        return status;

    g_OriginalIdleDisable = powerPolicy.IdleSettings.DisableIdle;
    // 禁用处理器空闲C状态
    powerPolicy.IdleSettings.DisableIdle = TRUE;

    status = PoSetPowerPolicy(NULL, sizeof(PROCESSOR_POWER_POLICY), &powerPolicy);
    return status;
}

// 电源设置变化回调函数
VOID PowerSettingCallback(
    PVOID Context,
    LPCGUID SettingGuid,
    ULONG DataSize,
    PVOID Data
)
{
    // 监听处理器空闲状态的修改
    if (IsEqualGUID(*SettingGuid, GUID_PROCESSOR_IDLE_DISABLE))
    {
        DWORD currentValue = *(PDWORD)Data;
        // 如果C状态被重新启用,立刻再次禁用
        if (currentValue == 0) // 0对应ENABLED,即允许C状态
        {
            DisableProcessorIdle();
        }
    }
}

// 驱动入口函数
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
    UNREFERENCED_PARAMETER(RegistryPath);

    NTSTATUS status;
    // 注册电源设置回调
    status = PoRegisterPowerSettingCallback(
        PowerSettingCallback,
        &GUID_PROCESSOR_IDLE_DISABLE,
        NULL
    );
    if (!NT_SUCCESS(status))
        return status;

    // 初始化时禁用C状态
    status = DisableProcessorIdle();
    if (!NT_SUCCESS(status))
    {
        PoUnregisterPowerSettingCallback(PowerSettingCallback);
        return status;
    }

    DriverObject->DriverUnload = DriverUnload;
    return STATUS_SUCCESS;
}

// 驱动卸载函数
VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
    UNREFERENCED_PARAMETER(DriverObject);

    PROCESSOR_POWER_POLICY powerPolicy;
    NTSTATUS status = PoGetPowerPolicy(NULL, sizeof(PROCESSOR_POWER_POLICY), &powerPolicy);
    if (NT_SUCCESS(status))
    {
        // 恢复原始的空闲状态设置
        powerPolicy.IdleSettings.DisableIdle = g_OriginalIdleDisable;
        PoSetPowerPolicy(NULL, sizeof(PROCESSOR_POWER_POLICY), &powerPolicy);
    }

    // 注销回调
    PoUnregisterPowerSettingCallback(PowerSettingCallback);
}

二、绑定设备状态的精准控制(更节能)

如果不想全局禁用C状态,只在音频设备活跃时阻止系统进入深度C状态,可以结合设备电源状态来实现:

核心思路

  1. 注册设备电源状态变化回调;
  2. 当设备进入D0(活跃)状态时,禁用处理器空闲C状态;
  3. 当设备进入D3(休眠)状态时,恢复原始设置。

这种方式既满足了音频实时处理的需求,又不会在设备闲置时浪费功耗。

三、利用WDM音频Port Class的内置支持

如果你的驱动是基于WDM Port Class开发的音频驱动,其实Port Class已经内置了针对实时音频流的电源管理优化——当音频流处于播放/录制状态时,Port Class会自动阻止处理器进入深度C状态,你只需要正确配置驱动的电源属性(比如开启D0唤醒支持、设置PowerManagedTRUE)即可,无需手动处理C状态。

四、高优先级线程辅助

将驱动中的中断服务例程(ISR)、延迟过程调用(DPC)设置为高优先级,同时创建一个实时优先级的工作线程,让CPU保持活跃状态,间接避免进入深度C状态:

// 设置线程为实时优先级
KeSetThreadPriority(Thread, HIGH_PRIORITY);
// 启用优先级提升,避免线程被抢占
KeSetPriorityBoost(Thread, FALSE);

内容的提问来源于stack exchange,提问作者Svetoslav Ilkov Enchev

火山引擎 最新活动