Skip to content

Commit f78cf97

Browse files
newrengitster
authored andcommitted
merge-ort: call diffcore_rename() directly
We want to pass additional information to diffcore_rename() (or some variant thereof) without plumbing that extra information through diff_tree_oid() and diffcore_std(). Further, since we will need to gather additional special information related to diffs and are walking the trees anyway in collect_merge_info(), it seems odd to have diff_tree_oid()/diffcore_std() repeat those tree walks. And there may be times where we can avoid traversing into a subtree in collect_merge_info() (based on additional information at our disposal), that the basic diff logic would be unable to take advantage of. For all these reasons, just create the add and delete pairs ourself and then call diffcore_rename() directly. This change is primarily about enabling future optimizations; the advantage of avoiding extra tree traversals is small compared to the cost of rename detection, and the advantage of avoiding the extra tree traversals is somewhat offset by the extra time spent in collect_merge_info() collecting the additional data anyway. However... For the testcases mentioned in commit 557ac03 ("merge-ort: begin performance work; instrument with trace2_region_* calls", 2020-10-28), this change improves the performance as follows: Before After no-renames: 13.294 s ± 0.103 s 12.775 s ± 0.062 s mega-renames: 187.248 s ± 0.882 s 188.754 s ± 0.284 s just-one-mega: 5.557 s ± 0.017 s 5.599 s ± 0.019 s Signed-off-by: Elijah Newren <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 07c9a7f commit f78cf97

File tree

1 file changed

+59
-7
lines changed

1 file changed

+59
-7
lines changed

merge-ort.c

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,23 @@ static void setup_path_info(struct merge_options *opt,
535535
result->util = mi;
536536
}
537537

538+
static void add_pair(struct merge_options *opt,
539+
struct name_entry *names,
540+
const char *pathname,
541+
unsigned side,
542+
unsigned is_add /* if false, is_delete */)
543+
{
544+
struct diff_filespec *one, *two;
545+
struct rename_info *renames = &opt->priv->renames;
546+
int names_idx = is_add ? side : 0;
547+
548+
one = alloc_filespec(pathname);
549+
two = alloc_filespec(pathname);
550+
fill_filespec(is_add ? two : one,
551+
&names[names_idx].oid, 1, names[names_idx].mode);
552+
diff_queue(&renames->pairs[side], one, two);
553+
}
554+
538555
static void collect_rename_info(struct merge_options *opt,
539556
struct name_entry *names,
540557
const char *dirname,
@@ -544,6 +561,7 @@ static void collect_rename_info(struct merge_options *opt,
544561
unsigned match_mask)
545562
{
546563
struct rename_info *renames = &opt->priv->renames;
564+
unsigned side;
547565

548566
/* Update dirs_removed, as needed */
549567
if (dirmask == 1 || dirmask == 3 || dirmask == 5) {
@@ -554,6 +572,21 @@ static void collect_rename_info(struct merge_options *opt,
554572
if (sides & 2)
555573
strset_add(&renames->dirs_removed[2], fullname);
556574
}
575+
576+
if (filemask == 0 || filemask == 7)
577+
return;
578+
579+
for (side = MERGE_SIDE1; side <= MERGE_SIDE2; ++side) {
580+
unsigned side_mask = (1 << side);
581+
582+
/* Check for deletion on side */
583+
if ((filemask & 1) && !(filemask & side_mask))
584+
add_pair(opt, names, fullname, side, 0 /* delete */);
585+
586+
/* Check for addition on side */
587+
if (!(filemask & 1) && (filemask & side_mask))
588+
add_pair(opt, names, fullname, side, 1 /* add */);
589+
}
557590
}
558591

559592
static int collect_merge_info_callback(int n,
@@ -2079,6 +2112,27 @@ static int process_renames(struct merge_options *opt,
20792112
return clean_merge;
20802113
}
20812114

2115+
static void resolve_diffpair_statuses(struct diff_queue_struct *q)
2116+
{
2117+
/*
2118+
* A simplified version of diff_resolve_rename_copy(); would probably
2119+
* just use that function but it's static...
2120+
*/
2121+
int i;
2122+
struct diff_filepair *p;
2123+
2124+
for (i = 0; i < q->nr; ++i) {
2125+
p = q->queue[i];
2126+
p->status = 0; /* undecided */
2127+
if (!DIFF_FILE_VALID(p->one))
2128+
p->status = DIFF_STATUS_ADDED;
2129+
else if (!DIFF_FILE_VALID(p->two))
2130+
p->status = DIFF_STATUS_DELETED;
2131+
else if (DIFF_PAIR_RENAME(p))
2132+
p->status = DIFF_STATUS_RENAMED;
2133+
}
2134+
}
2135+
20822136
static int compare_pairs(const void *a_, const void *b_)
20832137
{
20842138
const struct diff_filepair *a = *((const struct diff_filepair **)a_);
@@ -2089,8 +2143,6 @@ static int compare_pairs(const void *a_, const void *b_)
20892143

20902144
/* Call diffcore_rename() to compute which files have changed on given side */
20912145
static void detect_regular_renames(struct merge_options *opt,
2092-
struct tree *merge_base,
2093-
struct tree *side,
20942146
unsigned side_index)
20952147
{
20962148
struct diff_options diff_opts;
@@ -2108,11 +2160,11 @@ static void detect_regular_renames(struct merge_options *opt,
21082160
diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
21092161
diff_setup_done(&diff_opts);
21102162

2163+
diff_queued_diff = renames->pairs[side_index];
21112164
trace2_region_enter("diff", "diffcore_rename", opt->repo);
2112-
diff_tree_oid(&merge_base->object.oid, &side->object.oid, "",
2113-
&diff_opts);
2114-
diffcore_std(&diff_opts);
2165+
diffcore_rename(&diff_opts);
21152166
trace2_region_leave("diff", "diffcore_rename", opt->repo);
2167+
resolve_diffpair_statuses(&diff_queued_diff);
21162168

21172169
if (diff_opts.needed_rename_limit > renames->needed_limit)
21182170
renames->needed_limit = diff_opts.needed_rename_limit;
@@ -2212,8 +2264,8 @@ static int detect_and_process_renames(struct merge_options *opt,
22122264
memset(&combined, 0, sizeof(combined));
22132265

22142266
trace2_region_enter("merge", "regular renames", opt->repo);
2215-
detect_regular_renames(opt, merge_base, side1, MERGE_SIDE1);
2216-
detect_regular_renames(opt, merge_base, side2, MERGE_SIDE2);
2267+
detect_regular_renames(opt, MERGE_SIDE1);
2268+
detect_regular_renames(opt, MERGE_SIDE2);
22172269
trace2_region_leave("merge", "regular renames", opt->repo);
22182270

22192271
trace2_region_enter("merge", "directory renames", opt->repo);

0 commit comments

Comments
 (0)