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

Re: [PATCH v2 14/19] tree-diff: rework diff_tree interface to be sha1 based

From
Junio C Hamano <gitster@pobox.com>
Date
Mar 24, 2014, 21:36 UTC
Message-ID
<xmqqa9cfp9d5.fsf@gitster.dls.corp.google.com>
In-Reply-To
<0b82e2de0edee4a590e7b4165c65938aef7090f5.1393257006.git.kirr@mns.spb.ru>
Kirill Smelkov <kirr@mns.spb.ru> writes:
> The downside is that try_to_follow_renames(), if active, we cause
> re-reading of 2 initial trees, which was negligible based on my timings,

That would depend on how often the codepath triggered in your test case, but is totally understandable. It fires only when the path we have been following disappears from the parent, and the processing of try-to-follow itself is very compute-intensive (it needs to run find-copies-harder logic) that will end up reading many subtrees of the two initial trees; two more reading of tree objects will be dwarfed by the actual processing.

> and which is outweighed cogently by the upsides.
> Changes since v1:
>
>  - don't need to touch diff.h, as diff_tree() became static.

Nice. I wonder if it is an option to let the function keep its name diff_tree() without renaming it to __diff_tree_whatever(), though.

Show 127 quoted lines
>  tree-diff.c | 60 ++++++++++++++++++++++++++++--------------------------------
>  1 file changed, 28 insertions(+), 32 deletions(-)
>
> diff --git a/tree-diff.c b/tree-diff.c
> index b99622c..f90acf5 100644
> --- a/tree-diff.c
> +++ b/tree-diff.c
> @@ -137,12 +137,17 @@ static void skip_uninteresting(struct tree_desc *t, struct strbuf *base,
>  	}
>  }
>  
> -static int diff_tree(struct tree_desc *t1, struct tree_desc *t2,
> -		     const char *base_str, struct diff_options *opt)
> +static int __diff_tree_sha1(const unsigned char *old, const unsigned char *new,
> +			    const char *base_str, struct diff_options *opt)
>  {
> +	struct tree_desc t1, t2;
> +	void *t1tree, *t2tree;
>  	struct strbuf base;
>  	int baselen = strlen(base_str);
>  
> +	t1tree = fill_tree_descriptor(&t1, old);
> +	t2tree = fill_tree_descriptor(&t2, new);
> +
>  	/* Enable recursion indefinitely */
>  	opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE);
>  
> @@ -155,39 +160,41 @@ static int diff_tree(struct tree_desc *t1, struct tree_desc *t2,
>  		if (diff_can_quit_early(opt))
>  			break;
>  		if (opt->pathspec.nr) {
> -			skip_uninteresting(t1, &base, opt);
> -			skip_uninteresting(t2, &base, opt);
> +			skip_uninteresting(&t1, &base, opt);
> +			skip_uninteresting(&t2, &base, opt);
>  		}
> -		if (!t1->size && !t2->size)
> +		if (!t1.size && !t2.size)
>  			break;
>  
> -		cmp = tree_entry_pathcmp(t1, t2);
> +		cmp = tree_entry_pathcmp(&t1, &t2);
>  
>  		/* t1 = t2 */
>  		if (cmp == 0) {
>  			if (DIFF_OPT_TST(opt, FIND_COPIES_HARDER) ||
> -			    hashcmp(t1->entry.sha1, t2->entry.sha1) ||
> -			    (t1->entry.mode != t2->entry.mode))
> -				show_path(&base, opt, t1, t2);
> +			    hashcmp(t1.entry.sha1, t2.entry.sha1) ||
> +			    (t1.entry.mode != t2.entry.mode))
> +				show_path(&base, opt, &t1, &t2);
>  
> -			update_tree_entry(t1);
> -			update_tree_entry(t2);
> +			update_tree_entry(&t1);
> +			update_tree_entry(&t2);
>  		}
>  
>  		/* t1 < t2 */
>  		else if (cmp < 0) {
> -			show_path(&base, opt, t1, /*t2=*/NULL);
> -			update_tree_entry(t1);
> +			show_path(&base, opt, &t1, /*t2=*/NULL);
> +			update_tree_entry(&t1);
>  		}
>  
>  		/* t1 > t2 */
>  		else {
> -			show_path(&base, opt, /*t1=*/NULL, t2);
> -			update_tree_entry(t2);
> +			show_path(&base, opt, /*t1=*/NULL, &t2);
> +			update_tree_entry(&t2);
>  		}
>  	}
>  
>  	strbuf_release(&base);
> +	free(t2tree);
> +	free(t1tree);
>  	return 0;
>  }
>  
> @@ -202,7 +209,7 @@ static inline int diff_might_be_rename(void)
>  		!DIFF_FILE_VALID(diff_queued_diff.queue[0]->one);
>  }
>  
> -static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)
> +static void try_to_follow_renames(const unsigned char *old, const unsigned char *new, const char *base, struct diff_options *opt)
>  {
>  	struct diff_options diff_opts;
>  	struct diff_queue_struct *q = &diff_queued_diff;
> @@ -240,7 +247,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
>  	diff_opts.break_opt = opt->break_opt;
>  	diff_opts.rename_score = opt->rename_score;
>  	diff_setup_done(&diff_opts);
> -	diff_tree(t1, t2, base, &diff_opts);
> +	__diff_tree_sha1(old, new, base, &diff_opts);
>  	diffcore_std(&diff_opts);
>  	free_pathspec(&diff_opts.pathspec);
>  
> @@ -301,23 +308,12 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
>  
>  int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base, struct diff_options *opt)
>  {
> -	void *tree1, *tree2;
> -	struct tree_desc t1, t2;
> -	unsigned long size1, size2;
>  	int retval;
>  
> -	tree1 = fill_tree_descriptor(&t1, old);
> -	tree2 = fill_tree_descriptor(&t2, new);
> -	size1 = t1.size;
> -	size2 = t2.size;
> -	retval = diff_tree(&t1, &t2, base, opt);
> -	if (!*base && DIFF_OPT_TST(opt, FOLLOW_RENAMES) && diff_might_be_rename()) {
> -		init_tree_desc(&t1, tree1, size1);
> -		init_tree_desc(&t2, tree2, size2);
> -		try_to_follow_renames(&t1, &t2, base, opt);
> -	}
> -	free(tree1);
> -	free(tree2);
> +	retval = __diff_tree_sha1(old, new, base, opt);
> +	if (!*base && DIFF_OPT_TST(opt, FOLLOW_RENAMES) && diff_might_be_rename())
> +		try_to_follow_renames(old, new, base, opt);
> +
>  	return retval;
>  }
Previous: Kirill SmelkovNext: Kirill Smelkov
Message 23 of 64 in “Multiparent diff tree-walker + combine-diff speedup”
  1. 00/19 Multiparent diff tree-walker + combine-diff speedupKirill Smelkov, Feb 24, 2014
  2. 01/19 combine-diff: move show_log_first logic/action out of paths scanningKirill Smelkov, Feb 24, 2014
  3. 02/19 combine-diff: move changed-paths scanning logic into its own functionKirill Smelkov, Feb 24, 2014
  4. 03/19 tree-diff: no need to manually verify that there is no mode change for a pathKirill Smelkov, Feb 24, 2014
  5. 04/19 tree-diff: no need to pass match to skip_uninteresting()Kirill Smelkov, Feb 24, 2014
  6. 05/19 tree-diff: show_tree() is not neededKirill Smelkov, Feb 24, 2014
  7. 06/19 tree-diff: consolidate code for emitting diffs and recursion in one placeKirill Smelkov, Feb 24, 2014
  8. 07/19 tree-diff: don't assume compare_tree_entry() returns -1,0,1Kirill Smelkov, Feb 24, 2014
  9. 08/19 tree-diff: move all action-taking code out of compare_tree_entry()Kirill Smelkov, Feb 24, 2014
  10. 09/19 tree-diff: rename compare_tree_entry -> tree_entry_pathcmpKirill Smelkov, Feb 24, 2014
  11. 10/19 tree-diff: show_path prototype is not needed anymoreKirill Smelkov, Feb 24, 2014
  12. 11/19 tree-diff: simplify tree_entry_pathcmpKirill Smelkov, Feb 24, 2014
  13. Junio C HamanoMar 24, 2014
  14. Kirill SmelkovMar 25, 2014
  15. 12/19 tree-diff: remove special-case diff-emitting code for empty-tree casesKirill Smelkov, Feb 24, 2014
  16. Junio C HamanoMar 24, 2014
  17. Kirill SmelkovMar 25, 2014
  18. Junio C HamanoMar 25, 2014
  19. Junio C HamanoMar 25, 2014
  20. Kirill SmelkovMar 26, 2014
  21. 13/19 tree-diff: diff_tree() should now be staticKirill Smelkov, Feb 24, 2014
  22. 14/19 tree-diff: rework diff_tree interface to be sha1 basedKirill Smelkov, Feb 24, 2014
  23. Junio C HamanoMar 24, 2014
  24. Kirill SmelkovMar 25, 2014
  25. Junio C HamanoMar 25, 2014
  26. Kirill SmelkovMar 26, 2014
  27. Junio C HamanoMar 26, 2014
  28. Kirill SmelkovMar 27, 2014
  29. Junio C HamanoMar 27, 2014
  30. Kirill SmelkovMar 27, 2014
  31. Johannes SixtMar 28, 2014
  32. Junio C HamanoMar 28, 2014
  33. Johannes SixtMar 28, 2014
  34. Junio C HamanoMar 28, 2014
  35. Johannes SixtMar 28, 2014
  36. Junio C HamanoMar 28, 2014
  37. 15/19 tree-diff: no need to call "full" diff_tree_sha1 from show_path()Kirill Smelkov, Feb 24, 2014
  38. Kirill SmelkovMar 27, 2014
  39. 16/19 tree-diff: reuse base str(buf) memory on sub-tree recursionKirill Smelkov, Feb 24, 2014
  40. Junio C HamanoMar 24, 2014
  41. Kirill SmelkovMar 25, 2014
  42. Kirill SmelkovMar 27, 2014
  43. 17/19 Portable alloca for GitKirill Smelkov, Feb 24, 2014
  44. Thomas SchwingeFeb 28, 2014
  45. Erik Faye-LundFeb 28, 2014
  46. Erik Faye-LundFeb 28, 2014
  47. Kirill SmelkovFeb 28, 2014
  48. Erik Faye-LundFeb 28, 2014
  49. Kirill SmelkovMar 5, 2014
  50. Junio C HamanoMar 24, 2014
  51. Kirill SmelkovMar 27, 2014
  52. Kirill SmelkovApr 9, 2014
  53. Erik Faye-LundApr 9, 2014
  54. Junio C HamanoApr 10, 2014
  55. 18/19 tree-diff: rework diff_tree() to generate diffs for multiparent cases as wellKirill Smelkov, Feb 24, 2014
  56. Kirill SmelkovMar 27, 2014
  57. Junio C HamanoApr 4, 2014
  58. Kirill SmelkovApr 6, 2014
  59. Junio C HamanoApr 7, 2014
  60. Junio C HamanoApr 7, 2014
  61. Kirill SmelkovApr 7, 2014
  62. 19/19 combine-diff: speed it up, by using multiparent diff tree-walker directlyKirill Smelkov, Feb 24, 2014
  63. Duy NguyenFeb 24, 2014
  64. Kirill SmelkovFeb 25, 2014

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.