This is an automated email from the ASF dual-hosted git repository. morningman pushed a commit to branch master-catalog-spi-review-21 in repository https://gitbox.apache.org/repos/asf/doris.git
commit a7f141c91b8a92cd209a1c91a5e5b14e7e8d2119 Author: morningman <[email protected]> AuthorDate: Tue Jul 28 19:59:53 2026 +0800 [doc](test) record the fe-core unit-test runtime problem Measured while running the full fe-core suite to verify a base-class change: it was still going at 3h20m, and just under half that time was spent actually running tests. Root causes, with evidence rather than guesswork: - Every test class forks a fresh JVM. fe-core/pom.xml sets reuseForks=false, deliberately, to avoid singleton conflicts -- so this is not a subset of tests and not something to simply flip. - forkCount comes from fe_ut_parallel, which defaults to 1 and is only overridable through the FE_UT_PARALLEL environment variable. It was unset, so 15 of the machine's 16 cores sat idle. The pom comment even suggests raising it. - Roughly 5.5s of JVM startup per class, against 1225 classes, a third of which hold only one or two test cases. - nereids accounts for 72% of test execution time and is unrelated to the change that required the run. The note records data and preliminary directions only. Raising FE_UT_PARALLEL is untested here and carries the real risk that concurrent forks contend over ports, BDB directories and temp paths; the compile/test split behind the 5.5s figure is estimated, not measured. Both are called out as open. Filed standalone because the owner will handle it on a separate branch. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> --- plan-doc/fe-core-ut-runtime-problem.md | 183 +++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) diff --git a/plan-doc/fe-core-ut-runtime-problem.md b/plan-doc/fe-core-ut-runtime-problem.md new file mode 100644 index 00000000000..296cbe4602a --- /dev/null +++ b/plan-doc/fe-core-ut-runtime-problem.md @@ -0,0 +1,183 @@ +# 问题记录 — fe-core 全量单测跑一次要 3.5 小时,其中一半以上不在跑测试 + +> **性质**:问题记录 + 初步结论,**不是**执行方案。 +> **处置**:用户 2026-07-28 明确 —— **在另外的分支单独处理**,不并入 catalog-spi 主线, +> 也不属于 [`fecore-property-cleanup`](./fecore-property-cleanup/) 任务空间。 +> **数据来源**:`fecore-property-cleanup` 的 FPC-04 验证跑(改 `ExternalCatalog` 基类 ⇒ 按纪律必须跑全量)。 +> **⚠️ 数据是运行中快照**(跑到 3:20:08 / 1111 个测试类时采集),非最终值;量级结论不受影响。 + +--- + +## 1. 触发场景 + +改动落在 `ExternalCatalog`(**每个 catalog 都继承的基类**),窄 `-Dtest` 列表覆盖不到间接依赖基类 +行为的测试,所以按纪律必须跑全量: + +```bash +mvn -f <repo>/fe/pom.xml -pl fe-core -am test \ + -Dcheckstyle.skip=true -DfailIfNoTests=false \ + -Dmaven.build.cache.enabled=false --fail-at-end +``` + +结果:**跑了 3 小时 20 分还没结束**,而真正相关的改动只有 135 行纯删除。 + +--- + +## 2. 实测数据 + +### 2.1 总账(快照 @ 3:20:08) + +| | 秒 | 占比 | +|---|---|---| +| 主 maven 已运行 | 11841 | 100% | +| ├─ 测试真正执行(各类 `Time elapsed` 之和) | 5550 | **47%** | +| └─ 差额:编译 + JVM fork + reactor 开销 | 6291 | **53%** | + +**一半以上的时间不在跑测试。** + +### 2.2 按包分(测试执行时间,非总耗时) + +| 包 | 类数 | 测试执行 | fork 开销估算¹ | 合计估算 | +|---|---|---|---|---| +| `nereids` | 545 | 4023s | ~2998s | ~7021s | +| `datasource` | 114 | 304s | ~627s | ~931s | +| `common` | 73 | 236s | ~402s | ~637s | +| `qe` | 43 | 247s | ~236s | ~483s | +| `statistics` | 24 | 167s | ~132s | ~299s | +| `mtmv` | 18 | 149s | ~99s | ~248s | +| `persist` | 37 | 45s | ~204s | ~248s | +| `alter` | 13 | 111s | ~72s | ~182s | + +¹ 按下文估算的 **~5.5s/类** 乘类数,是估算不是实测,**别当精确值引用**。 + +**`nereids` 一个包占了测试执行时间的 72%**,而它与 catalog/storage 改动毫无关系。 +**`persist` 是 fork 开销最刺眼的例子**:45s 的测试背了约 204s 的 JVM 启动,**开销是测试本身的 4.5 倍**。 + +### 2.3 最慢的 12 个测试类 + +``` + 237.8s nereids.jobs.joinorder.joinhint.DistributeHintTest ← 一个类 4 分钟 + 64.8s nereids.jobs.joinorder.hypergraphv2.OtherJoinTest + 54.3s nereids.jobs.joinorder.hypergraphv2.GraphSimplifierConsistencyTest + 50.4s cluster.DecommissionBackendTest + 45.0s statistics.CacheTest + 38.6s journal.bdbje.BDBEnvironmentTest + 33.7s nereids.mv.PreMaterializedViewRewriterTest + 31.4s common.profile.ProfileManagerTest + 28.0s nereids.trees.plans.commands.CreateResourceCommandTest + 27.3s alter.SchemaChangeHandlerTest + 25.8s nereids.memo.StructInfoMapTest + 24.9s mtmv.MTMVPlanUtilTest +``` + +### 2.4 测试类的粒度分布 + +``` +类数=1110 用例数=8153 平均每类 7.3 个用例 +其中「只有 1-2 个用例」的类 = 368 个(33%) +``` + +⇒ **三分之一的测试类,为了 1-2 个用例付一次完整 JVM 启动。** + +--- + +## 3. 根因(**有证据,不是推测**) + +### 3.1 哪些测试 fork JVM?—— **全部,无一例外** + +`fe/fe-core/pom.xml:837-849`: + +```xml +<artifactId>maven-surefire-plugin</artifactId> +<configuration> + <!-->set larger, eg, 3, to reduce the time or running FE unit tests<--> + <forkCount>${fe_ut_parallel}</forkCount> + <!-->not reuse forked jvm, so that each unit test will run in separate jvm. to avoid singleton conflict<--> + <reuseForks>false</reuseForks> + ... + <argLine>-Xmx1024m ...</argLine> +</configuration> +``` + +`reuseForks=false` ⇒ **每一个测试类都起一个全新 JVM**。这不是某个子集的问题,是全局配置。 +注释写明了动机:**避免单例冲突**(Doris FE 大量 `Env` / `Catalog` 之类的进程级单例)。 +⇒ **这个设定有正当理由,不能简单地改成 `true`。** + +### 3.2 并发度是 1,而机器有 16 核 + +- `fe/fe-core/pom.xml:36` → `<fe_ut_parallel>1</fe_ut_parallel>` +- 唯一的覆盖入口是 profile `ut_parallel`(`fe-core/pom.xml:50-61`),靠**环境变量** `FE_UT_PARALLEL` 激活 +- 本次运行 **`FE_UT_PARALLEL` 未设置** ⇒ `forkCount=1` +- 机器:**16 核 / 123G 内存**,每个 fork `-Xmx1024m` + +⇒ **15 个核在空转。** 而且 pom 里那句注释 `set larger, eg, 3, to reduce the time` 说明 +**这个逃生舱是已知的,只是没人用**。 + +### 3.3 单类 JVM 启动开销估算 + +``` +(11841 总 − ~200 编译² − 5550 测试执行) / 1111 类 ≈ 5.5 s/类 +``` + +² 编译时间用先前独立跑的全反应堆 `test-compile`(136s)做同量级估计,**未实测本次 `-am` 的编译耗时**。 + +按 1225 个测试类算,**纯 JVM 启停约 112 分钟**。 + +--- + +## 4. 初步结论(**未验证,供另开分支时参考**) + +三个瓶颈性质完全不同,**不要混为一谈**: + +| # | 瓶颈 | 性质 | 初步方向 | +|---|---|---|---| +| A | `forkCount=1`,15 核空转 | **配置问题,最易改** | 设 `FE_UT_PARALLEL`(pom 注释建议 3)。**须先验证并发下的稳定性**:`reuseForks=false` 保证了类间隔离,但并发 fork 仍可能撞共享外部资源(端口、BDB 目录、临时文件、`Env` 落盘路径)。**这是本项最大风险,不是改个数字就完事。** | +| B | 每类 5.5s JVM 启动 × 1225 类 | **结构性,动机正当** | 不建议动 `reuseForks`。可考虑的是**减少类数**:33% 的类只有 1-2 个用例,合并同源小类能直接砍掉对应的 fork 次数。工作量大、收益线性。 | +| C | `nereids` 占测试时间 72% | **与 catalog 无关的重型套件** | 与本条线无关,另议。 | + +### 一条独立的流程建议(**需要用户拍板,我没有擅自改纪律**) + +给**删除型/基类改动**定义一个「相关片区快速通道」: + +``` +datasource + connector + filesystem + persist ≈ 260 个类 +``` + +实测这几片的测试执行时间合计**只有约 6 分钟**(fork 开销另计)。 +日常迭代跑它,**全量只在合入前跑一次**。 + +⚠️ **这条建议本身有风险**,正是 FPC-04 这类改动暴露的:改基类时,「相关片区」的边界很难先验判定 +—— `ExternalCatalog` 的方法可能被任何包间接依赖。所以快速通道**只能用于日常迭代反馈, +不能替代合入前的全量**。 + +--- + +## 5. 未验证 / 明确不知道 + +- **编译耗时未实测**(§3.3 的 ~200s 是同量级估计),所以 5.5s/类 是估算。 + 真要动手,第一步应该是**实测拆分**(`-o` 离线跑、分别计时 compile 与 test 阶段)。 +- **`FE_UT_PARALLEL>1` 下的稳定性完全没验过。** 并发 fork 是否撞端口/BDB 目录/临时路径未知。 +- 本次数据是**运行中快照**(3:20:08 / 1111 类),maven 自报的 `Total time` 与最终 + `Tests run / Failures / Errors / Skipped` 汇总行**尚未产出**。 +- **只测了这一台机器**(16 核 / 123G)。CI 机器的核数与该配置的交互未知。 +- 本次运行中另有其他 worktree 的 maven 在同机跑,**可能有资源竞争**,未量化其影响。 + +--- + +## 6. 附:复现命令 + +```bash +S=<log> +# 总账 +grep -oE 'Time elapsed: [0-9.]+ s' $S | grep -oE '[0-9.]+' | awk '{t+=$1} END {print int(t)" s"}' +# 按包 +grep 'Tests run:.*in org.apache.doris' $S \ + | sed -E 's/.*Time elapsed: ([0-9.]+) s - in org\.apache\.doris\.([a-z0-9]+).*/\1 \2/' \ + | awk '{t[$2]+=$1; c[$2]++} END {for (p in t) printf "%8.0f s %4d 类 %s\n", t[p], c[p], p}' | sort -rn +# 最慢类 +grep 'Tests run:.*in org.apache.doris' $S \ + | sed -E 's/.*Time elapsed: ([0-9.]+) s - in (.*)/\1 \2/' | sort -rn | head -20 +# 小类占比 +grep 'Tests run:.*in org.apache.doris' $S | grep -oE 'Tests run: [0-9]+' | grep -oE '[0-9]+' \ + | awk '{n++; s+=$1; if($1<=2) k++} END {printf "类=%d 用例=%d 仅1-2用例的类=%d (%.0f%%)\n", n, s, k, k*100/n}' +``` --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
