跳到主内容

实时确定性

核心概念

实时确定性

Real-Time Determinism 是 EnerOS 的性能保证:通过双执行架构(Dual-Execution Domain),同时满足 AI 推理的灵活性与电力保护逻辑的确定性。通用执行域处理非实时任务(Agent 编排、AI 推理、业务逻辑),实时执行域处理硬实时任务(继电保护、开关操作、紧急控制),实时域保证微秒级响应与零抖动。

设计动机

电力系统的实时性需求

电力系统不同任务对延迟的要求差异巨大:

任务类型延迟要求抖动容忍示例
继电保护< 4ms< 100μs故障检测与跳闸
紧急控制< 10ms< 1ms低频减载、稳定控制
安稳装置< 100ms< 10ms振荡解列
调度决策< 1s秒级经济调度
状态估计< 10s秒级潮流计算
负荷预测分钟级分钟级日前预测

传统单执行域架构无法同时满足微秒级保护与秒级 AI 推理:保护任务会被 AI 推理阻塞,AI 推理会被保护任务打断。

双执行架构的解决思路

EnerOS 将执行域分为两个隔离的层次:

┌──────────────────────────────────────────────────────────────┐
│                    通用执行域 (General Domain)                │
│                                                              │
│  · Agent 编排    · AI 推理    · 业务逻辑    · API 服务      │
│  · 调度策略:CFS(完全公平调度)                              │
│  · 延迟特性:概率性(1-50ms)                                 │
│  · CPU 隔离:Core 0-2                                        │
└──────────────────────────┬───────────────────────────────────┘


                  ┌─────────────────┐
                  │   安全网关       │
                  │  · 命令拦截      │
                  │  · 约束校验      │
                  │  · 可行性投影    │
                  │  · 优先级排序    │
                  └────────┬────────┘


┌──────────────────────────────────────────────────────────────┐
│                    实时执行域 (Real-Time Domain)              │
│                                                              │
│  · 保护逻辑    · 开关操作    · 紧急控制    · 看门狗          │
│  · 调度策略:FIFO + 静态优先级                                │
│  · 延迟特性:确定性(P99 < 1ms)                              │
│  · CPU 隔离:Core 3(隔离核)                                │
│  · 内核:PREEMPT_RT 或裸机                                   │
└──────────────────────────────────────────────────────────────┘

双执行架构详解

通用执行域

通用执行域运行标准 Linux 调度器,处理对延迟不敏感的任务:

属性
调度器CFS(Completely Fair Scheduler)
抢占模式自愿抢占
延迟范围1-50ms
抖动高(受系统负载影响)
CPU 亲和Core 0-2(可配置)
内存限制无特殊限制
适用场景Agent 编排、AI 推理、业务逻辑、API 服务
use eneros_os::domain::{GeneralDomain, DomainConfig};

let general = GeneralDomain::new(DomainConfig {
    cpu_affinity: vec![0, 1, 2],          // 绑定 Core 0-2
    scheduler: Scheduler::CFS,
    memory_limit_mb: 4096,                 // 4GB 内存上限
    io_priority: IoPriority::BestEffort,
});

// 在通用域中运行 Agent
general.spawn(async move {
    agent.run().await
}).await?;

实时执行域

实时执行域运行实时调度器,处理硬实时任务:

属性
调度器SCHED_FIFO + 静态优先级
抢占模式完全抢占(PREEMPT_RT)
延迟范围< 1ms(P99)
抖动极低(< 100μs)
CPU 亲和Core 3(隔离核,独占)
内存限制预分配 + mlock
适用场景继电保护、开关操作、紧急控制
use eneros_os::domain::{RealTimeDomain, RealTimeConfig};

let rt = RealTimeDomain::new(RealTimeConfig {
    cpu_affinity: vec![3],                // 独占 Core 3
    scheduler: Scheduler::Fifo,
    priority_range: (50, 99),              // 实时优先级范围
    memory_prealloc_mb: 256,               // 预分配 256MB
    mlock: true,                           // 锁定内存,禁止换页
    isolated: true,                        // CPU 隔离
});

