实时确定性
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-Linux | EnerOS 实时域 |
|---|---|---|
| 实现方式 | 内核补丁 | 内核组件 |
| 调度器 | SCHED_FIFO/RR | SCHED_FIFO + 静态优先级 |
| 抢占模式 | 完全抢占 | 完全抢占 |
| P99 延迟 | < 1ms | < 1ms |
| 优先级继承 | 支持 | 内置 |
| 看门狗 | 外部工具 | 内置 |
| 域隔离 | cgroups | CPU 亲和 + 隔离核 |
| 电力领域知识 | 无 | 内置保护逻辑框架 |
| 约束校验 | 无 | 内置约束引擎 |
| 部署复杂 | 高(需编译内核) | 低(开箱即用) |
与其他实时方案对比
| 方案 | 延迟 | 易用性 | 电力适配 | 适用场景 |
|---|---|---|---|---|
| RT-Linux | < 1ms | 中 | 无 | 通用实时 |
| Xenomai | < 500μs | 低 | 无 | 硬实时 |
| PREEMPT_RT | < 1ms | 中 | 无 | 通用实时 |
| VxWorks | < 100μs | 低 | 弱 | 嵌入式 |
| EnerOS 实时域 | < 1ms | 高 | 强 | 电力原生 |
限制与权衡
| 权衡点 | 说明 | 缓解策略 |
|---|---|---|
| CPU 占用 | 实时域独占一个核 | 多核系统推荐 ≥ 4 核 |
| 内存预分配 | 实时域需预分配内存 | 配置合理上限 |
| 部署限制 | 需要 PREEMPT_RT 或隔离核 | 通用域可独立部署 |
| 调试困难 | 实时域不易打断调试 | 提供调度追踪与统计 |
| 跨域通信开销 | 域间数据拷贝 | 无锁队列 + 共享内存 |
| 实时域不能阻塞 | 不能调用阻塞 API | 提供异步 IO 接口 |
下一步
- Power-Native First - 电力原生优先设计哲学
- 约束即法律 - 实时域约束校验
- 安全守卫 - 安全网关详解
- 实时双执行域 - 完整实时域能力