跳到主要内容

性能优化

扫描周期抖动太大怎么办?

抖动 (Jitter) 是扫描周期偏离目标值的波动。硬实时应用 (如 EtherCAT 伺服控制) 要求抖动 < 10us。

BIOS 设置优化

设置项推荐值说明
C-State关闭CPU 节能状态会导致唤醒延迟
SpeedStep (EIST)关闭频率切换导致执行时间波动
Turbo Boost关闭频率提升/回落导致不确定性
Hyper-Threading关闭超线程导致核心资源竞争
VT-d关闭I/O 虚拟化增加中断延迟
USB Legacy关闭USB 轮询产生 SMI 中断
Serial Port关闭串口中断干扰

操作系统优化

Windows:

# 设置电源计划为高性能
powercfg /setactive 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c

# 禁用动态时钟
bcdedit /set disabledynamictick yes

# 设置 OS 可用核心数 (给实时任务留出隔离核心)
bcdedit /set numproc 12 # 16核 CPU 留 4 核给实时任务

核心分配

IDE 内 设置 → 运行时 → 核心分配 页,可将实时任务绑定到独立 CPU 核心:

EtherCAT 收发   → 最高优先级核心
机器人运动学 → 独立计算核心
PLC 扫描 → 独立执行核心

默认配置已针对 8/16 核常见配置优化,无需手工调整。

抖动测试

使用性能面板的「最大抖动」指标持续观察。目标值:

  • EtherCAT 伺服: < 10 us
  • PLC 扫描: < 50 us
  • 通用控制: < 1 ms

1ms 周期下 CPU 占用率很高怎么办?

分析 CPU 占用

在性能面板中查看扫描周期利用率分解:

IO 输入读取:    50 us  ( 5%)
PLC 扫描: 320 us (32%)
IO 输出写入: 80 us ( 8%)
运动学计算: 200 us (20%)
通讯处理: 50 us ( 5%)
────────────────────────────
总计: 700 us (70%)
空闲: 300 us (30%)

优化方案

  1. 减少 PLC 扫描时间

    • 精简主循环逻辑
    • 将非实时任务移到低优先级 OB
    • 避免在主循环中使用字符串操作和浮点除法
  2. 优化运动学计算

    • 减少同时运动的机器人数量
    • 使用解析解 (SCARA/笛卡尔) 替代数值解 (6轴迭代)
    • 降低插补精度要求
  3. 降低周期频率

    • 如果应用不需要 1ms,将周期设为 2ms 或 4ms
    • 大多数 IO 控制场景 4ms 周期已足够
  4. 升级硬件

    • 使用更高频的 CPU
    • 使用更多核心并合理分配
注意

CPU 利用率持续超过 80% 时,应立即优化或降频。超过 100% 会导致扫描周期超时 (Overrun),影响控制精度甚至安全。

内存使用持续增长是内存泄漏吗?

正常增长场景

以下情况内存增长是正常的:

  • 趋势数据缓存 — 实时数据在内存中累积,达到上限后滚动丢弃
  • 报警历史 — 报警记录持续累积
  • 数据记录缓冲 — 刷盘前在内存中缓冲

异常增长排查

使用性能面板的「内存分析」功能:

  1. 观察内存分布饼图,确认哪个区域在增长
  2. 检查是否有变量被重复创建而未释放
  3. 检查通讯缓冲区是否因对端不消费导致堆积

常见内存泄漏原因

原因解决方案
字符串拼接循环限制字符串长度,使用固定缓冲
事件订阅未取消确保 Dispose 时取消所有订阅
数据记录未刷盘配置合理的刷盘间隔和缓冲上限
通讯消息堆积添加消息队列上限,溢出时丢弃旧消息

如何减少 IO 延迟?

IO 延迟组成

总延迟 = 扫描周期 + 通讯延迟 + 设备响应时间

EtherCAT: 1ms + 0.1ms + 0ms ≈ 1.1ms
Modbus TCP: 50ms + 3ms + 5ms ≈ 58ms
串口 RTU: 50ms + 15ms + 10ms ≈ 75ms

