Add a simple form of output rate limiting by counting the number of

certain C0 sequences (linefeeds, backspaces, carriage returns) and if it
exceeds a threshold (current default 50/millisecond), start to redraw
the pane every 100 milliseconds instead of making each change as it
comes. Two configuration options - c0-change-trigger and
c0-change-interval.

This makes tmux much more responsive under very fast output (for example
yes(1) or accidentally cat'ing a large file) but may not be perfect on
all terminals and connections - feedback very welcome, particularly
where this change has a negative rather than positive effect (making it
off by default is a possibility).

After much experimentation based originally on a request Robin Lee
Powell (which ended with a completely different solution), this idea
from discussion with Ailin Nemui.
pull/1/head
Nicholas Marriott 2012-03-20 11:01:00 +00:00
parent bf9e7a1c68
commit f59971276a
6 changed files with 93 additions and 5 deletions

16
input.c
View File

@ -908,6 +908,7 @@ input_c0_dispatch(struct input_ctx *ictx)
struct screen_write_ctx *sctx = &ictx->ctx;
struct window_pane *wp = ictx->wp;
struct screen *s = sctx->s;
u_int trigger;
log_debug("%s: '%c", __func__, ictx->ch);
@ -919,7 +920,7 @@ input_c0_dispatch(struct input_ctx *ictx)
break;
case '\010': /* BS */
screen_write_backspace(sctx);
break;
goto count_c0;
case '\011': /* HT */
/* Don't tab beyond the end of the line. */
if (s->cx >= screen_size_x(s) - 1)
@ -936,10 +937,10 @@ input_c0_dispatch(struct input_ctx *ictx)
case '\013': /* VT */
case '\014': /* FF */
screen_write_linefeed(sctx, 0);
break;
goto count_c0;
case '\015': /* CR */
screen_write_carriagereturn(sctx);
break;
goto count_c0;
case '\016': /* SO */
ictx->cell.attr |= GRID_ATTR_CHARSET;
break;
@ -951,6 +952,15 @@ input_c0_dispatch(struct input_ctx *ictx)
break;
}
return (0);
count_c0:
trigger = options_get_number(&wp->window->options, "c0-change-trigger");
if (++wp->changes == trigger) {
wp->flags |= PANE_DROP;
window_pane_timer_start(wp);
}
return (0);
}

View File

@ -465,6 +465,21 @@ const struct options_table_entry window_options_table[] = {
.default_num = 1
},
{ .name = "c0-change-trigger",
.type = OPTIONS_TABLE_NUMBER,
.default_num = 50,
.minimum = 0,
.maximum = USHRT_MAX
},
{ .name = "c0-change-interval",
.type = OPTIONS_TABLE_NUMBER,
.default_num = 100,
.minimum = 1,
.maximum = USHRT_MAX
},
{ .name = "clock-mode-colour",
.type = OPTIONS_TABLE_COLOUR,
.default_num = 4

18
tmux.1
View File

@ -2463,6 +2463,24 @@ It may be switched off globally with:
set-window-option -g automatic-rename off
.Ed
.Pp
.It Ic c0-change-interval Ar interval
.It Ic c0-change-trigger Ar trigger
These two options configure a simple form of rate limiting for a pane.
If
.Nm
sees more than
.Ar trigger
C0 sequences that modify the screen (for example, carriage returns, linefeeds
or backspaces) in one millisecond, it will stop updating the pane immediately and
instead redraw it entirely every
.Ar interval
milliseconds.
This helps to prevent fast output (such as
.Xr yes 1
overwhelming the terminal).
The default is a trigger of 50 and an interval of 100.
A trigger of zero disables the rate limiting.
.Pp
.It Ic clock-mode-colour Ar colour
Set clock colour.
.Pp

7
tmux.h
View File

@ -811,6 +811,7 @@ struct window_pane {
int flags;
#define PANE_REDRAW 0x1
#define PANE_DROP 0x2
char *cmd;
char *shell;
@ -819,6 +820,10 @@ struct window_pane {
pid_t pid;
char tty[TTY_NAME_MAX];
u_int changes;
struct event changes_timer;
u_int changes_redraw;
int fd;
struct bufferevent *event;
@ -1963,6 +1968,7 @@ void window_destroy_panes(struct window *);
struct window_pane *window_pane_find_by_id(u_int);
struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int);
void window_pane_destroy(struct window_pane *);
void window_pane_timer_start(struct window_pane *);
int window_pane_spawn(struct window_pane *, const char *,
const char *, const char *, struct environ *,
struct termios *, char **);
@ -1981,7 +1987,6 @@ int window_pane_visible(struct window_pane *);
char *window_pane_search(
struct window_pane *, const char *, u_int *);
char *window_printable_flags(struct session *, struct winlink *);
struct window_pane *window_pane_find_up(struct window_pane *);
struct window_pane *window_pane_find_down(struct window_pane *);
struct window_pane *window_pane_find_left(struct window_pane *);

2
tty.c
View File

@ -661,7 +661,7 @@ tty_write(
if (wp->window->flags & WINDOW_REDRAW || wp->flags & PANE_REDRAW)
return;
if (!window_pane_visible(wp))
if (!window_pane_visible(wp) || wp->flags & PANE_DROP)
return;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {

View File

@ -61,6 +61,7 @@ struct window_pane_tree all_window_panes;
u_int next_window_pane_id;
u_int next_window_id;
void window_pane_timer_callback(int, short, void *);
void window_pane_read_callback(struct bufferevent *, void *);
void window_pane_error_callback(struct bufferevent *, short, void *);
@ -648,6 +649,8 @@ window_pane_destroy(struct window_pane *wp)
{
window_pane_reset_mode(wp);
event_del(&wp->changes_timer);
if (wp->fd != -1) {
bufferevent_free(wp->event);
close(wp->fd);
@ -764,6 +767,43 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
return (0);
}
void
window_pane_timer_start(struct window_pane *wp)
{
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 1000;
evtimer_del(&wp->changes_timer);
evtimer_set(&wp->changes_timer, window_pane_timer_callback, wp);
evtimer_add(&wp->changes_timer, &tv);
}
void
window_pane_timer_callback(unused int fd, unused short events, void *data)
{
struct window_pane *wp = data;
struct window *w = wp->window;
u_int interval, trigger;
interval = options_get_number(&w->options, "c0-change-interval");
trigger = options_get_number(&w->options, "c0-change-trigger");
if (wp->changes_redraw++ == interval) {
wp->flags |= PANE_REDRAW;
wp->changes_redraw = 0;
}
if (trigger == 0 || wp->changes < trigger) {
wp->flags |= PANE_REDRAW;
wp->flags &= ~PANE_DROP;
} else
window_pane_timer_start(wp);
wp->changes = 0;
}
/* ARGSUSED */
void
window_pane_read_callback(unused struct bufferevent *bufev, void *data)