<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ida-tui.git/experiments/.gitignore, branch main</title>
<subtitle>tui for headless ida</subtitle>
<id>https://git.sl0p.foo/ida-tui.git/atom/experiments/.gitignore?h=main</id>
<link rel='self' href='https://git.sl0p.foo/ida-tui.git/atom/experiments/.gitignore?h=main'/>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/'/>
<updated>2026-07-23T23:09:51Z</updated>
<entry>
<title>experiments: in-process idalib vs mcp-transport spike (throwaway)</title>
<updated>2026-07-23T23:09:51Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-23T23:09:51Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=1eca8be6b517650e8c65df6422fed8afe6b480cf'/>
<id>urn:sha1:1eca8be6b517650e8c65df6422fed8afe6b480cf</id>
<content type='text'>
Standalone, not wired into the app. A tiny Backend seam (functions/resolve/
read_bytes/disasm_line/decompile/xrefs_to) with two impls — DirectBackend
(import idapro, in-process) and McpBackend (the current HTTP/JSON tool calls) —
so the "keep the transport or go direct?" question is measurable and feelable.

  --bench : A/B latency table (opens a copy in-process; also hits :8745 if up)
  --tui   : minimal Textual app on the in-process backend; F5 decompiles INLINE
            so you feel the main-thread hitch, 'd' decompiles all (big freeze)

Findings (echo, this box), all reproducible:
* open+auto-analysis in-process: ~0.4s (the whole "loading" cost, on the main
  thread).
* per-op latency, direct vs mcp:
    resolve            2.0us   4755us    2392x
    read_bytes(16)     1.2us   4657us    3845x
    read_bytes(4096)   112us   6037us      54x
    disasm_line        2.9us   5239us    1805x
    xrefs_to           25us    4962us     200x
    decompile(cached)  2.8ms   51ms        18x
  i.e. the mcp transport has a ~5ms/call floor regardless of op; the fast ops
  idatui spams while scrolling are 1000-4000x cheaper in-process (which is why
  the prefetch/paging/caching machinery exists).
* hard constraints proven separately: idalib must be imported/opened on the MAIN
  python thread (installs a SIGINT handler) and every call must be on it
  ("Function can be called from the main thread only"); execute_sync from a
  worker thread HANGS (no UI pump in headless). So in-process, IDA owns the one
  main thread and blocks the event loop for each call — fine at &lt;1ms, a hitch at
  decompile (~150ms cold), a freeze during analysis. That main-thread coupling,
  not just crash isolation, is what the subprocess boundary buys.
</content>
</entry>
</feed>
