This uses the new xdiff emit_func feature to directly generate the patch/chunk information from the low-level diff output, rather than generating and parsing a patch. This improves performance considerably for certain test cases: :; time git-blame -M -C -C -p --incremental server.c >/dev/null Before: 79.62user 0.10system 1:19.81elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+41189minor)pagefaults 0swaps After: 48.66user 0.08system 0:48.75elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+36961minor)pagefaults 0swaps Signed-off-by: Brian Downing <bdowning@xxxxxxxxx> --- builtin-blame.c | 90 +++++++++++++++++++------------------------------------ 1 files changed, 31 insertions(+), 59 deletions(-) diff --git a/builtin-blame.c b/builtin-blame.c index e4d12de..60f70bf 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -19,6 +19,10 @@ #include "string-list.h" #include "mailmap.h" #include "parse-options.h" +#include "xdiff/xtypes.h" +#include "xdiff/xdiffi.h" +#include "xdiff/xemit.h" +#include "xdiff/xmacros.h" static char blame_usage[] = "git blame [options] [rev-opts] [rev] [--] file"; @@ -464,62 +468,36 @@ struct patch { int num; }; -struct blame_diff_state { - struct patch *ret; - unsigned hunk_post_context; - unsigned hunk_in_pre_context : 1; -}; - -static void process_u_diff(void *state_, char *line, unsigned long len) +static int process_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, + xdemitconf_t const *xecfg) { - struct blame_diff_state *state = state_; + struct patch *patch = ecb->priv; + long s1, s2; + xdchange_t *xch, *xche; struct chunk *chunk; - int off1, off2, len1, len2, num; - num = state->ret->num; - if (len < 4 || line[0] != '@' || line[1] != '@') { - if (state->hunk_in_pre_context && line[0] == ' ') - state->ret->chunks[num - 1].same++; - else { - state->hunk_in_pre_context = 0; - if (line[0] == ' ') - state->hunk_post_context++; - else - state->hunk_post_context = 0; - } - return; - } + for (xch = xche = xscr; xch; xch = xche->next) { + xche = xdl_get_hunk(xch, xecfg); - if (num && state->hunk_post_context) { - chunk = &state->ret->chunks[num - 1]; - chunk->p_next -= state->hunk_post_context; - chunk->t_next -= state->hunk_post_context; - } - state->ret->num = ++num; - state->ret->chunks = xrealloc(state->ret->chunks, - sizeof(struct chunk) * num); - chunk = &state->ret->chunks[num - 1]; - if (parse_hunk_header(line, len, &off1, &len1, &off2, &len2)) { - state->ret->num--; - return; - } - - /* Line numbers in patch output are one based. */ - off1--; - off2--; + s1 = XDL_MAX(xch->i1 - xecfg->ctxlen, 0); + s2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0); - chunk->same = len2 ? off2 : (off2 + 1); + ++patch->num; + patch->chunks = xrealloc(patch->chunks, + sizeof(struct chunk) * patch->num); + chunk = &patch->chunks[patch->num - 1]; + chunk->same = s2 + XDL_MAX(xch->i1 - s1, 0); + chunk->p_next = xche->i1 + xche->chg1; + chunk->t_next = xche->i2 + xche->chg2; + } - chunk->p_next = off1 + (len1 ? len1 : 1); - chunk->t_next = chunk->same + len2; - state->hunk_in_pre_context = 1; - state->hunk_post_context = 0; + return 0; } static struct patch *compare_buffer(mmfile_t *file_p, mmfile_t *file_o, int context) { - struct blame_diff_state state; + struct patch *patch; xpparam_t xpp; xdemitconf_t xecfg; xdemitcb_t ecb; @@ -527,20 +505,14 @@ static struct patch *compare_buffer(mmfile_t *file_p, mmfile_t *file_o, xpp.flags = xdl_opts; memset(&xecfg, 0, sizeof(xecfg)); xecfg.ctxlen = context; - memset(&state, 0, sizeof(state)); - state.ret = xmalloc(sizeof(struct patch)); - state.ret->chunks = NULL; - state.ret->num = 0; - - xdi_diff_outf(file_p, file_o, process_u_diff, &state, &xpp, &xecfg, &ecb); + patch = xmalloc(sizeof(struct patch)); + patch->chunks = NULL; + patch->num = 0; + xecfg.emit_func = (void (*)())process_diff; + ecb.priv = patch; + xdi_diff(file_p, file_o, &xpp, &xecfg, &ecb); - if (state.ret->num) { - struct chunk *chunk; - chunk = &state.ret->chunks[state.ret->num - 1]; - chunk->p_next -= state.hunk_post_context; - chunk->t_next -= state.hunk_post_context; - } - return state.ret; + return patch; } /* -- 1.5.6.1 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html