git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 0/7] Optimization batch 14: trivial directory resolution

From
Elijah Newren via GitGitGadget <gitgitgadget@gmail.com>
Date
Jul 13, 2021, 19:32 UTC
Message-ID
<pull.988.v2.git.1626204784.gitgitgadget@gmail.com>
In-Reply-To
<pull.988.git.1625111177.gitgitgadget@gmail.com>

[This is mostly unchanged since v1; I'm primarily resending since it's been two weeks and I want to bump it so folks have a chance to notice and review it. But there was one change, noted below.]

This series depends textually on ort-perf-batch-12, but is semantically independent. (It is both semantically and textually independent of ort-perf-batch-13.)

Most of my previous series dramatically accelerated cases with lots of renames, while providing comparatively minor benefits for cases with few or no renames. This series is the opposite; it provides huge benefits when there are few or no renames, and comparatively smaller (though still quite decent) benefits for cases with many uncached renames.

Changes since v1:
 * Minor tweak to the final patch to correct implicit assumption that rename
   detection running implies all renames were found (rename limits could
   have been exceeded and prevented finding renames)
=== Basic Optimization idea ===

unpack_trees has had a concept of trivial merges for individual files (see Documentation/technical/trivial-merge.txt). The same idea can be applied in merge-ort. It'd be really nice to extend that idea to trees as well, as it could provide a huge performance boost; sadly however, applying it in general would wreck both regular rename detection (the unmatched side can have new files that serve as potential destinations in rename detection) and directory rename detection (the unmatched side could have a new directory that was moved into it).

If we somehow knew rename detection wasn't needed, we could do trivial directory resolution. In the past, this wasn't possible. However...

With recent optimizations we have created a possibility to do trivial directory resolutions in some cases. These came from the addition of the "skipping irrelevant renames" optimizations (from ort-perf-batch-9 and ort-perf-batch-10), and in particular noting that we added an ability to entirely skip rename detection in commit f89b4f2bee ("merge-ort: skip rename detection entirely if possible", 2021-03-11) when there are no relevant sources. We can detect if there are no relevant sources without recursing into the directories in question.

As a cherry on top, the caching of renames (from ort-perf-batch-11) allows us to cover additional cases.

This series is all about adding all the special checks needed to safely perform trival directory resolutions.

=== Results ===

For the testcases mentioned in commit 557ac0350d ("merge-ort: begin performance work; instrument with trace2_region_* calls", 2020-10-28), the changes in just this series improves the performance as follows:

                     Before Series           After Series
no-renames:        5.235 s ±  0.042 s   204.2  ms ±  3.0  ms
mega-renames:      9.419 s ±  0.107 s     1.076 s ±  0.015 s
just-one-mega:   480.1  ms ±  3.9  ms   364.1  ms ±  7.0  ms

As a reminder, before any merge-ort/diffcore-rename performance work, the performance results we started with (for merge-recursive as of git-2.30.0) were:

no-renames-am: 6.940 s ± 0.485 s no-renames: 18.912 s ± 0.174 s mega-renames: 5964.031 s ± 10.459 s just-one-mega: 149.583 s ± 0.751 s

Elijah Newren (7):
  merge-ort: resolve paths early when we have sufficient information
  merge-ort: add some more explanations in collect_merge_info_callback()
  merge-ort: add data structures for allowable trivial directory
    resolves
  merge-ort: add a handle_deferred_entries() helper function
  merge-ort: defer recursing into directories when merge base is matched
  merge-ort: avoid recursing into directories when we don't need to
  merge-ort: restart merge with cached renames to reduce process entry
    cost
 merge-ort.c                         | 408 +++++++++++++++++++++++++++-
 t/t6423-merge-rename-directories.sh |   2 +-
 2 files changed, 398 insertions(+), 12 deletions(-)
base-commit: 2eeee12b02e441ac05054a5a5ecbcea6964a1e6b
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-988%2Fnewren%2Fort-perf-batch-14-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-988/newren/ort-perf-batch-14-v2
Pull-Request: https://github.com/gitgitgadget/git/pull/988
Range-diff vs v1:
 1:  5dca982c0b = 1:  5dca982c0b merge-ort: resolve paths early when we have sufficient information
 2:  8aea371390 = 2:  8aea371390 merge-ort: add some more explanations in collect_merge_info_callback()
 3:  f7ac01055d = 3:  f7ac01055d merge-ort: add data structures for allowable trivial directory resolves
 4:  7e28323b62 = 4:  7e28323b62 merge-ort: add a handle_deferred_entries() helper function
 5:  317553eadb = 5:  317553eadb merge-ort: defer recursing into directories when merge base is matched
 6:  3409a6cd63 = 6:  3409a6cd63 merge-ort: avoid recursing into directories when we don't need to
 7:  76bc73262c ! 7:  7133f0efa5 merge-ort: restart merge with cached renames to reduce process entry cost
     @@ merge-ort.c: static void detect_regular_renames(struct merge_options *opt,
       	}
       
       	partial_clear_dir_rename_count(&renames->dir_rename_count[side_index]);
     +@@ merge-ort.c: static void detect_regular_renames(struct merge_options *opt,
     + 	trace2_region_leave("diff", "diffcore_rename", opt->repo);
     + 	resolve_diffpair_statuses(&diff_queued_diff);
     + 
     ++	if (diff_opts.needed_rename_limit > 0)
     ++		renames->redo_after_renames = 0;
     + 	if (diff_opts.needed_rename_limit > renames->needed_limit)
     + 		renames->needed_limit = diff_opts.needed_rename_limit;
     + 
      @@ merge-ort.c: static void detect_regular_renames(struct merge_options *opt,
       	diff_queued_diff.nr = 0;
       	diff_queued_diff.queue = NULL;
       	diff_flush(&diff_opts);
      +
     -+	if (renames->redo_after_renames) {
     -+		int i;
     -+		struct diff_filepair *p;
     -+
     -+		renames->redo_after_renames = 2;
     -+		for (i = 0; i < renames->pairs[side_index].nr; ++i) {
     -+			p = renames->pairs[side_index].queue[i];
     -+			possibly_cache_new_pair(renames, p, side_index, NULL);
     -+		}
     -+	}
      +	return 1;
       }
       
     @@ merge-ort.c: static int detect_and_process_renames(struct merge_options *opt,
      +	detection_run |= detect_regular_renames(opt, MERGE_SIDE1);
      +	detection_run |= detect_regular_renames(opt, MERGE_SIDE2);
      +	if (renames->redo_after_renames && detection_run) {
     ++		int i, side;
     ++		struct diff_filepair *p;
     ++
     ++		/* Cache the renames, we found */
     ++		for (side = MERGE_SIDE1; side <= MERGE_SIDE2; side++) {
     ++			for (i = 0; i < renames->pairs[side].nr; ++i) {
     ++				p = renames->pairs[side].queue[i];
     ++				possibly_cache_new_pair(renames, p, side, NULL);
     ++			}
     ++		}
     ++
     ++		/* Restart the merge with the cached renames */
     ++		renames->redo_after_renames = 2;
      +		trace2_region_leave("merge", "regular renames", opt->repo);
      +		goto cleanup;
      +	}
-- 
gitgitgadget
Previous: Elijah NewrenNext: Elijah Newren via GitGitGadget
Message 12 of 52 in “Optimization batch 14: trivial directory resolution”
  1. 0/7 Optimization batch 14: trivial directory resolutionElijah Newren via GitGitGadget, Jul 1, 2021
  2. 2/7 merge-ort: add some more explanations in collect_merge_info_callback()Elijah Newren via GitGitGadget, Jul 1, 2021
  3. 1/7 merge-ort: resolve paths early when we have sufficient informationElijah Newren via GitGitGadget, Jul 1, 2021
  4. 5/7 merge-ort: defer recursing into directories when merge base is matchedElijah Newren via GitGitGadget, Jul 1, 2021
  5. 4/7 merge-ort: add a handle_deferred_entries() helper functionElijah Newren via GitGitGadget, Jul 1, 2021
  6. 3/7 merge-ort: add data structures for allowable trivial directory resolvesElijah Newren via GitGitGadget, Jul 1, 2021
  7. 6/7 merge-ort: avoid recursing into directories when we don't need toElijah Newren via GitGitGadget, Jul 1, 2021
  8. 7/7 merge-ort: restart merge with cached renames to reduce process entry costElijah Newren via GitGitGadget, Jul 1, 2021
  9. Ævar Arnfjörð BjarmasonJul 1, 2021
  10. Elijah NewrenJul 1, 2021
  11. Elijah NewrenJul 1, 2021
  12. 0/7 Optimization batch 14: trivial directory resolutionElijah Newren via GitGitGadget, Jul 13, 2021
  13. 1/7 merge-ort: resolve paths early when we have sufficient informationElijah Newren via GitGitGadget, Jul 13, 2021
  14. 2/7 merge-ort: add some more explanations in collect_merge_info_callback()Elijah Newren via GitGitGadget, Jul 13, 2021
  15. Bagas SanjayaJul 13, 2021
  16. Elijah NewrenJul 14, 2021
  17. 3/7 merge-ort: add data structures for allowable trivial directory resolvesElijah Newren via GitGitGadget, Jul 13, 2021
  18. Derrick StoleeJul 15, 2021
  19. Elijah NewrenJul 15, 2021
  20. 7/7 merge-ort: restart merge with cached renames to reduce process entry costElijah Newren via GitGitGadget, Jul 13, 2021
  21. Derrick StoleeJul 15, 2021
  22. Elijah NewrenJul 15, 2021
  23. Derrick StoleeJul 15, 2021
  24. Elijah NewrenJul 15, 2021
  25. 4/7 merge-ort: add a handle_deferred_entries() helper functionElijah Newren via GitGitGadget, Jul 13, 2021
  26. Derrick StoleeJul 15, 2021
  27. Elijah NewrenJul 15, 2021
  28. 5/7 merge-ort: defer recursing into directories when merge base is matchedElijah Newren via GitGitGadget, Jul 13, 2021
  29. Derrick StoleeJul 15, 2021
  30. Elijah NewrenJul 15, 2021
  31. Derrick StoleeJul 15, 2021
  32. 6/7 merge-ort: avoid recursing into directories when we don't need toElijah Newren via GitGitGadget, Jul 13, 2021
  33. Derrick StoleeJul 15, 2021
  34. Elijah NewrenJul 15, 2021
  35. 0/7 Optimization batch 14: trivial directory resolutionElijah Newren via GitGitGadget, Jul 16, 2021
  36. 1/7 merge-ort: resolve paths early when we have sufficient informationElijah Newren via GitGitGadget, Jul 16, 2021
  37. 2/7 merge-ort: add some more explanations in collect_merge_info_callback()Elijah Newren via GitGitGadget, Jul 16, 2021
  38. 4/7 merge-ort: add a handle_deferred_entries() helper functionElijah Newren via GitGitGadget, Jul 16, 2021
  39. 3/7 merge-ort: add data structures for allowable trivial directory resolvesElijah Newren via GitGitGadget, Jul 16, 2021
  40. 5/7 merge-ort: defer recursing into directories when merge base is matchedElijah Newren via GitGitGadget, Jul 16, 2021
  41. 6/7 merge-ort: avoid recursing into directories when we don't need toElijah Newren via GitGitGadget, Jul 16, 2021
  42. 7/7 merge-ort: restart merge with cached renames to reduce process entry costElijah Newren via GitGitGadget, Jul 16, 2021
  43. Derrick StoleeJul 20, 2021
  44. Junio C HamanoJul 20, 2021
  45. 0/7 Optimization batch 14: trivial directory resolutionElijah Newren via GitGitGadget, Jul 21, 2021
  46. 1/7 merge-ort: resolve paths early when we have sufficient informationElijah Newren via GitGitGadget, Jul 21, 2021
  47. 2/7 merge-ort: add some more explanations in collect_merge_info_callback()Elijah Newren via GitGitGadget, Jul 21, 2021
  48. 3/7 merge-ort: add data structures for allowable trivial directory resolvesElijah Newren via GitGitGadget, Jul 21, 2021
  49. 4/7 merge-ort: add a handle_deferred_entries() helper functionElijah Newren via GitGitGadget, Jul 21, 2021
  50. 5/7 merge-ort: defer recursing into directories when merge base is matchedElijah Newren via GitGitGadget, Jul 21, 2021
  51. 6/7 merge-ort: avoid recursing into directories when we don't need toElijah Newren via GitGitGadget, Jul 21, 2021
  52. 7/7 merge-ort: restart merge with cached renames to reduce process entry costElijah Newren via GitGitGadget, Jul 21, 2021

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.