// 在实时域中运行保护逻辑
rt.spawn_realtime(move || {
    protection_loop();
}).await?;

域间通信

两个执行域通过无锁队列通信,避免锁竞争影响实时性:

use eneros_os::domain::{Channel, ChannelConfig};

// 创建域间通道(无锁 SPSC 队列)
let (tx, rx) = Channel::new(ChannelConfig {
    capacity: 1024,
    lock_free: true,                       // 无锁
    cache_line_size: 64,                   // 缓存行对齐
});

// 通用域发送命令
general.spawn(async move {
    tx.send(Command::OpenBreaker(breaker_id)).await?;
}).await?;

// 实时域接收并执行
rt.spawn_realtime(move || {
    loop {
        match rx.recv_nonblocking() {
            Some(cmd) => execute_command(cmd),
            None => cpu_relax(),
        }
    }
}).await?;

实时域调度策略

优先级层次

实时域使用 SCHED_FIFO 调度,优先级层次如下:

优先级任务类型响应要求示例
99硬件中断< 10μs故障检测
95-98保护逻辑< 1ms跳闸命令
90-94紧急控制< 10ms低频减载
80-89安稳控制< 100ms振荡解列
70-79实时监测< 100ms状态采集
60-69域间通信< 1ms命令分发
50-59后台任务< 100ms日志记录

任务注册

use eneros_os::realtime::{RealTimeTask, Priority, Schedule};

// 注册保护逻辑任务(最高优先级)
rt.register_task(RealTimeTask::new(
    "protection_main",
    Priority::new(96),
    Schedule::Periodic { period_us: 1000 }, // 1ms 周期
    move || {
        protection_loop();
    },
)).await?;

// 注册紧急控制任务
rt.register_task(RealTimeTask::new(
    "emergency_control",
    Priority::new(92),
    Schedule::Sporadic { deadline_us: 5000 }, // 5ms 截止
    move || {
        emergency_handler();
    },
)).await?;

// 启动实时域
rt.start().await?;

优先级反转处理

优先级反转问题

当低优先级任务持有高优先级任务所需的资源时,会导致高优先级任务被阻塞:

时间 →
高优先级任务 H:     ████████等待资源████████执行
中优先级任务 M:               ████████████████
低优先级任务 L:     ██持有资源██

解决方案:优先级继承协议

EnerOS 在实时域实现优先级继承协议(Priority Inheritance Protocol):

use eneros_os::realtime::{PriorityInheritance, RtMutex};

// 启用优先级继承的互斥锁
let mutex = RtMutex::new_with_inheritance(resource);

// 低优先级任务获取锁时,临时提升到等待者的优先级
rt.spawn_realtime(move || {
    let _guard = mutex.lock();  // 自动提升优先级
    use_resource(&mut resource);
    // 释放锁时恢复原优先级
}).await?;

// 高优先级任务等待锁
rt.spawn_realtime(move || {
    let _guard = mutex.lock();  // 阻塞,但低优先级任务已提升
    use_resource(&mut resource);
}).await?;

配置选项

use eneros_os::realtime::RtConfig;

let config = RtConfig::new()
    .priority_inheritance(true)            // 启用优先级继承
    .priority_ceiling(false)               // 优先级天花板(更激进)
    .max_blocked_us(100)                   // 最大阻塞时间 100μs
    .watchdog_timeout_ms(10)               // 看门狗超时 10ms
    .cpu_isolation(true)                   // CPU 隔离
    .disable_irq_balance(true);            // 禁用 IRQ 负载均衡

中断响应

中断处理层次

┌─────────────────────────────────────┐
│  硬件中断 (IRQ)                      │  ← 硬件触发,< 1μs
│  · 故障检测                          │
│  · 计时器                            │
│  · 网卡接收                          │
├─────────────────────────────────────┤
│  顶半部 (Top Half)                   │  ← 原子执行,< 10μs
│  · 紧急操作(如跳闸)                │
│  · 唤醒实时任务                      │
├─────────────────────────────────────┤
│  底半部 (Bottom Half)                │  ← 实时任务,< 100μs
│  · 详细分析                          │
│  · 日志记录                          │
│  · 通知通用域                        │
└─────────────────────────────────────┘

