diff options
Diffstat (limited to 'idatui')
| -rw-r--r-- | idatui/highlight.py | 24 | ||||
| -rw-r--r-- | idatui/worker_client.py | 13 |
2 files changed, 32 insertions, 5 deletions
diff --git a/idatui/highlight.py b/idatui/highlight.py index 5f504bf..a19f86a 100644 --- a/idatui/highlight.py +++ b/idatui/highlight.py @@ -41,11 +41,24 @@ _DEFAULT = Style(color="#c3cad3") # 11.0:1 body _lexer = CLexer(stripnl=False, ensurenl=False) +#: Resolved styles by token type. Pygments token types are interned singletons +#: and a whole decompilation only ever uses about eighteen of them, but +#: ``token in ttype`` is a hierarchy walk and _STYLES is scanned in order -- so +#: without this every token in the body pays up to nine of those walks. It was a +#: quarter of the time spent highlighting a function. +_STYLE_CACHE: dict[object, Style] = {} + + def _style_for(token) -> Style: - for ttype, style in _STYLES: - if token in ttype: - return style - return _DEFAULT + style = _STYLE_CACHE.get(token) + if style is None: + style = _DEFAULT + for ttype, candidate in _STYLES: + if token in ttype: + style = candidate + break + _STYLE_CACHE[token] = style + return style def highlight_c(code: str) -> list[list[Segment]]: @@ -55,6 +68,9 @@ def highlight_c(code: str) -> list[list[Segment]]: if not value: continue style = _style_for(token) + if "\n" not in value: # the common case: a token inside one line + lines[-1].append(Segment(value, style)) + continue parts = value.split("\n") for i, part in enumerate(parts): if i > 0: diff --git a/idatui/worker_client.py b/idatui/worker_client.py index 59c62a1..4f90700 100644 --- a/idatui/worker_client.py +++ b/idatui/worker_client.py @@ -116,7 +116,17 @@ class WorkerClient: # fifth of a second even when the worker was ready in milliseconds # (a small binary, or a seeded .i64), which is most of the time in # the tests and noticeable on a re-open. + # + # Backing off geometrically from the first probe was still too eager: + # a seeded database is ready at ~250ms, by which point the delay has + # grown to 134ms, so every open waited ~350ms whatever the binary -- + # the same number for a 47KB `echo` and a 1.2MB `bash`, which is what + # gives a polling artefact away. Hold the fast rate for the first few + # seconds (a connect attempt on an absent socket is microseconds) and + # only slow down for a genuine cold auto-analysis, which runs for + # minutes and does not care about 200ms. delay = 0.005 + fast_until = t0 + 5.0 while time.time() < deadline: try: s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) @@ -132,7 +142,8 @@ class WorkerClient: progress(f"auto-analyzing {os.path.basename(self._bin)}… " f"({int(time.time() - t0)}s)") time.sleep(delay) - delay = min(delay * 1.6, 0.2) + if time.time() > fast_until: + delay = min(delay * 1.6, 0.2) raise IDAConnectionError("worker did not become ready in time") @property |
