diag: 统计回写的实体类,定位到 AecDbEwPipeBase 基类实例 #102
No files matched your search
@@ -1289,6 +1289,7 @@ Acad::ErrorStatus AecDbEwPipeBase::RegionAcisoutDwgOutFields(AcDbDwgFiler* pFile
|
||||
|
||||
SectionPerf::Scope perfScope("EwPipe::RegionAcisout");
|
||||
SectionPerf::NoteWriteBack("EwPipe::RegionAcisout");
|
||||
SectionPerf::NoteWriteBackClass(CStringA(isA()->name()));
|
||||
|
||||
if (m_pRegion == NULL)
|
||||
return Acad::eInvalidInput;
|
||||
|
||||
@@ -65,6 +65,9 @@ namespace
|
||||
|
||||
// 属性 key:class 名 -> 唯一/命中统计
|
||||
std::map<std::string, KeyStat> attrStats;
|
||||
|
||||
// 回写次数:实体类 -> 次数
|
||||
std::map<std::string, unsigned long long> writeBackByClass;
|
||||
};
|
||||
|
||||
// 故意用函数内 static:AGENTS.md 禁止文件级 static。
|
||||
@@ -262,6 +265,15 @@ namespace SectionPerf
|
||||
}
|
||||
}
|
||||
|
||||
void NoteWriteBackClass(const char* pszClass)
|
||||
{
|
||||
Stats& s = GetStats();
|
||||
if (!s.bEnabled)
|
||||
return;
|
||||
std::string key(pszClass != NULL ? pszClass : "?");
|
||||
++s.writeBackByClass[key];
|
||||
}
|
||||
|
||||
void Dump()
|
||||
{
|
||||
Stats& s = GetStats();
|
||||
@@ -288,6 +300,18 @@ namespace SectionPerf
|
||||
s.nTempFiles, s.nTempFileBytes, s.nWriteBacks);
|
||||
out += szLine;
|
||||
|
||||
if (!s.writeBackByClass.empty())
|
||||
{
|
||||
out += "---- write-backs by entity class ----\n";
|
||||
out += " count class\n";
|
||||
for (std::map<std::string, unsigned long long>::const_iterator it = s.writeBackByClass.begin();
|
||||
it != s.writeBackByClass.end(); ++it)
|
||||
{
|
||||
sprintf_s(szLine, sizeof(szLine), " %-8llu %s\n", it->second, it->first.c_str());
|
||||
out += szLine;
|
||||
}
|
||||
}
|
||||
|
||||
if (!s.attrStats.empty())
|
||||
{
|
||||
out += "---- attr key (by class, would-be cache hit rate) ----\n";
|
||||
@@ -417,5 +441,6 @@ namespace SectionPerf
|
||||
s.nTempFileBytes = 0;
|
||||
s.nWriteBacks = 0;
|
||||
s.attrStats.clear();
|
||||
s.writeBackByClass.clear();
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,9 @@ namespace SectionPerf
|
||||
// 记录一次回写(Region -> SAT 文本)
|
||||
void NoteWriteBack(const char* pszTag);
|
||||
|
||||
// 记录一次回写,并按实体类分开统计(谁在开图期回写)
|
||||
void NoteWriteBackClass(const char* pszClass);
|
||||
|
||||
// 打印 + 写文件
|
||||
void Dump();
|
||||
|
||||
|
||||
@@ -322,6 +322,37 @@ pClone->dwgIn(&filer); // → dwgInFields → acisIn 读回来
|
||||
(`AecDbX3dPartEntity.cpp:757` 直接 `clone()`),但**尚未证实它就是本次的调用者**,
|
||||
需要用 PDB 解析上面三个 RVA 才能钉死。
|
||||
|
||||
**哪个类在回写**(按实体类统计):
|
||||
|
||||
```
|
||||
---- write-backs by entity class ----
|
||||
1140 AecDbEwPipeBase
|
||||
```
|
||||
|
||||
全部 1140 次都是 **`AecDbEwPipeBase` 基类实例**(不是 `AecDbEwPipe`,也不是任何具名子类)。
|
||||
它与属性 key 统计里 `AecDbEwPipeBase` 1172 次几乎一一对应 →
|
||||
图纸里有约 1172 个基类实例,绘制期每个被深拷贝一次。
|
||||
(这些实例由 `AecDbAssembleWell.cpp` 的装配井代码创建,多为矩形截面段。)
|
||||
|
||||
**完整调用链**(文件:行):
|
||||
|
||||
| 层次 | 位置 |
|
||||
| --- | --- |
|
||||
| 视口绘制 | `AecDbEntityCommon::base_ViewportDraw` → `AecDbCurveBase::subViewportDraw` |
|
||||
| 取变换副本 | `AecDbCurveBase::subGetTransformedCopy`(`AecRxBase/AecDbCurveBase.cpp:307`) |
|
||||
| ↑ 其中的 `clone()` | 触发深拷贝 |
|
||||
| 深拷贝实现 | `AecDbEntityCommon::base_DeepClone`(`AecRxBase/AecDbEntityCommon.cpp:1232`,`dwgOut` 在 :1265) |
|
||||
| 写字段 | `AecDbEwPipeBase::dwgOutFields`(`CoreLibrary/AecDbEwPipeBase.cpp:1440`) |
|
||||
| **写截面** | **`AecDbEwPipeBase::RegionAcisoutDwgOutFields`(`CoreLibrary/AecDbEwPipeBase.cpp:1275`)** |
|
||||
|
||||
即:`getTransformedCopy` → `clone()` → 全实体序列化 → 截面走 `acisOut` 写临时 SAT 文件。
|
||||
|
||||
注意 `AecDbEwPipeBase::copyFrom`(:1605)里复制截面用的是
|
||||
`m_pRegion->copyFrom(...)`(内存级 ACIS 拷贝),比"写文件再读回"便宜得多。
|
||||
所以最局部的修法可能是:给管系实体加一个 `subGetTransformedCopy` 重载,
|
||||
用 `isA()->create()` + `copyFrom()` 代替 `clone()`,绕开整条序列化链路。
|
||||
**但 clone 与 copyFrom 的语义并不完全等价,需要先核对**(扩展字典、XData、数据库驻留属性等)。
|
||||
|
||||
可选修法(都需要动 `base_DeepClone` 的契约,属于结构性改动,建议单独立项):
|
||||
|
||||
| 方案 | 做法 | 风险 |
|
||||
|
||||
Reference in new issue
Block a user