summaryrefslogtreecommitdiff
path: root/src/detached
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-30 14:25:52 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:17 -0300
commit1d0f8cd158bb47941c0187d32422787c92e8feeb (patch)
treeb7f6806cc431c5e2339cdd4887405275a6f2c635 /src/detached
parent69c5e62fe45a3768edff14993789f2aadfafadec (diff)
downloadpardes-1d0f8cd158bb47941c0187d32422787c92e8feeb.tar.gz
pardes-1d0f8cd158bb47941c0187d32422787c92e8feeb.zip
A detached session no client watches draws no frames: yes | head -c 50M through pty/run goes from over 30 s to 11 s
Profiling the 50 MB run showed 70% of its time in draw.render, recolorAnsi alone 43%, walking cells through PageList.pin. The detached session drew a frame after every pty read, with no client attached to see it. A host now says whether anyone watches (Host.VTable.watched). The detached server answers whether a client is attached, and while none is the core keeps the frame owed instead of drawing it. A /screen read draws its own, and a client attaching gets one (hello sets needs_frame). Debug, 80x24: 10 MB went from 7.36 s to 2.10 s, and 50 MB from over the 30 s client timeout (about 37 s by rate) to 11.08 s. What is left is the terminal's own parsing and scrollback growth. A session a frontend shows still draws after every read. Pacing those frames is the next step if that case matters. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/detached')
-rw-r--r--src/detached/server.zig10
1 files changed, 10 insertions, 0 deletions
diff --git a/src/detached/server.zig b/src/detached/server.zig
index d8379793..001acc47 100644
--- a/src/detached/server.zig
+++ b/src/detached/server.zig
@@ -376,6 +376,7 @@ pub const Session = struct {
.now = clockNow,
.present = present,
.poll_frame = pollFrame,
+ .watched = watched,
.spawn = spawn,
.pty_write = ptyWrite,
.pty_resize = ptyResize,
@@ -641,6 +642,12 @@ pub const Session = struct {
s.mailbox.signal();
}
+ fn watched(ctx: ?*anyopaque) bool {
+ const s = of(ctx);
+ for (&s.clients) |*c| if (c.attached) return true;
+ return false;
+ }
+
fn pollFrame(ctx: ?*anyopaque) void {
const s = of(ctx);
if (s.ninep) |l| s.ninep_pending = l.tick().pending;
@@ -1052,6 +1059,9 @@ pub const Session = struct {
c.attached = true;
c.need_full = true;
c.greet = true;
+ // Unwatched until now, it may have drawn nothing: a frame
+ // for the one attaching (watched).
+ s.core.needs_frame = true;
},
.bye => s.close(c, .bye),
.event => |ev| {