Merge branch 'vd/skip-cache-tree-update'

Avoid calling 'cache_tree_update()' when doing so would be redundant.

* vd/skip-cache-tree-update:
  rebase: use 'skip_cache_tree_update' option
  read-tree: use 'skip_cache_tree_update' option
  reset: use 'skip_cache_tree_update' option
  unpack-trees: add 'skip_cache_tree_update' option
  cache-tree: add perf test comparing update and prime
This commit is contained in:
Taylor Blau 2022-11-18 18:43:56 -05:00
commit a92fce4c50
14 changed files with 145 additions and 3 deletions

View file

@ -787,6 +787,7 @@ TEST_BUILTINS_OBJS += test-advise.o
TEST_BUILTINS_OBJS += test-bitmap.o
TEST_BUILTINS_OBJS += test-bloom.o
TEST_BUILTINS_OBJS += test-bundle-uri.o
TEST_BUILTINS_OBJS += test-cache-tree.o
TEST_BUILTINS_OBJS += test-chmtime.o
TEST_BUILTINS_OBJS += test-config.o
TEST_BUILTINS_OBJS += test-crontab.o

View file

@ -249,6 +249,10 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
if (opts.debug_unpack)
opts.fn = debug_merge;
/* If we're going to prime_cache_tree later, skip cache tree update */
if (nr_trees == 1 && !opts.prefix)
opts.skip_cache_tree_update = 1;
cache_tree_free(&active_cache_tree);
for (i = 0; i < nr_trees; i++) {
struct tree *tree = trees[i];

View file

@ -73,9 +73,11 @@ static int reset_index(const char *ref, const struct object_id *oid, int reset_t
case HARD:
opts.update = 1;
opts.reset = UNPACK_RESET_OVERWRITE_UNTRACKED;
opts.skip_cache_tree_update = 1;
break;
case MIXED:
opts.reset = UNPACK_RESET_PROTECT_UNTRACKED;
opts.skip_cache_tree_update = 1;
/* but opts.update=0, so working tree not updated */
break;
default:

View file

@ -128,6 +128,7 @@ int reset_head(struct repository *r, const struct reset_head_opts *opts)
unpack_tree_opts.update = 1;
unpack_tree_opts.merge = 1;
unpack_tree_opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
unpack_tree_opts.skip_cache_tree_update = 1;
init_checkout_metadata(&unpack_tree_opts.meta, switch_to_branch, oid, NULL);
if (reset_hard)
unpack_tree_opts.reset = UNPACK_RESET_PROTECT_UNTRACKED;

View file

@ -3748,6 +3748,7 @@ static int do_reset(struct repository *r,
unpack_tree_opts.merge = 1;
unpack_tree_opts.update = 1;
unpack_tree_opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
unpack_tree_opts.skip_cache_tree_update = 1;
init_checkout_metadata(&unpack_tree_opts.meta, name, &oid, NULL);
if (repo_read_index_unmerged(r)) {

View file

@ -0,0 +1,64 @@
#include "test-tool.h"
#include "cache.h"
#include "tree.h"
#include "cache-tree.h"
#include "parse-options.h"
static char const * const test_cache_tree_usage[] = {
N_("test-tool cache-tree <options> (control|prime|update)"),
NULL
};
int cmd__cache_tree(int argc, const char **argv)
{
struct object_id oid;
struct tree *tree;
int empty = 0;
int invalidate_qty = 0;
int i;
struct option options[] = {
OPT_BOOL(0, "empty", &empty,
N_("clear the cache tree before each iteration")),
OPT_INTEGER_F(0, "invalidate", &invalidate_qty,
N_("number of entries in the cache tree to invalidate (default 0)"),
PARSE_OPT_NONEG),
OPT_END()
};
setup_git_directory();
argc = parse_options(argc, argv, NULL, options, test_cache_tree_usage, 0);
if (read_cache() < 0)
die(_("unable to read index file"));
oidcpy(&oid, &the_index.cache_tree->oid);
tree = parse_tree_indirect(&oid);
if (!tree)
die(_("not a tree object: %s"), oid_to_hex(&oid));
if (empty) {
/* clear the cache tree & allocate a new one */
cache_tree_free(&the_index.cache_tree);
the_index.cache_tree = cache_tree();
} else if (invalidate_qty) {
/* invalidate the specified number of unique paths */
float f_interval = (float)the_index.cache_nr / invalidate_qty;
int interval = f_interval < 1.0 ? 1 : (int)f_interval;
for (i = 0; i < invalidate_qty && i * interval < the_index.cache_nr; i++)
cache_tree_invalidate_path(&the_index, the_index.cache[i * interval]->name);
}
if (argc != 1)
usage_with_options(test_cache_tree_usage, options);
else if (!strcmp(argv[0], "prime"))
prime_cache_tree(the_repository, &the_index, tree);
else if (!strcmp(argv[0], "update"))
cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);
/* use "control" subcommand to specify no-op */
else if (!!strcmp(argv[0], "control"))
die(_("Unhandled subcommand '%s'"), argv[0]);
return 0;
}

View file

@ -14,6 +14,7 @@ static struct test_cmd cmds[] = {
{ "bitmap", cmd__bitmap },
{ "bloom", cmd__bloom },
{ "bundle-uri", cmd__bundle_uri },
{ "cache-tree", cmd__cache_tree },
{ "chmtime", cmd__chmtime },
{ "config", cmd__config },
{ "crontab", cmd__crontab },

View file

@ -8,6 +8,7 @@ int cmd__advise_if_enabled(int argc, const char **argv);
int cmd__bitmap(int argc, const char **argv);
int cmd__bloom(int argc, const char **argv);
int cmd__bundle_uri(int argc, const char **argv);
int cmd__cache_tree(int argc, const char **argv);
int cmd__chmtime(int argc, const char **argv);
int cmd__config(int argc, const char **argv);
int cmd__crontab(int argc, const char **argv);

View file

@ -49,6 +49,14 @@ test_perf "read-tree br_base br_ballast ($nr_files)" '
git read-tree -n -m br_base br_ballast
'
test_perf "read-tree br_ballast_plus_1 ($nr_files)" '
# Run read-tree 100 times for clearer performance results & comparisons
for i in $(test_seq 100)
do
git read-tree -n -m br_ballast_plus_1 || return 1
done
'
test_perf "switch between br_base br_ballast ($nr_files)" '
git checkout -q br_base &&
git checkout -q br_ballast

36
t/perf/p0090-cache-tree.sh Executable file
View file

@ -0,0 +1,36 @@
#!/bin/sh
test_description="Tests performance of cache tree update operations"
. ./perf-lib.sh
test_perf_large_repo
test_checkout_worktree
count=100
test_expect_success 'setup cache tree' '
git write-tree
'
test_cache_tree () {
test_perf "$1, $3" "
for i in \$(test_seq $count)
do
test-tool cache-tree $4 $2
done
"
}
test_cache_tree_update_functions () {
test_cache_tree 'no-op' 'control' "$1" "$2"
test_cache_tree 'prime_cache_tree' 'prime' "$1" "$2"
test_cache_tree 'cache_tree_update' 'update' "$1" "$2"
}
test_cache_tree_update_functions "clean" ""
test_cache_tree_update_functions "invalidate 2" "--invalidate 2"
test_cache_tree_update_functions "invalidate 50" "--invalidate 50"
test_cache_tree_update_functions "empty" "--empty"
test_done

21
t/perf/p7102-reset.sh Executable file
View file

@ -0,0 +1,21 @@
#!/bin/sh
test_description='performance of reset'
. ./perf-lib.sh
test_perf_default_repo
test_checkout_worktree
test_perf 'reset --hard with change in tree' '
base=$(git rev-parse HEAD) &&
test_commit --no-tag A &&
new=$(git rev-parse HEAD) &&
for i in $(test_seq 10)
do
git reset --hard $new &&
git reset --hard $base || return $?
done
'
test_done

View file

@ -19,7 +19,7 @@ test_expect_success 'read-tree in partial clone prefetches in one batch' '
git -C server config uploadpack.allowfilter 1 &&
git -C server config uploadpack.allowanysha1inwant 1 &&
git clone --bare --filter=blob:none "file://$(pwd)/server" client &&
GIT_TRACE_PACKET="$(pwd)/trace" git -C client read-tree $TREE &&
GIT_TRACE_PACKET="$(pwd)/trace" git -C client read-tree $TREE $TREE &&
# "done" marks the end of negotiation (once per fetch). Expect that
# only one fetch occurs.

View file

@ -2043,7 +2043,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
if (!ret) {
if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
cache_tree_verify(the_repository, &o->result);
if (!cache_tree_fully_valid(o->result.cache_tree))
if (!o->skip_cache_tree_update &&
!cache_tree_fully_valid(o->result.cache_tree))
cache_tree_update(&o->result,
WRITE_TREE_SILENT |
WRITE_TREE_REPAIR);

View file

@ -71,7 +71,8 @@ struct unpack_trees_options {
quiet,
exiting_early,
show_all_errors,
dry_run;
dry_run,
skip_cache_tree_update;
enum unpack_trees_reset_type reset;
const char *prefix;
int cache_bottom;