The last diff was slightly wrong, please test this instead.

This should not only fix the problem but can also be a spectacular
optimisation when tmux is running locally (not over ssh).

This makes it so that if the reader (typically xterm) cannot keep up
with the output, tmux ONLY updates its internal screen and does not
attempt to write anything to the tty. Then when the reader recovers, it
just redraws the screen.

This means that anything producing output very fast that would normally
be limited by a slow consumer (xterm) will be mostly talking to a fast
consumer (tmux).

For example, an extreme case, "time jot 100000" drops from about 20
seconds to about 2 seconds.

Obviously there will be regressive cases, for example if you backoff at
16 KB but then write only another 1 byte, tmux will write a total of 16
KB + the size of the terminal (20-40 KB usually), but I think that in
most cases if a producer writes enough fast enough to be backed off
usually they will be writing enough to make this a good thing.

Plus it also satisfies the original aim of keeping tmux fairly
responsive (including ^C) with fast output in one or more of the
windows.

ssh renders this useless because it is itself a fast consumer so tmux
never backs off and you have to wait while xterm catches up to the data
from ssh before any key presses are responded to.



Index: server-client.c
===================================================================
RCS file: /cvs/src/usr.bin/tmux/server-client.c,v
retrieving revision 1.35
diff -u -p -r1.35 server-client.c
--- server-client.c     19 Jul 2010 18:27:38 -0000      1.35
+++ server-client.c     23 Jul 2010 01:27:49 -0000
@@ -29,6 +29,7 @@
 
 void   server_client_handle_key(int, struct mouse_event *, void *);
 void   server_client_repeat_timer(int, short, void *);
+void   server_client_check_backoff(struct client *);
 void   server_client_check_redraw(struct client *);
 void   server_client_set_title(struct client *);
 void   server_client_reset_state(struct client *);
@@ -393,6 +394,7 @@ server_client_loop(void)
                if (c == NULL || c->session == NULL)
                        continue;
 
+               server_client_check_backoff(c); /* before redraw */
                server_client_check_redraw(c);
                server_client_reset_state(c);
        }
@@ -457,6 +459,50 @@ server_client_repeat_timer(unused int fd
                c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT);
 }
 
+/*
+ * Check if the client should backoff. During backoff, data from external
+ * programs is not written to the terminal. When the existing data drains, the
+ * client is redrawn.
+ *
+ * There are two backoff phases - both the tty and client have backoff flags -
+ * the first to allow existing data to drain and the latter to ensure backoff
+ * is disabled until the redraw has finished and prevent the redraw triggering
+ * another backoff.
+ */
+void
+server_client_check_backoff(struct client *c)
+{
+       struct tty      *tty = &c->tty;
+       size_t           used;
+
+       used = EVBUFFER_LENGTH(tty->event->output);
+
+       /*
+        * If in the second backoff phase (redrawing), don't check backoff
+        * until the redraw has completed (or enough of it to drop below the
+        * backoff threshold).
+        */
+       if (c->flags & CLIENT_BACKOFF) {
+               if (used > BACKOFF_THRESHOLD)
+                       return;
+               c->flags &= ~CLIENT_BACKOFF;
+               return;
+       }
+
+       /* Once drained, allow data through again and schedule redraw. */
+       if (tty->flags & TTY_BACKOFF) {
+               if (used != 0)
+                       return;
+               tty->flags &= ~TTY_BACKOFF;
+               c->flags |= (CLIENT_BACKOFF|CLIENT_REDRAWWINDOW|CLIENT_STATUS);
+               return;
+       }
+
+       /* If too much data, start backoff. */
+       if (used > BACKOFF_THRESHOLD)
+               tty->flags |= TTY_BACKOFF;
+}
+
 /* Check for client redraws. */
 void
 server_client_check_redraw(struct client *c)
@@ -485,6 +531,10 @@ server_client_check_redraw(struct client
        if (c->flags & CLIENT_REDRAW) {
                screen_redraw_screen(c, 0, 0);
                c->flags &= ~(CLIENT_STATUS|CLIENT_BORDERS);
+       } else if (c->flags & CLIENT_REDRAWWINDOW) {
+               TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry)
+                       screen_redraw_pane(c, wp);
+               c->flags &= ~CLIENT_REDRAWWINDOW;
        } else {
                TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
                        if (wp->flags & PANE_REDRAW)
Index: server-window.c
===================================================================
RCS file: /cvs/src/usr.bin/tmux/server-window.c,v
retrieving revision 1.16
diff -u -p -r1.16 server-window.c
--- server-window.c     19 Jul 2010 21:13:03 -0000      1.16
+++ server-window.c     23 Jul 2010 01:27:50 -0000
@@ -29,31 +29,6 @@ int  server_window_check_activity(struct 
 int    server_window_check_content(
            struct session *, struct winlink *, struct window_pane *);
 
-/* Check if this window should suspend reading. */
-int
-server_window_backoff(struct window_pane *wp)
-{
-       struct client   *c;
-       u_int            i;
-
-       if (!window_pane_visible(wp))
-               return (0);
-
-       for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
-               c = ARRAY_ITEM(&clients, i);
-               if (c == NULL || c->session == NULL)
-                       continue;
-               if ((c->flags & (CLIENT_SUSPENDED|CLIENT_DEAD)) != 0)
-                       continue;
-               if (c->session->curw->window != wp->window)
-                       continue;
-
-               if (EVBUFFER_LENGTH(c->tty.event->output) > BACKOFF_THRESHOLD)
-                       return (1);
-       }
-       return (0);
-}
-
 /* Window functions that need to happen every loop. */
 void
 server_window_loop(void)
@@ -68,17 +43,6 @@ server_window_loop(void)
                w = ARRAY_ITEM(&windows, i);
                if (w == NULL)
                        continue;
-
-               TAILQ_FOREACH(wp, &w->panes, entry) {
-                       if (wp->fd == -1)
-                               continue;
-                       if (!(wp->flags & PANE_FREEZE)) {
-                               if (server_window_backoff(wp))
-                                       bufferevent_disable(wp->event, EV_READ);
-                               else
-                                       bufferevent_enable(wp->event, EV_READ);
-                       }
-               }
 
                for (j = 0; j < ARRAY_LENGTH(&sessions); j++) {
                        s = ARRAY_ITEM(&sessions, j);
Index: tmux.h
===================================================================
RCS file: /cvs/src/usr.bin/tmux/tmux.h,v
retrieving revision 1.235
diff -u -p -r1.235 tmux.h
--- tmux.h      14 Jul 2010 18:37:49 -0000      1.235
+++ tmux.h      23 Jul 2010 01:27:51 -0000
@@ -59,8 +59,8 @@ extern char   **environ;
 /* Automatic name refresh interval, in milliseconds. */
 #define NAME_INTERVAL 500
 
-/* Maximum data to buffer for output before suspending reading from panes. */
-#define BACKOFF_THRESHOLD 1024
+/* Maximum data to buffer for output before suspending writing to a tty. */
+#define BACKOFF_THRESHOLD 16384
 
 /*
  * Maximum sizes of strings in message data. Don't forget to bump
@@ -1017,6 +1017,7 @@ struct tty {
 #define TTY_UTF8 0x8
 #define TTY_STARTED 0x10
 #define TTY_OPENED 0x20
+#define TTY_BACKOFF 0x40
        int              flags;
 
        int              term_flags;
@@ -1118,6 +1119,8 @@ struct client {
 #define CLIENT_DEAD 0x200
 #define CLIENT_BORDERS 0x400
 #define CLIENT_READONLY 0x800
+#define CLIENT_BACKOFF 0x1000
+#define CLIENT_REDRAWWINDOW 0x2000
        int              flags;
 
        struct event     identify_timer;
Index: tty.c
===================================================================
RCS file: /cvs/src/usr.bin/tmux/tty.c,v
retrieving revision 1.88
diff -u -p -r1.88 tty.c
--- tty.c       5 Jun 2010 16:47:11 -0000       1.88
+++ tty.c       23 Jul 2010 01:27:51 -0000
@@ -578,7 +578,9 @@ tty_write(void (*cmdfn)(
                        continue;
 
                if (c->session->curw->window == wp->window) {
-                       if (c->tty.flags & TTY_FREEZE || c->tty.term == NULL)
+                       if (c->tty.term == NULL)
+                               continue;
+                       if (c->tty.flags & (TTY_FREEZE|TTY_BACKOFF))
                                continue;
                        cmdfn(&c->tty, ctx);
                }


------------------------------------------------------------------------------
This SF.net email is sponsored by Sprint
What will you do first with EVO, the first 4G phone?
Visit sprint.com/first -- http://p.sf.net/sfu/sprint-com-first
_______________________________________________
tmux-users mailing list
tmux-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tmux-users

Reply via email to