fix: AecDbX3dPart 记住"已尝试建过",避免 Hide 构件被反复重建
现象:开图时 X3dPart 的 EnsureCreated 命中率只有 10.1%,1914 次重建里 721 次产出 NULL(38%),单个对象最多被重建 544 次。 根因:EnsureCreated 的命中条件是 !m_bNeedCreate && m_pSolid != NULL, 而 Rebuild() 里对 Hide 构件是"故意不建几何、直接 return true"—— m_pSolid 按设计就是 NULL,于是每次访问都重新走一遍 Rebuild,永远不可能命中。 子项全为空的构件同理。 修复: - 新增 m_bCreated 标记"已经尝试建过"(无论是否产出实体) - EnsureCreated 命中条件改为 !m_bNeedCreate && (m_bCreated || m_pSolid != NULL) - Rebuild 入口置 m_bCreated = true;所有设 m_bNeedCreate = true 的 setter 同时置 m_bCreated = false,保证参数变化后仍会重建 - 重建后仍无实体时打一条日志(限前 5 条,带 m_sName),方便定位是哪些构件 实测(big1.dwg / R230 Debug): X3dPart 命中率 10.1% -> 41.4% 重建次数 1914 -> 1248(-666) rebuild_null 721 -> 55 单对象最多重建 544 -> <=3 开图墙钟 93 s -> 93 s(无变化) 注意:这 666 次空转没有带来可测的提速,因为 Rebuild 里 Hide 的早退分支在 布尔运算之前,每次只有几微秒。所以这是正确性/整洁度修复,不是性能修复; 但消除了"个别构件被重试几百次"这种病态行为,也暴露了"哪些构件建不出实体"。 顺带新增诊断(Debug + AEC_PERF_COUNTER=1 才生效,Release 无开销): - SectionPerf::NoteEnsure():按 tag 统计"延迟建几何"的命中/重建, 并给出对象维度直方图与重建次数最高的对象 - AecDbX3dPart::Rebuild / AcDbX3dSolid::EnsureCreated / AecDbGuardBar::Draw3d 打点 - tools/run_acad_perf.ps1 增加 -CpuTrace:用 xperf 采 CPU 采样并 merge 成 etl, 可直接喂 tools/perf_diagsession.py(VS 的 VSDiagnostics 在这台机器上会卡住, wpr -stop 有 COM 线程模式 bug,故用 xperf) 验证:R230 Debug 编译通过并部署,自动开图取数;截面缓存与回写仍为 0/正常。
This commit is contained in:
1 parent
56c89c5fa4
commit
facf14699b
7 files changed
+154
-3
No files matched your search
@@ -36,6 +36,17 @@ namespace
|
||||
std::set<unsigned long long> seen;
|
||||
};
|
||||
|
||||
// 每个"延迟建几何"缓存点的统计
|
||||
struct EnsureStat
|
||||
{
|
||||
EnsureStat() : nTotal(0), nHits(0), nRebuilds(0) {}
|
||||
|
||||
unsigned long long nTotal;
|
||||
unsigned long long nHits;
|
||||
unsigned long long nRebuilds;
|
||||
std::map<const void*, int> builds; // 对象 -> 被建次数
|
||||
};
|
||||
|
||||
struct Stats
|
||||
{
|
||||
Stats()
|
||||
@@ -66,6 +77,9 @@ namespace
|
||||
// 属性 key:class 名 -> 唯一/命中统计
|
||||
std::map<std::string, KeyStat> attrStats;
|
||||
|
||||
// 延迟建几何:tag -> 统计
|
||||
std::map<std::string, EnsureStat> ensureStats;
|
||||
|
||||
// 回写次数:实体类 -> 次数
|
||||
std::map<std::string, unsigned long long> writeBackByClass;
|
||||
};
|
||||
@@ -274,6 +288,25 @@ namespace SectionPerf
|
||||
++s.writeBackByClass[key];
|
||||
}
|
||||
|
||||
void NoteEnsure(const char* pszTag, const void* pObj, bool bRebuilt)
|
||||
{
|
||||
Stats& s = GetStats();
|
||||
if (!s.bEnabled)
|
||||
return;
|
||||
std::string key(pszTag != NULL ? pszTag : "?");
|
||||
EnsureStat& st = s.ensureStats[key];
|
||||
++st.nTotal;
|
||||
if (bRebuilt)
|
||||
{
|
||||
++st.nRebuilds;
|
||||
++st.builds[pObj];
|
||||
}
|
||||
else
|
||||
{
|
||||
++st.nHits;
|
||||
}
|
||||
}
|
||||
|
||||
void Dump()
|
||||
{
|
||||
Stats& s = GetStats();
|
||||
@@ -300,6 +333,40 @@ namespace SectionPerf
|
||||
s.nTempFiles, s.nTempFileBytes, s.nWriteBacks);
|
||||
out += szLine;
|
||||
|
||||
if (!s.ensureStats.empty())
|
||||
{
|
||||
out += "---- lazy-create cache (by tag) ----\n";
|
||||
out += " tag total hits rebuild hit_rate objects built_once built_2_3 built_4p\n";
|
||||
for (std::map<std::string, EnsureStat>::const_iterator it = s.ensureStats.begin();
|
||||
it != s.ensureStats.end(); ++it)
|
||||
{
|
||||
const EnsureStat& e = it->second;
|
||||
int nOnce = 0, n23 = 0, n4p = 0;
|
||||
for (std::map<const void*, int>::const_iterator b = e.builds.begin(); b != e.builds.end(); ++b)
|
||||
{
|
||||
if (b->second <= 1) ++nOnce;
|
||||
else if (b->second <= 3) ++n23;
|
||||
else ++n4p;
|
||||
}
|
||||
const double rate = e.nTotal ? (100.0 * (double)e.nHits / (double)e.nTotal) : 0.0;
|
||||
sprintf_s(szLine, sizeof(szLine), " %-12s %-9llu %-7llu %-8llu %7.1f%% %-7llu %-11d %-10d %d\n",
|
||||
it->first.c_str(), e.nTotal, e.nHits, e.nRebuilds, rate,
|
||||
(unsigned long long)e.builds.size(), nOnce, n23, n4p);
|
||||
out += szLine;
|
||||
// top offenders:被重建次数最多的对象
|
||||
const void* pWorst = NULL; int nWorst = 0;
|
||||
for (std::map<const void*, int>::const_iterator b = e.builds.begin(); b != e.builds.end(); ++b)
|
||||
{
|
||||
if (b->second > nWorst) { nWorst = b->second; pWorst = b->first; }
|
||||
}
|
||||
if (nWorst > 3)
|
||||
{
|
||||
sprintf_s(szLine, sizeof(szLine), " worst object %p rebuilt %d times\n", pWorst, nWorst);
|
||||
out += szLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!s.writeBackByClass.empty())
|
||||
{
|
||||
out += "---- write-backs by entity class ----\n";
|
||||
@@ -457,5 +524,6 @@ namespace SectionPerf
|
||||
s.nWriteBacks = 0;
|
||||
s.attrStats.clear();
|
||||
s.writeBackByClass.clear();
|
||||
s.ensureStats.clear();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user