// SectionPerfCounter.h —— Phase 0 计数器:截面(Region)恢复路径的实测探针 // // 目的(见 pipe-section-region-performance-plan.md 的 Phase 0): // 1. 每次截面恢复到底多贵(µs),一次开图总共多少次、多少时间; // 2. 同一份 SAT 文本被重复恢复多少次(唯一 hash 数、模拟命中率)—— // 这个数字直接决定 Phase 1 截面缓存能省多少; // 3. 临时文件写入次数与累计字节(杀软扫描影响面); // 4. 放回写(RegionToString / RegionAcisoutDwgOutFields)的次数。 // // 使用方式: // set AEC_PERF_COUNTER=1 必须在启动 CAD 前设好(进程内只读一次) // ENVIPERFDUMP 在 CAD 命令行打印汇总,同时追加到 %TEMP%\aec_section_perf.txt // ENVIPERFRESET 清零 // // 只在 _DEBUG 下生效:Release 里 Enabled() 恒为 false,调用点只剩一次 bool 判断。 // 不改变任何几何逻辑与存盘格式。 #ifndef SECTION_PERF_COUNTER_H #define SECTION_PERF_COUNTER_H #include #include namespace SectionPerf { // 环境变量 AEC_PERF_COUNTER 是否开启,且当前是 Debug 构建 bool Enabled(); // 计时作用域:函数入口构造,离开时累加耗时与次数 class Scope { public: explicit Scope(const char* pszTag); ~Scope(); private: Scope(const Scope&); Scope& operator=(const Scope&); const char* m_pszTag; long long m_nStart; bool m_bActive; }; // 记录一次"待恢复的 SAT 文本":内部按内容算 64 位 hash, // 统计唯一 hash 数与被重复命中的次数(模拟命中率) void NoteRegionText(const char* pszTxt, size_t nLen); // 属性 key:用"实体数据"而不是 SAT 文本做 key 时的模拟命中统计。 // 调用方把参与 key 的字段逐个 Add 进来,析构时统一记一次。 // 用途:比较"内容 hash"与"属性 key"两种缓存键的命中率,再决定 Phase 1 用哪个。 class AttrKey { public: // pszClass 一般是 isA()->name(),用于隔离不同实体类 explicit AttrKey(const TCHAR* pszClass); ~AttrKey(); void Add(const void* pData, size_t nLen); private: AttrKey(const AttrKey&); AttrKey& operator=(const AttrKey&); unsigned long long m_nHash; std::string m_sClass; bool m_bActive; }; // 记录一次临时文件写入 void NoteTempFile(size_t nBytes); // 记录一次回写(Region -> SAT 文本) void NoteWriteBack(const char* pszTag); // 记录一次回写,并按实体类分开统计(谁在开图期回写) void NoteWriteBackClass(const char* pszClass); // 打印 + 写文件 void Dump(); // 只追加文本到 %TEMP%\aec_section_perf.txt(供其它模块复用同一份报告) void AppendReport(const char* pszText); // 抓一次调用栈写进报告,用于定位"谁在开图期回写实体"这类问题 void TraceCallStack(const char* pszTag, int nSkip = 1); // 清零 void Reset(); } #endif // SECTION_PERF_COUNTER_H