company-desktop
|
f840d733ca
|
diag: 量 X3dPart 几何存盘的真实体积与序列化成本
问题:上一轮判定"3D 缓存存盘对管道不做"时,顺带给 X3dPart(Rebuild 占开图
18~22%)估了个"体积 +10~40 MB、存盘 +1.5~4 s"——这是估算,没有实测,结论可能
把这条路误杀了。本次补上测量。
改动:AecDbX3dPart::EnsureCreated 里加一个探针(AEC_X3D_SIZEPROBE=1 才生效,
Release 零开销):每个 part 重建后对它的 m_pSolid 做一次 AcDbBody::acisOut
到临时文件,记录 SAT 字节数与耗时,然后删文件;每 100 个 part 把汇总写
%TEMP%\aec_x3d_probe.txt。同时记录同一次 Rebuild 的耗时用于对比。
big1.dwg 实测(AutoCAD 2020 / R230 Debug,开图 95 s):
- 有几何的 part:1200(1248 个里 48 个 Hide/空,无 solid)
- SAT 总字节 3.56 MB,平均 2968 B/part,最大 36086 B
- acisOut 平均 0.799 ms/part;Rebuild 平均 15.3 ms/part(本次合计 20.4 s)
- 重建 / 序列化 = 19.1 倍
据此(都取保守侧):
- DWG 体积增量 ≤ 3.4 MB(8.2 -> ~11.6 MB,+42%)——DWG 里存的是二进制 SAB,
通常比 SAT 文本更小;
- 每次存盘多花 ≤ 0.96 s(1200 x 0.8 ms),且二进制写比转文本便宜、不落盘;
- 开图预计省 15~18 s(重建 18~20 s,恢复按 acisOut 同量级估 1~2 s)。
结论修正:X3dPart 这条"几何存盘"是值得做的,之前的体积/耗时估算高估了 3~10 倍。
配套说明写进 3d-cache-dwg-verdict.md §7。
|
2026-10-29 23:00:03 +08:00 |
|
company-desktop
|
ece4788723
|
diag: 实测 3D 缓存存盘方案,判定对管道不做
现象:工作计划第 2 项要求把自定义实体的 3D 缓存(m_ar3DDrableBufPtrs_)
用 acdbModelerSave/RestoreEntities*Filer 存进 DWG,再用 AecDbEwPipe 做开图时间对比,
判断这套机制有没有必要。
结论:按原方案对管道不做。数据(big1.dwg,AutoCAD 2020 / R230 Debug,开图 89 s):
- EwPipeBase::Draw3d 整函数 0.20~3.34 s(106~650 次),占开图 0.2~3.7%,
而且随"开图时视图里有多少管道"变化;1088 个管道里大部分根本没画 3D。
- X3dPart::Rebuild 16.4~19.4 s(1248 次),占 18~22%,才是几何重建的大头。
- 基础体构造(GDU DrawPipe/Loft/Cylinder/Cone)合计 36.7 s,与上面有重叠,
大头不在管道身上。
机制层面撞到三个坑(都写进文档了):
1. 附加块只能挂在叶子类。第一版挂在 AecDbEwPipeBase::dwgOut/InFields,
AecDbBDPipeBase / XWall / XSlab / Beam / Weir 等派生类都继承它并在其后继续写字段,
基类读尾部块等于吃掉派生类第一个字段,XWall 曲线长度读成垃圾后无限 append,
开图从 89 s 变 10 分钟开不出来(xperf 采样定位到 AecComplexCurve::append)。
2. 增量存盘下 dwgOutFields 不会被调用。跟踪确认:开图期 AecDbEwPipe::dwgInFields
被调 1088 次,而存盘时 AecDbEwPipe::dwgOutFields 被调 0 次;同一次存盘里
XSlab 374 / XWall 333 / Weir 144 / Beam 126 等都写了(它们载入时被改脏)。
ISAVEPERCENT=0、SAVEAS 到新文件都改变不了。→ "存盘顺带写字"只对本次改过的对象成立。
3. 3D 缓存本身只在画过之后才有内容,没画到的对象缓冲区是空的。
改动范围:
- 只保留两处 Debug-only 计时(AEC_PERF_COUNTER=1 才生效,Release 零开销):
AecDbEwPipeBase::Draw3d(总耗时/重建/命中)与 AecDbX3dPart::EnsureCreated
(构件重建耗时,作为"几何存盘"收益天花板)。
- modeler filer 试点代码(写块/读块/补非 brep)全部回退,不留死代码。
- 新增 3d-cache-dwg-verdict.md 记录数据、三个坑与建议。
验证方式:R230 Debug 编译通过并部署;big1.dwg 冷启动多次实测,
计数器见 %TEMP%\aec_section_perf.txt;卡死那次的栈用 tools/perf_diagsession.py 解析。
未做 R190 / Z2026 编译(本轮没有平台相关代码,试点代码已回退)。
已知风险:无(新增代码只在 Debug+AEC_PERF_COUNTER=1 下计时)。
|
2026-10-29 21:26:53 +08:00 |
|
company-desktop
|
facf14699b
|
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/正常。
|
2026-10-28 22:51:01 +08:00 |
|
company-desktop
|
8ca9519320
|
refactor: X3dPart 的懒加载标志改名 m_bNeedCreate 并加 mutable
与 AcDbX3dSolid::m_bNeedCreate 对齐:同一个语义(派生几何缓存失效,
首次使用时再算),用同一个名字,避免 m_bDirty 被理解成"参数没写完"。
声明为 mutable,与 AcDbX3dSolid 一致;清标志仍在 Rebuild() 里做。
|
2026-10-22 15:41:14 +08:00 |
|
company-desktop
|
5a5cd08721
|
perf: X3dPart 布尔结果改为按需重建,开图不再逐件建体
方案 A(见 AcDbX3dSolid-refactor-plan.md 第 13 节)。开图慢的瓶颈是
AecDbX3dPartEntity::dwgInFields 无条件调 m_pPart->Create(),每个 part 都要
N 次建体 + N 次布尔。
A1:引入 m_bDirty
- AecDbX3dPart 增加 m_bDirty,构造/拷贝构造置 true
- 15 个改参数的接口置脏:AddX3dSolid、RemoveAt、RemoveAll3dSolidRec、
SetOrgPoint、SetAxis、SetBoolOperFor、SetHide、SetActive、PeelOffTheSkin、
AddMove×2、ResetMove、AddRotate、ResetRotate、CopyFrom
- 新增 Rebuild()(protected):清标志后无条件重建,原 Create() 的函数体
- 新增 EnsureCreated():m_bDirty 或 m_pSolid 为空时才 Rebuild
Create() 保持「显式调用一律重建」的语义,内部转调 Rebuild()。原因是外部
有 10 处先取 GetX3dSolid(0) 直接改(如 AecDbBDPipeBase:941 调 TransformBy)
再调 Create(),部件感知不到这类改动,做成幂等会漏掉重建。
A2:开图不建几何
- AecDbX3dPartEntity::dwgInFields 去掉 m_pPart->Create(),由
AecDbX3dPart::dwgInFields 结尾置脏
- 读入口统一先 EnsureCreated:CreateDraw3dSolid、Draw3d、getOsnapPoints、
GetForHouseSubtract
收益:关闭/冻结图层、视口外、XREF/审核/发布等不绘制的场景完全省掉建体与
布尔;全图可见时开图时间下降、首次 regen 补回。
|
2026-10-22 15:07:18 +08:00 |
|
gjm
|
164968b62e
|
chore
把非utf8-bom编码的cpp/h文件改为 utf8 bom 编码, msvc识别utf8编码时,如果不是bom格式的,会使用当前cp_oem来解码.
|
2026-10-04 00:04:20 +08:00 |
|
gjm
|
345044cb46
|
初始化提交
|
2026-09-28 15:28:50 +08:00 |
|