I just made this core so maybe wait for a wee bit first :-).
On Sun, Feb 10, 2013 at 02:06:12PM +0000, Nicholas Marriott wrote:
> Hi
>
> The current reflow code is nice and simple but as Thomas has discovered
> it is pretty slow. Particularly on FreeBSD apparently, my guess would be
> because it does a lot of realloc and is hitting some suboptimal case in
> their libc.
>
> So the diff below avoids allocation and does memcpy rather than
> cell-by-cell copies.
>
> Tests, comments please.
>
> If this doesn't fix the problem then we shall have to think again :-).
>
>
> diff --git a/grid.c b/grid.c
> index aabf66c..cad8187 100644
> --- a/grid.c
> +++ b/grid.c
> @@ -70,6 +70,10 @@ grid_check_y(struct grid *gd, u_int py)
> }
> #endif
>
> +void grid_reflow_join(struct grid *, u_int *, struct grid_line *, u_int);
> +void grid_reflow_split(struct grid *, u_int *, struct grid_line *, u_int);
> +void grid_reflow_move(struct grid *, u_int *, struct grid_line *);
> +
> /* Create a new grid. */
> struct grid *
> grid_create(u_int sx, u_int sy, u_int hlimit)
> @@ -461,43 +465,147 @@ grid_duplicate_lines(
> }
> }
>
> +/* Join line data. */
> +void
> +grid_reflow_join(struct grid *dst, u_int *py, struct grid_line *src_gl,
> + u_int new_x)
> +{
> + struct grid_line *dst_gl = &dst->linedata[*py];
> + u_int left, to_copy, ox, nx;
> +
> + /* How much is left on the old line? */
> + left = new_x - dst_gl->cellsize;
> +
> + /* Work out how much to append. */
> + to_copy = src_gl->cellsize;
> + if (to_copy > left)
> + to_copy = left;
> + ox = dst_gl->cellsize;
> + nx = ox + to_copy;
> +
> + /* Resize the destination line. */
> + dst_gl->celldata = xrealloc(dst_gl->celldata, nx,
> + sizeof *dst_gl->celldata);
> + dst_gl->cellsize = nx;
> +
> + /* Append as much as possible. */
> + memcpy(&dst_gl->celldata[ox], &src_gl->celldata[0],
> + src_gl->cellsize * sizeof src_gl->celldata[0]);
> +
> + /* If there is any left in the source, add a new line with it. */
> + if (src_gl->cellsize > to_copy) {
> + (*py)++;
> + if (*py >= dst->hsize + dst->sy)
> + grid_scroll_history(dst);
> + dst_gl = &dst->linedata[*py];
> +
> + memcpy(dst_gl, src_gl, sizeof *dst_gl);
> + dst_gl->flags |= GRID_LINE_WRAPPED;
> +
> + dst_gl->cellsize -= to_copy;
> + memmove(&dst_gl->celldata[0], &dst_gl->celldata[to_copy],
> + dst_gl->cellsize * sizeof dst_gl->celldata[0]);
> + }
> +
> + /* Clear source data. */
> + src_gl->celldata = NULL;
> +}
> +
> +/* Split line data. */
> +void
> +grid_reflow_split(struct grid *dst, u_int *py, struct grid_line *src_gl,
> + u_int new_x)
> +{
> + struct grid_line *dst_gl;
> + u_int offset, to_copy;
> +
> + /* Loop and copy sections of the source line. */
> + offset = 0;
> + while (src_gl->cellsize > 0)
> + {
> + /* Create new line. */
> + (*py)++;
> + if (*py >= dst->hsize + dst->sy)
> + grid_scroll_history(dst);
> + dst_gl = &dst->linedata[*py];
> +
> + /* How much should we copy? */
> + to_copy = new_x;
> + if (to_copy > src_gl->cellsize)
> + to_copy = src_gl->cellsize;
> +
> + /* Expand destination line. */
> + dst_gl->celldata = xmalloc(to_copy * sizeof *dst_gl->celldata);
> + dst_gl->cellsize = to_copy;
> + dst_gl->flags |= GRID_LINE_WRAPPED;
> +
> + /* Copy the data. */
> + memcpy (&dst_gl->celldata[0], &src_gl->celldata[offset],
> + to_copy * sizeof dst_gl->celldata[0]);
> +
> + /* Move offset and reduce old line size. */
> + offset += to_copy;
> + src_gl->cellsize -= to_copy;
> + }
> +
> + /* Last line is not wrapped. */
> + dst_gl->flags &= ~GRID_LINE_WRAPPED;
> +}
> +
> +/* Move line data. */
> +void
> +grid_reflow_move(struct grid *dst, u_int *py, struct grid_line *src_gl)
> +{
> + struct grid_line *dst_gl;
> +
> + /* Create new line. */
> + (*py)++;
> + if (*py >= dst->hsize + dst->sy)
> + grid_scroll_history(dst);
> + dst_gl = &dst->linedata[*py];
> +
> + /* Copy the old line. */
> + memcpy(dst_gl, src_gl, sizeof *dst_gl);
> + dst_gl->flags &= ~GRID_LINE_WRAPPED;
> +
> + /* Clear old line. */
> + src_gl->celldata = NULL;
> +}
> +
> /*
> - * Reflow lines from src grid into dst grid based on width sx. Returns number
> - * of lines fewer in the visible area, or zero.
> + * Reflow lines from src grid into dst grid of width new_x. Returns number of
> + * lines fewer in the visible area. The source grid is destroyed.
> */
> u_int
> -grid_reflow(struct grid *dst, const struct grid *src, u_int sx)
> +grid_reflow(struct grid *dst, struct grid *src, u_int new_x)
> {
> - u_int px, py, line, cell;
> + u_int py, sy, line;
> int previous_wrapped;
> - struct grid_line *gl;
> + struct grid_line *src_gl;
> +
> + py = 0;
> + sy = src->sy;
>
> - px = py = 0;
> previous_wrapped = 1;
> - for (line = 0; line < src->sy + src->hsize; line++) {
> - gl = src->linedata + line;
> + for (line = 0; line < sy + src->hsize; line++) {
> + src_gl = src->linedata + line;
> if (!previous_wrapped) {
> - px = 0;
> - py++;
> - if (py >= dst->hsize + dst->sy)
> - grid_scroll_history(dst);
> - }
> - for (cell = 0; cell < gl->cellsize; cell++) {
> - if (px == sx) {
> - dst->linedata[py].flags |= GRID_LINE_WRAPPED;
> - px = 0;
> - py++;
> - if (py >= dst->hsize + dst->sy)
> - grid_scroll_history(dst);
> - }
> - grid_set_cell(dst, px, py, gl->celldata + cell);
> - px++;
> + /* Wasn't wrapped. If smaller, move to destination. */
> + if (src_gl->cellsize < new_x)
> + grid_reflow_move(dst, &py, src_gl);
> + else
> + grid_reflow_split(dst, &py, src_gl, new_x);
> + } else {
> + /* Previous was wrapped. Try to join. */
> + grid_reflow_join(dst, &py, src_gl, new_x);
> }
> - previous_wrapped = gl->flags & GRID_LINE_WRAPPED;
> + previous_wrapped = src_gl->flags & GRID_LINE_WRAPPED;
> }
> py++; /* account for final line, which never wraps */
>
> - if (py > src->sy)
> + grid_destroy(src);
> +
> + if (py > sy)
> return (0);
> - return (src->sy - py);
> + return (sy - py);
> }
> diff --git a/screen.c b/screen.c
> index fe0b738..e92c6aa 100644
> --- a/screen.c
> +++ b/screen.c
> @@ -363,15 +363,10 @@ screen_check_selection(struct screen *s, u_int px,
> u_int py)
>
> /* Reflow wrapped lines. */
> void
> -screen_reflow(struct screen *s, u_int sx)
> +screen_reflow(struct screen *s, u_int new_x)
> {
> - struct grid *old, *new;
> + struct grid *old = s->grid;
>
> - old = s->grid;
> - new = grid_create(old->sx, old->sy, old->hlimit);
> -
> - s->cy -= grid_reflow(new, old, sx);
> - s->grid = new;
> -
> - grid_destroy(old);
> + s->grid = grid_create(old->sx, old->sy, old->hlimit);
> + s->cy -= grid_reflow(s->grid, old, new_x);
> }
> diff --git a/tmux.h b/tmux.h
> index 1dd11ad..fd67724 100644
> --- a/tmux.h
> +++ b/tmux.h
> @@ -1960,7 +1960,7 @@ void grid_move_cells(struct grid *, u_int, u_int,
> u_int, u_int);
> char *grid_string_cells(struct grid *, u_int, u_int, u_int);
> void grid_duplicate_lines(
> struct grid *, u_int, struct grid *, u_int, u_int);
> -u_int grid_reflow(struct grid *, const struct grid *, u_int);
> +u_int grid_reflow(struct grid *, struct grid *, u_int);
>
> /* grid-cell.c */
> u_int grid_cell_width(const struct grid_cell *);
>
>
>
------------------------------------------------------------------------------
Free Next-Gen Firewall Hardware Offer
Buy your Sophos next-gen firewall before the end March 2013
and get the hardware for free! Learn more.
http://p.sf.net/sfu/sophos-d2d-feb
_______________________________________________
tmux-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tmux-users