优化方法

  1. 使用 EtherCAT — 硬实时,延迟最低
  2. 缩短扫描周期 — 从 50ms 降到 10ms 可显著降低响应延迟
  3. IO 地址打包 — 相邻地址合并为批量读写,减少通讯次数
  4. 异步预读 — 在主循环外提前发起 IO 读取请求

EtherCAT DC 同步精度不好怎么调?

Distributed Clock (DC) 同步精度受以下因素影响:

影响因素

因素影响优化
参考时钟选择第一个支持 DC 的从站选择网络拓扑中最稳定的从站
传播延迟补偿帧到达各从站的时间差运行时自动测量并补偿
系统时钟漂移长时间运行后累积偏差周期性重同步 (默认每 10 秒)
网络拓扑从站数量和级联深度减少级联层数,使用星型拓扑

DC 配置

DCConfig.SyncMode   := DC_SYNC0;       (* SYNC0 中断同步 *)
DCConfig.CycleTime := T#1ms; (* 同步周期 *)
DCConfig.ShiftTime := T#200us; (* 偏移时间, 留出处理余量 *)
提示

DC 同步精度的目标值通常为 < 1us。可在诊断面板中查看各从站的 DC 偏差值 (System Time Difference)。

如何评估系统是否满足实时性要求?

运行以下检查清单:

检查项合格标准测量方法
扫描周期抖动< 目标周期 10%性能面板 → 最大抖动
CPU 利用率< 80%性能面板 → CPU 仪表
内存使用< 70% 上限性能面板 → 内存饼图
WKC 错误率< 0.001%诊断面板 → EtherCAT 统计
DC 同步偏差< 1 us诊断面板 → DC 偏差
连续运行> 24 小时无超时报警历史 → 过滤超时报警

部署与运维层性能问题

扫描周期抖动 >50μs 排查清单

当抖动超出预期值时, 按下表从外到内逐层排查:

检查项典型现象工具
硬件C-State / Turbo / HT 未关周期性大抖动 (秒级)BIOS 核查
硬件SMI 中断 (系统管理中断)规律性毛刺 (10-100ms)C:\Windows\LatencyMon.exe
驱动第三方 NDIS 协议抢占突发大抖动设备管理器看网卡协议栈
驱动非实时驱动 ISR 过长抖动源来自特定中断号DPCLat / Xperf
系统Windows Update 守护进程下班后半夜抖动暴增确认更新已禁用
系统杀毒软件扫描抖动与磁盘 I/O 同步Defender 排除或禁用
系统GC (托管 Service)抖动周期约几秒一次性能计数器 .NET GC
应用大数组/字符串在主循环稳态抖动偏高扫描周期分析面板
应用日志写盘阻塞大抖动点恰好在记录处改异步日志
LatencyMon 截图阅读

LatencyMon 输出的 "DPC count" 排名前三的驱动就是主要抖动源。常见嫌犯: 无线网卡驱动 (关掉!) / 显卡驱动 / 蓝牙。

EtherCAT DC 同步失败

DC (Distributed Clock) 同步失败表现: 从站诊断中 DcSyncStatus != InSync 或 SYNC0 中断漂移大。

原因处理
参考时钟选错 (选了不稳定从站)IDE 配置中手工指定参考从站为主站旁第一个
参考从站不支持 64 位 DC升级从站固件或换支持 64 位的型号
传播延迟测量失败重启主站让主站重新测量 (自动)
参考从站掉线主站自动选次优从站, 日志会报记录
网线过长 (>100m) 信号失真加中继或改光纤段
DC 抖动 >1μs减小总线周期或检查 BIOS C-State

查看当前参考时钟:

ecat dc status
Reference Clock: Slave[1] (0x1002)
System Time Offset: +125 ns
DC Sync Status: InSync

内存泄漏定位

