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 tmux-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tmux-users