软件诊断 Cluster(SoftwareDiagnostics)
Cluster ID: 0x0034 |
所在 Endpoint: Endpoint 0(Root / Node 级别) |
角色: Server(只读 + 一个重置命令)
SoftwareDiagnostics 用于暴露设备固件的运行时健康状态 —— 包括线程栈使用情况、堆内存分配和软件故障记录。 这是 Matter 中面向开发者和运维人员的诊断 Cluster,帮助在不连接调试器的情况下了解嵌入式设备的内部状态。
设备运行一段时间后行为异常?读取堆内存属性检查是否存在内存泄漏。 怀疑某个线程栈溢出?查看 ThreadMetrics 中的 StackFreeMinimum。 OTA 升级后想确认固件稳定性?监控 SoftwareFault 事件和高水位线变化。 这些信息在产品量产后的远程诊断中尤其有用。
Feature 位图
SoftwareDiagnostics Cluster 通过 FeatureMap(0xFFFC)声明设备支持的可选能力:
FeatureMap = 0x01(WTRMRK):设备追踪堆内存使用峰值,可通过 ResetWatermarks 命令重置。
FeatureMap = 0x00(无 Feature):仅提供实时堆内存和线程指标,不记录历史峰值。
属性
所有属性均为只读。堆内存相关属性为可选,ThreadMetrics 也为可选。点击属性 ID 可跳转到详细说明。
| ID | 名称 | 类型 | 条件 | 说明 |
|---|---|---|---|---|
0x00 |
ThreadMetrics | list<ThreadMetricsStruct> | 可选 | 当前运行的线程列表及栈使用情况 |
0x01 |
CurrentHeapFree | uint64 | 可选 | 当前堆空闲字节数 |
0x02 |
CurrentHeapUsed | uint64 | 可选 | 当前堆已用字节数 |
0x03 |
CurrentHeapHighWatermark | uint64 | WTRMRK | 堆使用历史峰值(高水位线) |
ThreadMetrics(线程指标列表)
返回设备当前所有运行线程的栈使用信息。每个条目是一个 ThreadMetricsStruct,包含线程 ID、名称和栈使用统计。
这是排查栈溢出的关键数据来源。
ThreadMetricsStruct 结构
| ID | 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
0x00 |
Id | uint64 | 是 | 线程唯一标识符 |
0x01 |
Name | string(最长 8 字符) | 可选 | 线程名称(如 "Main"、"BLE"、"WiFi") |
0x02 |
StackFreeCurrent | uint32 | 可选 | 当前栈剩余空闲字节数 |
0x03 |
StackFreeMinimum | uint32 | 可选 | 栈剩余空闲的历史最小值(栈使用水位线) |
0x04 |
StackSize | uint32 | 可选 | 线程栈总大小(字节) |
当 StackFreeMinimum 接近 0 时,意味着该线程曾经几乎用完了栈空间,存在栈溢出风险。
一般建议保持 StackFreeMinimum / StackSize > 10% 的安全余量。
如果低于这个阈值,应考虑增大该线程的栈分配或优化其调用深度。
CurrentHeapFree(堆空闲字节数)
设备堆内存中当前可用于分配的字节数。在资源受限的嵌入式设备上(如 ESP32 系列), 这个值持续下降可能意味着内存泄漏。
CurrentHeapUsed(堆已用字节数)
设备堆内存中当前已被分配使用的字节数。与 CurrentHeapFree 互补 ——
两者之和近似等于堆总大小(可能有碎片和管理开销的差异)。
CurrentHeapHighWatermark(堆使用高水位线)
自上次 ResetWatermarks 命令或设备启动以来,CurrentHeapUsed 达到过的最大值。
这个属性需要 WTRMRK Feature 支持。
高水位线是评估设备内存裕度的重要指标 —— 它反映的是「最坏情况下用了多少内存」,
而不是某一时刻的快照。即使当前 CurrentHeapUsed 看起来正常,高水位线也可能揭示间歇性的内存尖峰。
命令(Commands)
SoftwareDiagnostics 只有一个命令,需要 WTRMRK Feature 支持。
| ID | 名称 | 条件 | 说明 |
|---|---|---|---|
0x00 |
ResetWatermarks | WTRMRK | 重置堆使用高水位线和线程栈最小空闲值 |
ResetWatermarks —— 重置水位线(0x00)
将 CurrentHeapHighWatermark 重置为当前的 CurrentHeapUsed 值,
同时将所有线程的 StackFreeMinimum 重置为当前的 StackFreeCurrent 值。
该命令不接受任何参数。
典型用法:OTA 升级后发一次 ResetWatermarks,然后观察新固件运行一段时间后的高水位线, 评估新版本的内存占用是否有回退。也适用于排查特定操作的内存影响 —— 重置后执行操作,再读取水位线。
请求示例:
{
"invokeRequests": [{
"commandPath": {
"endpointId": 0,
"clusterId": "0x0034",
"commandId": "0x00" // ResetWatermarks
},
"commandFields": {} // 无参数
}]
}
事件(Events)
设备运行过程中检测到软件故障时,会上报 SoftwareFault 事件。该事件为可选支持。
| ID | 名称 | 优先级 | 说明 |
|---|---|---|---|
0x00 |
SoftwareFault | Info | 检测到软件故障时触发 |
SoftwareFault —— 软件故障事件(0x00)
当设备固件检测到软件异常(如未处理的异常、断言失败、看门狗触发等)时上报此事件。 事件数据携带故障线程信息和可选的故障现场记录。
| 字段 | ID | 类型 | 说明 |
|---|---|---|---|
| Id | 0x00 |
uint64 | 故障发生时的线程 ID |
| Name | 0x01 |
string(最长 8 字符) | 故障线程名称(可选) |
| FaultRecording | 0x02 |
octstr(最长 1024 字节) | 故障现场数据,格式由厂商定义(可选) |
FaultRecording 是一段厂商自定义的二进制数据,可能包含寄存器快照、调用栈回溯、
崩溃地址等调试信息。不同芯片平台的格式不同,需要配合厂商的解码工具使用。
App 端通常只需要将原始数据上传到云端,由后台服务解析。
事件上报示例:
{
"eventReports": [{
"eventData": {
"path": {
"endpointId": 0,
"clusterId": "0x0034",
"eventId": "0x00" // SoftwareFault
},
"eventNumber": 7,
"priority": "INFO",
"data": {
"0": 42, // Id = 42(故障线程 ID)
"1": "BLE", // Name = "BLE"(故障线程名)
"2": "RkVUQ0g6IDB4..." // FaultRecording(Base64 编码的故障现场数据)
}
}
}]
}
示例数据
读取一个 ESP32 设备的 SoftwareDiagnostics Cluster 属性:
{
// --- 属性 ---
"0x0": [ // ThreadMetrics(线程指标列表)
{
"0": 1, // Id = 1
"1": "Main", // Name = "Main"
"2": 2048, // StackFreeCurrent = 2048 字节
"3": 1024, // StackFreeMinimum = 1024 字节
"4": 8192 // StackSize = 8192 字节
},
{
"0": 2, // Id = 2
"1": "BLE", // Name = "BLE"
"2": 4096, // StackFreeCurrent = 4096 字节
"3": 2048, // StackFreeMinimum = 2048 字节
"4": 8192 // StackSize = 8192 字节
}
],
"0x1": 65536, // CurrentHeapFree = 64 KB
"0x2": 131072, // CurrentHeapUsed = 128 KB
"0x3": 196608 // CurrentHeapHighWatermark = 192 KB(需 WTRMRK Feature)
}
常见场景
场景 1:内存泄漏监控
设备长时间运行后响应变慢、功能异常,怀疑存在内存泄漏。
- 定期读取
CurrentHeapFree和CurrentHeapUsed(如每小时一次) - 记录到时序数据库或日志中,绘制内存趋势图
- 如果
CurrentHeapFree持续下降且不回升,基本可以确认存在内存泄漏 - 结合
ThreadMetrics排查是否某个线程的栈使用异常 - 进一步通过 OTA 修复后,重置水位线观察新版本表现
场景 2:线程栈健康检查
设备偶发崩溃重启,怀疑某个线程栈空间不足导致溢出。
- 读取
ThreadMetrics列表,关注每个线程的StackFreeMinimum - 计算栈使用率:
(StackSize - StackFreeMinimum) / StackSize - 使用率超过 90% 的线程有栈溢出风险,需要关注
- 对比
StackFreeCurrent和StackFreeMinimum的差距 —— 差距越大说明栈使用波动越剧烈 - 调整固件中对应线程的栈分配大小,OTA 后再次检查
场景 3:OTA 后高水位线对比
固件升级后需要评估新版本的内存表现是否有回退。需要 WTRMRK Feature 支持。
- OTA 完成后,设备重启,水位线自动重置
- 让设备正常运行一段时间(建议 24-48 小时,覆盖各种使用场景)
- 读取
CurrentHeapHighWatermark,与旧版本的记录对比 - 如果新版本水位线明显高于旧版本,说明新代码引入了额外的内存开销
- 也可以手动发
ResetWatermarks后执行特定操作,精确测量该操作的内存峰值