跳转至

P5.U-perf-service · 性能监控 per-module 实装(ADR-AIOS-08 §2.3 fork)

目标 worker:ClaudeB(主仓 04_development/ · P5-backend-csharp 主战场) [涉及部门]:后端 (backend-csharp) · 推荐 skill:dotnet-realtime-communication 预计:2.0d · 优先级:P1 · 状态:⚪ ready(2026-05-30 09:09 派发 · ADR-AIOS-08 accepted v1.1)


🔍 触发与解锁链

触发 hash 状态 影响
ADR-AIOS-08 accepted v1.1 2026-05-29 17:25 ✅ 用户拍板 10 fork U-thread 启动 · 后端三线先派
用户拍板方向 A 就地扩展 2026-05-30 09:00 ✅ 用户原话 "zhujian" ❗ 不许新建 PerformanceService 类 · 必须扩展 MetricsAggregator
MetricsAggregator.cs(167 行) 已实装 Phase 8 ✅ 永久 系统级 metrics_update 100ms 推送已就位 · 本任务填充 per-module
DspManifestInterop.TryGetMetrics 已实装 ✅ 永久 DLL 暴露聚合 CPU% · per-module 字段需 P6-dsp 配合

→ 跨栈独立(后端 .NET) · 不修改 contract-v1.0(已 frozen) · 走 dev-api GET /api/perf/per-module(待 K2-protocol-v2 正式入)。


完整 prompt(直接复制粘贴 worker 终端)

[U-thread]   P5.U-perf-service
[部门]       后端 .NET · ADR-AIOS-08 §2.3 性能监控实装 · skill: dotnet-realtime-communication
[Worker CWD] d:/work/25_claude/workspace/AlgoDepartment/04_development/
[Occupies]   P5.K-services-metrics(write · 扩展 MetricsAggregator + 新增 PerModuleMetricsCollector) + P5.K-api-routes(write · 新增 /api/perf/per-module) + P5.K-controllers(write · 新增 PerfController)
[优先级]     P1 · 2.0d · 跨栈独立 · 与 P5.U-error-channel(0.5d) / P5.U-runtime-mode-refactor(2.0d) 同 ClaudeB 并行(三 fork 文件正交)
[ADR]        d:/work/25_claude/workspace/AlgoDepartment/06_docs/site-build/docs/08-implementation/40-aios/ADR/ADR-AIOS-08-xilink-stage-ux.md (§2.3 + §3.2 边界铁律 #5 + §4.1 fork P5.U-perf-service)
[参考文档]
  - 上述 ADR 主文(accepted v1.1)· 重点读 §2.3 双层界面(Layer 1 概况 + Layer 2 Per-Module 表格)+ §3.2 边界铁律 #5(perf 数据采集复用现有进程 · 严禁起 daemon)+ §4.1 fork 实施清单
  - 同部门标本(强制 read · 4 维度对齐):d:/work/25_claude/workspace/AlgoDepartment/06_docs/site-build/docs/08-implementation/40-aios/prompts/done/P5.U-meter-tap-multi-tool--48cf0ba.md(同部门 ClaudeB · 同 P5 · 同 WS 路由 · MeterToolRouter 模式参考)
  - **🚨 现状必读(本 fork 核心 · "就地扩展"方向用户已拍板 · 不许新建 PerformanceService 类)**:
    · backend_csharp/Services/Metrics/MetricsAggregator.cs(167 行 · Phase 8 已实装 · 重点读全文):
      - 第 7-13 行 ModuleMetrics(已定义 InstanceId / ProcessTimeUs / ProcessTimeUs_Ewma / CpuPercentOfBlock)
      - 第 15-24 行 MetricsSnapshot(已定义 CpuLoadPercent/Peak/Underrun/Overrun/TotalLatencyMs/Modules/TimestampMs)
      - 第 30-167 行 MetricsAggregator(100ms 定时聚合 + EWMA + DspManifestInterop.TryGetMetrics + WS broadcast metrics_update)
      - ⚠️ 第 134 行 `Modules = new List<ModuleMetrics>()` 当前永远是空 list(本任务的核心填充点)
    · backend_csharp/Interop/DspManifestInterop.cs(看 TryGetMetrics 现状 · 是否能拿 per-module · 如果不能 · 本任务做 EWMA 聚合方案)
    · backend_csharp/Services/AudioEngine/AudioEngineService.cs / AudioEngineChainBuilder.cs(看 module 实例如何创建/索引 · 拿 instanceId 列表)
    · backend_csharp/Services/AudioEngine/WasapiDrivenEngine.cs(看 RecordBlockTime 调用方 · 看是否能扩展为 per-module 计时)
    · backend_csharp/Routes/(看现有 REST 路由风格 · 如 LegacyTestRoutes / MeterDevApiRoutes)
  - 上游 ADR:d:/work/25_claude/workspace/AlgoDepartment/06_docs/site-build/docs/08-implementation/40-aios/ADR/ADR-AIOS-07-p3-p4-overlap.md(§1.3.4 三层分工铁律 · 必读)
  - contract-v1.0(已 frozen · 不修改):d:/work/25_claude/workspace/AlgoDepartment/06_docs/site-build/docs/08-implementation/40-aios/contracts/protocol-v1.md(本任务走 dev-api · 待 K2-protocol-v2 正式入)
  - 同期派发 P5.U-error-channel(读以同步 namespace · 避免冲突):d:/work/25_claude/workspace/AlgoDepartment/06_docs/site-build/docs/08-implementation/40-aios/prompts/active/P5.U-error-channel.md

【背景】
ADR-AIOS-08 已 accepted v1.1(2026-05-29 17:25)· 用户 2026-05-30 09:00 拍板「方向 A 就地扩展」原话"zhujian"。

🚨 **真值核查发现**(.clinerules v1.3 §🚨 真值核查铁律):
ADR-08 §1.3 第二份 subagent 核查写"无 PerformanceService / MetricsService / TelemetryService"是字面正确(类名确实没有) · 但 **`MetricsAggregator.cs` 已存在 167 行 · 已实装 100ms 定时 metrics_update WS 广播 + EWMA + DspManifestInterop.TryGetMetrics 对接** · 系统级指标 99% 就位 · 仅 per-module 数据未填充(第 134 行空 list)。

**本任务核心**:**扩展不重写**。
- ✅ 把 `MetricsAggregator.MetricsSnapshot.Modules` 字段从空 list 填实(per-module 数据)
- ✅ 新增 `PerModuleMetricsCollector` 服务 · 从 AudioEngine 链路实例 + DLL DspManifestInterop 收集 per-module 指标
- ✅ 新增 REST `GET /api/perf/per-module` · 拉详细模块级表格(ADR §2.3 Layer 2)
- ❌ **不新建 `PerformanceService` 类**(避免与 MetricsAggregator 命名重叠)
- ❌ **不新建 `/ws/perf` channel**(现有 100ms `metrics_update` 已足够 · ADR 1Hz 是字面要求 · 实测 100ms 更好)
- ❌ **不改 100ms 定时频率**(零回归)

**ADR §2.3 双层界面**:
- Layer 1 概况(系统级):CPU% / Mem / Latency / Buffer / TickHz · ✅ 现有 metrics_update 已含 4 项 · 仅缺 Mem 和 TickHz · 本任务补
- Layer 2 详细(per-module):每模块 PeakCPU / AvgCPU / PeakMem / TickRate · ❌ 当前空 · 本任务核心实装

**DLL 配合策略**(.clinerules §跨栈协作):
- DspManifestInterop.TryGetMetrics 当前只暴露聚合 · 若 DLL 不能拿 per-module → 本任务用 .NET 端 RecordBlockTime 现有 EWMA 机制 + module 实例列表 + 模拟 / 估算 per-module(避免阻塞 P6)
- commit message 写 `[need: ClaudeB-P6] expose DSPAlgo_GetPerModuleMetrics(moduleId, out ModuleMetrics)` 留 P6 后续接入(本任务先用估算)

**契约策略**:不修改 contract-v1.0(已 frozen) · `metrics_update` WS 字段扩展(向后兼容)+ `/api/perf/per-module` 走 dev-api 桥接(待 K2-protocol-v2 正式入)。

【执行步骤】
1. 自查 + 读现状(必读 · 本 fork 核心):
   git status                                           # 工作区干净
   git branch --show-current                            # = xistudio
   git pull origin xistudio --no-rebase                 # 拿同期派 P5.U-error-channel(若已 push)
   # 必读现状(>= 5 文件):
   cat backend_csharp/Services/Metrics/MetricsAggregator.cs                 # 167 行全文
   cat backend_csharp/Interop/DspManifestInterop.cs                         # 看 TryGetMetrics 字段
   cat backend_csharp/Services/AudioEngine/AudioEngineChainBuilder.cs       # 看 module 实例创建/索引
   cat backend_csharp/Services/AudioEngine/WasapiDrivenEngine.cs            # 看 RecordBlockTime 调用方
   ls backend_csharp/Routes/                                                 # 看 REST 路由风格

2. 扩展 backend_csharp/Services/Metrics/MetricsAggregator.cs(就地扩展 · 不重命名类):
   - **保留** Phase 8 现有 100ms 定时 + EWMA + metrics_update 广播(零回归)
   - 第 22 行 `MetricsSnapshot` 加可选字段:
     · long ProcessMemoryBytes      // 系统级内存(System.Diagnostics.Process.GetCurrentProcess().WorkingSet64)
     · int  TickRateHz              // 系统级 Tick 频率(48000 / blockSize · 从 LinkPropagator 拿 blockSize 推算)
   - 第 7-13 行 `ModuleMetrics` 加字段:
     · double PeakCpuPercent        // 模块级峰值 CPU%
     · double AvgCpuPercent         // 模块级平均 CPU%(沿用 CpuPercentOfBlock 现有概念)
     · long   PeakMemoryBytes       // 模块级峰值内存(估算 · 见 step 3)
     · int    ModuleTickRateHz      // 模块级采样率(从 SignalProvider 拿)
   - 第 96-166 行 `Aggregate()` 内部:
     · 在现有 systemic 指标聚合后 · 调 PerModuleMetricsCollector.Collect() 填 snapshot.Modules
     · WS 广播 metrics_update JSON 增加 modules 数组(每元素含 InstanceId + 4 新字段)· **向后兼容**(旧客户端忽略新字段)

3. 新增 backend_csharp/Services/Metrics/PerModuleMetricsCollector.cs(独立收集器):
   - public interface IPerModuleMetricsCollector {
       List<ModuleMetrics> Collect();              // 100ms 调一次
       ModuleMetrics? GetByInstanceId(string instanceId);  // REST 端点用
       void RecordModuleBlockTime(string instanceId, double processTimeUs);  // 后续 dsp 端可用
     }
   - 数据来源(优先级):
     · ① P6-DLL DspManifestInterop.TryGetPerModuleMetrics(可选 · DLL 未实装则 fallback)
     · ② .NET 端 EWMA 估算:从 AudioEngineChainBuilder 拿 module 实例列表 + 复用 MetricsAggregator EWMA · 按 module 占用比例分配
     · ③ Memory 用 ProcessMemoryUsage 总值 / module 数(粗估 · 留 P6 精确化)
   - ❌ 不做 FFT/RMS/相位等数学(三层分工铁律)· 仅做计数/聚合/字段映射

4. DI 注册(Program.cs):
   - AddSingleton<IPerModuleMetricsCollector, PerModuleMetricsCollector>()
   - 验证 MetricsAggregator 已注册(应已落)
   - 注入 PerModuleMetricsCollector 到 MetricsAggregator(若用构造函数 · 注意循环依赖)

5. 新增 backend_csharp/Models/Perf/(目录新建):
   - PerfPerModuleResponse.cs(record · REST /api/perf/per-module 响应):
     · List<ModuleMetricsRow> Modules(InstanceId/ModuleType/PeakCpu/AvgCpu/PeakMem/TickRate)
     · long TimestampMs
     · string SortBy(默认 "PeakCpuDesc" · 可选 "AvgCpu" / "PeakMem")

6. 新增 backend_csharp/Controllers/Perf/PerfController.cs:
   - [Route("api/perf")](走 /api/perf/* · 命名空间统一)
   - GET /api/perf/per-module:可选 query ?sortBy=PeakCpu|AvgCpu|PeakMem(默认 PeakCpu)· 返回 PerfPerModuleResponse
   - 调 IPerModuleMetricsCollector.Collect() · 排序 · 包装返回
   - 错误处理:链路未启动返回 200 + 空 modules · 内部错误 500
   - **不修改既有** REST(零回归)

7. 单测 + 验收:
   cd backend_csharp
   # 新增 Tests/Services/Metrics/PerModuleMetricsCollectorTests.cs(>= 4 case:Collect 空链路 + 单 module + 多 module + GetByInstanceId)
   # 新增 Tests/Services/Metrics/MetricsAggregatorPerModuleTests.cs(>= 2 case:扩展 Aggregate 后 modules 字段填充 + JSON 序列化向后兼容)
   # 新增 Tests/Controllers/Perf/PerfControllerTests.cs(>= 3 case:默认排序 + sortBy=AvgCpu + 空链路 200)
   # 至少 9 个新 case
   dotnet build                                         # 零错误零警告
   dotnet test                                          # 通过 + 新增 >= 9 用例(基线 147/0 → >= 156/0)
   # 手动 e2e(可选):
   curl http://localhost:5000/api/perf/per-module?sortBy=PeakCpu

8. Commit + push:
   git add backend_csharp/Services/Metrics/ \
           backend_csharp/Models/Perf/ \
           backend_csharp/Controllers/Perf/ \
           backend_csharp/Tests/Services/Metrics/ \
           backend_csharp/Tests/Controllers/Perf/ \
           backend_csharp/Program.cs
   git commit -m "..."(见下)
   git push origin xistudio

【验收】
- 8-10 文件落地(Services/Metrics ×2 改动 + Models/Perf ×1 + Controllers/Perf ×1 + Tests ×3 + Program.cs DI)
- dotnet build 零错误零警告 · dotnet test 全绿(基线 147/0 → >= 156/0 · +9 用例)
- ✅ **现状未破坏**:旧 metrics_update 100ms 推送(零回归 · 现有 4 字段 cpuLoadPercent/cpuLoadPeak/underrunCount/overrunCount 完整 · 新增 modules 数组 + processMemoryBytes + tickRateHz)
- ✅ **per-module 数据可见**:metrics_update 推送时 modules 数组非空(非空链路场景)· 单测覆盖
- ✅ **REST 端点可达**:GET /api/perf/per-module 返回 200 + 排序正确 · Swagger UI 可见
- ❌ **PR 自查 1**:确认未新建 PerformanceService 类(grep "class PerformanceService" 应零命中)
- ❌ **PR 自查 2**:确认未新建 /ws/perf channel(grep "ws/perf" 应在 Tests 之外零命中)
- ❌ **PR 自查 3**:确认 Aggregate() 100ms 频率未改(diff 第 70 行 TimeSpan.FromMilliseconds(100) 应保持)
- ❌ **PR 自查 4**:确认 .NET 代码零数学(grep MathNet|FFT|fft 在 Tests 之外零命中)· 所有数学走 P6-DLL 或 P7-pysidecar
- 三元组 trailer 完整 · commit hash 7 位

【commit】
commit subject:`feat(P5): fill MetricsAggregator per-module + add /api/perf/per-module REST (in-place expansion · backward-compat) [ADR-AIOS-08 §2.3 fork]`

trailer(必须精确):
[step=1/1] [pid=P5] [uid=U-perf-service] [occupies=P5.K-services-metrics+P5.K-api-routes+P5.K-controllers]
[files=backend_csharp/Services/Metrics/MetricsAggregator.cs, backend_csharp/Services/Metrics/PerModuleMetricsCollector.cs, backend_csharp/Models/Perf/**, backend_csharp/Controllers/Perf/PerfController.cs, backend_csharp/Tests/Services/Metrics/**, backend_csharp/Tests/Controllers/Perf/**, backend_csharp/Program.cs]
[ipc=ws/metrics_update(extended-modules-field), api/perf/per-module]
[need: ClaudeB-P6] expose DSPAlgo_GetPerModuleMetrics(instanceId, out ModuleMetrics) for accurate per-module data (current using .NET EWMA estimation)

回告格式参考 done/P5.U-meter-tap-multi-tool--48cf0ba.md 末尾(同部门 · 同 metrics 模式)。

【禁止】
- ❌ **不许新建 PerformanceService / MetricsService / TelemetryService 类**(用户拍板方向 A 就地扩展 · 必须扩展现有 MetricsAggregator)
- ❌ **不许新建 /ws/perf WS channel**(现有 metrics_update 100ms 已足够)
- ❌ **不许改 100ms 定时频率**(MetricsAggregator 第 70 行 TimeSpan.FromMilliseconds(100) 零修改 · ADR §2.3 1Hz 字面要求让位现实)
- ❌ **不许在 .NET 实装数学计算**(FFT / RMS / 相位 / 功率谱 / 频域分析 全部禁止 · 三层分工铁律 ADR-07 §1.3.4)
- ❌ **不许引入 MathNet.Numerics / Accord.NET / 任何 .NET 数学库**
- ❌ 不许修改 contracts/protocol-v1.md(已 frozen · 留 K2-protocol-v2)
- ❌ 不许修改 MetricsAggregator 第 154-165 行 error_event 广播(同期派 P5.U-error-channel 拥有此区域所有权)
- ❌ 不许改前端代码(P1.U-perf-monitor-frontend 由 ClaudeA 跑)
- ❌ 不许改 P6-dsp_algo / pysidecar 代码(留 commit trailer [need: ClaudeB-P6] 协调)
- ❌ 不许跳验收 · dotnet build/test 任一红必须修到全绿
- ❌ 不许省略三元组 trailer
- ❌ 不许自改本 prompt 文件

解锁链(本任务 zombie 后)

  • ✅ P1.U-perf-monitor-frontend 解锁(前端 ClaudeA · 1.5d · DrawerMetrics 双层显示 · 切真接口 metrics_update 扩展字段 + /api/perf/per-module)
  • ✅ ADR-AIOS-08 §2.3 后端侧落地 · per-module 数据从空到非空
  • ✅ 给 P6-dsp_algo 留 [need: ClaudeB-P6] trailer · 后续 DLL 精确化
  • ✅ K2-protocol-v2 起草时(P_contracts.U-protocol-v2-bootstrap)有 PerfFrame 实测数据支撑

风险评估

风险 缓解
DLL DspManifestInterop 不能拿 per-module · 估算误差大 文档明确"本期 .NET EWMA 估算" · commit trailer [need: ClaudeB-P6] 留 P6 精确化 · ADR §2.3 双层界面 Layer 2 标 "estimated" 字段
Aggregate() 加 PerModuleCollect 调用增 100ms 周期开销 Collect() 必须 lock-free / O(N modules) · 测量 N=20 模块场景 < 0.5ms · 不影响 100ms 周期
ProcessMemoryUsage 在 Linux/Windows 行为差异 用 System.Diagnostics.Process.GetCurrentProcess().WorkingSet64(跨平台 OK)· 单测不依赖具体值 · 仅测字段非零
MetricsAggregator + PerModuleMetricsCollector 循环依赖 PerModuleMetricsCollector 不依赖 MetricsAggregator · MetricsAggregator 单向依赖 PerModuleMetricsCollector · DI 顺序 PerModule 先
同期 P5.U-error-channel commit 冲突 MetricsAggregator 本任务改 22-24 行(MetricsSnapshot 字段) + 96-150 行(Aggregate 体) · error-channel 改 154-165 行(error_event)· 文件正交 · 同 push 周期可合并

历史

时间 事件 hash
2026-05-30 09:09 首次派发(ADR-AIOS-08 accepted v1.1 后第 2 个后端 fork · 用户拍板方向 A 就地扩展 · 真值核查发现 ADR §1.3 第二份漏报 MetricsAggregator 已存在 metrics_update + EWMA 全部就位 · 仅 Modules 字段空) -