Add change documentation for 2026-05-12 eqpalg optimizations
This commit is contained in:
parent
e21b2af2a6
commit
2c62f9c4a3
161
eqpalg/eqpalg_changes_2026-05-12.md
Normal file
161
eqpalg/eqpalg_changes_2026-05-12.md
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
# eqpalg 优化改动记录 — 2026-05-12
|
||||||
|
|
||||||
|
## 改动总览
|
||||||
|
|
||||||
|
| # | Commit | 内容 | 涉及文件 |
|
||||||
|
|---|--------|------|----------|
|
||||||
|
| 1 | `973921f` | RuleStat 热冷分离:展示数据走本地缓存,冷数据共享内存用进程间锁 | `shm/RuleStatShm.h`, `eqpalg/utility/eqp_stat.h/.cc`, `eqpalg/alg_base.h/.cpp` |
|
||||||
|
| 2 | `1e70af7` | 移除 `rm -rf MapRuleStat`(原 bipc::string 段错误已自然消除) | `eqpalg/eqpalg_icei.cpp` |
|
||||||
|
| 3 | `1ca922a` | Task 线程生命周期修复:空闲自毁 + handles_mutex 串行化清理 | `eqpalg/threads/handler_exec.cc`, `eqpalg/threads/manager.cc`, `eqpalg/alg_base.cpp` |
|
||||||
|
| 4 | `e21b2af` | TaskData 固定 518MB 数组改动态向量,移除 `rm -rf` | `shm/TaskData.h`, `eqpalg/algs/exp_base.cpp/.h`, `eqpalg/eqpalg_icei.cpp` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. RuleStat 热冷分离
|
||||||
|
|
||||||
|
### 问题
|
||||||
|
`RuleStatShm::MapRuleStat` 用全局 `std::mutex` 保护所有共享内存 map 操作。展示数据(alarm_value、current_value 等)和冷数据(stat_values、running_time 等)混在同一把锁里。1500 规则 × 15 线程 × ~500ms 触发,写-写竞争严重。且 `std::mutex` 是线程锁,mon/cron 跨进程互不可见——存在隐藏的数据竞争 bug。
|
||||||
|
|
||||||
|
### 改动
|
||||||
|
|
||||||
|
**数据拆分**:
|
||||||
|
```
|
||||||
|
修改前: RuleStat(全量字段,共享内存分配器)
|
||||||
|
↓ 全局 std::mutex → 共享内存 map → GetDataJson → Memcached
|
||||||
|
|
||||||
|
修改后: RuleStatLocal(全量字段,标准类型,AlgBase 本地)
|
||||||
|
├─ update_display() → DisplayCache(本地 map + std::mutex)→ 画面 JSON
|
||||||
|
└─ update_cold() → 共享内存(RuleStatCold,仅冷字段)
|
||||||
|
boost::interprocess::interprocess_mutex
|
||||||
|
```
|
||||||
|
|
||||||
|
**新类型**:
|
||||||
|
```cpp
|
||||||
|
// 本地完整数据(AlgBase 持有)
|
||||||
|
struct RuleStatLocal {
|
||||||
|
double alarm_value, current_value, limit_up, limit_down;
|
||||||
|
std::vector<std::string> items;
|
||||||
|
std::vector<double> stat_values;
|
||||||
|
double running_time;
|
||||||
|
int64_t shear_times, alarm_times;
|
||||||
|
std::string last_alarm_time, dev_coder, unit;
|
||||||
|
bool fetch_mark;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 共享内存冷数据(mon↔cron 交换用)
|
||||||
|
struct RuleStatCold {
|
||||||
|
vector_d stat_values;
|
||||||
|
bool fetch_mark;
|
||||||
|
double running_time;
|
||||||
|
int64_t shear_times, alarm_times;
|
||||||
|
bipc::string last_alarm_time, dev_coder;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**DisplayCache**:本地 `std::map<string, DisplayEntry>` + `std::mutex`。`update_display()` 纳秒级临界区,`get_json()` 锁外拼 JSON。
|
||||||
|
|
||||||
|
**算法子类零改动**:`RuleStatLocal` 字段名与原 `RuleStat` 完全一致。
|
||||||
|
|
||||||
|
### 效果
|
||||||
|
- 展示热路径:无共享内存锁,15 线程写入本地缓存互不阻塞
|
||||||
|
- 冷路径:真正的进程间锁,修了跨进程数据竞争 bug
|
||||||
|
- GetDataJson:从本地缓存读取,不再持全局锁
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 移除 rm -rf MapRuleStat
|
||||||
|
|
||||||
|
### 问题
|
||||||
|
`EqpAlgICEI::~EqpAlgICEI()` 在 mon 进程退出时 `rm -rf MapRuleStat_boost.mmap`。原因是 `RuleStat::items`(`vector_s<bipc::string>`)中 tag 名超过 23 字节时,`bipc::string` 的堆指针在重启后失效导致段错误。删文件是绕过 bug 的 workaround,但破坏了 mon↔cron 的共享内存通道。
|
||||||
|
|
||||||
|
### 改动
|
||||||
|
`items` 已迁到 `RuleStatLocal::items`(`std::vector<std::string>`,本地堆),不再涉及共享内存分配器。共享内存中剩下 `last_alarm_time` 和 `dev_coder` 两个 `bipc::string`,长度远在 SSO 阈值内(~19 字符和 9 字符)。原 bug 不复存在,移除 `rm -rf`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Task 线程生命周期修复
|
||||||
|
|
||||||
|
### 问题
|
||||||
|
1. **LOG 文件串线**:`LOG::doConfigure` 疑似进程级全局状态,首个 HandlerExec 线程调用成功后,后续线程的调用返回 3("不能执行多遍"),所有日志写入第一个线程的 log 文件。
|
||||||
|
2. **线程永不清理**:task 模式下 HandlerExec 执行完任务后 `rule_pointers_` 已空,但 `is_running_` 保持 `true`,线程无限空转。Manager::start() 的 `test_label` 检查逻辑永远为 false,`handles_.clear()` 是死代码。
|
||||||
|
3. **logReset 自赋值**:`AlgBase::logReset(int task_seq)` 中 `task_seq = task_seq` 是 no-op,参数被丢弃。
|
||||||
|
|
||||||
|
### 改动
|
||||||
|
|
||||||
|
**HandlerExec 自毁**(`handler_exec.cc`):
|
||||||
|
```cpp
|
||||||
|
if (this->rule_pointers_.empty()) {
|
||||||
|
std::lock_guard<std::mutex> guard(mutex_);
|
||||||
|
if (this->once_exec_queue_.empty()) {
|
||||||
|
this->is_running_ = false; // 通知 Manager 可析构
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Manager 清理**(`manager.cc`):
|
||||||
|
```cpp
|
||||||
|
// 两阶段:shared_lock 收集 → unique_lock 销毁
|
||||||
|
std::vector<string> to_remove;
|
||||||
|
{ shared_lock read_lock(handles_mutex); /* 收集 !is_running_ */ }
|
||||||
|
for (auto &name : to_remove) {
|
||||||
|
unique_lock write_lock(handles_mutex);
|
||||||
|
/* recheck + destroy + erase */
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**exec_task 判活**(`manager.cc`):
|
||||||
|
```cpp
|
||||||
|
unique_lock write_lock(handles_mutex);
|
||||||
|
if (handler存在 && !handler->get_is_running()) {
|
||||||
|
destroy() + erase(); // 清理死线程
|
||||||
|
}
|
||||||
|
if (handler不存在) { create new; }
|
||||||
|
handler->submit(task);
|
||||||
|
```
|
||||||
|
|
||||||
|
**竞态保证**:`exec_task()` 和 Manager cleanup 都持有 `unique_lock(handles_mutex)`,互斥。
|
||||||
|
- 如果 cleanup 先拿到锁 → destroy + erase → exec_task 发现不存在 → create new
|
||||||
|
- 如果 exec_task 先拿到锁 → submit → handler 的 `once_exec_queue_` 非空 → 不自毁
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. TaskData 动态向量
|
||||||
|
|
||||||
|
### 问题
|
||||||
|
`TaskData.h` 中 `DataRecord` 固定分配 `float[30×86400×50]`(518 MB/条),共享内存文件 5 GB。task 用共享内存而非堆是为了文件映射不消耗 swap。但每条 record 不管实际收集多少数据点都占满 518 MB,极度浪费。进程退出时 `rm -rf` 清理。
|
||||||
|
|
||||||
|
### 改动
|
||||||
|
|
||||||
|
**TaskData.h**:
|
||||||
|
```cpp
|
||||||
|
// 修改前
|
||||||
|
struct DataRecord {
|
||||||
|
float data_record[129600000]; // 固定 518 MB
|
||||||
|
};
|
||||||
|
|
||||||
|
// 修改后
|
||||||
|
struct TaskRecord {
|
||||||
|
shm_vector_f data_record; // boost::container::vector<float, 共享内存分配器>
|
||||||
|
TaskRecord(const void_allocator &alloc) : data_record(alloc) {}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
文件上限从 5 GB → 10 MB 起始,按需增长。
|
||||||
|
|
||||||
|
**exp_base.cpp**:
|
||||||
|
- 写入:`data_record[idx++]` → `data_record.push_back(val)`
|
||||||
|
- 读取:`for (j < task_data_size)` → `for (j < data_record.size())`
|
||||||
|
- 移除 `task_data_size` 成员变量
|
||||||
|
|
||||||
|
**eqpalg_icei.cpp**:移除 `rm -rf TaskData_boost.mmap`。vector 析构时自动归还内存到共享内存段。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 部署注意事项
|
||||||
|
|
||||||
|
1. **清理旧共享内存文件**(数据结构已不兼容):
|
||||||
|
```bash
|
||||||
|
rm -rf /users/dsc/shm/MapRuleStat_boost.mmap
|
||||||
|
rm -rf /users/dsc/shm/TaskData_boost.mmap
|
||||||
|
```
|
||||||
|
2. `boost::interprocess::interprocess_mutex` 需确认在目标环境的 Boost 版本中可用。
|
||||||
|
3. `DisplayCache` 依赖 nlohmann::json(`mix_cc::json`),项目已有此依赖。
|
||||||
Loading…
Reference in New Issue
Block a user