From b981fe930a65489bd8ac3a05dbf83b06bd59e144 Mon Sep 17 00:00:00 2001 From: company-desktop-computer Date: Wed, 28 Oct 2026 21:57:31 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E6=8A=A4=E6=A0=8F/=E7=88=AC=E6=A2=AF?= =?UTF-8?q?=E7=AD=89=E6=9E=84=E4=BB=B6=E7=9A=84=E7=AE=A1=E9=81=93=E5=89=AF?= =?UTF-8?q?=E6=9C=AC=E6=94=B9=E4=B8=BA"=E5=8F=AA=E5=AD=98=E5=8F=82?= =?UTF-8?q?=E6=95=B0"=EF=BC=8C=E6=B6=88=E9=99=A4=E5=BC=80=E5=9B=BE?= =?UTF-8?q?=E6=9C=9F=201140=20=E6=AC=A1=E6=88=AA=E9=9D=A2=E5=9B=9E?= =?UTF-8?q?=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 现象:开图期间 AecDbEwPipeBase::RegionAcisoutDwgOutFields 被调用 1140 次、耗时 2.38 s, 把截面写成临时 SAT 文件。用 AEC_WRITEBACK_TRACE 抓栈 + tools/resolve_rva.ps1 解符号, 定位到 AecDbZLineStair::DrawGuarBar3d 里的 pipe.clone(): clone 走 AcDbObject → AecDbEwPipeBase::copyFrom → CopyObject(整实体 dwgOutFields/dwgInFields 往返),于是截面被写成临时文件再读回。 这些 clone 的唯一用途是存进 m_pipes,供 ToJson() 导出 __pipes__,而截面参数在 SetSection 时已经写进 spec XData(KEY_SECSHAPE / KEY_SIZE1 / KEY_SIZE2 / PIPE_THICK / KEY_SECCEN),完全可以按参数重建。因此把"建几何"推迟到导出时: - AecDbEwPipeBase::BuildSectionFromXData():按 XData 参数重建截面(圆形/矩形; 自定义截面返回 NULL,那种只能存在于 SAT 里) - AecDbEwPipeBase::CloneParamsOnly():生成只带参数(XData、放样线、实体属性、GUID、 Breaks)、不含截面几何的副本,不触发任何序列化 - AecDbEwPipeBase::ToJson():GetSection() 为空时回退到 BuildSectionFromXData(), 保证 __section__ / __section2__ 仍然导出 - 30 处 m_pipes.push_back((AecDbEwPipe*)pipe.clone()) 改为 pipe.CloneParamsOnly(): ClimbStair(10)、ZLineStair(6)、BossHolder(4)、MRPLineStair(4)、Hanger(3)、Holder(3) 过程:先只改楼梯两个文件,回写从 1140 降到 960;再抓栈解析出剩余 960 全部来自 AecDbClimbStair::DrawLadderH3d,于是把其余 20 处一并改掉,最终归零。 实测(big1.dwg / AutoCAD 2020 / R230 Debug): 开图墙钟 初始 108~113 s -> 缓存后 98 s -> 本次 93 s 开图期回写 1140 次/2.38 s -> 1140 次 -> 0 RegionAcisIn 3082 次 -> 3082 次 -> 1942 次 临时文件 6773/9.34MB -> 2694/3.34MB -> 1733/2.34MB 截面恢复总耗时 22.4 s -> 9.87 s -> 9.4 s 另外把 SectionPerf::TraceCallStack 的输出改写到独立的 aec_writeback_trace.txt, 不再写进 ENVIPERFDUMP 的报告文件(否则脚本会把"栈写出来了"误判成"开图完成")。 验证:R230 Debug 编译通过并部署;用 tools/run_acad_perf.ps1 自动开图取数。 待验证:JSON 导出。m_pipes 里现在是不含几何的参数副本,ToJson 靠 BuildSectionFromXData() 重建,需要实际触发一次导出,确认 __pipes__ 里每条仍有 __section__ / __section2__ 且与改动前一致。 --- .../Code2026/CoreLibrary/AecDbBossHolder.cpp | 8 +-- .../Code2026/CoreLibrary/AecDbClimbStair.cpp | 20 +++---- .../Code2026/CoreLibrary/AecDbEwPipeBase.cpp | 55 +++++++++++++++++++ .../Code2026/CoreLibrary/AecDbHanger.cpp | 6 +- .../Code2026/CoreLibrary/AecDbHolder.cpp | 6 +- .../CoreLibrary/AecDbMRPLineStair.cpp | 8 +-- .../Code2026/CoreLibrary/AecDbZLineStair.cpp | 12 ++-- .../CoreLibrary/SectionPerfCounter.cpp | 17 +++++- SourceCode/Code2026/inc/AecDbEwPipeBase.h | 8 +++ pipe-section-region-performance-plan.md | 37 +++++++++++++ 10 files changed, 146 insertions(+), 31 deletions(-) diff --git a/SourceCode/Code2026/CoreLibrary/AecDbBossHolder.cpp b/SourceCode/Code2026/CoreLibrary/AecDbBossHolder.cpp index f7d1ce2..cadb788 100644 --- a/SourceCode/Code2026/CoreLibrary/AecDbBossHolder.cpp +++ b/SourceCode/Code2026/CoreLibrary/AecDbBossHolder.cpp @@ -1126,7 +1126,7 @@ AcDb3dSolid *AecDbBossHolder::Create3dRod(const AcGePoint3d &ptFr, const AcGePoi pipe.SetSectionRotation(dRegRoate); pipe.SetStartPoint(ptFr); pipe.SetEndPoint(ptTo); - m_pipes.push_back((AecDbEwPipe *)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 pipe.Draw3d(dcTmp); pPipe = pipe.GetCreatPipe3dSolid(); @@ -1145,7 +1145,7 @@ AcDb3dSolid* AecDbBossHolder::Create3dRod(const AcGePoint3d& ptFr,const AcGePoin pipe.SetStartPoint(ptFr); pipe.SetEndPoint(ptTo); - m_pipes.push_back((AecDbEwPipe*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 pipe.Draw3d(dcTmp); pPipe = pipe.GetCreatPipe3dSolid(); @@ -1157,7 +1157,7 @@ AcDb3dSolid* AecDbBossHolder::Create3dRod(const AcGePoint3d& ptFr,const AcGePoin pipe.SetSectionRotation(dRegRoate); pipe.SetStartPoint(ptFr); pipe.SetEndPoint(ptTo); - m_pipes.push_back((AecDbEwPipe*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 pipe.Draw3d(dcTmp); pPipe = pipe.GetCreatPipe3dSolid(); @@ -1169,7 +1169,7 @@ AcDb3dSolid* AecDbBossHolder::Create3dRod(const AcGePoint3d& ptFr,const AcGePoin pipe.SetSectionRotation(dRegRoate); pipe.SetStartPoint(ptFr); pipe.SetEndPoint(ptTo); - m_pipes.push_back((AecDbEwPipe*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 pipe.Draw3d(dcTmp); pPipe = pipe.GetCreatPipe3dSolid(); diff --git a/SourceCode/Code2026/CoreLibrary/AecDbClimbStair.cpp b/SourceCode/Code2026/CoreLibrary/AecDbClimbStair.cpp index 3c4d959..5d440c4 100644 --- a/SourceCode/Code2026/CoreLibrary/AecDbClimbStair.cpp +++ b/SourceCode/Code2026/CoreLibrary/AecDbClimbStair.cpp @@ -669,7 +669,7 @@ Acad::ErrorStatus AecDbClimbStair::DrawLadderH3d(AcGiDraw &dc,const AcGeVector3d pEnt3d = dc.DrawPipe(&ln,pReg,AcGePoint3d::kOrigin); pipe.SetBaseCurve(&ln); pipe.SetSection(pReg,AcGePoint3d::kOrigin); - m_pipes.push_back((AecDbEwPipeBase*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 if (pEnt3d != NULL) { Add3DBuffer(pEnt3d); @@ -692,7 +692,7 @@ Acad::ErrorStatus AecDbClimbStair::DrawLadderH3d(AcGiDraw &dc,const AcGeVector3d pEnt3d = dc.DrawPipe(&ln,pReg,AcGePoint3d::kOrigin); pipe.SetBaseCurve(&ln); pipe.SetSection(pReg, AcGePoint3d::kOrigin); - m_pipes.push_back((AecDbEwPipeBase*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 if (pEnt3d != NULL) { Add3DBuffer(pEnt3d); @@ -705,7 +705,7 @@ Acad::ErrorStatus AecDbClimbStair::DrawLadderH3d(AcGiDraw &dc,const AcGeVector3d pEnt3d = dc.DrawPipe(&ln,pReg,AcGePoint3d::kOrigin); pipe.SetBaseCurve(&ln); pipe.SetSection(pReg, AcGePoint3d::kOrigin); - m_pipes.push_back((AecDbEwPipeBase*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 if (pEnt3d != NULL) { Add3DBuffer(pEnt3d); @@ -732,7 +732,7 @@ Acad::ErrorStatus AecDbClimbStair::DrawLadderH3d(AcGiDraw &dc,const AcGeVector3d pEnt3d = dc.DrawPipe(&ln,pReg,AcGePoint3d::kOrigin); pipe.SetBaseCurve(&ln); pipe.SetSection(pReg, AcGePoint3d::kOrigin); - m_pipes.push_back((AecDbEwPipeBase*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 if (pEnt3d != NULL) { Add3DBuffer(pEnt3d); @@ -752,7 +752,7 @@ Acad::ErrorStatus AecDbClimbStair::DrawLadderH3d(AcGiDraw &dc,const AcGeVector3d pEnt3d = dc.DrawPipe(&ln,pReg,AcGePoint3d::kOrigin); pipe.SetBaseCurve(&ln); pipe.SetSection(pReg, AcGePoint3d::kOrigin); - m_pipes.push_back((AecDbEwPipeBase*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 if (pEnt3d != NULL) { Add3DBuffer(pEnt3d); @@ -848,7 +848,7 @@ Acad::ErrorStatus AecDbClimbStair::DrawGuardBar3d(AcGiDraw &dc,const AcGeVector3 pEnt3d = dc.DrawPipe(pPl,pRegCln,AcGePoint3d::kOrigin); pipe.SetBaseCurve(pPl); pipe.SetSection(pRegCln, AcGePoint3d::kOrigin); - m_pipes.push_back((AecDbEwPipeBase*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 if (pEnt3d != NULL) { Add3DBuffer(pEnt3d); @@ -868,7 +868,7 @@ Acad::ErrorStatus AecDbClimbStair::DrawGuardBar3d(AcGiDraw &dc,const AcGeVector3 pEnt3d = dc.DrawPipe(pPl,pRegCln,AcGePoint3d::kOrigin); pipe.SetBaseCurve(pPl); pipe.SetSection(pRegCln, AcGePoint3d::kOrigin); - m_pipes.push_back((AecDbEwPipeBase*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 if (pEnt3d != NULL) { Add3DBuffer(pEnt3d); @@ -899,7 +899,7 @@ Acad::ErrorStatus AecDbClimbStair::DrawGuardBar3d(AcGiDraw &dc,const AcGeVector3 pEnt3d = dc.DrawPipe(pLn,pRegCln,AcGePoint3d::kOrigin); pipe.SetBaseCurve(pLn); pipe.SetSection(pRegCln, AcGePoint3d::kOrigin); - m_pipes.push_back((AecDbEwPipeBase*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 if (pEnt3d != NULL) { Add3DBuffer(pEnt3d); @@ -924,7 +924,7 @@ Acad::ErrorStatus AecDbClimbStair::DrawGuardBar3d(AcGiDraw &dc,const AcGeVector3 pEnt3d = dc.DrawPipe(pLn,pRegCln,AcGePoint3d::kOrigin); pipe.SetBaseCurve(pLn); pipe.SetSection(pRegCln, AcGePoint3d::kOrigin); - m_pipes.push_back((AecDbEwPipeBase*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 if (pEnt3d != NULL) { Add3DBuffer(pEnt3d); @@ -955,7 +955,7 @@ Acad::ErrorStatus AecDbClimbStair::DrawGuardBar3d(AcGiDraw &dc,const AcGeVector3 pEnt3d = dc.DrawPipe(pLn,pRegCln,AcGePoint3d::kOrigin); pipe.SetBaseCurve(pLn); pipe.SetSection(pRegCln, AcGePoint3d::kOrigin); - m_pipes.push_back((AecDbEwPipeBase*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 if (pEnt3d != NULL) { Add3DBuffer(pEnt3d); diff --git a/SourceCode/Code2026/CoreLibrary/AecDbEwPipeBase.cpp b/SourceCode/Code2026/CoreLibrary/AecDbEwPipeBase.cpp index 659bf52..d773b8e 100644 --- a/SourceCode/Code2026/CoreLibrary/AecDbEwPipeBase.cpp +++ b/SourceCode/Code2026/CoreLibrary/AecDbEwPipeBase.cpp @@ -7820,6 +7820,59 @@ AcDbObjectId AecDbEwPipeBase::GetCenterLayer() const return m_idCenterLayer; } + +AcDbRegion* AecDbEwPipeBase::BuildSectionFromXData() const +{ + int nShape = 0; + if (!m_mapSpecXData.GetAt(KEY_SECSHAPE, nShape)) + return NULL; + + double d1 = 0.0, d2 = 0.0, dt = 0.0; + if (!m_mapSpecXData.GetAt(KEY_SIZE1, d1)) + return NULL; + m_mapSpecXData.GetAt(KEY_SIZE2, d2); + m_mapSpecXData.GetAt(PIPE_THICK, dt); + + // 借一个临时对象复用 SetSection 的全部逻辑,取到 clone 后临时对象析构 + AecDbEwPipeBase tmp; + Acad::ErrorStatus es = Acad::eInvalidInput; + if (nShape == eCircle) + es = tmp.SetSection(d1, dt); + else if (nShape == eRect) + es = tmp.SetSection(d1, d2, dt); + else + return NULL; // 自定义截面(SAT 里才有)无法由参数重建 + + if (es != Acad::eOk) + return NULL; + return tmp.GetSection(); +} + +AecDbEwPipeBase* AecDbEwPipeBase::CloneParamsOnly() const +{ + AecDbEwPipeBase* pNew = (AecDbEwPipeBase*)AecDbEwPipeBase::desc()->create(); + if (pNew == NULL) + return NULL; + + // 图层/颜色/线型等实体属性 + pNew->setPropertiesFrom(this); + // 专业数据(含截面参数、GUID 等) + pNew->m_mapSpecXData.CopyFrom(&m_mapSpecXData); + pNew->m_sGUID = m_sGUID; + // 放样线 + AcDbCurve* pCurve = GetBaseCurve(); + if (pCurve != NULL) + { + pNew->SetBaseCurve(pCurve); + DELETE_PTR(pCurve); + } + pNew->m_nInfActive = m_nInfActive; + pNew->m_arBreaks.removeAll(); + pNew->m_arBreaks.append(m_arBreaks); + // 故意不复制 m_pRegion:截面交给 ToJson() 按参数重建 + return pNew; +} + SHJson::WValue& AecDbEwPipeBase::ToJson(bool bExprotGeo) const { using namespace SHJson; @@ -7836,6 +7889,8 @@ SHJson::WValue& AecDbEwPipeBase::ToJson(bool bExprotGeo) const addMember(v, _T("__path__"), GEO2JSON::path(*pBaseCurve).ToJson()); AcDbRegion *pReg(GetSection()); + if (pReg == NULL) + pReg = BuildSectionFromXData(); // 延迟导出:绘制期没留几何,这里按参数重建 if (pReg) { addMember(v, _T("__section__"), GEO2JSON::region(*pReg).ToJson()); diff --git a/SourceCode/Code2026/CoreLibrary/AecDbHanger.cpp b/SourceCode/Code2026/CoreLibrary/AecDbHanger.cpp index 2ba079d..4350ab1 100644 --- a/SourceCode/Code2026/CoreLibrary/AecDbHanger.cpp +++ b/SourceCode/Code2026/CoreLibrary/AecDbHanger.cpp @@ -1003,7 +1003,7 @@ AcDb3dSolid* AecDbHanger::Create3dRod(const AcGePoint3d& ptFr,const AcGePoint3d& pipe.SetSection(dL1,0.0); pipe.SetStartPoint(ptFr); pipe.SetEndPoint(ptTo); - m_pipes.push_back((AecDbEwPipe*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 pipe.Draw3d(dcTmp); pPipe = pipe.GetCreatPipe3dSolid(); @@ -1015,7 +1015,7 @@ AcDb3dSolid* AecDbHanger::Create3dRod(const AcGePoint3d& ptFr,const AcGePoint3d& pipe.SetSectionRotation(dRegRoate); pipe.SetStartPoint(ptFr); pipe.SetEndPoint(ptTo); - m_pipes.push_back((AecDbEwPipe*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 pipe.Draw3d(dcTmp); pPipe = pipe.GetCreatPipe3dSolid(); @@ -1027,7 +1027,7 @@ AcDb3dSolid* AecDbHanger::Create3dRod(const AcGePoint3d& ptFr,const AcGePoint3d& pipe.SetSectionRotation(dRegRoate); pipe.SetStartPoint(ptFr); pipe.SetEndPoint(ptTo); - m_pipes.push_back((AecDbEwPipe*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 pipe.Draw3d(dcTmp); pPipe = pipe.GetCreatPipe3dSolid(); } diff --git a/SourceCode/Code2026/CoreLibrary/AecDbHolder.cpp b/SourceCode/Code2026/CoreLibrary/AecDbHolder.cpp index 7cc4437..1339ad2 100644 --- a/SourceCode/Code2026/CoreLibrary/AecDbHolder.cpp +++ b/SourceCode/Code2026/CoreLibrary/AecDbHolder.cpp @@ -870,7 +870,7 @@ AcDb3dSolid* AecDbHolder::Create3dRod(const AcGePoint3d& ptFr,const AcGePoint3d& pipe.SetSection(dL1,0.0); pipe.SetStartPoint(ptFr); pipe.SetEndPoint(ptTo); - m_pipes.push_back((AecDbEwPipe*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 pipe.Draw3d(dcTmp); pPipe = pipe.GetCreatPipe3dSolid(); @@ -882,7 +882,7 @@ AcDb3dSolid* AecDbHolder::Create3dRod(const AcGePoint3d& ptFr,const AcGePoint3d& pipe.SetSectionRotation(dRegRoate); pipe.SetStartPoint(ptFr); pipe.SetEndPoint(ptTo); - m_pipes.push_back((AecDbEwPipe*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 pipe.Draw3d(dcTmp); pPipe = pipe.GetCreatPipe3dSolid(); @@ -894,7 +894,7 @@ AcDb3dSolid* AecDbHolder::Create3dRod(const AcGePoint3d& ptFr,const AcGePoint3d& pipe.SetSectionRotation(dRegRoate); pipe.SetStartPoint(ptFr); pipe.SetEndPoint(ptTo); - m_pipes.push_back((AecDbEwPipe*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 pipe.Draw3d(dcTmp); pPipe = pipe.GetCreatPipe3dSolid(); } diff --git a/SourceCode/Code2026/CoreLibrary/AecDbMRPLineStair.cpp b/SourceCode/Code2026/CoreLibrary/AecDbMRPLineStair.cpp index cc26ed9..ff6e901 100644 --- a/SourceCode/Code2026/CoreLibrary/AecDbMRPLineStair.cpp +++ b/SourceCode/Code2026/CoreLibrary/AecDbMRPLineStair.cpp @@ -916,7 +916,7 @@ Acad::ErrorStatus AecDbMRPLineStair::DrawGuarBar3d(AcGiDraw &dc,AcGePoint3dArray if (data.nGarBarLR != 1)//左有 { pipe.Draw3d(dc2); - m_pipes.push_back((AecDbEwPipeBase*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 pipe.Clean3DBufferNoDel(); } @@ -932,7 +932,7 @@ Acad::ErrorStatus AecDbMRPLineStair::DrawGuarBar3d(AcGiDraw &dc,AcGePoint3dArray if (data.nGarBarLR > 0)//右有 { pipe.Draw3d(dc2); - m_pipes.push_back((AecDbEwPipeBase*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 pipe.Clean3DBufferNoDel(); } } @@ -967,7 +967,7 @@ Acad::ErrorStatus AecDbMRPLineStair::DrawGuarBar3d(AcGiDraw &dc,AcGePoint3dArray if (data.nGarBarLR != 1)//左有 { pipe.Draw3d(dc2); - m_pipes.push_back((AecDbEwPipeBase*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 pipe.Clean3DBufferNoDel(); } delete pPl; @@ -986,7 +986,7 @@ Acad::ErrorStatus AecDbMRPLineStair::DrawGuarBar3d(AcGiDraw &dc,AcGePoint3dArray if (data.nGarBarLR > 0)//右有 { pipe.Draw3d(dc2); - m_pipes.push_back((AecDbEwPipeBase*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 pipe.Clean3DBufferNoDel(); } diff --git a/SourceCode/Code2026/CoreLibrary/AecDbZLineStair.cpp b/SourceCode/Code2026/CoreLibrary/AecDbZLineStair.cpp index 877f2f6..476a936 100644 --- a/SourceCode/Code2026/CoreLibrary/AecDbZLineStair.cpp +++ b/SourceCode/Code2026/CoreLibrary/AecDbZLineStair.cpp @@ -1073,7 +1073,7 @@ Acad::ErrorStatus AecDbZLineStair::DrawGuarBar3d(AcGiDraw &dc,AcGePoint3dArray& pipe.SetBaseCurve(&ln); pipe.Draw3d(dc2); - m_pipes.push_back((AecDbEwPipeBase*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 pipe.Clean3DBufferNoDel(); @@ -1086,7 +1086,7 @@ Acad::ErrorStatus AecDbZLineStair::DrawGuarBar3d(AcGiDraw &dc,AcGePoint3dArray& pipe.SetBaseCurve(&ln); pipe.Draw3d(dc2); - m_pipes.push_back((AecDbEwPipeBase*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 pipe.Clean3DBufferNoDel(); } @@ -1102,7 +1102,7 @@ Acad::ErrorStatus AecDbZLineStair::DrawGuarBar3d(AcGiDraw &dc,AcGePoint3dArray& pipe.SetBaseCurve(&ln); pipe.Draw3d(dc2); - m_pipes.push_back((AecDbEwPipeBase*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 pipe.Clean3DBufferNoDel(); //扶手伸出 @@ -1116,7 +1116,7 @@ Acad::ErrorStatus AecDbZLineStair::DrawGuarBar3d(AcGiDraw &dc,AcGePoint3dArray& pipe.SetBaseCurve(&ln); pipe.Draw3d(dc2); - m_pipes.push_back((AecDbEwPipeBase*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 pipe.Clean3DBufferNoDel(); //对称位置 @@ -1127,7 +1127,7 @@ Acad::ErrorStatus AecDbZLineStair::DrawGuarBar3d(AcGiDraw &dc,AcGePoint3dArray& pipe.SetBaseCurve(&ln); pipe.Draw3d(dc2); - m_pipes.push_back((AecDbEwPipeBase*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 pipe.Clean3DBufferNoDel(); //扶手伸出 @@ -1137,7 +1137,7 @@ Acad::ErrorStatus AecDbZLineStair::DrawGuarBar3d(AcGiDraw &dc,AcGePoint3dArray& pipe.SetBaseCurve(&ln); pipe.Draw3d(dc2); - m_pipes.push_back((AecDbEwPipeBase*)pipe.clone()); + m_pipes.push_back(pipe.CloneParamsOnly()); // 只存参数,截面在 ToJson() 时重建 pipe.Clean3DBufferNoDel(); int nCrbk = dc.GetColor(); diff --git a/SourceCode/Code2026/CoreLibrary/SectionPerfCounter.cpp b/SourceCode/Code2026/CoreLibrary/SectionPerfCounter.cpp index c52f11a..7f5c4b2 100644 --- a/SourceCode/Code2026/CoreLibrary/SectionPerfCounter.cpp +++ b/SourceCode/Code2026/CoreLibrary/SectionPerfCounter.cpp @@ -411,7 +411,22 @@ namespace SectionPerf sprintf_s(szLine, sizeof(szLine), " %-28s +0x%llx\n", szMod, (unsigned long long)(nAddr - (DWORD64)hMod)); out += szLine; } - AppendReport(out.c_str()); + // 写到独立文件:不打扰 ENVIPERFDUMP 的报告文件(脚本靠它判断就绪) + { + char szTmp[MAX_PATH + 1]; + ::memset(szTmp, 0, sizeof(szTmp)); + if (::GetTempPathA(MAX_PATH, szTmp) != 0) + { + 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, "%s", out.c_str()); + fclose(fp); + } + } + } } void AppendReport(const char* pszText) diff --git a/SourceCode/Code2026/inc/AecDbEwPipeBase.h b/SourceCode/Code2026/inc/AecDbEwPipeBase.h index 02829f8..413f1e7 100644 --- a/SourceCode/Code2026/inc/AecDbEwPipeBase.h +++ b/SourceCode/Code2026/inc/AecDbEwPipeBase.h @@ -239,6 +239,14 @@ public: //获取截面的复制 AcDbRegion* GetSection() const; + // 按 XData 里存的截面参数(SECS HAP/SIZE1/SIZE2/THICK)重建截面,调用方负责释放。 + // 用于"延迟导出":绘制期只留参数副本,导出 JSON 时再建几何。 + AcDbRegion* BuildSectionFromXData() const; + + // 生成一个只带参数(不含截面几何)的副本,供 m_pipes 之类"延迟导出"的容器使用。 + // 与 clone() 的区别:不触发 dwgOutFields 序列化,因此不会把截面写成临时 SAT 文件。 + AecDbEwPipeBase* CloneParamsOnly() const; + //设置界面绕轴旋转,以X 方向为基准 Acad::ErrorStatus SetSectionRotation(double dAngle); diff --git a/pipe-section-region-performance-plan.md b/pipe-section-region-performance-plan.md index 1627759..8f8a7d1 100644 --- a/pipe-section-region-performance-plan.md +++ b/pipe-section-region-performance-plan.md @@ -377,6 +377,43 @@ pClone->dwgIn(&filer); // → dwgInFields → acisIn 读回来 > 再用 `tools/resolve_rva.ps1` 把"模块+RVA"解析成函数名。 > 单靠栈不解析符号很容易误判(本次就误判了两次)。 +### 开图期回写的修复:把 clone 延迟到 ToJson() + +按上面的结论,`m_pipes` 的唯一用途是 `ToJson()` 导出 `__pipes__`, +而截面参数(`KEY_SECSHAPE` / `KEY_SIZE1` / `KEY_SIZE2` / `PIPE_THICK` / `KEY_SECCEN`) +在建截面时已经写进 spec XData,**完全可以按参数重建**。 +所以绘制期不必保留几何,等导出时再建。 + +改动: + +1. `AecDbEwPipeBase` 新增两个方法 + - `BuildSectionFromXData()`:按 XData 参数重建截面(圆形 / 矩形),自定义截面返回 NULL + - `CloneParamsOnly()`:生成只带参数(XData / 放样线 / 实体属性 / GUID / Breaks)、 + **不含截面几何**的副本 +2. `AecDbEwPipeBase::ToJson()`:`GetSection()` 为空时回退到 `BuildSectionFromXData()`, + 保证 `__section__` / `__section2__` 仍在 +3. 把所有 `m_pipes.push_back((AecDbEwPipeBase*)pipe.clone())` 改成 + `m_pipes.push_back(pipe.CloneParamsOnly())`,共 **30 处 / 6 个文件**: + ClimbStair(10)、ZLineStair(6)、BossHolder(4)、MRPLineStair(4)、Hanger(3)、Holder(3) + +先只改楼梯两处时,回写从 1140 降到 960 —— 用 `AEC_WRITEBACK_TRACE` 再抓栈, +解析出剩余 960 全部来自 `AecDbClimbStair::DrawLadderH3d`(爬梯), +恰好对应 ClimbStair 的 10 处,于是把其余 20 处一并改掉。 + +实测(big1.dwg,AutoCAD 2020 / R230 Debug): + +| 指标 | 初始 | 加缓存后 | 本次修复后 | +| --- | ---: | ---: | ---: | +| 开图墙钟 | 108~113 s | 98 s | **93 s** | +| 开图期回写 | 1140 次 / 2.38 s | 1140 次 | **0** | +| `EwPipe::RegionAcisIn` | 3082 次 | 3082 次 | **1942 次** | +| 临时文件 | 6773 次 / 9.34 MB | 2694 次 / 3.34 MB | **1733 次 / 2.34 MB** | +| 截面恢复总耗时 | 22.4 s | 9.87 s | **9.4 s** | + +**待验证(本次没条件跑)**:JSON 导出。`m_pipes` 里现在是"无几何的参数副本", +`ToJson()` 靠 `BuildSectionFromXData()` 重建,需要实际触发一次导出, +确认 `__pipes__` 里每条仍有 `__section__` / `__section2__` 且数值与改动前一致。 + ### Phase 2:临时目录治理(可选,止血) Phase 1 之后残余落盘只剩"每个唯一截面一次",收益小;但如果现场仍被杀软拖慢,可做这一步: