summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-07 04:48:25 +0200
committeruser <user@clank>2026-08-07 04:48:25 +0200
commitda1dfe8b2ba4d6795d85b645e7962a5388c180c0 (patch)
tree080406eba952215e8816aca07129fb6c6d17a6ec /server
parentRE-BASELINE (v6 bench). The split view ('s') was not covered at all, and it t... (diff)
downloadida-tui-da1dfe8b2ba4d6795d85b645e7962a5388c180c0.tar.gz
ida-tui-da1dfe8b2ba4d6795d85b645e7962a5388c180c0.tar.xz
ida-tui-da1dfe8b2ba4d6795d85b645e7962a5388c180c0.zip
decomp_map: stop sweeping every column three times over. It allocated three ctree_item_t SWIG objects PER COLUMN, swept the tagged line length (124 columns for a 23-column line), and called dstr() — which formats a whole 'EA: description' string — for every column even though consecutive columns report the same ctree item. Now: one item, no head/tail, visible columns only, and dstr() only when the item's obj_id changes.
Result: {"status":"keep","total_ms":19834.8,"lg_boot_ms":676.9,"lg_decomp_ms":2698.8,"lg_graph_ms":892.1,"lg_hex_ms":440.4,"lg_index_ms":93.6,"lg_listing_cold_ms":438.5,"lg_listing_warm_ms":420.8,"lg_nav_ms":6646.7,"lg_palette_ms":4.7,"lg_render_ms":215.1,"lg_search_ms":767,"lg_split_ms":1327.6,"pure_graph_ms":213.6,"sm_boot_ms":468,"sm_decomp_ms":1317.1,"sm_graph_ms":730.7,"sm_hex_ms":483.2,"sm_index_ms":2.6,"sm_listing_cold_ms":266.1,"sm_listing_warm_ms":268.1,"sm_nav_ms":288.6,"sm_palette_ms":0.3,"sm_render_ms":253,"sm_search_ms":47.1,"sm_split_ms":874.2,"fails":0}
Diffstat (limited to 'server')
-rw-r--r--server/patch_server.py33
1 files changed, 28 insertions, 5 deletions
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()