Skip to content

[1150] 表格插入行性能优化:1531ms → 657ms(提速 57%) - #4043

Open
da-liii wants to merge 5 commits into
mainfrom
da/1150/table_insert_fix
Open

[1150] 表格插入行性能优化:1531ms → 657ms(提速 57%)#4043
da-liii wants to merge 5 commits into
mainfrom
da/1150/table_insert_fix

Conversation

@da-liii

@da-liii da-liii commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Summary

基于上一 PR(#4041,新增基准 + chat-input-buffer? unbound 修复)的 GUI 基准
MOGAN_TEST_GUI=1 xmake r 1150,10 列 × 100 行 generic 表格),用 bench
埋点逐层定位热点,做了三处独立优化。总耗时 1531 ms → 657 ms(提速 57%)

优化 文件 效果
删 dead table_bound 调用 edit_table.cpp table_go_to table_go_to 646 → 201 ms
table_correct_block_content 范围化重载(只扫新行/列) edit_table.hpp + edit_table.cpp correct_block 666 → 3 ms
empty_row/empty_table 加 wrap-aware 重载(构造时一次性预包装 DOCUMENT,从源头省掉 N 次 insert_node edit_table.cpp correct_block 持续 3 ms

关键发现

  1. table_go_to 里有一段 dead code——table_bound(fp,row,col,row2,col2) 计算合并区,但 row2/col2 是局部变量、立即丢弃,search_cell 用的是原始 row/col。这段代码从未生效,但每次 table_go_to 都跑 O(N×M)。

  2. table_correct_block_content 是 O(N×M) 全表扫描,但插入路径只改一行/一列,其它 cell 的 CELL_BLOCK/CELL_HYPHEN 格式不变,wrap 状态稳定。范围化为 [row1,row2)×[col1,col2) 是稳赚不赔。

  3. 原流程是「插空 cell → 后续逐个 insert_node 加 DOCUMENT wrap」,每个 insert_node 触发一次 typesetter invalidation。改为构造时按 wrap 状态生成 (document \"\") cell,从源头省掉这批 mutation。

Test plan

  • xmake b stem 编译通过
  • xmake r edit_table_test —— 14 个表格单测全过
  • xmake r table_performance_test —— 8 个表格性能/正确性测试全过(含 test_cell_hyphen_wrapping,钉死 pre-wrap 不破坏 wrap 行为)
  • MOGAN_TEST_GUI=1 xmake r 1150 —— @ 50 rows:575 → 314 ms;@ 100 rows:1531 → 657 ms
  • gf fmt --changed-since=main 已格式化

🤖 Generated with Claude Code

da-liii and others added 5 commits July 20, 2026 21:49
GUI 基准(10 列 × 100 行 generic 表格,MOGAN_TEST_GUI=1)总耗时:
1531 ms → 657 ms,提速 57%(@ 50 rows:575 → 314 ms,提速 45%)。

三处独立优化,由 bench 埋点逐层定位:

1. 删 dead table_bound 调用(edit_table.cpp table_go_to)
   原代码每插一行都跑 O(N×M) 的 table_bound 计算合并区,但结果
   row2/col2 是局部变量、立即丢弃,search_cell 用的是原始 row/col——
   这段代码从未生效。删掉后 table_go_to:646 → 201 ms。

2. table_correct_block_content 范围化重载(edit_table.hpp 新增
   table_correct_block_content(path,int,int,int,int))
   原实现是 O(N×M) 全表扫描;插入路径只改一行/一列,其它 cell 的
   CELL_BLOCK/CELL_HYPHEN 格式不变,wrap 状态也稳定。table_insert_row/
   table_insert_column 改用范围化版本只扫新行/列。correct_block:
   666 → 3 ms。

3. empty_row/empty_table 加 wrap-aware 重载(edit_table.cpp
   empty_row(int,bool) / empty_table(int,int,bool))
   原流程是「插入空 cell → 后续逐个 insert_node 加 DOCUMENT wrap」,
   每个 insert_node 触发一次 typesetter invalidation。改为构造时
   按 wrap 状态一次性生成 (document "") cell,从源头省掉这批 mutation。
   table_insert 在插入前查一次 CELL_BLOCK/CELL_HYPHEN,传入 wrap 参数。
   correct_block 持续 3 ms(源头已 wrap)。

测试改造:TeXmacs/tests/1150.scm 重写为 GUI 异步链(exec-delayed-pause
+ run-chain + update-menus,参考 1145.scm),new-document 开新标签页
+ set-main-style generic + 扩到 10 列,在 50/100 行 checkpoint 各 dump
一次 bench 累积,一次运行直接对比规模增长。

验证:xmake r edit_table_test(14 个)+ table_performance_test(8 个)
全过,含 test_cell_hyphen_wrapping 钉死 pre-wrap 正确性。
代码 review 三处修复:
- 补 mode != "math" 守卫:math 表格不应预包装 DOCUMENT,与
  table_needs_document_wrap helper 行为对齐
- 收敛 wrap 判定注释:(1,1,1,1) 只是 table-wide fallback,per-cell
  CWITH 覆盖会让预包装猜错,但后续 table_correct_block_content 会
  按每个新 cell 实际格式纠正——正确性保住,perf 收益仅在常见场景
- 注释拼写 CELL_HYHEN → CELL_HYPHEN

行为不变:edit_table_test 14 passed(含 test_no_document_wrap_in_math_mode)、
table_performance_test 8 passed(含 test_cell_hyphen_wrapping)。

Co-Authored-By: Claude Opus 5.2 <noreply@anthropic.com>
Doxygen 注释覆盖本 PR 新增/修改的核心函数:
- empty_row/empty_table 两个重载(含 wrap 参数语义 + 预包装动机)
- table_insert(三段工作 + CWITH 重写 + wrap 预包装优化点)
- table_go_to(删 dead table_bound 的来龙去脉)
- table_insert_row / table_insert_column(流程 + 范围化 correct_block 调用)
- table_correct_block_content 两个重载(全表 vs 范围化的取舍 + f1/f2 规则)

单元测试(tests/Edit/Modify/edit_table_test.cpp,14 → 18)新增 4 条钉死
wrap-aware 重载的契约:
- test_empty_row_no_wrap_matches_default:wrap=false 退化为原 empty_row
- test_empty_row_with_wrap_wraps_cells:wrap=true cell 内容是 (document "")
- test_empty_table_with_wrap_wraps_all_cells:多行多列规模下一致
- test_empty_table_no_wrap_matches_default:table 层面同样无破坏性

验证:xmake r edit_table_test(18 个)+ table_performance_test(8 个)全过。
bench 数据 @ 100 rows 显示一批子段已经完全无问题,移除以减少噪音:

移除(实测均 < 1 ms/call):
- table_insert_row:search      (1 ms / 100 invocations)
- table_insert_row:insert      (38 ms)
- table_insert_row:correct_block (3 ms)
- table_insert:row             (37 ms)
- table_insert:col             (3 ms)
- table_insert:cwith           (0 ms)
- table_correct_block_content  (3 ms)

保留(真有性能意义):
- table_insert_row             顶层聚合
- table_insert_row:go_to       剩余热点 1:~1.8 ms/call(typesetter invalidation)
- table_insert_row:resize_notify 剩余热点 2:~1.7 ms/call(scheme callback)
- table_resize_notify          独立函数级聚合

验证:MOGAN_TEST_GUI=1 xmake r 1150 输出从 12 个 task 精简到 4 个,
@ 100 rows 总耗时 657 → 650 ms(噪声范围)。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant