xdiff/xprepare: improve O(n*m) performance in xdl_cleanup_records()

In xdl_cleanup_records(), we see O(n*m) performance, where n is the number of records from xdf->dstart to xdf->dend, and m is the size of a bucket in xdf->rhash (<= by mlim). Here, we improve this to O(n) by pre-computing nm (in rcrec->len(1|2)) in xdl_classify_record(). Reported-by: Marat Radchenko <marat@slonopotamus.org> Signed-off-by: Tay Ray Chuan <rctay89@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Tay Ray Chuan committed Aug 17, 2011 at 09:53 UTC 27af01d552331eacf1ed2671b2b4b6ad4c268106
1 file changed +50 -36
xdiff/xprepare.c
+50 -36
@@ -34,6 +34,7 @@ typedef struct s_xdlclass {
34 char const *line;
35 long size;
36 long idx;
37 + long len1, len2;
38 } xdlclass_t;
39
40 typedef struct s_xdlclassifier {
@@ -41,6 +42,8 @@ typedef struct s_xdlclassifier {
42 long hsize;
43 xdlclass_t **rchash;
44 chastore_t ncha;
45 + xdlclass_t **rcrecs;
46 + long alloc;
47 long count;
48 long flags;
49 } xdlclassifier_t;
@@ -50,15 +53,15 @@ typedef struct s_xdlclassifier {
53
54 static int xdl_init_classifier(xdlclassifier_t *cf, long size, long flags);
55 static void xdl_free_classifier(xdlclassifier_t *cf);
53 -static int xdl_classify_record(xdlclassifier_t *cf, xrecord_t **rhash, unsigned int hbits,
54 - xrecord_t *rec);
55 -static int xdl_prepare_ctx(mmfile_t *mf, long narec, xpparam_t const *xpp,
56 +static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t **rhash,
57 + unsigned int hbits, xrecord_t *rec);
58 +static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_t const *xpp,
59 xdlclassifier_t *cf, xdfile_t *xdf);
60 static void xdl_free_ctx(xdfile_t *xdf);
61 static int xdl_clean_mmatch(char const *dis, long i, long s, long e);
59 -static int xdl_cleanup_records(xdfile_t *xdf1, xdfile_t *xdf2);
62 +static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2);
63 static int xdl_trim_ends(xdfile_t *xdf1, xdfile_t *xdf2);
61 -static int xdl_optimize_ctxs(xdfile_t *xdf1, xdfile_t *xdf2);
64 +static int xdl_optimize_ctxs(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2);
65
66
67
@@ -83,6 +86,14 @@ static int xdl_init_classifier(xdlclassifier_t *cf, long size, long flags) {
86 for (i = 0; i < cf->hsize; i++)
87 cf->rchash[i] = NULL;
88
89 + cf->alloc = size;
90 + if (!(cf->rcrecs = (xdlclass_t **) xdl_malloc(cf->alloc * sizeof(xdlclass_t *)))) {
91 +
92 + xdl_free(cf->rchash);
93 + xdl_cha_free(&cf->ncha);
94 + return -1;
95 + }
96 +
97 cf->count = 0;
98
99 return 0;
@@ -91,16 +102,18 @@ static int xdl_init_classifier(xdlclassifier_t *cf, long size, long flags) {
102
103 static void xdl_free_classifier(xdlclassifier_t *cf) {
104
105 + xdl_free(cf->rcrecs);
106 xdl_free(cf->rchash);
107 xdl_cha_free(&cf->ncha);
108 }
109
110
99 -static int xdl_classify_record(xdlclassifier_t *cf, xrecord_t **rhash, unsigned int hbits,
100 - xrecord_t *rec) {
111 +static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t **rhash,
112 + unsigned int hbits, xrecord_t *rec) {
113 long hi;
114 char const *line;
115 xdlclass_t *rcrec;
116 + xdlclass_t **rcrecs;
117
118 line = rec->ptr;
119 hi = (long) XDL_HASHLONG(rec->ha, cf->hbits);
@@ -116,13 +129,25 @@ static int xdl_classify_record(xdlclassifier_t *cf, xrecord_t **rhash, unsigned
129 return -1;
130 }
131 rcrec->idx = cf->count++;
132 + if (cf->count > cf->alloc) {
133 + cf->alloc *= 2;
134 + if (!(rcrecs = (xdlclass_t **) xdl_realloc(cf->rcrecs, cf->alloc * sizeof(xdlclass_t *)))) {
135 +
136 + return -1;
137 + }
138 + cf->rcrecs = rcrecs;
139 + }
140 + cf->rcrecs[rcrec->idx] = rcrec;
141 rcrec->line = line;
142 rcrec->size = rec->size;
143 rcrec->ha = rec->ha;
144 + rcrec->len1 = rcrec->len2 = 0;
145 rcrec->next = cf->rchash[hi];
146 cf->rchash[hi] = rcrec;
147 }
148
149 + (pass == 1) ? rcrec->len1++ : rcrec->len2++;
150 +
151 rec->ha = (unsigned long) rcrec->idx;
152
153 hi = (long) XDL_HASHLONG(rec->ha, hbits);
@@ -133,7 +158,7 @@ static int xdl_classify_record(xdlclassifier_t *cf, xrecord_t **rhash, unsigned
158 }
159
160
136 -static int xdl_prepare_ctx(mmfile_t *mf, long narec, xpparam_t const *xpp,
161 +static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_t const *xpp,
162 xdlclassifier_t *cf, xdfile_t *xdf) {
163 unsigned int hbits;
164 long i, nrec, hsize, bsize;
@@ -200,7 +225,7 @@ static int xdl_prepare_ctx(mmfile_t *mf, long narec, xpparam_t const *xpp,
225 crec->ha = hav;
226 recs[nrec++] = crec;
227
203 - if (xdl_classify_record(cf, rhash, hbits, crec) < 0) {
228 + if (xdl_classify_record(pass, cf, rhash, hbits, crec) < 0) {
229
230 xdl_free(rhash);
231 xdl_free(recs);
@@ -276,28 +301,28 @@ int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
301 return -1;
302 }
303
279 - if (xdl_prepare_ctx(mf1, enl1, xpp, &cf, &xe->xdf1) < 0) {
304 + if (xdl_prepare_ctx(1, mf1, enl1, xpp, &cf, &xe->xdf1) < 0) {
305
306 xdl_free_classifier(&cf);
307 return -1;
308 }
284 - if (xdl_prepare_ctx(mf2, enl2, xpp, &cf, &xe->xdf2) < 0) {
309 + if (xdl_prepare_ctx(2, mf2, enl2, xpp, &cf, &xe->xdf2) < 0) {
310
311 xdl_free_ctx(&xe->xdf1);
312 xdl_free_classifier(&cf);
313 return -1;
314 }
315
291 - xdl_free_classifier(&cf);
292 -
316 if (!(xpp->flags & XDF_PATIENCE_DIFF) &&
294 - xdl_optimize_ctxs(&xe->xdf1, &xe->xdf2) < 0) {
317 + xdl_optimize_ctxs(&cf, &xe->xdf1, &xe->xdf2) < 0) {
318
319 xdl_free_ctx(&xe->xdf2);
320 xdl_free_ctx(&xe->xdf1);
321 return -1;
322 }
323
324 + xdl_free_classifier(&cf);
325 +
326 return 0;
327 }
328
@@ -372,11 +397,10 @@ static int xdl_clean_mmatch(char const *dis, long i, long s, long e) {
397 * matches on the other file. Also, lines that have multiple matches
398 * might be potentially discarded if they happear in a run of discardable.
399 */
375 -static int xdl_cleanup_records(xdfile_t *xdf1, xdfile_t *xdf2) {
376 - long i, nm, rhi, nreff, mlim;
377 - unsigned long hav;
400 +static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2) {
401 + long i, nm, nreff;
402 xrecord_t **recs;
379 - xrecord_t *rec;
403 + xdlclass_t *rcrec;
404 char *dis, *dis1, *dis2;
405
406 if (!(dis = (char *) xdl_malloc(xdf1->nrec + xdf2->nrec + 2))) {
@@ -387,26 +411,16 @@ static int xdl_cleanup_records(xdfile_t *xdf1, xdfile_t *xdf2) {
411 dis1 = dis;
412 dis2 = dis1 + xdf1->nrec + 1;
413
390 - if ((mlim = xdl_bogosqrt(xdf1->nrec)) > XDL_MAX_EQLIMIT)
391 - mlim = XDL_MAX_EQLIMIT;
414 for (i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart]; i <= xdf1->dend; i++, recs++) {
393 - hav = (*recs)->ha;
394 - rhi = (long) XDL_HASHLONG(hav, xdf2->hbits);
395 - for (nm = 0, rec = xdf2->rhash[rhi]; rec; rec = rec->next)
396 - if (rec->ha == hav && ++nm == mlim)
397 - break;
398 - dis1[i] = (nm == 0) ? 0: (nm >= mlim) ? 2: 1;
415 + rcrec = cf->rcrecs[(*recs)->ha];
416 + nm = rcrec ? rcrec->len2 : 0;
417 + dis1[i] = (nm == 0) ? 0: 1;
418 }
419
401 - if ((mlim = xdl_bogosqrt(xdf2->nrec)) > XDL_MAX_EQLIMIT)
402 - mlim = XDL_MAX_EQLIMIT;
420 for (i = xdf2->dstart, recs = &xdf2->recs[xdf2->dstart]; i <= xdf2->dend; i++, recs++) {
404 - hav = (*recs)->ha;
405 - rhi = (long) XDL_HASHLONG(hav, xdf1->hbits);
406 - for (nm = 0, rec = xdf1->rhash[rhi]; rec; rec = rec->next)
407 - if (rec->ha == hav && ++nm == mlim)
408 - break;
409 - dis2[i] = (nm == 0) ? 0: (nm >= mlim) ? 2: 1;
421 + rcrec = cf->rcrecs[(*recs)->ha];
422 + nm = rcrec ? rcrec->len1 : 0;
423 + dis2[i] = (nm == 0) ? 0: 1;
424 }
425
426 for (nreff = 0, i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart];
@@ -468,10 +482,10 @@ static int xdl_trim_ends(xdfile_t *xdf1, xdfile_t *xdf2) {
482 }
483
484
471 -static int xdl_optimize_ctxs(xdfile_t *xdf1, xdfile_t *xdf2) {
485 +static int xdl_optimize_ctxs(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2) {
486
487 if (xdl_trim_ends(xdf1, xdf2) < 0 ||
474 - xdl_cleanup_records(xdf1, xdf2) < 0) {
488 + xdl_cleanup_records(cf, xdf1, xdf2) < 0) {
489
490 return -1;
491 }