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

Re: [PATCH 0/2] Reinstate the helpful message when `git pull --rebase` fails

From
Junio C Hamano <gitster@pobox.com>
Date
Oct 12, 2015, 20:28 UTC
Message-ID
<xmqqio6bltkq.fsf@gitster.mtv.corp.google.com>
In-Reply-To
<ed70803ecd73415f1bbafb68502fbbda@dscho.org>
Johannes Schindelin <johannes.schindelin@gmx.de> writes:
Show 13 quoted lines
>> I think the most sensible regression fix as the first step at this
>> point is to call it as a separate process, just like the code calls
>> "apply" as a separate process for each patch.  Optimization can come
>> later when it is shown that it matters---we need to regain
>> correctness first.
>
> I fear that you might underestimate the finality of this "first
> step". If you reintroduce that separate process, not only is it a
> performance regression, but could we really realistically expect any
> further steps to happen after that? I do not think so.
> ...
> For the above reasons, I respectfully remain convinced that
> reintroducing the separate process would be a mistake.
I am not saying we should forever do run_command() going forward.

But I do not want to keep the direct call to merge_recursive() in 'maint'. The topic was supposed to be "rewrite in C". I do not recall (and do not feel the need to read "git log" output to find out) exactly how the series progressed, but a logical progression would have been to run merge-recursive via run_command() like I showed in the quick-fix in an early part of the series, followed by a patch to turn it into a direct call to merge_recursive() as an optimization change.

And the latter step turned out to be a regression caused by a premature optimization. If something introduces a regression, it gets reverted. As the scripted version certainly did not make an internal call, we should just run_command(). And that is what we want to have in the stable version people use every day.

The only thing I am saying is that the change to make a direct call should come on top of the run_command() version with its own justification as an optimization patch.

Going that route may require you to redo your patch, measure performance improvements, ensure there is no unintended fallout in other callers and longer term maintainability of the codebaths involved, write a good log message, etc. And such a fix to merge_recursive() needs to be cooked sufficiently in 'pu' and 'next'. And I view all that as a good thing. I really hate to see that this premature optimization to come back and bite us again---we didn't see it while reviewing because "builtin-am: implement --3way" was done in a single step with premature optimization from the beginning.

Now, there are many reasons why the "first step" might turn out to be the permanent optimal solution.

I did an unscientific experiment to rebase each of the 25 topics that are cooking in 'next' on top of 'master'. Only 3 of them will fall back to the three-way merge machinery. One possible reason why the "first step" could stay a good-enough solution is that people would not care and/or notice, because it is not like you are paying unnecessary cost to spawn merge-recursive for each and every change. It only kicks in when the patch does not apply.

Then I randomly picked one (jc/merge-drop-old-syntax) of the three topics that does fall back, made it into a patch and ran "am -3" on top of 'master' with and without the "first step". The numbers from 5 runs of each look like this:

    real    0m0.109s                      real    0m0.109s
    user    0m0.080s                      user    0m0.079s
    sys     0m0.034s                      sys     0m0.035s
    real    0m0.109s                      real    0m0.105s
    user    0m0.095s                      user    0m0.087s
    sys     0m0.018s                      sys     0m0.022s
    real    0m0.109s                      real    0m0.110s
    user    0m0.075s                      user    0m0.086s
    sys     0m0.038s                      sys     0m0.028s
    real    0m0.107s                      real    0m0.108s
    user    0m0.083s                      user    0m0.075s
    sys     0m0.029s                      sys     0m0.038s
    real    0m0.106s                      real    0m0.108s
    user    0m0.086s                      user    0m0.090s
    sys     0m0.025s                      sys     0m0.023s

I am curious to see a similar number on platforms with slower run_command(). From the above numbers alone, I cannot even see which ones are with run_command(), even though I know the numbers on the right hand side column were taken with run_command() and the numbers on the left hand side column were taken with internal call.

Another possible reason why the "first step" could stay a good-enough solution is that merge_recursive() in itself is a heavy-weight operation that the cost of spawning a process is not even felt [*1*]. After all, it's not like we are talking about spawning the cost of "update-ref HEAD" dominating the cost of the actual operation.

By the way, in order to make sure that I am running the correct binary, I did "strace -f -e execve" on "am -3". "mailsplit" and "mailinfo", both of which are a lot more likely to be affected by the cost of spawning because they are mostly dumb and straight text-to-text filters, are spawned via run_command() interface. And then we do "apply --index" (which is always done), and after seeing that fail, we do "apply --build-fake-ancestor" and "apply --cached" before finally spawning merge-recursive (or making a direct call internally before the "quick-fix") when we fall back to threeway.

Among the run_commands() invocations in the "am -3", I do not think the one that spawns "merge-recursive" is the most profitable one to turn into an internal call. Libifying mailsplit and/or mailinfo and making them directly callable may be a lot more useful thing to do if you want to avoid run_command().

[Footnote]

*1* That is what I am seeing here, but this _is_ platform dependent and that is why I said I am curious.

Previous: Johannes SchindelinNext: Johannes Schindelin
Message 21 of 22 in “Reinstate the helpful message when `git pull --rebase` fails”
  1. 0/2 Reinstate the helpful message when `git pull --rebase` failsJohannes Schindelin, Oct 8, 2015
  2. 1/2 merge_recursive_options: introduce the "gentle" flagJohannes Schindelin, Oct 8, 2015
  3. 2/2 pull --rebase: reinstate helpful message on abortJohannes Schindelin, Oct 8, 2015
  4. Junio C HamanoOct 9, 2015
  5. Johannes SchindelinOct 12, 2015
  6. Junio C HamanoOct 12, 2015
  7. Junio C HamanoOct 9, 2015
  8. Paul TanOct 9, 2015
  9. Johannes SchindelinOct 9, 2015
  10. Johannes SchindelinOct 9, 2015
  11. Junio C HamanoOct 9, 2015
  12. Torsten BögershausenOct 10, 2015
  13. Torsten BögershausenOct 10, 2015
  14. Johannes SchindelinOct 12, 2015
  15. Junio C HamanoOct 9, 2015
  16. Junio C HamanoOct 9, 2015
  17. Junio C HamanoOct 9, 2015
  18. Johannes SchindelinOct 12, 2015
  19. Junio C HamanoOct 9, 2015
  20. Johannes SchindelinOct 12, 2015
  21. Junio C HamanoOct 12, 2015
  22. Johannes SchindelinOct 13, 2015

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.