summaryrefslogtreecommitdiffstats
path: root/idatui
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-07 02:12:27 +0200
committeruser <user@clank>2026-08-07 02:12:27 +0200
commit414873898f236cdc1ab0d7c6a83f1a58f57f2d6b (patch)
tree3609de900f289cb2b3538d427c1c20089ca75854 /idatui
parentThree micro-wins on the listing-row path: merge the colour-tag and operand-ta... (diff)
downloadida-tui-414873898f236cdc1ab0d7c6a83f1a58f57f2d6b.tar.gz
ida-tui-414873898f236cdc1ab0d7c6a83f1a58f57f2d6b.tar.xz
ida-tui-414873898f236cdc1ab0d7c6a83f1a58f57f2d6b.zip
Two hot-path fixes found by profiling the plain-line builder: the opcode-bytes column used a per-byte f-string generator where bytes.hex(' ').upper() does it in one C call (12x), and ListingModel._phys/_head_index_at re-imported bisect on every call. _line_plain 2.64 -> 1.57 us/row.
Result: {"status":"keep","total_ms":19476.3,"lg_boot_ms":756.3,"lg_decomp_ms":2495.1,"lg_graph_ms":946,"lg_hex_ms":905.4,"lg_index_ms":72,"lg_listing_cold_ms":547.5,"lg_listing_warm_ms":410.4,"lg_nav_ms":6723.4,"lg_palette_ms":5,"lg_render_ms":218.8,"lg_search_ms":2312.4,"pure_graph_ms":239.5,"sm_boot_ms":535.3,"sm_decomp_ms":616.4,"sm_graph_ms":682.2,"sm_hex_ms":824.9,"sm_index_ms":0,"sm_listing_cold_ms":258.9,"sm_listing_warm_ms":261,"sm_nav_ms":339.5,"sm_palette_ms":0.3,"sm_render_ms":248.7,"sm_search_ms":77.3,"fails":0}
Diffstat (limited to 'idatui')
-rw-r--r--idatui/app.py11
-rw-r--r--idatui/domain.py5
2 files changed, 11 insertions, 5 deletions
diff --git a/idatui/app.py b/idatui/app.py
index 0af47c0..d07a188 100644
--- a/idatui/app.py
+++ b/idatui/app.py
@@ -901,11 +901,16 @@ class ListingView(SearchMixin, NavMixin, ColumnCursor, ScrollView, can_focus=Tru
def _op_bytes_text(self, h: Head) -> str:
"""Hex bytes for ``h``, truncated with an ellipsis in 'limited' mode so a
- long x86-64 instruction doesn't blow out the column."""
+ long x86-64 instruction doesn't blow out the column.
+
+ ``bytes.hex(" ")`` rather than a per-byte f-string generator: this is
+ called for every row of every plain line, and search builds the plain
+ line for the whole segment.
+ """
raw = h.raw or b""
if self._op_mode == 1 and len(raw) > _OP_LIMIT:
- return " ".join(f"{b:02X}" for b in raw[:_OP_LIMIT]) + "\u2026"
- return " ".join(f"{b:02X}" for b in raw)
+ return raw[:_OP_LIMIT].hex(" ").upper() + "\u2026"
+ return raw.hex(" ").upper()
@staticmethod
def _span_segments(h: Head, fallback: Style):
diff --git a/idatui/domain.py b/idatui/domain.py
index 645d111..8b423e3 100644
--- a/idatui/domain.py
+++ b/idatui/domain.py
@@ -754,7 +754,9 @@ class ListingModel:
def _phys(self, row: int) -> tuple[int, int]:
"""(physical head index, byte offset into it) for logical ``row``."""
- import bisect
+ # bisect is imported at module scope; re-importing it here cost a
+ # sys.modules lookup on a function that runs once per rendered row and
+ # once per row a search reads.
i = bisect.bisect_right(self._row_at, row) - 1
if i < 0:
return (-1, 0)
@@ -909,7 +911,6 @@ class ListingModel:
def _head_index_at(self, ea: int) -> int:
"""Index of the physical head containing ``ea`` (caller holds the lock)."""
- import bisect
eas = self._head_eas
i = bisect.bisect_right(eas, ea) - 1
return i if 0 <= i < len(self._heads) else -1