Here is a better version that makes tmux also drop line feeds when it
doesn't need them. This makes it faster than screen for me, but it is
still faster per byte, it's just that we are now writing bytes out:
diff --git a/input.c b/input.c
index 17f81dd7..4653c992 100644
--- a/input.c
+++ b/input.c
@@ -871,9 +871,10 @@ input_parse(struct window_pane *wp)
buf = EVBUFFER_DATA(evb);
len = EVBUFFER_LENGTH(evb);
- notify_input(wp, evb);
off = 0;
+ notify_input(wp, evb);
+
log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id,
ictx->state->name, len, (int)len, buf);
diff --git a/screen-write.c b/screen-write.c
index 227316cb..d8558faf 100644
--- a/screen-write.c
+++ b/screen-write.c
@@ -38,22 +38,62 @@ static const struct grid_cell screen_write_pad_cell = {
GRID_FLAG_PADDING, 0, 8, 8, { { 0 }, 0, 0, 0 }
};
-#define screen_dirty_bit(s, x, y) (((y) * screen_size_x(s)) + (x))
-#define screen_dirty_clear(s, sx, sy, ex, ey) \
- do { \
- if (s->dirty != NULL) { \
- bit_nclear(s->dirty, \
- screen_dirty_bit(s, sx, sy), \
- screen_dirty_bit(s, ex, ey)); \
- } \
- } while (0)
+struct screen_write_dirty_item {
+ struct grid_cell gc;
+ u_int x;
+ u_int y;
+
+ TAILQ_ENTRY (screen_write_dirty_item) entry;
+};
+TAILQ_HEAD(screen_write_dirty_list, screen_write_dirty_item);
+struct screen_write_dirty_list freelist = TAILQ_HEAD_INITIALIZER(freelist);
+
+/* Set a dirty bit. */
+static void
+screen_write_dirty_set(struct screen_write_ctx *ctx, u_int x, u_int y,
+ const struct grid_cell *gc)
+{
+ struct screen *s = ctx->s;
+ struct screen_write_dirty_item *di;
+
+ di = TAILQ_FIRST(&freelist);
+ if (di != NULL)
+ TAILQ_REMOVE(&freelist, di, entry);
+ else
+ di = xmalloc(sizeof *di);
+ TAILQ_INSERT_TAIL(&ctx->dirtylist, di, entry);
+
+ di->x = x;
+ di->y = y;
+ memcpy(&di->gc, gc, sizeof di->gc);
+
+ ctx->dirty++;
+}
+
+/* Clear a dirty region. */
+static void
+screen_write_dirty_clear(struct screen_write_ctx *ctx, u_int sx, u_int sy,
+ u_int ex, u_int ey)
+{
+ struct screen *s = ctx->s;
+ struct screen_write_dirty_item *di, *di1;
+
+ if (TAILQ_EMPTY (&ctx->dirtylist))
+ return;
+
+ TAILQ_FOREACH_SAFE(di, &ctx->dirtylist, entry, di1) {
+ if (di->x < sx || di->x > ex || di->y < sy || di->y > ey)
+ continue;
+ TAILQ_REMOVE(&ctx->dirtylist, di, entry);
+ TAILQ_INSERT_TAIL(&freelist, di, entry);
+ }
+}
/* Initialize writing with a window. */
void
screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp,
struct screen *s)
{
- u_int size;
char tmp[16];
const char *cp = tmp;
@@ -63,12 +103,7 @@ screen_write_start(struct screen_write_ctx *ctx, struct
window_pane *wp,
else
ctx->s = s;
- size = screen_size_x(ctx->s) * screen_size_y(ctx->s);
- if (ctx->s->dirtysize != size) {
- free(ctx->s->dirty);
- ctx->s->dirty = NULL;
- ctx->s->dirtysize = size;
- }
+ TAILQ_INIT(&ctx->dirtylist);
ctx->dirty = 0;
ctx->cells = ctx->written = ctx->skipped = 0;
@@ -95,42 +130,33 @@ screen_write_stop(struct screen_write_ctx *ctx)
static void
screen_write_flush(struct screen_write_ctx *ctx)
{
- struct screen *s = ctx->s;
- struct tty_ctx ttyctx;
- u_int x, y, offset, cx, cy, dirty;
- struct grid_cell gc;
+ struct screen *s = ctx->s;
+ struct screen_write_dirty_item *di, *di1;
+ u_int cx, cy;
+ struct tty_ctx ttyctx;
if (ctx->dirty == 0)
return;
- dirty = 0;
log_debug("%s: dirty %u", __func__, ctx->dirty);
cx = s->cx;
cy = s->cy;
- offset = 0;
- for (y = 0; y < screen_size_y(s); y++) {
- for (x = 0; x < screen_size_x(s); x++) {
- offset++;
- if (!bit_test(s->dirty, offset - 1))
- continue;
- bit_clear(s->dirty, offset - 1);
+ TAILQ_FOREACH_SAFE(di, &ctx->dirtylist, entry, di1) {
+ screen_write_cursormove(ctx, di->x, di->y);
+ screen_write_initctx(ctx, &ttyctx);
- screen_write_cursormove(ctx, x, y);
- grid_view_get_cell(s->grid, x, y, &gc);
+ ttyctx.cell = &di->gc;
+ tty_write(tty_cmd_cell, &ttyctx);
- screen_write_initctx(ctx, &ttyctx);
- ttyctx.cell = &gc;
- tty_write(tty_cmd_cell, &ttyctx);
- ctx->written++;
+ ctx->written++;
- if (++dirty == ctx->dirty)
- break;
- }
- if (dirty == ctx->dirty)
- break;
+ TAILQ_REMOVE(&ctx->dirtylist, di, entry);
+ TAILQ_INSERT_TAIL(&freelist, di, entry);
}
+
ctx->dirty = 0;
+ ctx->scrolled = 0;
s->cx = cx;
s->cy = cy;
@@ -590,7 +616,7 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx)
screen_write_initctx(ctx, &ttyctx);
- screen_dirty_clear(s, 0, 0, sx - 1, sy - 1);
+ screen_write_dirty_clear(ctx, 0, 0, sx - 1, sy - 1);
memcpy(&gc, &grid_default_cell, sizeof gc);
utf8_set(&gc.data, 'E');
@@ -679,7 +705,8 @@ screen_write_clearcharacter(struct screen_write_ctx *ctx,
u_int nx)
screen_write_initctx(ctx, &ttyctx);
if (s->cx <= screen_size_x(s) - 1) {
- screen_dirty_clear(s, s->cx, s->cy, s->cx + nx - 1, s->cy);
+ screen_write_dirty_clear(ctx, s->cx, s->cy, s->cx + nx - 1,
+ s->cy);
grid_view_clear(s->grid, s->cx, s->cy, nx, 1, 8);
} else
return;
@@ -798,7 +825,7 @@ screen_write_clearline(struct screen_write_ctx *ctx, u_int
bg)
if (gl->cellsize == 0 && bg == 8)
return;
- screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
+ screen_write_dirty_clear(ctx, 0, s->cy, sx - 1, s->cy);
grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
tty_write(tty_cmd_clearline, &ttyctx);
@@ -820,7 +847,7 @@ screen_write_clearendofline(struct screen_write_ctx *ctx,
u_int bg)
if (s->cx > sx - 1 || (s->cx >= gl->cellsize && bg == 8))
return;
- screen_dirty_clear(s, s->cx, s->cy, sx - 1, s->cy);
+ screen_write_dirty_clear(ctx, s->cx, s->cy, sx - 1, s->cy);
grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg);
tty_write(tty_cmd_clearendofline, &ttyctx);
@@ -838,10 +865,10 @@ screen_write_clearstartofline(struct screen_write_ctx
*ctx, u_int bg)
ttyctx.bg = bg;
if (s->cx > sx - 1) {
- screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
+ screen_write_dirty_clear(ctx, 0, s->cy, sx - 1, s->cy);
grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
} else {
- screen_dirty_clear(s, 0, s->cy, s->cx, s->cy);
+ screen_write_dirty_clear(ctx, 0, s->cy, s->cx, s->cy);
grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg);
}
@@ -901,6 +928,8 @@ screen_write_scrollregion(struct screen_write_ctx *ctx,
u_int rupper,
s->rupper = rupper;
s->rlower = rlower;
+
+ ctx->scrolled = 0;
}
/* Line feed. */
@@ -911,6 +940,7 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int
wrapped)
struct grid_line *gl;
struct tty_ctx ttyctx;
u_int sx = screen_size_x(s), sy = screen_size_y(s);
+ struct screen_write_dirty_item *di, *di1;
screen_write_initctx(ctx, &ttyctx);
@@ -921,14 +951,21 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int
wrapped)
gl->flags &= ~GRID_LINE_WRAPPED;
if (s->cy == s->rlower) {
- screen_dirty_clear(s, 0, s->rupper, sx - 1, s->rupper);
- screen_write_flush(ctx);
+ TAILQ_FOREACH_SAFE(di, &ctx->dirtylist, entry, di1) {
+ if (di->y == s->rupper) {
+ TAILQ_REMOVE(&ctx->dirtylist, di, entry);
+ TAILQ_INSERT_TAIL(&freelist, di, entry);
+ } else if (di->y > s->rupper && di->y <= s->rlower)
+ di->y--;
+ }
grid_view_scroll_region_up(s->grid, s->rupper, s->rlower);
+ if (ctx->scrolled < s->rlower - s->rupper) {
+ ttyctx.num = wrapped;
+ tty_write(tty_cmd_linefeed, &ttyctx);
+ }
+ ctx->scrolled++;
} else if (s->cy < sy - 1)
s->cy++;
-
- ttyctx.num = wrapped;
- tty_write(tty_cmd_linefeed, &ttyctx);
}
/* Carriage return (cursor to start of line). */
@@ -953,15 +990,16 @@ screen_write_clearendofscreen(struct screen_write_ctx
*ctx, u_int bg)
/* Scroll into history if it is enabled and clearing entire screen. */
if (s->cx == 0 && s->cy == 0 && s->grid->flags & GRID_HISTORY) {
- screen_dirty_clear(s, 0, 0, sx - 1, sy - 1);
+ screen_write_dirty_clear(ctx, 0, 0, sx - 1, sy - 1);
grid_view_clear_history(s->grid, bg);
} else {
if (s->cx <= sx - 1) {
- screen_dirty_clear(s, s->cx, s->cy, sx - 1, s->cy);
+ screen_write_dirty_clear(ctx, s->cx, s->cy, sx - 1,
+ s->cy);
grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1,
bg);
}
- screen_dirty_clear(s, 0, s->cy + 1, sx - 1, sy - 1);
+ screen_write_dirty_clear(ctx, 0, s->cy + 1, sx - 1, sy - 1);
grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1),
bg);
}
@@ -980,14 +1018,14 @@ screen_write_clearstartofscreen(struct screen_write_ctx
*ctx)
screen_write_initctx(ctx, &ttyctx);
if (s->cy > 0) {
- screen_dirty_clear(s, 0, 0, sx - 1, s->cy);
+ screen_write_dirty_clear(ctx, 0, 0, sx - 1, s->cy);
grid_view_clear(s->grid, 0, 0, sx, s->cy, 8);
}
if (s->cx > sx - 1) {
- screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
+ screen_write_dirty_clear(ctx, 0, s->cy, sx - 1, s->cy);
grid_view_clear(s->grid, 0, s->cy, sx, 1, 8);
} else {
- screen_dirty_clear(s, 0, s->cy, s->cx, s->cy);
+ screen_write_dirty_clear(ctx, 0, s->cy, s->cx, s->cy);
grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, 8);
}
@@ -1005,7 +1043,7 @@ screen_write_clearscreen(struct screen_write_ctx *ctx,
u_int bg)
screen_write_initctx(ctx, &ttyctx);
ttyctx.bg = bg;
- screen_dirty_clear(s, 0, 0, sx - 1, sy - 1);
+ screen_write_dirty_clear(ctx, 0, 0, sx - 1, sy - 1);
/* Scroll into history if it is enabled. */
if (s->grid->flags & GRID_HISTORY)
@@ -1180,24 +1218,8 @@ screen_write_cell(struct screen_write_ctx *ctx, const
struct grid_cell *gc)
ttyctx.cell = gc;
tty_write(tty_cmd_cell, &ttyctx);
ctx->written++;
- } else {
- /*
- * If wp is NULL, we are not updating the terminal and
- * don't care about actually writing the cells
- * (tty_write will just return). So don't even bother
- * allocating the dirty array.
- */
- if (ctx->wp != NULL && s->dirty == NULL) {
- log_debug("%s: allocating %u bits", __func__,
- s->dirtysize);
- s->dirty = bit_alloc(s->dirtysize);
- }
- if (s->dirty != NULL) {
- bit_set(s->dirty, screen_dirty_bit(s,
- ttyctx.ocx, ttyctx.ocy));
- ctx->dirty++;
- }
- }
+ } else if (ctx->wp != NULL)
+ screen_write_dirty_set(ctx, ttyctx.ocx, ttyctx.ocy, gc);
} else
ctx->skipped++;
}
diff --git a/screen.c b/screen.c
index d6fbfecd..6088c14a 100644
--- a/screen.c
+++ b/screen.c
@@ -40,9 +40,6 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int
hlimit)
s->ccolour = xstrdup("");
s->tabs = NULL;
- s->dirty = NULL;
- s->dirtysize = 0;
-
screen_reinit(s);
}
@@ -69,7 +66,6 @@ screen_reinit(struct screen *s)
void
screen_free(struct screen *s)
{
- free(s->dirty);
free(s->tabs);
free(s->title);
free(s->ccolour);
diff --git a/tmux.h b/tmux.h
index 9dee7a1a..1b050526 100644
--- a/tmux.h
+++ b/tmux.h
@@ -71,10 +71,10 @@ struct tmuxproc;
* in succession switch to SLOW, and return when we hit EMPTY the same number
* of times.
*/
-#define READ_FAST_SIZE 4096
-#define READ_SLOW_SIZE 128
+#define READ_FAST_SIZE 65536
+#define READ_SLOW_SIZE 65536
-#define READ_FULL_SIZE (4096 - 16)
+#define READ_FULL_SIZE (65536 - 16)
#define READ_EMPTY_SIZE 16
#define READ_CHANGE_HITS 3
@@ -662,17 +662,18 @@ struct screen {
bitstr_t *tabs;
- bitstr_t *dirty;
- u_int dirtysize;
-
struct screen_sel sel;
};
/* Screen write context. */
+struct screen_write_dirty_item;
struct screen_write_ctx {
struct window_pane *wp;
struct screen *s;
+
+ TAILQ_HEAD(, screen_write_dirty_item) dirtylist;
u_int dirty;
+ u_int scrolled;
u_int cells;
u_int written;
On Fri, Feb 03, 2017 at 08:20:41PM +0000, Nicholas Marriott wrote:
> OK I took a look and there are a few problems:
>
> - An options_get_number() call has (re)appeared in tty_write(). I am
> sure I took this out before but I guess either I didn't, or it was
> added back. This is slow, but we can cache it.
>
> - We are allocating every time we need to add a cell rather than
> only every few cells, this is also a regression.
>
> - The dirty cell detection seems to have a very poor worst case, and
> scrolling is about as worst case as it gets. But we can do it better,
> by building a list of only the cells that are dirty. If we cache a
> copy of the cell we need it saves looking it up again as well.
>
> With this, tmux is quite a bit faster (assuming you bump
> READ_SLOW_SIZE).
>
> We are still faster than screen when the terminal content isn't actually
> changing (because we suppress it), but still slower when it does
> change. I now get, with various test files:
>
> tmux screen
> loads of lines 1.354 0.852
> home, clear, cat file 2.372 1.825
> home, cat file 0.555 1.664
> home, cat file1, cat file2 1.967 3.376
>
> There is probably still gains to be made by I can't see anything else
> obvious, and since it is fast enough that it will never affect anyone's
> use in any way whatsoever (and we artificially slow down large data
> anyway), I'm not sure I'll try too much harder right now.
>
> You can try this if you like:
>
>
> diff --git a/cmd-set-option.c b/cmd-set-option.c
> index c7cef42c..cc8b7570 100644
> --- a/cmd-set-option.c
> +++ b/cmd-set-option.c
> @@ -248,6 +248,8 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item
> *item)
> RB_FOREACH(w, windows, &windows)
> layout_fix_panes(w, w->sx, w->sy);
> }
> + RB_FOREACH (s, sessions, &sessions)
> + status_update_saved(s);
>
> /*
> * Update sizes and redraw. May not always be necessary but do it
> diff --git a/grid.c b/grid.c
> index dbb4fe64..e959bf4f 100644
> --- a/grid.c
> +++ b/grid.c
> @@ -291,6 +291,10 @@ grid_expand_line(struct grid *gd, u_int py, u_int sx,
> u_int bg)
> gl = &gd->linedata[py];
> if (sx <= gl->cellsize)
> return;
> + if (sx < gd->sx / 2)
> + sx = gd->sx / 2;
> + else
> + sx = gd->sx;
>
> gl->celldata = xreallocarray(gl->celldata, sx, sizeof *gl->celldata);
> for (xx = gl->cellsize; xx < sx; xx++)
> diff --git a/resize.c b/resize.c
> index 2d3f02cc..ba8078bc 100644
> --- a/resize.c
> +++ b/resize.c
> @@ -89,6 +89,8 @@ recalculate_sizes(void)
>
> s->sx = ssx;
> s->sy = ssy;
> +
> + status_update_saved(s);
> }
>
> RB_FOREACH(w, windows, &windows) {
> diff --git a/screen-write.c b/screen-write.c
> index 227316cb..a7e8cdc6 100644
> --- a/screen-write.c
> +++ b/screen-write.c
> @@ -38,15 +38,62 @@ static const struct grid_cell screen_write_pad_cell = {
> GRID_FLAG_PADDING, 0, 8, 8, { { 0 }, 0, 0, 0 }
> };
>
> -#define screen_dirty_bit(s, x, y) (((y) * screen_size_x(s)) + (x))
> -#define screen_dirty_clear(s, sx, sy, ex, ey) \
> - do { \
> - if (s->dirty != NULL) { \
> - bit_nclear(s->dirty, \
> - screen_dirty_bit(s, sx, sy), \
> - screen_dirty_bit(s, ex, ey)); \
> - } \
> - } while (0)
> +struct screen_write_dirty_item {
> + int used;
> +
> + struct grid_cell gc;
> + u_int x;
> + u_int y;
> +
> + TAILQ_ENTRY (screen_write_dirty_item) entry;
> +};
> +#define screen_write_dirty_bit(s, x, y) (((y) * screen_size_x(s)) + (x))
> +
> +static struct screen_write_dirty_item *screen_write_dirty;
> +static u_int screen_write_dirty_size;
> +
> +/* Set a dirty bit. */
> +static void
> +screen_write_dirty_set(struct screen_write_ctx *ctx, u_int x, u_int y,
> + const struct grid_cell *gc)
> +{
> + struct screen *s = ctx->s;
> + struct screen_write_dirty_item *di;
> +
> + di = &screen_write_dirty[screen_write_dirty_bit(s, x, y)];
> + TAILQ_INSERT_TAIL(&ctx->dirtylist, di, entry);
> + di->used = 1;
> +
> + di->x = x;
> + di->y = y;
> + memcpy(&di->gc, gc, sizeof di->gc);
> +
> + ctx->dirty++;
> +}
> +
> +/* Clear a dirty region. */
> +static void
> +screen_write_dirty_clear(struct screen_write_ctx *ctx, u_int sx, u_int sy,
> + u_int ex, u_int ey)
> +{
> + struct screen *s = ctx->s;
> + struct screen_write_dirty_item *di;
> + u_int start, end, i;
> +
> + if (TAILQ_EMPTY (&ctx->dirtylist))
> + return;
> +
> + start = screen_write_dirty_bit(s, sx, sy);
> + end = screen_write_dirty_bit(s, ex, ey);
> +
> + for (i = start; i < end + 1; i++) {
> + di = &screen_write_dirty[i];
> + if (di->used) {
> + di->used = 0;
> + TAILQ_REMOVE(&ctx->dirtylist, di, entry);
> + }
> + }
> +}
>
> /* Initialize writing with a window. */
> void
> @@ -64,11 +111,13 @@ screen_write_start(struct screen_write_ctx *ctx, struct
> window_pane *wp,
> ctx->s = s;
>
> size = screen_size_x(ctx->s) * screen_size_y(ctx->s);
> - if (ctx->s->dirtysize != size) {
> - free(ctx->s->dirty);
> - ctx->s->dirty = NULL;
> - ctx->s->dirtysize = size;
> + if (size > screen_write_dirty_size) {
> + screen_write_dirty_size = size;
> + screen_write_dirty = xreallocarray(screen_write_dirty, size,
> + sizeof *screen_write_dirty);
> }
> +
> + TAILQ_INIT(&ctx->dirtylist);
> ctx->dirty = 0;
>
> ctx->cells = ctx->written = ctx->skipped = 0;
> @@ -95,41 +144,30 @@ screen_write_stop(struct screen_write_ctx *ctx)
> static void
> screen_write_flush(struct screen_write_ctx *ctx)
> {
> - struct screen *s = ctx->s;
> - struct tty_ctx ttyctx;
> - u_int x, y, offset, cx, cy, dirty;
> - struct grid_cell gc;
> + struct screen *s = ctx->s;
> + struct screen_write_dirty_item *di;
> + u_int cx, cy;
> + struct tty_ctx ttyctx;
>
> if (ctx->dirty == 0)
> return;
> - dirty = 0;
> log_debug("%s: dirty %u", __func__, ctx->dirty);
>
> cx = s->cx;
> cy = s->cy;
>
> - offset = 0;
> - for (y = 0; y < screen_size_y(s); y++) {
> - for (x = 0; x < screen_size_x(s); x++) {
> - offset++;
> - if (!bit_test(s->dirty, offset - 1))
> - continue;
> - bit_clear(s->dirty, offset - 1);
> -
> - screen_write_cursormove(ctx, x, y);
> - grid_view_get_cell(s->grid, x, y, &gc);
> + TAILQ_FOREACH(di, &ctx->dirtylist, entry) {
> + screen_write_cursormove(ctx, di->x, di->y);
> + screen_write_initctx(ctx, &ttyctx);
>
> - screen_write_initctx(ctx, &ttyctx);
> - ttyctx.cell = &gc;
> - tty_write(tty_cmd_cell, &ttyctx);
> - ctx->written++;
> + ttyctx.cell = &di->gc;
> + tty_write(tty_cmd_cell, &ttyctx);
>
> - if (++dirty == ctx->dirty)
> - break;
> - }
> - if (dirty == ctx->dirty)
> - break;
> + ctx->written++;
> + di->used = 0;
> }
> +
> + TAILQ_INIT(&ctx->dirtylist);
> ctx->dirty = 0;
>
> s->cx = cx;
> @@ -590,7 +628,7 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx)
>
> screen_write_initctx(ctx, &ttyctx);
>
> - screen_dirty_clear(s, 0, 0, sx - 1, sy - 1);
> + screen_write_dirty_clear(ctx, 0, 0, sx - 1, sy - 1);
>
> memcpy(&gc, &grid_default_cell, sizeof gc);
> utf8_set(&gc.data, 'E');
> @@ -679,7 +717,8 @@ screen_write_clearcharacter(struct screen_write_ctx *ctx,
> u_int nx)
> screen_write_initctx(ctx, &ttyctx);
>
> if (s->cx <= screen_size_x(s) - 1) {
> - screen_dirty_clear(s, s->cx, s->cy, s->cx + nx - 1, s->cy);
> + screen_write_dirty_clear(ctx, s->cx, s->cy, s->cx + nx - 1,
> + s->cy);
> grid_view_clear(s->grid, s->cx, s->cy, nx, 1, 8);
> } else
> return;
> @@ -798,7 +837,7 @@ screen_write_clearline(struct screen_write_ctx *ctx,
> u_int bg)
> if (gl->cellsize == 0 && bg == 8)
> return;
>
> - screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
> + screen_write_dirty_clear(ctx, 0, s->cy, sx - 1, s->cy);
> grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
>
> tty_write(tty_cmd_clearline, &ttyctx);
> @@ -820,7 +859,7 @@ screen_write_clearendofline(struct screen_write_ctx *ctx,
> u_int bg)
> if (s->cx > sx - 1 || (s->cx >= gl->cellsize && bg == 8))
> return;
>
> - screen_dirty_clear(s, s->cx, s->cy, sx - 1, s->cy);
> + screen_write_dirty_clear(ctx, s->cx, s->cy, sx - 1, s->cy);
> grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg);
>
> tty_write(tty_cmd_clearendofline, &ttyctx);
> @@ -838,10 +877,10 @@ screen_write_clearstartofline(struct screen_write_ctx
> *ctx, u_int bg)
> ttyctx.bg = bg;
>
> if (s->cx > sx - 1) {
> - screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
> + screen_write_dirty_clear(ctx, 0, s->cy, sx - 1, s->cy);
> grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
> } else {
> - screen_dirty_clear(s, 0, s->cy, s->cx, s->cy);
> + screen_write_dirty_clear(ctx, 0, s->cy, s->cx, s->cy);
> grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg);
> }
>
> @@ -921,7 +960,7 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int
> wrapped)
> gl->flags &= ~GRID_LINE_WRAPPED;
>
> if (s->cy == s->rlower) {
> - screen_dirty_clear(s, 0, s->rupper, sx - 1, s->rupper);
> + screen_write_dirty_clear(ctx, 0, s->rupper, sx - 1, s->rupper);
> screen_write_flush(ctx);
> grid_view_scroll_region_up(s->grid, s->rupper, s->rlower);
> } else if (s->cy < sy - 1)
> @@ -953,15 +992,16 @@ screen_write_clearendofscreen(struct screen_write_ctx
> *ctx, u_int bg)
>
> /* Scroll into history if it is enabled and clearing entire screen. */
> if (s->cx == 0 && s->cy == 0 && s->grid->flags & GRID_HISTORY) {
> - screen_dirty_clear(s, 0, 0, sx - 1, sy - 1);
> + screen_write_dirty_clear(ctx, 0, 0, sx - 1, sy - 1);
> grid_view_clear_history(s->grid, bg);
> } else {
> if (s->cx <= sx - 1) {
> - screen_dirty_clear(s, s->cx, s->cy, sx - 1, s->cy);
> + screen_write_dirty_clear(ctx, s->cx, s->cy, sx - 1,
> + s->cy);
> grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1,
> bg);
> }
> - screen_dirty_clear(s, 0, s->cy + 1, sx - 1, sy - 1);
> + screen_write_dirty_clear(ctx, 0, s->cy + 1, sx - 1, sy - 1);
> grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1),
> bg);
> }
> @@ -980,14 +1020,14 @@ screen_write_clearstartofscreen(struct
> screen_write_ctx *ctx)
> screen_write_initctx(ctx, &ttyctx);
>
> if (s->cy > 0) {
> - screen_dirty_clear(s, 0, 0, sx - 1, s->cy);
> + screen_write_dirty_clear(ctx, 0, 0, sx - 1, s->cy);
> grid_view_clear(s->grid, 0, 0, sx, s->cy, 8);
> }
> if (s->cx > sx - 1) {
> - screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
> + screen_write_dirty_clear(ctx, 0, s->cy, sx - 1, s->cy);
> grid_view_clear(s->grid, 0, s->cy, sx, 1, 8);
> } else {
> - screen_dirty_clear(s, 0, s->cy, s->cx, s->cy);
> + screen_write_dirty_clear(ctx, 0, s->cy, s->cx, s->cy);
> grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, 8);
> }
>
> @@ -1005,7 +1045,7 @@ screen_write_clearscreen(struct screen_write_ctx *ctx,
> u_int bg)
> screen_write_initctx(ctx, &ttyctx);
> ttyctx.bg = bg;
>
> - screen_dirty_clear(s, 0, 0, sx - 1, sy - 1);
> + screen_write_dirty_clear(ctx, 0, 0, sx - 1, sy - 1);
>
> /* Scroll into history if it is enabled. */
> if (s->grid->flags & GRID_HISTORY)
> @@ -1180,24 +1220,8 @@ screen_write_cell(struct screen_write_ctx *ctx, const
> struct grid_cell *gc)
> ttyctx.cell = gc;
> tty_write(tty_cmd_cell, &ttyctx);
> ctx->written++;
> - } else {
> - /*
> - * If wp is NULL, we are not updating the terminal and
> - * don't care about actually writing the cells
> - * (tty_write will just return). So don't even bother
> - * allocating the dirty array.
> - */
> - if (ctx->wp != NULL && s->dirty == NULL) {
> - log_debug("%s: allocating %u bits", __func__,
> - s->dirtysize);
> - s->dirty = bit_alloc(s->dirtysize);
> - }
> - if (s->dirty != NULL) {
> - bit_set(s->dirty, screen_dirty_bit(s,
> - ttyctx.ocx, ttyctx.ocy));
> - ctx->dirty++;
> - }
> - }
> + } else if (ctx->wp != NULL)
> + screen_write_dirty_set(ctx, ttyctx.ocx, ttyctx.ocy, gc);
> } else
> ctx->skipped++;
> }
> diff --git a/screen.c b/screen.c
> index d6fbfecd..6088c14a 100644
> --- a/screen.c
> +++ b/screen.c
> @@ -40,9 +40,6 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int
> hlimit)
> s->ccolour = xstrdup("");
> s->tabs = NULL;
>
> - s->dirty = NULL;
> - s->dirtysize = 0;
> -
> screen_reinit(s);
> }
>
> @@ -69,7 +66,6 @@ screen_reinit(struct screen *s)
> void
> screen_free(struct screen *s)
> {
> - free(s->dirty);
> free(s->tabs);
> free(s->title);
> free(s->ccolour);
> diff --git a/session.c b/session.c
> index d89bc6a0..e2ff65b1 100644
> --- a/session.c
> +++ b/session.c
> @@ -130,6 +130,8 @@ session_create(const char *name, int argc, char **argv,
> const char *path,
> s->options = options_create(global_s_options);
> s->hooks = hooks_create(global_hooks);
>
> + status_update_saved(s);
> +
> s->tio = NULL;
> if (tio != NULL) {
> s->tio = xmalloc(sizeof *s->tio);
> diff --git a/status.c b/status.c
> index c4f79050..6cc1ee37 100644
> --- a/status.c
> +++ b/status.c
> @@ -192,17 +192,26 @@ status_timer_start_all(void)
> status_timer_start(c);
> }
>
> +/* Update status cache. */
> +void
> +status_update_saved(struct session *s)
> +{
> + if (!options_get_number(s->options, "status"))
> + s->statusat = -1;
> + else if (options_get_number(s->options, "status-position") == 0)
> + s->statusat = 0;
> + else
> + s->statusat = 1;
> +}
> +
> /* Get screen line of status line. -1 means off. */
> int
> status_at_line(struct client *c)
> {
> struct session *s = c->session;
>
> - if (!options_get_number(s->options, "status"))
> - return (-1);
> -
> - if (options_get_number(s->options, "status-position") == 0)
> - return (0);
> + if (s->statusat != 1)
> + return (s->statusat);
> return (c->tty.sy - 1);
> }
>
> diff --git a/tmux.h b/tmux.h
> index 69f99d63..fb6c8444 100644
> --- a/tmux.h
> +++ b/tmux.h
> @@ -547,7 +547,6 @@ struct grid_cell {
> int fg;
> int bg;
> struct utf8_data data;
> -
> };
> struct grid_cell_entry {
> u_char flags;
> @@ -663,16 +662,16 @@ struct screen {
>
> bitstr_t *tabs;
>
> - bitstr_t *dirty;
> - u_int dirtysize;
> -
> struct screen_sel sel;
> };
>
> /* Screen write context. */
> +struct screen_write_dirty_item;
> struct screen_write_ctx {
> struct window_pane *wp;
> struct screen *s;
> +
> + TAILQ_HEAD(, screen_write_dirty_item) dirtylist;
> u_int dirty;
>
> u_int cells;
> @@ -938,6 +937,8 @@ struct session {
> struct winlink_stack lastw;
> struct winlinks windows;
>
> + int statusat;
> +
> struct hooks *hooks;
> struct options *options;
>
> @@ -1866,6 +1867,7 @@ void server_unzoom_window(struct window *);
> /* status.c */
> void status_timer_start(struct client *);
> void status_timer_start_all(void);
> +void status_update_saved(struct session *s);
> int status_at_line(struct client *);
> struct window *status_get_window_at(struct client *, u_int);
> int status_redraw(struct client *);
>
>
>
>
> On Fri, Feb 03, 2017 at 05:13:24PM +0000, Nicholas Marriott wrote:
> > It depends on the file :-).
> >
> > $ rm foo; for i in `seq 20000`; do (printf '\033[H'; cat /etc/fstab) >>foo;
> > done
> > $ wc -l foo
> > 260000 foo
> >
> > $ screen
> > $ clear; time cat foo
> > ...
> > real 0m1.687s
> > user 0m0.000s
> > sys 0m0.260s
> >
> > $ tmux
> > $ clear; time cat foo
> > ...
> > real 0m1.308s
> > user 0m0.000s
> > sys 0m0.196s
> >
> > $ sed -i 's|\(READ_...._SIZE\) .*|\1 4096|g' tmux.h
> > $ make
> > ...
> > $ ./tmux
> > $ clear; time cat foo
> > ...
> > real 0m0.519s
> > user 0m0.000s
> > sys 0m0.232s
> >
> > Of course this is a cheat, because I know it is optimized.
> >
> > We are definitely a bit slower than we should be... would merit some
> > investigation. IIRC it used to be faster.
> >
> >
> >
> >
> > On Fri, Feb 03, 2017 at 09:21:58AM -0600, Josef Fortier wrote:
> > > I saw this posted on reddit:
> > > https://www.reddit.com/r/tmux/comments/5or3e4/tmux_really_slows_down_the_terminal_performance_a/
> > >
> > > Basically:
> > > time cat large_file
> > >
> > > tmux is much slower then screen, dvtm (an order of magnitude)
> > > It's not a huge issue, but it is a little disconcerting.
> > >
> > > Early in the thread there's this comment:
> > > "Please verify that you're using the newest tmux version available.
> > > The slowdown is known and there are multiple tickets about that in the
> > > project."
> > >
> > > I looked for tickets, and mostly saw references to CTRL-C not
> > > registering (and mostly on MacOS)
> > > This doesn't seem to address this issue.
> > >
> > > Is this actually a known issue?
> > > Can anyone point me to better understanding about why this is?
> > >
> > > Thanks :-)
> > >
> > > --
> > > Josef Fortier
> > >
> > > --
> > > You received this message because you are subscribed to the Google Groups
> > > "tmux-users" group.
> > > To unsubscribe from this group and stop receiving emails from it, send an
> > > email to [email protected].
> > > To post to this group, send an email to [email protected].
> > > For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups
"tmux-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send an email to [email protected].
For more options, visit https://groups.google.com/d/optout.