<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>HCP Docs Blog</title>
        <link>http://hcpdoc.samplix.cn/blog</link>
        <description>HCP Docs Blog</description>
        <lastBuildDate>Tue, 16 Jun 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[浅谈HCP平台及其设计理念]]></title>
            <link>http://hcpdoc.samplix.cn/blog/2026/06/16/hcp-design</link>
            <guid>http://hcpdoc.samplix.cn/blog/2026/06/16/hcp-design</guid>
            <pubDate>Tue, 16 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[控制保护装置是电力设备的二次核心。无论是电力电子、继电保护还是自动化领域，都需要一个统一的控制器平台来支撑业务开发。近年来，随着控制平台技术的不断进步，许多长期困扰研发人员的问题已得到改善，但仍有一些根本性痛点尚未被彻底解决。]]></description>
            <content:encoded><![CDATA[<p>控制保护装置是电力设备的二次核心。无论是电力电子、继电保护还是自动化领域，都需要一个统一的控制器平台来支撑业务开发。近年来，随着控制平台技术的不断进步，许多长期困扰研发人员的问题已得到改善，但仍有一些根本性痛点尚未被彻底解决。</p>
<ol>
<li class="">
<p>软硬件的强耦合
微机控制器的发展始终紧跟芯片技术的迭代速度，硬件快速更新，每次更换都要求软件重新适配，导致适配和验证成本居高不下。为此，“软件平台”的概念应运而生：将应用程序与硬件解耦，应用只能通过平台提供的标准接口操作硬件。这样，硬件升级时只需适配平台层，应用程序即可无缝迁移，大幅降低适配代价。</p>
</li>
<li class="">
<p>软件的验证成本高
电力设备对可靠性要求极高，而软件又天然需要不断迭代。任何一次验证中发现问题，往往需要从头再来，验证成本甚至远超开发成本。虽然业界已尝试对控制保护装置进行自动化验证，但装置对外接口的不统一，仍使自动化验证的推广存在较大局限。</p>
</li>
<li class="">
<p>开发语言的表达能力与业务不匹配
嵌入式裸机开发受限于硬件资源，多采用C语言。理论上C语言可以完成任何逻辑，但其面向过程的编程范式在面对特定业务逻辑时抽象能力不足。工业控制领域较早发现了这一问题，由此诞生了PLC，支持梯形图、功能块图、顺序功能图等多种编程语言，各自适应不同场景，弥补了纯C语言抽象能力不足的缺点。然而，这种领域特定语言在泛化能力上又有其局限性。</p>
</li>
<li class="">
<p>软件的可维护性差
在软件平台出现之前，控制保护装置多基于裸机开发，组件高度耦合，应用与底层往往需要联合编译，维护成本极高。更关键的是，随着功能持续扩展，代码量很快就会超出单人维护的极限，多人协作同一套代码的难度很大，这严重制约了程序规模的提升。</p>
</li>
</ol>
<p>这些痛点中，既有电力控制领域的特有问题，也有软件工程领域的普遍挑战。领先的电力系统控制平台已经开始吸收操作系统技术实现硬软解耦与模块隔离，并借鉴工业控制领域的PLC可视化编程思想。站在2026年这个时间点，如果从零开始设计一套全新的控制保护平台，如何在前人工作的基础上，进一步汲取更先进的技术与开发范式，从更深层次解决上述问题？HCP异构控制平台（Heterogeneous Control Platform）正是在这一背景下，提出了三大设计理念：AI化、融合化、虚拟化。</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="ai化面向大模型的开发范式重构">AI化：面向大模型的开发范式重构<a href="http://hcpdoc.samplix.cn/blog/2026/06/16/hcp-design#ai%E5%8C%96%E9%9D%A2%E5%90%91%E5%A4%A7%E6%A8%A1%E5%9E%8B%E7%9A%84%E5%BC%80%E5%8F%91%E8%8C%83%E5%BC%8F%E9%87%8D%E6%9E%84" class="hash-link" aria-label="Direct link to AI化：面向大模型的开发范式重构" title="Direct link to AI化：面向大模型的开发范式重构" translate="no">​</a></h4>
<p>大模型的快速发展正在重塑编程工具，从2022年底ChatGPT掀起的对话式交互，到代码补全，再到如今的Agent自主开发，AI正逐步打通从编码、编译、测试到部署的全闭环。一旦AI能够自主闭环完成开发任务，它带来的效率提升将是颠覆性的。</p>
<p>然而，大模型在当前阶段仍存在两个显著局限：其一，对图形的理解能力远逊于语言能力，即便许多模型宣称支持多模态，理解图形化编程逻辑仍十分困难，这使得对人类友好的图形编程反而成为AI的短板；其二，上下文窗口有限，难以直接胜任复杂的大规模任务，需要人类辅助进行任务分解和功能定义。</p>
<p>针对这两个问题，HCP平台采用了“功能块开发→功能块集成”的两段式开发理念。单个功能块要求以纯C语言实现，一方面能充分利用大模型强大的语言编程能力，另一方面也通过限制功能块的规模，解决了上下文不足的问题。为支撑这一理念，平台不仅提供了图形化开发工具HCP BlockEditor，还配套了HCP BlockEditor CLI。借助配套的Skill，开发者可直接在Claude Code、Codex等主流Agent编程工具中，以自然语言驱动功能块的自主开发、编译与验证。</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="融合化多尺度实时任务的统一承载">融合化：多尺度实时任务的统一承载<a href="http://hcpdoc.samplix.cn/blog/2026/06/16/hcp-design#%E8%9E%8D%E5%90%88%E5%8C%96%E5%A4%9A%E5%B0%BA%E5%BA%A6%E5%AE%9E%E6%97%B6%E4%BB%BB%E5%8A%A1%E7%9A%84%E7%BB%9F%E4%B8%80%E6%89%BF%E8%BD%BD" class="hash-link" aria-label="Direct link to 融合化：多尺度实时任务的统一承载" title="Direct link to 融合化：多尺度实时任务的统一承载" translate="no">​</a></h4>
<p>任何计算机系统设计都面临吞吐量与实时性之间的矛盾。大多数通用系统追求高吞吐量，虚拟内存、分支预测、乱序执行、多发射等技术皆为此服务。而控制保护装置往往更关注实时性，但同时也承载着大量非实时业务。</p>
<p>若以时间尺度来界定不同业务的实时性需求，电力电子控制通常在微秒级，继电保护与一般工业控制要求毫秒级，人机交互、后台通信等则只需几十至几百毫秒甚至秒级响应。如何在同一平台上同时满足从微秒到秒级的差异化实时需求，是HCP平台必须回答的核心问题。</p>
<p>HCP平台采用功能异构的系统架构来融合这些任务。以RK3568四核ARM Cortex-A55处理器为例，虽然其四颗核心在硬件上同构，但平台通过非对称多处理（AMP）模式实现了功能层面的异构：核心0运行Linux RT操作系统，承载软实时与非实时任务，如人机交互、后台通信，并提供软PLC控制运行时；核心1-3直接运行裸机程序，统一承载硬实时任务，涵盖微秒级高实时控制以及毫秒级保护逻辑等。这种架构既通过核心0的复用提升了CPU资源利用率，又利用核心1-3保证了最苛刻的硬实时性需求。</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="虚拟化从硬件在环到软件在环的闭环验证">虚拟化：从硬件在环到软件在环的闭环验证<a href="http://hcpdoc.samplix.cn/blog/2026/06/16/hcp-design#%E8%99%9A%E6%8B%9F%E5%8C%96%E4%BB%8E%E7%A1%AC%E4%BB%B6%E5%9C%A8%E7%8E%AF%E5%88%B0%E8%BD%AF%E4%BB%B6%E5%9C%A8%E7%8E%AF%E7%9A%84%E9%97%AD%E7%8E%AF%E9%AA%8C%E8%AF%81" class="hash-link" aria-label="Direct link to 虚拟化：从硬件在环到软件在环的闭环验证" title="Direct link to 虚拟化：从硬件在环到软件在环的闭环验证" translate="no">​</a></h4>
<p>虚拟化技术在嵌入式领域早有应用，最著名的当属QEMU。它利用TCG（Tiny Code Generator）技术实现跨架构的动态二进制翻译，使得在x86平台上能够直接运行ARM、PowerPC、RISC-V等架构的二进制程序。这项技术最初是为了让软件开发不依赖实体硬件，与硬件并行推进，从而缩短项目周期。而在当下，虚拟化又被赋予了新的意义：AI天然更易于操作计算机系统而非物理世界，通过虚拟化技术，可以方便地利用AI对控制器软件进行自动化闭环验证。</p>
<p>实际上，控制保护领域广泛使用的硬件在环仿真（HIL）在本质上也是一种虚拟化——它虚拟化了一次设备。将真实控制器接入HIL仿真平台，就能在不接入实际一次设备的情况下验证控制器软件的功能。但主流HIL平台如RTDS、RTLAB等售价高昂，难以大规模配备给每一位开发人员。</p>
<p>为此，HCP平台进一步提出了软件在环闭环验证方案。该方案基于MATLAB、PSCAD等离线仿真环境，并集成了虚拟化指令集模拟技术，使得编译生成的目标机二进制程序能够直接在仿真模型中闭环运行。这就相当于以极低的成本为每一位开发者提供了一个“虚拟硬件在环”环境，可随时对控制保护软件的二进制程序进行全面验证。这一做法大大降低了验证的门槛和成本，显著提升了研发效率。</p>
<p>从AI化的开发范式重构，到融合化的多实时任务统一承载，再到虚拟化的低成本闭环验证，HCP异构控制平台的三大设计理念环环相扣，直指当前控制保护装置开发中最为核心的痛点。它们共同勾勒出了下一代控制平台的发展方向，也为电力系统控制软件的高效、可靠开发提供了更为坚实的技术底座。</p>]]></content:encoded>
            <category>HCP</category>
            <category>设计</category>
            <category>平台</category>
        </item>
        <item>
            <title><![CDATA[SOE 高频上报问题分析与优化报告]]></title>
            <link>http://hcpdoc.samplix.cn/blog/2026/06/15/soe-rpmsg-flow-control</link>
            <guid>http://hcpdoc.samplix.cn/blog/2026/06/15/soe-rpmsg-flow-control</guid>
            <pubDate>Mon, 15 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[一、现象描述与初步分析]]></description>
            <content:encoded><![CDATA[<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="一现象描述与初步分析">一、现象描述与初步分析<a href="http://hcpdoc.samplix.cn/blog/2026/06/15/soe-rpmsg-flow-control#%E4%B8%80%E7%8E%B0%E8%B1%A1%E6%8F%8F%E8%BF%B0%E4%B8%8E%E5%88%9D%E6%AD%A5%E5%88%86%E6%9E%90" class="hash-link" aria-label="Direct link to 一、现象描述与初步分析" title="Direct link to 一、现象描述与初步分析" translate="no">​</a></h4>
<p>在 DAB 功率模块实验过程中，上位机通过 TCP Modbus 与控制器进行通信。控制器启动并运行一段时间后，上位机与控制器之间的 TCP 连接异常中断。随后通过串口登录控制器 Linux 系统进行检查，发现 Linux 侧所有应用程序均已退出，且未生成任何异常退出日志。</p>
<p>问题初期怀疑与程序启动方式有关。由于控制器软件曾通过 SSH 或串口终端远程启动，当调试笔记本与控制器断开连接后，登录 shell 可能被系统回收，进而导致其子进程被动退出。为排除该因素，后续将 Linux 侧启动方式修改为开机自启动，并增加异常退出诊断机制：一方面在应用程序崩溃后自动生成 CoreDump 文件；另一方面修改应用加载程序 <code>hcploader</code>，使其在启动成功后点亮主控板背后的绿色运行指示灯，并捕捉 <code>SIGINT</code>、<code>SIGTERM</code>、<code>SIGQUIT</code>、<code>SIGABRT</code>、<code>SIGSEGV</code>、<code>SIGBUS</code>、<code>SIGILL</code>、<code>SIGFPE</code> 等异常退出信号，在异常退出时点亮红色告警灯。</p>
<p>但在后续实验过程中，问题仍然复现。复现时系统未产生异常日志，未生成 CoreDump 文件，红色告警灯也未点亮。这说明应用程序并未通过上述可捕捉信号正常退出或崩溃退出。结合现象判断，进程存在被系统以不可捕捉信号终止的可能，其中重点怀疑 Linux OOM 机制触发后使用 <code>SIGKILL</code> 杀死进程，导致应用程序无法执行退出处理逻辑。</p>
<p><img decoding="async" loading="lazy" alt="bug_before_usage.png" src="http://hcpdoc.samplix.cn/assets/images/bug_before_usage-51ec3921c31a95f7374c5e82f884a775.png" width="1480" height="827" class="img_ev3q"></p>
<p>再次通过 SSH 登录控制器后，使用 <code>top</code> 命令查看系统资源占用情况，发现 <code>hcploader</code> 进程以及 <code>[irq/81-fe780000]</code> 内核线程的 CPU 和内存占用均异常偏高。进一步查阅 RK3568 硬件手册可知，<code>fe780000</code> 对应 mailbox 硬件模块；在 HCP 平台中，该 mailbox 中断用于 Linux 与裸核引擎之间的消息交互。</p>
<p><img decoding="async" loading="lazy" alt="bug_before_interrupts.png" src="http://hcpdoc.samplix.cn/assets/images/bug_before_interrupts-24824aec341dd399a3a8bc2f2719ba51.png" width="1019" height="212" class="img_ev3q"></p>
<p>随后通过 <code>cat /proc/interrupts</code> 查看系统中断计数，发现 IRQ 216 的触发频率异常，中断计数约以每秒 20k 次的速度增长，该频率与控制周期基本一致。由此基本可以判断，裸核引擎侧 SOE 事件触发频率过高，导致 mailbox 中断持续高频上报，Linux 侧应用程序和中断处理线程来不及处理消息，最终形成消息拥塞和资源持续增长。当系统内存压力进一步增大后，<code>hcploader</code> 等应用进程可能被 Linux OOM 机制杀死，因此未能留下应用层异常日志、CoreDump 文件或红色异常灯状态。</p>
<p>综上，当前问题的直接表现为 Linux 侧应用程序异常消失；其可能原因并非普通程序崩溃，而是 SOE 高频触发导致 Linux 与裸核之间的消息通道拥塞，进一步引发系统资源耗尽，并最终触发 OOM 杀进程机制。</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="二-soe-实现机制的问题分析">二、 SOE 实现机制的问题分析<a href="http://hcpdoc.samplix.cn/blog/2026/06/15/soe-rpmsg-flow-control#%E4%BA%8C-soe-%E5%AE%9E%E7%8E%B0%E6%9C%BA%E5%88%B6%E7%9A%84%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90" class="hash-link" aria-label="Direct link to 二、 SOE 实现机制的问题分析" title="Direct link to 二、 SOE 实现机制的问题分析" translate="no">​</a></h4>
<p>结合 HCP 引擎侧 SOE 的实现机制分析，本次异常退出问题与 SOE 高频变位上报具有直接关联。</p>
<p>HCP 引擎中的 SOE 并不是由硬件中断直接触发，而是在每个 FB 任务周期末尾进行扫描。任务调度流程中，<code>hcp_soe_scan()</code> 位于 <code>pre_task</code>、<code>run</code>、<code>post_task</code> 之后执行：</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">void</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">hcp_task_handler</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">void</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token class-name" style="color:rgb(255, 203, 107)">uint64_t</span><span class="token plain"> start_time</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> end_time</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> exec_time</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    start_time </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">HAL_GetSysTimerCount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token function" style="color:rgb(130, 170, 255)">HCP_LIKELY</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token function" style="color:rgb(130, 170, 255)">hcp_fb_is_ready</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token function" style="color:rgb(130, 170, 255)">hcp_fb_pre_task</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token function" style="color:rgb(130, 170, 255)">hcp_fb_run</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token function" style="color:rgb(130, 170, 255)">hcp_fb_post_task</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token function" style="color:rgb(130, 170, 255)">hcp_soe_scan</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token function" style="color:rgb(130, 170, 255)">hcp_fault_scan</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>这种设计可以保证 SOE 扫描时，输入已经更新、功能块逻辑已经执行完成、输出结果也已经写出。此时读取功能块成员变量，得到的是本周期最终稳定值，可以避免扫描到中间态数据。但这也意味着，SOE 的扫描频率基本等于 FB 任务周期。如果 FB 任务周期为 50 μs，则 SOE 扫描频率约为 20 kHz。</p>
<p>SOE 监测点注册后，引擎会保存被监测变量的内存地址以及上一次扫描值：</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">typedef</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">struct</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token class-name" style="color:rgb(255, 203, 107)">uint8_t</span><span class="token plain"> active</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token class-name" style="color:rgb(255, 203, 107)">uint8_t</span><span class="token plain"> value_type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token class-name" style="color:rgb(255, 203, 107)">uint8_t</span><span class="token plain"> width</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token class-name" style="color:rgb(255, 203, 107)">uint8_t</span><span class="token plain"> reserved</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">volatile</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">void</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">*</span><span class="token plain">addr</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain">      </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">/* 被监测变量地址 */</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token class-name" style="color:rgb(255, 203, 107)">uint32_t</span><span class="token plain"> current_raw</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain">     </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">/* 上一次扫描值 */</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">hcp_soe_entry_t</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>每次执行 <code>hcp_soe_scan()</code> 时，引擎都会读取当前值，并与 <code>current_raw</code> 进行比较。如果值发生变化，则生成 SOE 通知并通过 rpmsg 信道发送给 Linux 侧：</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">void</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">hcp_soe_scan</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">void</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">hcp_soe_flush_pending</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">for</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">i </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> i </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain"> s_active_count</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">++</span><span class="token plain">i</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        next_raw </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">hcp_soe_read_raw</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">entry</span><span class="token operator" style="color:rgb(137, 221, 255)">-&gt;</span><span class="token plain">addr</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> entry</span><span class="token operator" style="color:rgb(137, 221, 255)">-&gt;</span><span class="token plain">value_type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">next_raw </span><span class="token operator" style="color:rgb(137, 221, 255)">==</span><span class="token plain"> entry</span><span class="token operator" style="color:rgb(137, 221, 255)">-&gt;</span><span class="token plain">current_raw</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token keyword" style="font-style:italic">continue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        notify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">engine_index </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> i</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        notify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">timer5_count </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">HAL_GetSysTimerCount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        notify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">old_raw_u32  </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> entry</span><span class="token operator" style="color:rgb(137, 221, 255)">-&gt;</span><span class="token plain">current_raw</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        notify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">new_raw_u32  </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> next_raw</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        entry</span><span class="token operator" style="color:rgb(137, 221, 255)">-&gt;</span><span class="token plain">current_raw </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> next_raw</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token function" style="color:rgb(130, 170, 255)">hcp_soe_send_notify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">&amp;</span><span class="token plain">notify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>由此可见，只要某个 SOE 监测变量在相邻两个任务周期之间持续变化，就会在每个任务周期都触发一次 SOE 通知。例如，如果将周期计数器、实时采样值、中间计算量、调试变量或快速翻转的状态量注册为 SOE 监测点，就可能导致 SOE 事件以控制周期频率持续产生。</p>
<p>SOE 通知通过独立 rpmsg 信道发送，发送方式为非阻塞：</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">int</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">hcp_soe_send_notify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">hcp_soe_notify_t</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">*</span><span class="token plain">notify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    ret </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">rpmsg_lite_send</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">s_rpmsg</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">                          s_soe_ept</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">                          s_linux_soe_ept_addr</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">                          </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">char</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">*</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain">notify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">                          </span><span class="token keyword" style="font-style:italic">sizeof</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">*</span><span class="token plain">notify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">                          RL_DONT_BLOCK</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">ret </span><span class="token operator" style="color:rgb(137, 221, 255)">==</span><span class="token plain"> RL_SUCCESS</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>非阻塞发送可以避免 Linux 侧处理较慢时反向阻塞引擎实时任务，但该机制本身没有流控能力。也就是说，引擎只负责按照 SOE 变位产生速度持续发送通知，并不会等待 Linux 侧处理完成。当 SOE 触发频率过高时，Linux 侧会被大量 rpmsg 消息持续打断和唤醒。</p>
<p>本次实验中，通过 <code>/proc/interrupts</code> 观察到 IRQ 216 的中断计数约以每秒 20k 次增长，该频率与控制任务周期基本一致。而 <code>[irq/81-fe780000]</code> 对应 RK3568 mailbox 中断处理线程，在 HCP 平台中用于 Linux 与裸核引擎之间的 rpmsg 消息交互。因此可以判断，引擎侧很可能存在 SOE 监测点在每个 FB 周期都发生变位，导致 SOE 通知以约 20k/s 的频率持续上报，从而引起 mailbox 中断异常频繁触发。</p>
<p>Linux 侧 <code>hcp_soe_service</code> 接收到 SOE 通知后，还需要完成事件解析、时间戳校正、CSV 文件写入以及 NNG 消息发布等处理。当 SOE 事件以 20k/s 左右的速率持续输入时，Linux 侧处理能力可能不足，进而造成 CPU 占用升高、消息积压、文件写入压力增大以及内存占用持续增长。</p>
<p>因此，本次问题可以归纳为以下链路：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">SOE 注册点包含高频变化变量</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        ↓</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">每个 FB 任务周期都检测到变位</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        ↓</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">引擎通过 rpmsg SOE 信道持续发送通知</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        ↓</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">RK3568 mailbox 中断被高频触发</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        ↓</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">IRQ 216 中断计数约 20k/s 增长</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        ↓</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">Linux 侧 hcp_soe_service 处理不过来</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        ↓</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">CPU 和内存占用异常升高</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        ↓</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">系统触发 OOM，应用进程被 SIGKILL 杀死</span><br></div></code></pre></div></div>
<p>由于 <code>SIGKILL</code> 无法被应用程序捕捉，进程在被 OOM 杀死前无法执行异常处理逻辑。因此，即使 <code>hcploader</code> 已经注册了异常信号处理函数，也不会生成应用层异常日志，不会生成普通崩溃路径下的 CoreDump 文件，红色异常灯也不会被点亮。</p>
<p>综上，本次现象更符合“SOE 高频变位上报导致 Linux 侧 rpmsg/mailbox 消息拥塞，最终引起资源耗尽并触发 OOM 杀进程”的故障链路，而不是普通程序崩溃或可捕捉异常退出。</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="三修改方案增加-soe-rpmsg-发送侧流控机制">三、修改方案：增加 SOE rpmsg 发送侧流控机制<a href="http://hcpdoc.samplix.cn/blog/2026/06/15/soe-rpmsg-flow-control#%E4%B8%89%E4%BF%AE%E6%94%B9%E6%96%B9%E6%A1%88%E5%A2%9E%E5%8A%A0-soe-rpmsg-%E5%8F%91%E9%80%81%E4%BE%A7%E6%B5%81%E6%8E%A7%E6%9C%BA%E5%88%B6" class="hash-link" aria-label="Direct link to 三、修改方案：增加 SOE rpmsg 发送侧流控机制" title="Direct link to 三、修改方案：增加 SOE rpmsg 发送侧流控机制" translate="no">​</a></h4>
<p>针对 SOE 高频变位导致 Linux 侧 rpmsg/mailbox 消息拥塞的问题，本次修改在引擎侧 SOE 发送路径中增加流控机制。修改目标是在不影响 FB 实时任务执行的前提下，限制单位时间内实际发送到 Linux 侧的 SOE 通知数量，避免故障动作或异常变位风暴场景下，Linux 侧 <code>hcp_soe_service</code> 因持续处理高频 SOE 消息而出现 CPU 占满、内存增长、系统卡顿甚至 OOM 杀进程的问题。</p>
<p>原有 SOE 机制中，<code>hcp_soe_scan()</code> 在每个 FB 任务周期末尾执行。只要监测点发生变位，引擎就会立即通过 rpmsg SOE 信道向 Linux 侧发送 <code>hcp_soe_notify_t</code> 通知。该发送过程采用非阻塞方式，可以保证 Linux 侧处理较慢时不会反向阻塞引擎实时任务，但原机制缺少发送速率限制。当 SOE 监测点出现控制周期级变位时，Linux 侧可能在短时间内收到大量通知，最终造成消息处理拥塞。</p>
<p>本次修改采用基于 TIMER5 计数的秒级窗口限速方案。TIMER5 频率为 24 MHz，即 1 秒对应 24,000,000 个 tick。引擎侧通过当前 <code>HAL_GetSysTimerCount()</code> 计算当前所处的秒级窗口，并统计该窗口内已经成功发送的 SOE 通知数量。每个 CPU 核每秒最多允许实际发送 256 条 SOE 通知，超过该数量后，新的 SOE 变位通知将被主动丢弃并累计丢弃计数。</p>
<p>核心限速逻辑如下：</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="font-style:italic">define</span><span class="token macro property"> </span><span class="token macro property macro-name">HCP_SOE_TICKS_PER_SEC</span><span class="token macro property">   </span><span class="token macro property expression">PLL_INPUT_OSC_RATE</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token macro property directive-hash">#</span><span class="token macro property directive keyword" style="font-style:italic">define</span><span class="token macro property"> </span><span class="token macro property macro-name">HCP_SOE_MAX_PER_SEC</span><span class="token macro property">     </span><span class="token macro property expression number" style="color:rgb(247, 140, 108)">256U</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">uint64_t</span><span class="token plain"> s_rate_window</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">uint32_t</span><span class="token plain"> s_rate_sent</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">int</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">hcp_soe_rate_check</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">void</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token class-name" style="color:rgb(255, 203, 107)">uint64_t</span><span class="token plain"> now </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">HAL_GetSysTimerCount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token class-name" style="color:rgb(255, 203, 107)">uint64_t</span><span class="token plain"> window </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> now </span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token plain"> HCP_SOE_TICKS_PER_SEC</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">window </span><span class="token operator" style="color:rgb(137, 221, 255)">!=</span><span class="token plain"> s_rate_window</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        s_rate_window </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> window</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        s_rate_sent </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0U</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">s_rate_sent </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain"> HCP_SOE_MAX_PER_SEC</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>流控逻辑加在真正调用 <code>hcp_soe_send_notify()</code> 之前。对于新检测到的 SOE 变位，如果当前秒级窗口仍有发送配额，则正常发送；只有发送成功后才累计 <code>s_rate_sent</code>。如果当前窗口配额已经用尽，则该条新变位通知直接丢弃，并累计背压丢弃计数。</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">entry</span><span class="token operator" style="color:rgb(137, 221, 255)">-&gt;</span><span class="token plain">current_raw </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> next_raw</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain">   </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">/* 本地状态先更新 */</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token function" style="color:rgb(130, 170, 255)">hcp_soe_rate_check</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    s_backpressure_drop_count</span><span class="token operator" style="color:rgb(137, 221, 255)">++</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">continue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token function" style="color:rgb(130, 170, 255)">hcp_soe_send_notify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">&amp;</span><span class="token plain">notify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">!=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">hcp_soe_enqueue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">&amp;</span><span class="token plain">notify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">else</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    s_rate_sent</span><span class="token operator" style="color:rgb(137, 221, 255)">++</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>对于 pending 队列中的历史待发送通知，处理策略与新变位不同。pending 队列中的消息表示此前已经检测到变位并完成组包，只是由于 rpmsg 通道暂时不可发送而进入重试队列。因此，当本秒发送配额用尽时，pending 消息不会被丢弃，而是保留在队列中，等待下一秒窗口恢复后继续发送。</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">while</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">s_pending_count </span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0U</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token function" style="color:rgb(130, 170, 255)">hcp_soe_rate_check</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain">   </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">/* 本秒配额用尽，保留 pending 队列 */</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token function" style="color:rgb(130, 170, 255)">hcp_soe_send_notify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">&amp;</span><span class="token plain">notify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">!=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain">   </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">/* rpmsg 仍发送失败，下周期继续重试 */</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    s_rate_sent</span><span class="token operator" style="color:rgb(137, 221, 255)">++</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">/* 发送成功后再出队 */</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>本次修改后，SOE 丢弃分为两类：一类是原有 pending 队列满导致的丢弃，表示 rpmsg 发送失败后重试缓冲区溢出；另一类是新增的流控丢弃，表示当前秒级窗口发送配额已经用尽，新产生的 SOE 变位被主动丢弃。新增流控丢弃计数通过 <code>s_backpressure_drop_count</code> 统计，并通过 <code>GET_STATUS</code> 接口上报为 <code>soe_drop_count</code>，最终由 debug adapter 转换为 JSON 字段 <code>soeDropCount</code>，并在上位机 Resource Explorer 中显示为 <code>SOE: dropped N</code>。这样现场人员可以直接观察当前是否发生 SOE 背压丢弃，从而判断系统是否仍存在高频 SOE 变位问题。</p>
<p>本方案的主要特点是：流控完全在引擎发送侧实现，不依赖 Linux 侧 ACK 或协议交互；使用已有 TIMER5 时间基准，与 SOE 通知时间戳体系一致；每核每秒 256 条的发送上限能够满足一般 SOE 事件记录需求，同时可以有效抑制控制周期级变位风暴；超限丢弃具备可观测性，便于现场定位和验证。</p>
<p>需要说明的是，该方案的目标是保护 Linux 侧系统资源，避免 SOE 高频上报拖垮 rpmsg、CSV 写入和 NNG 发布链路，并不保证 SOE 事件的完整可靠传输。当系统进入流控状态后，部分新变位事件会被主动丢弃，且由于 <code>current_raw</code> 已经更新，这些事件后续无法恢复。因此，后续仍需要从配置和应用层面避免将周期计数器、实时采样值、中间计算量、快速翻转状态量等控制周期级变化变量注册为 SOE 监测点。</p>
<p>综上，本次修改通过“秒级窗口限速 + 新变位主动丢弃 + pending 跨窗口保留重试 + 丢弃计数上报”的方式，在引擎侧为 SOE rpmsg 通道增加了基础背压保护能力。该机制可以有效降低 SOE 变位风暴对 Linux 侧的冲击，避免因 mailbox 中断和用户态 SOE 处理链路长期过载而引发系统资源耗尽</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="四修改后验证结果">四、修改后验证结果<a href="http://hcpdoc.samplix.cn/blog/2026/06/15/soe-rpmsg-flow-control#%E5%9B%9B%E4%BF%AE%E6%94%B9%E5%90%8E%E9%AA%8C%E8%AF%81%E7%BB%93%E6%9E%9C" class="hash-link" aria-label="Direct link to 四、修改后验证结果" title="Direct link to 四、修改后验证结果" translate="no">​</a></h4>
<p><img decoding="async" loading="lazy" alt="bug_after_explore.png" src="http://hcpdoc.samplix.cn/assets/images/bug_after_explore-eb167ecc941838e45b75aa9b26b64d40.png" width="1616" height="1069" class="img_ev3q"></p>
<p>完成 SOE rpmsg 发送侧流控修改后，再次进行 DAB 功率模块实验验证。从上位机 Resource Explorer 观察结果看，Core 1 页面已经能够正常显示 SOE 背压丢弃统计，当前显示 <code>SOE: dropped 6026052</code>，说明引擎侧限流机制已经生效：当 SOE 变位事件超过每秒发送上限后，新产生的 SOE 通知被主动丢弃并累计计数，而不是继续无速率限制地推送给 Linux 侧。</p>
<p><img decoding="async" loading="lazy" alt="bug_after_usage.png" src="http://hcpdoc.samplix.cn/assets/images/bug_after_usage-22dc0b08952741fadf0d8c0b9e7aaa73.png" width="1434" height="384" class="img_ev3q"></p>
<p>同时，通过控制器 Linux 侧 <code>top</code> 命令观察系统资源占用情况，系统总体 CPU 占用明显降低，CPU 空闲率保持在约 75%，内存占用也保持在较低水平，未再出现修改前 <code>hcploader</code> 和 mailbox 中断线程长时间高负载、内存持续增长的现象。当前 <code>hcploader</code>、<code>hcp_modbus</code>、<code>hcprecord</code> 等应用进程仍保持正常运行，说明 SOE 高频变位虽然仍然存在，但其对 Linux 侧 rpmsg 接收、CSV 写入和 NNG 发布链路的冲击已经被有效抑制。</p>
<p>从验证结果看，本次修改达到了预期目标：当现场存在 SOE 变位风暴时，引擎侧能够通过秒级窗口限速主动削峰，避免 SOE 消息持续压垮 Linux 侧处理链路；同时，丢弃事件能够通过 <code>soeDropCount</code> 上报到上位机界面，便于现场判断当前是否存在 SOE 高频触发问题。后续仍需进一步排查具体 SOE 注册点，避免将周期计数器、实时采样值、快速翻转状态量等高频变化变量配置为 SOE 监测对象。</p>]]></content:encoded>
            <category>SOE</category>
            <category>rpmsg</category>
            <category>Linux</category>
            <category>性能优化</category>
        </item>
    </channel>
</rss>