Skip to content

Commit 57fbd8e

Browse files
committed
Merge branch 'sb/histogram-less-memory'
"git diff --histogram" had a bad memory usage pattern, which has been rearranged to reduce the peak usage. * sb/histogram-less-memory: xdiff/histogram: remove tail recursion xdiff/xhistogram: move index allocation into find_lcs xdiff/xhistogram: factor out memory cleanup into free_index() xdiff/xhistogram: pass arguments directly to fall_back_to_classic_diff
2 parents 4bea848 + 79cb2eb commit 57fbd8e

File tree

1 file changed

+78
-55
lines changed

1 file changed

+78
-55
lines changed

xdiff/xhistogram.c

Lines changed: 78 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -233,54 +233,31 @@ static int try_lcs(struct histindex *index, struct region *lcs, int b_ptr,
233233
return b_next;
234234
}
235235

236-
static int find_lcs(struct histindex *index, struct region *lcs,
237-
int line1, int count1, int line2, int count2) {
238-
int b_ptr;
239-
240-
if (scanA(index, line1, count1))
241-
return -1;
242-
243-
index->cnt = index->max_chain_length + 1;
244-
245-
for (b_ptr = line2; b_ptr <= LINE_END(2); )
246-
b_ptr = try_lcs(index, lcs, b_ptr, line1, count1, line2, count2);
247-
248-
return index->has_common && index->max_chain_length < index->cnt;
249-
}
250-
251-
static int fall_back_to_classic_diff(struct histindex *index,
236+
static int fall_back_to_classic_diff(xpparam_t const *xpp, xdfenv_t *env,
252237
int line1, int count1, int line2, int count2)
253238
{
254-
xpparam_t xpp;
255-
xpp.flags = index->xpp->flags & ~XDF_DIFF_ALGORITHM_MASK;
239+
xpparam_t xpparam;
240+
xpparam.flags = xpp->flags & ~XDF_DIFF_ALGORITHM_MASK;
256241

257-
return xdl_fall_back_diff(index->env, &xpp,
242+
return xdl_fall_back_diff(env, &xpparam,
258243
line1, count1, line2, count2);
259244
}
260245

261-
static int histogram_diff(xpparam_t const *xpp, xdfenv_t *env,
262-
int line1, int count1, int line2, int count2)
246+
static inline void free_index(struct histindex *index)
263247
{
264-
struct histindex index;
265-
struct region lcs;
266-
int sz;
267-
int result = -1;
268-
269-
if (count1 <= 0 && count2 <= 0)
270-
return 0;
271-
272-
if (LINE_END(1) >= MAX_PTR)
273-
return -1;
248+
xdl_free(index->records);
249+
xdl_free(index->line_map);
250+
xdl_free(index->next_ptrs);
251+
xdl_cha_free(&index->rcha);
252+
}
274253

275-
if (!count1) {
276-
while(count2--)
277-
env->xdf2.rchg[line2++ - 1] = 1;
278-
return 0;
279-
} else if (!count2) {
280-
while(count1--)
281-
env->xdf1.rchg[line1++ - 1] = 1;
282-
return 0;
283-
}
254+
static int find_lcs(xpparam_t const *xpp, xdfenv_t *env,
255+
struct region *lcs,
256+
int line1, int count1, int line2, int count2)
257+
{
258+
int b_ptr;
259+
int sz, ret = -1;
260+
struct histindex index;
284261

285262
memset(&index, 0, sizeof(index));
286263

@@ -318,9 +295,55 @@ static int histogram_diff(xpparam_t const *xpp, xdfenv_t *env,
318295
index.ptr_shift = line1;
319296
index.max_chain_length = 64;
320297

298+
if (scanA(&index, line1, count1))
299+
goto cleanup;
300+
301+
index.cnt = index.max_chain_length + 1;
302+
303+
for (b_ptr = line2; b_ptr <= LINE_END(2); )
304+
b_ptr = try_lcs(&index, lcs, b_ptr, line1, count1, line2, count2);
305+
306+
if (index.has_common && index.max_chain_length < index.cnt)
307+
ret = 1;
308+
else
309+
ret = 0;
310+
311+
cleanup:
312+
free_index(&index);
313+
return ret;
314+
}
315+
316+
static int histogram_diff(xpparam_t const *xpp, xdfenv_t *env,
317+
int line1, int count1, int line2, int count2)
318+
{
319+
struct region lcs;
320+
int lcs_found;
321+
int result;
322+
redo:
323+
result = -1;
324+
325+
if (count1 <= 0 && count2 <= 0)
326+
return 0;
327+
328+
if (LINE_END(1) >= MAX_PTR)
329+
return -1;
330+
331+
if (!count1) {
332+
while(count2--)
333+
env->xdf2.rchg[line2++ - 1] = 1;
334+
return 0;
335+
} else if (!count2) {
336+
while(count1--)
337+
env->xdf1.rchg[line1++ - 1] = 1;
338+
return 0;
339+
}
340+
321341
memset(&lcs, 0, sizeof(lcs));
322-
if (find_lcs(&index, &lcs, line1, count1, line2, count2))
323-
result = fall_back_to_classic_diff(&index, line1, count1, line2, count2);
342+
lcs_found = find_lcs(xpp, env, &lcs, line1, count1, line2, count2);
343+
if (lcs_found < 0)
344+
goto out;
345+
else if (lcs_found)
346+
result = fall_back_to_classic_diff(xpp, env, line1, count1, line2, count2);
324347
else {
325348
if (lcs.begin1 == 0 && lcs.begin2 == 0) {
326349
while (count1--)
@@ -333,21 +356,21 @@ static int histogram_diff(xpparam_t const *xpp, xdfenv_t *env,
333356
line1, lcs.begin1 - line1,
334357
line2, lcs.begin2 - line2);
335358
if (result)
336-
goto cleanup;
337-
result = histogram_diff(xpp, env,
338-
lcs.end1 + 1, LINE_END(1) - lcs.end1,
339-
lcs.end2 + 1, LINE_END(2) - lcs.end2);
340-
if (result)
341-
goto cleanup;
359+
goto out;
360+
/*
361+
* result = histogram_diff(xpp, env,
362+
* lcs.end1 + 1, LINE_END(1) - lcs.end1,
363+
* lcs.end2 + 1, LINE_END(2) - lcs.end2);
364+
* but let's optimize tail recursion ourself:
365+
*/
366+
count1 = LINE_END(1) - lcs.end1;
367+
line1 = lcs.end1 + 1;
368+
count2 = LINE_END(2) - lcs.end2;
369+
line2 = lcs.end2 + 1;
370+
goto redo;
342371
}
343372
}
344-
345-
cleanup:
346-
xdl_free(index.records);
347-
xdl_free(index.line_map);
348-
xdl_free(index.next_ptrs);
349-
xdl_cha_free(&index.rcha);
350-
373+
out:
351374
return result;
352375
}
353376

0 commit comments

Comments
 (0)