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.

Reply via email to