Files
envi-code/SourceCode/Code2026/inc/PerfTraceMark.h
T
company-desktop 7038a98441 diag: 用 PDB 解析栈帧,定位到 AecDbEwPipeBase::copyFrom 里的多余序列化
上一版只给了"模块+RVA"的栈,我据此先后推断成
AecDbCurveBase::subGetTransformedCopy 和 AecDbEntityCommon::base_DeepClone,两者都是错的
(用户在那里下断点不命中;新加的 PerfTraceMark 打点也没有触发)。本次用符号解析定死。

本次改动:
- 新增 inc/PerfTraceMark.h:inline 的"某函数被调用过"打点,Debug 且 AEC_WRITEBACK_TRACE=1
  才生效。AecRxBase.arx 不链接 CoreLibrary(静态库只被 CoreCommand 链接),拿不到 SectionPerf,
  所以做成 header-only。
- 在 5 个候选入口打点:AecDbCurveBase::subGetTransformedCopy / subDeepClone、
  AecDbEntityBase::subDeepClone、AecDbEntityCommon::base_DeepClone、CKTCadUtility::CloneObject。
  跑一次开图,5 个都没触发 —— 这些候选被排除。
- 新增 tools/resolve_rva.ps1:用 dbghelp 的 SymLoadModuleEx / SymFromAddr 配本地 PDB,
  把"模块+RVA"解析成函数名。Windows 没有自带 symbolizer,这个脚本很轻,可反复用。

解析结果(CoreCommand.arx):
  0x58f051  AecDbEwPipeBase::copyFrom+0x41
  0x7e1300  AecDbZLineStair::DrawGuarBar3d+0x2c0
  0x7e09d0  AecDbZLineStair::DrawSteep3d+0xbe0
  0x7ddcef  AecDbZLineStair::Draw3d+0x34f

真实成因:Z 型楼梯画护栏(DrawGuarBar3d)时 copyFrom 一份管道实体,
而 AecDbEwPipeBase::copyFrom 用通用的 CopyObject(inc/AecDbEntityCommon.h:331)
做"整实体 dwgOutFields/dwgInFields 往返"来拷字段,于是截面被写成临时 SAT 文件再读回来。

而且这次序列化是多余的:copyFrom 随后把所有字段又用内存级方式拷了一遍
(曲线 clone/copyFrom、截面 clone/copyFrom、XData CopyFrom、m_arUserInfs append、
标志位/图层/线型/Breaks 逐项赋值),WriteUserInterface 写的也只是 m_arUserInfs。
所以最小修改是把那句 CopyObject 去掉,并补上源为 NULL 时清空目标的分支
(目前这个"清空"是 CopyObject 顺带完成的)。

本次只做定位与记录(分析写进 pipe-section-region-performance-plan.md 并纠正了上一版的误判),
不改 copyFrom 的行为——它影响所有管系实体的复制粘贴/块内拷贝,需要单独验证。
2026-10-28 21:28:00 +08:00

59 lines
1.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// PerfTraceMark.h —— 极轻量的"某函数被调用过"打点,用于在没有调试器时定位调用路径
//
// 用法:在候选函数入口写 PerfTraceMark("函数名"),
// 每次进程内该 tag 只记录第一次,追加到 %TEMP%\aec_writeback_trace.txt。
// 只在 Debug(NDEBUG 未定义)且环境变量 AEC_WRITEBACK_TRACE=1 时生效,发布版本零开销。
//
// 为什么不用 SectionPerf:AecRxBase.arx 不链接 CoreLibrary(静态库只被 CoreCommand 链接),
// 所以 AecRxBase 的文件里拿不到 SectionPerf 的符号。本头文件是 inline 的,哪个模块都能用。
#ifndef PERF_TRACE_MARK_H
#define PERF_TRACE_MARK_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <set>
#include <string>
inline void PerfTraceMark(const char* pszTag)
{
#ifndef NDEBUG
static bool s_bInit = false;
static bool s_bOn = false;
static std::set<std::string> s_seen;
if (!s_bInit)
{
s_bInit = true;
const char* psz = ::getenv("AEC_WRITEBACK_TRACE");
s_bOn = (psz != NULL && psz[0] != '0');
}
if (!s_bOn || pszTag == NULL)
return;
const std::string sTag(pszTag);
if (s_seen.find(sTag) != s_seen.end())
return;
s_seen.insert(sTag);
char szTmp[MAX_PATH + 1];
::memset(szTmp, 0, sizeof(szTmp));
if (::GetTempPathA(MAX_PATH, szTmp) == 0)
return;
std::string sPath(szTmp);
sPath += "aec_writeback_trace.txt";
FILE* fp = NULL;
if (fopen_s(&fp, sPath.c_str(), "ab") == 0 && fp != NULL)
{
fprintf(fp, "[mark] %s\n", pszTag);
fclose(fp);
}
#else
(void)pszTag;
#endif
}
#endif // PERF_TRACE_MARK_H