Service 进程内存持续上涨 (超过 4 GB 或持续增长 24 小时不回落) 视为泄漏。定位步骤:

  1. 确认是否真泄漏

    # 连续采样 1 小时, 每分钟记录
    while ($true) {
    $p = Get-Process DarraService -ErrorAction SilentlyContinue
    "{0:yyyy-MM-dd HH:mm} {1:N0} KB" -f (Get-Date), ($p.WorkingSet64/1KB)
    Start-Sleep 60
    }

    趋势持续上涨 = 泄漏; 震荡 = 正常缓存。

  2. 用 VMMap 看内存分布

    • SysInternals VMMap 附加到 DarraService
    • 观察 "Heap" / "Managed Heap" 哪部分在涨
    • Heap 涨 = 原生泄漏; Managed Heap 涨 = .NET 对象未释放
  3. Perfmon 计数器

    • Process\Private Bytes — 整体内存
    • .NET CLR Memory\# Bytes in all Heaps — 托管堆
    • .NET CLR Memory\# Gen 2 Collections — 应周期发生, 不发生说明 GC 失效
  4. 常见泄漏模式

模式排查
Historian 缓冲未刷盘historian.flushIntervalMs 小一点
订阅未解绑OPC UA 客户端断开时未 -= 事件
通讯队列无上限通讯队列配 maxQueueSize = 10000
string 拼接循环主循环改 StringBuilder 固定大小

日志写磁盘导致性能下降

表现: 主循环偶发卡顿 100-500 ms, 时刻对应大量日志写入。

处理效果
生产环境改 Info 级别 (从 Debug)降 90% 日志量
改异步日志 (NLog AsyncWrapper)不阻塞写入线程
SSD 替换机械硬盘写延迟 10ms → 0.5ms
日志目录放到独立磁盘隔离业务 I/O
关闭 Windows 文件索引减少后台磁盘争用
# 关闭 %AppData%\DarraPLC 目录的索引
$folder = "$env:AppData\DarraPLC"
attrib +I $folder /S /D

Historian 写入拖慢扫描

当 Historian 以同步方式写数据时, 每次扫描会阻塞等磁盘返回, 周期超时风险高。对策:

  • 异步数据库管道: 扫描只把数据投入内存队列, 专门线程批量落盘
  • 批量大小建议 100-1000 条/批
  • 磁盘 SSD + 日志分盘

参考实现思路类似 "Producer-Consumer" 模式, 详见 PLC 模块内高速采样相关文档。

多核 CPU 核心分配

推荐分配 (8 核 CPU 为例):

用途优先级
Core 0Windows 内核 + 驱动 ISR默认
Core 1Windows 其他应用默认
Core 2DarraRT_Eth.sys EtherCAT 收发最高
Core 3DarraRT_PLC.sys PLC 扫描最高
Core 4机器人运动学计算
Core 5Service 通讯线程
Core 6HMI Web / OPC UA
Core 7Historian / 日志

配置方法: IDE → 设置 → 运行时 → 核心分配。使用 IOCTL_DARRT_ISOLATE_CORE 向内核注册隔离核心, Windows 调度器不会把普通线程派到这些核上。

网络拥塞 (办公网和控制网必须分离)

网络必须独立原因
EtherCAT 总线 (LAN2)绝对独立专用 DarraRT_Eth 协议, 与 IP 不共存
管理网 (LAN1)推荐独立 VLAN办公广播风暴影响中断
同步链路 (冗余)必须独立心跳丢失 = 切换误触发
存储/数据库可共用管理网不频繁则 OK

办公网不隔离典型故障: 上午 9 点打印机批量启动, PLC 扫描周期集体抖动。详见 冗余功能

长期运行性能退化

连续运行 30 天后性能变差的常见原因:

原因排查
日志文件未清理, 磁盘满自动清理策略见 general.md
Historian 数据库索引膨胀每季度 VACUUM 一次 SQLite
RETAIN 持久化文件碎片停机时 Service 会自动整理
Windows 页面文件碎片季度维护窗口内 defrag
风扇积灰导致降频现场维护计划

维护建议周期:

周期任务
每天查看报警历史, 确认无致命报警
每周检查磁盘空间, 日志量
每月重启 Service 清理缓存 (低峰期)
每季度数据库 VACUUM + 硬件清灰
每年硬件全面检查, UPS 电池检测