Actually ignore this, it is wrong.
On Sat, Feb 04, 2017 at 01:18:30AM +0000, Nicholas Marriott wrote:
> 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.