perf: 增加截面 Region 缓存,开图恢复耗时降 56%
一次开图要做 5641 次截面恢复(22.4 s),其中大量内容重复,
而每次恢复都是"写临时 SAT 文件 + 从盘 acisIn + 删文件",单次 2.7~5.5 ms,
还要过一次杀软。本提交加一级母体缓存,命中直接 clone 返回。
新增 CoreLibrary/SectionRegionCache.{h,cpp},三个通道按 key 的正确性强度分开:
- kParam:纯参数 hash,用于 AecDbEwFitting::GetSection 的两个重载
(key = dD/dt/HLR 标志 或 W/H/dt/HLR 标志,同参数必同几何)
- kAttr:类名 + spec XData(排除编号,并跳过 Id/点/向量/矩阵/二进制类型),
只给 AecDbEwPipe 用。AecDbEwPipeBase 是很多类的基类,其余派生类实例间的
区别就是截面,不满足"同数据必同截面",所以一律走内容 hash
- kText:SAT 文本内容 hash,用于 RegionAcisInDwgInFields 的其它类
与 CoreTools::StringToRegion 的两个重载
约定:母体由缓存持有、永不外泄,Acquire/Put 都返回 clone,调用方拥有返回值;
母体不入库;每条通道 4096 条上限(AEC_SECTION_CACHE_MAX 可调),超出按 FIFO 淘汰;
AEC_SECTION_CACHE=0 可整体关闭做 A/B;卸载时 ClearAll() 释放,避免 DLL 析构顺序问题。
关键发现:SAT 文本第 2 行带存盘时间戳
16 Autodesk AutoCAD 19 ASM 219.0.0.5600 NT 24 Thu Oct 22 10:19:20 2026
同一几何存盘时间不同,整份文本就不同(采样里两份 2596 字节的文本只差
10:19:20 与 10:19:16),这正是内容 hash 命中率只有 54% 的原因,与截面无关。
因此新增 HashSatText():算 hash 时跳过第 2 行,仅当该行含 "Autodesk" 时才跳过。
计数器也改用同一口径,避免两套统计互相矛盾。
实测(big1.dwg / AutoCAD 2020 / R230 Debug,AEC_SECTION_CACHE 关 vs 开):
开图墙钟 108~113 s -> 98 s
截面恢复总耗时 22.4 s -> 9.87 s(-56%)
StringToRegion 14.05 s -> 7.73 s
RegionAcisIn 8.38 s -> 2.14 s
临时文件 6773 次/9.34MB -> 2875 次/3.61MB
命中率 text 65.5% / attr 84.1% / param 88.8%
clone 开销 命中 58us、未命中 73us(合计 0.37 s,可忽略)
顺带:
- tools/run_acad_perf.ps1 增加 -CacheOff 开关,用于同一构建上的 A/B 对比
- SectionPerfCounter 增加 AppendReport(),让缓存统计也写进同一份报告文件
- 诊断口子 AEC_SAT_SAMPLE=n 可导出未命中的 SAT 原文,用于定位这类差异
验证:R230 Debug 编译通过并部署;用脚本自动开图各跑一次(缓存关/开),
数据已写入 pipe-section-region-performance-plan.md。
尚未做:R190 编译(本机缺 v100 工具集)、Release 构建的收益复测、
开图期间 1140 次 RegionAcisout 回写(与本缓存无关,需单独立项)。
This commit is contained in:
1 parent
fd5bbb60ab
commit
f8d10d5a3b
11 files changed
+594
-2
No files matched your search
@@ -21,6 +21,7 @@
|
||||
#include "gpc.h"
|
||||
#include "ImpMD5.h"
|
||||
#include "SectionPerfCounter.h"
|
||||
#include "SectionRegionCache.h"
|
||||
#include "breptools.h"
|
||||
#include "DimScaleZoneDlg.h"
|
||||
#include "simpleProperty.h"
|
||||
@@ -3523,6 +3524,11 @@ bool CoreTools::CurveToString(const AcDbCurve * pCurve, CString & sScr2)
|
||||
|
||||
AcDbRegion* CoreTools::StringToRegion(const CString & sRegionScrp)
|
||||
{
|
||||
// 截面缓存:SAT 文本内容 hash(字节相同即几何相同,对所有实体类都成立)
|
||||
SectionRegionCache::Channel chCache = SectionRegionCache::kText;
|
||||
unsigned long long nCacheKey = 0;
|
||||
const bool bCacheOn = SectionRegionCache::Enabled();
|
||||
|
||||
// Phase 0 计数:截面恢复耗时/次数/文本唯一性,见 pipe-section-region-performance-plan.md
|
||||
SectionPerf::Scope perfScope("CoreTools::StringToRegion");
|
||||
|
||||
@@ -3546,6 +3552,14 @@ AcDbRegion* CoreTools::StringToRegion(const CString & sRegionScrp)
|
||||
CString sFullPath = MakeTempSatPath();
|
||||
if (sFullPath.IsEmpty()) return NULL;
|
||||
|
||||
if (bCacheOn)
|
||||
{
|
||||
nCacheKey = SectionRegionCache::HashSatText(sNewSrc.c_str(), sNewSrc.size());
|
||||
AcDbRegion* pHit = SectionRegionCache::Acquire(chCache, nCacheKey, sNewSrc.c_str(), sNewSrc.size());
|
||||
if (pHit != NULL)
|
||||
return pHit;
|
||||
}
|
||||
|
||||
SectionPerf::NoteRegionText(sNewSrc.c_str(), sNewSrc.size());
|
||||
|
||||
if (file.Open(sFullPath, CFile::modeCreate | CFile::modeWrite))
|
||||
@@ -3586,11 +3600,20 @@ AcDbRegion* CoreTools::StringToRegion(const CString & sRegionScrp)
|
||||
DELETE_PTR(arBodyPtrs[i]);
|
||||
|
||||
::DeleteFile(sFullPath);
|
||||
|
||||
if (bCacheOn)
|
||||
return SectionRegionCache::Put(chCache, nCacheKey, pReg);
|
||||
|
||||
return pReg;
|
||||
}
|
||||
|
||||
AcDbRegion *CoreTools::StringToRegion(Adesk::UInt64 nLen, char *pszReg)
|
||||
{
|
||||
// 截面缓存(同 CString 重载)
|
||||
SectionRegionCache::Channel chCache = SectionRegionCache::kText;
|
||||
unsigned long long nCacheKey = 0;
|
||||
const bool bCacheOn = SectionRegionCache::Enabled();
|
||||
|
||||
SectionPerf::Scope perfScope("CoreTools::StringToRegion(buf)");
|
||||
|
||||
std::string sNewSrc;
|
||||
@@ -3610,6 +3633,14 @@ AcDbRegion *CoreTools::StringToRegion(Adesk::UInt64 nLen, char *pszReg)
|
||||
CString sFullPath = MakeTempSatPath();
|
||||
if (sFullPath.IsEmpty()) return NULL;
|
||||
|
||||
if (bCacheOn)
|
||||
{
|
||||
nCacheKey = SectionRegionCache::HashSatText(sNewSrc.c_str(), sNewSrc.size());
|
||||
AcDbRegion* pHit = SectionRegionCache::Acquire(chCache, nCacheKey, sNewSrc.c_str(), sNewSrc.size());
|
||||
if (pHit != NULL)
|
||||
return pHit;
|
||||
}
|
||||
|
||||
SectionPerf::NoteRegionText(sNewSrc.c_str(), sNewSrc.size());
|
||||
|
||||
CFile file;
|
||||
@@ -3650,6 +3681,10 @@ AcDbRegion *CoreTools::StringToRegion(Adesk::UInt64 nLen, char *pszReg)
|
||||
DELETE_PTR(arBodyPtrs[i]);
|
||||
|
||||
::DeleteFile(sFullPath);
|
||||
|
||||
if (bCacheOn)
|
||||
return SectionRegionCache::Put(chCache, nCacheKey, pReg);
|
||||
|
||||
return pReg;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "AecDbDimScaleZone.h"
|
||||
#include "AecDbJoggedCamera.h"
|
||||
#include "SectionPerfCounter.h"
|
||||
#include "SectionRegionCache.h"
|
||||
|
||||
#include "breptools.h"
|
||||
#include "HlrCutOption.h"
|
||||
@@ -474,6 +475,7 @@ acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt)
|
||||
// && g_lockState == BIT_SUCCESS)
|
||||
// 验证是否成功,都应该自行注销
|
||||
UnloadApplication();
|
||||
SectionRegionCache::ClearAll();
|
||||
//else
|
||||
// return AcRx::kRetError;
|
||||
#if ARX > 18
|
||||
@@ -549,6 +551,7 @@ KTDocReactor *g_pDocReactor(NULL);
|
||||
void envierpf_dump()
|
||||
{
|
||||
SectionPerf::Dump();
|
||||
SectionRegionCache::Dump();
|
||||
}
|
||||
|
||||
void envierpf_reset()
|
||||
|
||||
Reference in new issue
Block a user