diag: 增加调用栈抓取,定位开图期 1140 次截面回写的成因
现象:开图期间 EwPipe::RegionAcisout 被调用 1140 次、耗时 2.38 s, 把几何又序列化回 SAT。之前只知现象不知来源。 新增 SectionPerf::TraceCallStack():用 RtlCaptureStackBackTrace + GetModuleHandleExW 把栈帧解析成 "模块名 + RVA" 并写进报告文件。正式代码里不开启, 只在 AEC_WRITEBACK_TRACE=1 时于 RegionAcisoutDwgOutFields 首次调用处抓一次。 结论(栈已定位): subViewportDraw -> base_ViewportDraw -> ... -> base_DeepClone -> AcDbObject::dwgOut -> AecDbEwPipeBase::dwgOutFields -> RegionAcisout 即:不是保存,而是绘制期的深拷贝。AecDbEntityCommon::base_DeepClone (AecRxBase/AecDbEntityCommon.cpp:1265)用 AcDbDeepCloneFiler filer; GetMe()->dwgOut(&filer); pClone->dwgIn(&filer); 实现拷贝,于是每次克隆实体,截面都要写一个临时 SAT 文件再读回来。 读的那一半现在已被 kText 缓存吃掉,剩下 acisOut 写文件这半(2.38 s)。 顺带修正一个文档缺陷:inc/SectionPerfCounter.h 里 %TEMP%\aec_section_perf.txt 的注释之前被转义吃掉变成了 %TEMP%<BEL>ec_section_perf.txt。 修法(跳过深拷贝期的区域序列化 / 直接写缓存里的 SAT 原文)都需要动 AecDbEntityCommon 的拷贝契约或先审计 m_pRegion 的写操作,风险面不一致, 只把分析与三种方案写进 pipe-section-region-performance-plan.md,本次不改行为。 验证:R230 Debug 编译通过并部署;AEC_WRITEBACK_TRACE=1 跑图一次,栈如文档所示。
This commit is contained in:
1 parent
f8d10d5a3b
commit
67d6545e6c
4 files changed
+112
-3
No files matched your search
@@ -344,6 +344,52 @@ namespace SectionPerf
|
||||
}
|
||||
}
|
||||
|
||||
void TraceCallStack(const char* pszTag, int nSkip)
|
||||
{
|
||||
typedef USHORT(WINAPI* PFN_CaptureStack)(ULONG, ULONG, PVOID*, PULONG);
|
||||
static PFN_CaptureStack s_pfn = NULL;
|
||||
static bool s_bTried = false;
|
||||
if (!s_bTried)
|
||||
{
|
||||
s_bTried = true;
|
||||
HMODULE hNtdll = ::GetModuleHandleA("ntdll.dll");
|
||||
if (hNtdll != NULL)
|
||||
s_pfn = (PFN_CaptureStack)::GetProcAddress(hNtdll, "RtlCaptureStackBackTrace");
|
||||
}
|
||||
if (s_pfn == NULL)
|
||||
return;
|
||||
|
||||
void* frames[24];
|
||||
::memset(frames, 0, sizeof(frames));
|
||||
const USHORT nGot = s_pfn((ULONG)(nSkip > 0 ? nSkip : 0), 24, frames, NULL);
|
||||
|
||||
std::string out = "\n[stack] ";
|
||||
out += (pszTag != NULL ? pszTag : "?");
|
||||
out += "\n";
|
||||
char szLine[1024];
|
||||
for (USHORT i = 0; i < nGot; ++i)
|
||||
{
|
||||
const DWORD64 nAddr = (DWORD64)frames[i];
|
||||
HMODULE hMod = NULL;
|
||||
if (!::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||
(LPCWSTR)nAddr, &hMod) || hMod == NULL)
|
||||
continue;
|
||||
|
||||
WCHAR szPath[MAX_PATH];
|
||||
::memset(szPath, 0, sizeof(szPath));
|
||||
::GetModuleFileNameW(hMod, szPath, MAX_PATH);
|
||||
const WCHAR* pszBase = wcsrchr(szPath, L'\\');
|
||||
pszBase = (pszBase != NULL) ? pszBase + 1 : szPath;
|
||||
|
||||
char szMod[MAX_PATH * 2];
|
||||
::memset(szMod, 0, sizeof(szMod));
|
||||
::WideCharToMultiByte(CP_ACP, 0, pszBase, -1, szMod, sizeof(szMod) - 1, NULL, NULL);
|
||||
sprintf_s(szLine, sizeof(szLine), " %-28s +0x%llx\n", szMod, (unsigned long long)(nAddr - (DWORD64)hMod));
|
||||
out += szLine;
|
||||
}
|
||||
AppendReport(out.c_str());
|
||||
}
|
||||
|
||||
void AppendReport(const char* pszText)
|
||||
{
|
||||
if (pszText == NULL)
|
||||
|
||||
Reference in new issue
Block a user