From bfdbb469e45ce66d82723da307efc49c17d5f074 Mon Sep 17 00:00:00 2001 From: blasty Date: Thu, 23 Jul 2026 01:59:16 +0200 Subject: perf: stream the listing incrementally instead of load_all on open (M4) Opening a listing walked the WHOLE segment (load_all) before showing anything -- a blank pane for seconds on a big .text. Now _prime loads just the viewport around the cursor (appears instantly) and _grow streams the rest in the background, growing virtual_size as pages land (throttled). Search finishes loading first (needs the whole segment). ListingModel gains a _load_lock so the grower and an in-view search can both drive page loads without double-fetching; new public load_next_page. Verified: ensure(1100)->partial(1500,incomplete), load_all->full(5036,complete); 3 concurrent loaders -> 0 duplicate heads; UI listing+search 30/0 (in-process). --- idatui/domain.py | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'idatui/domain.py') diff --git a/idatui/domain.py b/idatui/domain.py index f26354c..e70182c 100644 --- a/idatui/domain.py +++ b/idatui/domain.py @@ -526,8 +526,19 @@ class ListingModel: self._next: int | None = seg_start # next address to fetch from self._done = False self._lock = threading.Lock() + # Serializes page loads so a background grower and an in-view search can + # both drive loading without double-fetching the same page. + self._load_lock = threading.Lock() + + def load_next_page(self) -> int: + """Load one more page of heads; returns how many were added.""" + return self._load_next_page() def _load_next_page(self) -> int: + with self._load_lock: + return self._load_next_page_locked() + + def _load_next_page_locked(self) -> int: with self._lock: if self._done or self._next is None: return 0 -- cgit v1.3.1-sl0p