summaryrefslogtreecommitdiffstats
path: root/.auto/wip-decompmap.patch
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-07 04:45:10 +0200
committeruser <user@clank>2026-08-07 04:45:10 +0200
commit7ea3ca16efaa9ac82b712841e82f4d4e5284a448 (patch)
treee7b08a17c9b4f5f0700f326d35ec6e8592f93a12 /.auto/wip-decompmap.patch
parentbench: cover the split view ('s'), whose decomp_map cost was entirely unmeasured (diff)
downloadida-tui-7ea3ca16efaa9ac82b712841e82f4d4e5284a448.tar.gz
ida-tui-7ea3ca16efaa9ac82b712841e82f4d4e5284a448.tar.xz
ida-tui-7ea3ca16efaa9ac82b712841e82f4d4e5284a448.zip
RE-BASELINE (v6 bench). The split view ('s') was not covered at all, and it turns out to be the most expensive thing in the app: 16.2s of a 33.5s session (lg_split 10189 + sm_split 6034), or 500ms per function on echo and 850ms on bash, just to open it.
Result: {"status":"keep","total_ms":33502.3,"lg_boot_ms":772.2,"lg_decomp_ms":2546.9,"lg_graph_ms":903.4,"lg_hex_ms":434.1,"lg_index_ms":97.7,"lg_listing_cold_ms":420.2,"lg_listing_warm_ms":397.4,"lg_nav_ms":6501.1,"lg_palette_ms":4.9,"lg_render_ms":212.4,"lg_search_ms":760.4,"lg_split_ms":10189.2,"pure_graph_ms":212.3,"sm_boot_ms":443.8,"sm_decomp_ms":1275.3,"sm_graph_ms":720.5,"sm_hex_ms":451,"sm_index_ms":2.5,"sm_listing_cold_ms":263.3,"sm_listing_warm_ms":264.7,"sm_nav_ms":302.8,"sm_palette_ms":0.3,"sm_render_ms":248.4,"sm_search_ms":43.9,"sm_split_ms":6033.6,"fails":0}
Diffstat (limited to '.auto/wip-decompmap.patch')
-rw-r--r--.auto/wip-decompmap.patch49
1 files changed, 49 insertions, 0 deletions
diff --git a/.auto/wip-decompmap.patch b/.auto/wip-decompmap.patch
new file mode 100644
index 0000000..a11db98
--- /dev/null
+++ b/.auto/wip-decompmap.patch
@@ -0,0 +1,49 @@
+diff --git a/server/patch_server.py b/server/patch_server.py
+index fe16ede..b8f5453 100644
+--- a/server/patch_server.py
++++ b/server/patch_server.py
+@@ -884,16 +884,39 @@ def decomp_map(
+ return {"error": f"decompile failed: {e}"}
+ if cfunc is None:
+ return {"error": "decompile failed"}
++ import ida_lines
++ # Three things this loop must not do, each measured on real functions (the 25
++ # largest of bash went 68.3s -> 6.5s; echo's 60 largest 5.4s -> 0.6s, with
++ # byte-identical output):
++ #
++ # * allocate ctree_item_t's per COLUMN. They are SWIG objects and this is
++ # the innermost loop; one per call is enough, and head/tail are never
++ # read, so don't ask for them at all.
++ # * sweep the TAGGED length. ``x`` is a screen column but ``sl.line`` still
++ # carries IDA's colour tags, so a 23-column line was swept 124 times.
++ # * call dstr() per column. It formats a whole 'EA: description' string, and
++ # consecutive columns are nearly always the same ctree item -- so ask the
++ # item for its id first and only format when it changes. (The result is
++ # deduped by ``seen`` anyway, so skipping a repeat cannot change it.)
++ item = ida_hexrays.ctree_item_t()
++ tag_remove = ida_lines.tag_remove
++ get_line_item = cfunc.get_line_item
+ lines = []
+ for sl in cfunc.get_pseudocode():
+ line = sl.line
+ eas, seen = [], set()
+- for x in range(len(line) + 1):
+- head = ida_hexrays.ctree_item_t()
+- item = ida_hexrays.ctree_item_t()
+- tail = ida_hexrays.ctree_item_t()
+- if not cfunc.get_line_item(line, x, False, head, item, tail):
++ prev_id = None
++ for x in range(len(tag_remove(line)) + 1):
++ if not get_line_item(line, x, False, None, item, None):
+ continue
++ it = item.it
++ if it is not None:
++ oid = it.obj_id
++ if oid == prev_id:
++ continue
++ prev_id = oid
++ else:
++ prev_id = None
+ # Match the /*ea*/ marker's source (decompile_function_safe): the
+ # item's dstr() is 'EA: description'; get_ea() reports a different ea.
+ dstr = item.dstr()