中断注册

use eneros_os::realtime::{IrqHandler, IrqConfig};

// 注册故障检测中断
rt.register_irq(IrqHandler::new(
    IrqConfig::new(irq_number)
        .priority(99)                      // 最高优先级
        .threaded(false),                  // 非线程化(顶半部执行)
    move |irq| {
        // 顶半部:紧急跳闸
        trip_breaker(fault_breaker_id);
        // 唤醒实时任务处理细节
        rt.wake_task("fault_handler");
        IrqResult::Handled
    },
)).await?;

// 注册故障处理实时任务
rt.register_task(RealTimeTask::new(
    "fault_handler",
    Priority::new(97),
    Schedule::Sporadic { deadline_us: 1000 },
    move || {
        let fault = read_fault_details();
        log_fault(&fault);
        notify_general_domain(fault);
    },
)).await?;

看门狗机制

软看门狗

EnerOS 在实时域内置软看门狗,监控任务执行:

use eneros_os::realtime::{Watchdog, WatchdogConfig};

let watchdog = Watchdog::new(WatchdogConfig {
    timeout_ms: 10,                        // 10ms 超时
    action_on_timeout: WatchdogAction::Reboot, // 超时重启
    stats_interval_ms: 1000,
});

// 任务定期喂狗
rt.register_task(RealTimeTask::new(
    "protection_main",
    Priority::new(96),
    Schedule::Periodic { period_us: 1000 },
    move || {
        watchdog.kick();                   // 喂狗
        protection_loop();
    },
)).await?;

watchdog.start().await?;

硬看门狗

支持硬件看门狗,确保内核完全卡死时也能恢复:

use eneros_os::realtime::HardwareWatchdog;

let hw_watchdog = HardwareWatchdog::open("/dev/watchdog")?
    .timeout_ms(100)                       // 100ms 超时
    .auto_kick(true);                      // 实时域自动喂狗

hw_watchdog.start()?;

看门狗超时处理

超时场景检测方式处理动作
任务未喂狗软看门狗重启任务
实时域卡死软看门狗重启实时域
内核卡死硬看门狗硬件重启
调度延迟超限调度追踪告警 + 降级

安全网关

安全网关是两个执行域之间的桥梁,负责命令的安全传递:

use eneros_os::gateway::{SafetyGateway, GatewayConfig, Priority};

let gateway = SafetyGateway::new(GatewayConfig {
    constraint_engine: constraints.clone(),
    channel_capacity: 1024,
    max_command_rate: 10000,                // 每秒最大命令数
    enable_projection: true,                // 启用可行性投影
});

// Agent 通过网关下发命令
let result = gateway.execute(
    Command::SetGeneration { bus: 1, mw: 80.0 },
    Priority::Normal,
).await?;

match result {
    ExecuteResult::Executed => {
        log::info!("命令已执行");
    }
    ExecuteResult::Projected(projected) => {
        log::warn!("命令被投影: {:?}", projected);
    }
    ExecuteResult::Rejected(reason) => {
        log::error!("命令被拒绝: {}", reason);
    }
    ExecuteResult::Queued => {
        log::info!("命令已排队,等待实时域处理");
    }
}

紧急命令优先

// 紧急命令(如保护跳闸)优先处理
gateway.execute(
    Command::TripBreaker(fault_breaker_id),
    Priority::Emergency,                    // 紧急优先级
).await?;
// 紧急命令会在 < 100μs 内到达实时域

实时性能指标

延迟指标

操作通用域实时域
平均延迟1-10ms< 0.5ms
P99 延迟10-50ms< 1ms
P99.9 延迟50-200ms< 2ms
最大抖动50ms< 100μs
中断响应10-100μs< 10μs
域间通信-< 50μs

吞吐指标

操作通用域实时域
命令处理1万/秒10万/秒
事件广播1万/秒5万/秒
时序写入100万点/秒50万点/秒
约束校验10万次/秒100万次/秒

调度延迟测试

use eneros_os::realtime::{LatencyTest, LatencyResult};

// 运行调度延迟测试
let result: LatencyResult = rt.test_latency(Duration::seconds(60)).await?;

println!("平均延迟: {} μs", result.avg_us);
println!("P99 延迟: {} μs", result.p99_us);
println!("P99.9 延迟: {} μs", result.p999_us);
println!("最大延迟: {} μs", result.max_us);
println!("超限次数: {}", result.violations);

完整示例:保护逻辑实时执行

use eneros_os::{domain::{RealTimeDomain, RealTimeConfig}, realtime::*};
use eneros_constraint::ConstraintEngine;
use std::time::Duration;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 创建实时域
    let rt = RealTimeDomain::new(RealTimeConfig {
        cpu_affinity: vec![3],
        scheduler: Scheduler::Fifo,
        priority_range: (50, 99),
        memory_prealloc_mb: 256,
        mlock: true,
        isolated: true,
    });

    // 2. 启用优先级继承
    rt.set_config(RtConfig::new()
        .priority_inheritance(true)
        .max_blocked_us(100)
        .watchdog_timeout_ms(10)
        .cpu_isolation(true));

    // 3. 注册故障检测中断
    rt.register_irq(IrqHandler::new(
        IrqConfig::new(IRQ_FAULT_DETECT)
            .priority(99)
            .threaded(false),
        move |_irq| {
            trip_breaker(FAULT_BREAKER_ID);
            rt.wake_task("fault_handler");
            IrqResult::Handled
        },
    ))?;

    // 4. 注册保护逻辑周期任务
    rt.register_task(RealTimeTask::new(
        "protection_main",
        Priority::new(96),
        Schedule::Periodic { period_us: 1000 },
        move || {
            watchdog.kick();
            protection_loop();
        },
    ))?;

    // 5. 注册故障处理任务
    rt.register_task(RealTimeTask::new(
        "fault_handler",
        Priority::new(97),
        Schedule::Sporadic { deadline_us: 1000 },
        move || {
            let fault = read_fault_details();
            log_fault(&fault);
            notify_general_domain(fault);
        },
    ))?;

    // 6. 启动看门狗
    let watchdog = Watchdog::new(WatchdogConfig {
        timeout_ms: 10,
        action_on_timeout: WatchdogAction::Reboot,
        stats_interval_ms: 1000,
    });
    watchdog.start()?;

    // 7. 启动实时域
    rt.start()?;

    Ok(())
}

与 RT-Linux 对比

维度RT-LinuxEnerOS 实时域
实现方式内核补丁内核组件
调度器SCHED_FIFO/RRSCHED_FIFO + 静态优先级
抢占模式完全抢占完全抢占
P99 延迟< 1ms< 1ms
优先级继承支持内置
看门狗外部工具内置
域隔离cgroupsCPU 亲和 + 隔离核
电力领域知识内置保护逻辑框架
约束校验内置约束引擎
部署复杂高(需编译内核)低(开箱即用)

与其他实时方案对比

方案延迟易用性电力适配适用场景
RT-Linux< 1ms通用实时
Xenomai< 500μs硬实时
PREEMPT_RT< 1ms通用实时
VxWorks< 100μs嵌入式
EnerOS 实时域< 1ms电力原生

限制与权衡

权衡点说明缓解策略
CPU 占用实时域独占一个核多核系统推荐 ≥ 4 核
内存预分配实时域需预分配内存配置合理上限
部署限制需要 PREEMPT_RT 或隔离核通用域可独立部署
调试困难实时域不易打断调试提供调度追踪与统计
跨域通信开销域间数据拷贝无锁队列 + 共享内存
实时域不能阻塞不能调用阻塞 API提供异步 IO 接口

下一步