Hot read_directory() codepaths are tracked. This could be helpful to see how changes affect read_directory() performance. Results are printed when environment variable GIT_MEASURE_EXCLUDE is set. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- dir.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 100 insertions(+), 9 deletions(-) diff --git a/dir.c b/dir.c index 57394e4..69c045b 100644 --- a/dir.c +++ b/dir.c @@ -12,6 +12,32 @@ #include "refs.h" #include "wildmatch.h" +#ifdef MEASURE_EXCLUDE +static uint32_t tv_treat_leading_path; +static uint32_t tv_read_directory; +static uint32_t tv_treat_one_path; +static uint32_t tv_is_excluded; +static uint32_t tv_prep_exclude; +static uint32_t tv_last_exclude_matching; +static uint32_t tv_dir_add_name; +static uint32_t tv_directory_exists_in_index; +static uint32_t tv_simplify_away; +static uint32_t tv_index_name_exists; +static uint32_t tv_lazy_init_name_hash; +#define START_CLOCK() \ + { \ + struct timeval tv1, tv2; \ + gettimeofday(&tv1, NULL); +#define STOP_CLOCK(v) \ + gettimeofday(&tv2, NULL); \ + v += (uint64_t)tv2.tv_sec * 1000000 + tv2.tv_usec - \ + (uint64_t)tv1.tv_sec * 1000000 - tv1.tv_usec; \ + } +#else +#define START_CLOCK() +#define STOP_CLOCK(v) +#endif + struct path_simplify { int len; const char *path; @@ -768,8 +794,11 @@ static struct exclude *last_exclude_matching(struct dir_struct *dir, const char *basename = strrchr(pathname, '/'); basename = (basename) ? basename+1 : pathname; + START_CLOCK(); prep_exclude(dir, pathname, basename-pathname); + STOP_CLOCK(tv_prep_exclude); + START_CLOCK(); for (i = EXC_CMDL; i <= EXC_FILE; i++) { group = &dir->exclude_list_group[i]; for (j = group->nr - 1; j >= 0; j--) { @@ -780,6 +809,7 @@ static struct exclude *last_exclude_matching(struct dir_struct *dir, return exclude; } } + STOP_CLOCK(tv_last_exclude_matching); return NULL; } @@ -897,9 +927,14 @@ static struct dir_entry *dir_entry_new(const char *pathname, int len) static struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len) { - if (!(dir->flags & DIR_SHOW_IGNORED) && - cache_name_exists(pathname, len, ignore_case)) - return NULL; + if (!(dir->flags & DIR_SHOW_IGNORED)) { + struct cache_entry *ce; + START_CLOCK(); + ce = cache_name_exists(pathname, len, ignore_case); + STOP_CLOCK(tv_index_name_exists); + if (ce) + return NULL; + } ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc); return dir->entries[dir->nr++] = dir_entry_new(pathname, len); @@ -1034,8 +1069,12 @@ static enum directory_treatment treat_directory(struct dir_struct *dir, const char *dirname, int len, int exclude, const struct path_simplify *simplify) { + int ret; + START_CLOCK(); /* The "len-1" is to strip the final '/' */ - switch (directory_exists_in_index(dirname, len-1)) { + ret = directory_exists_in_index(dirname, len-1); + STOP_CLOCK(tv_directory_exists_in_index); + switch (ret) { case index_directory: if ((dir->flags & DIR_SHOW_OTHER_DIRECTORIES) && exclude) break; @@ -1179,7 +1218,9 @@ static int get_index_dtype(const char *path, int len) int pos; struct cache_entry *ce; + START_CLOCK(); ce = cache_name_exists(path, len, 0); + STOP_CLOCK(tv_index_name_exists); if (ce) { if (!ce_uptodate(ce)) return DT_UNKNOWN; @@ -1244,7 +1285,12 @@ static enum path_treatment treat_one_path(struct dir_struct *dir, const struct path_simplify *simplify, int dtype, struct dirent *de) { - int exclude = is_excluded(dir, path->buf, &dtype); + int exclude; + + START_CLOCK(); + exclude = is_excluded(dir, path->buf, &dtype); + STOP_CLOCK(tv_is_excluded); + if (exclude && (dir->flags & DIR_COLLECT_IGNORED) && exclude_matches_pathspec(path->buf, path->len, simplify)) dir_add_ignored(dir, path->buf, path->len); @@ -1292,17 +1338,23 @@ static enum path_treatment treat_path(struct dir_struct *dir, int baselen, const struct path_simplify *simplify) { - int dtype; + int dtype, ret; if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git")) return path_ignored; strbuf_setlen(path, baselen); strbuf_addstr(path, de->d_name); - if (simplify_away(path->buf, path->len, simplify)) + START_CLOCK(); + ret = simplify_away(path->buf, path->len, simplify); + STOP_CLOCK(tv_simplify_away); + if (ret) return path_ignored; dtype = DTYPE(de); - return treat_one_path(dir, path, simplify, dtype, de); + START_CLOCK(); + ret = treat_one_path(dir, path, simplify, dtype, de); + STOP_CLOCK(tv_treat_one_path); + return ret; } /* @@ -1345,7 +1397,9 @@ static int read_directory_recursive(struct dir_struct *dir, contents++; if (check_only) break; + START_CLOCK(); dir_add_name(dir, path.buf, path.len); + STOP_CLOCK(tv_dir_add_name); } closedir(fdir); out: @@ -1405,6 +1459,7 @@ static int treat_leading_path(struct dir_struct *dir, len--; if (!len) return 1; + START_CLOCK(); baselen = 0; while (1) { cp = path + baselen + !!baselen; @@ -1428,6 +1483,7 @@ static int treat_leading_path(struct dir_struct *dir, } } strbuf_release(&sb); + STOP_CLOCK(tv_treat_leading_path); return rc; } @@ -1439,8 +1495,43 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const char return dir->nr; simplify = create_simplify(pathspec); - if (!len || treat_leading_path(dir, path, len, simplify)) + if (!len || treat_leading_path(dir, path, len, simplify)) { +#ifdef MEASURE_EXCLUDE + /* The first call triggers lazy_init_name_hash() */ + START_CLOCK(); + index_name_exists(&the_index, "", 0, ignore_case); + STOP_CLOCK(tv_lazy_init_name_hash); +#endif + START_CLOCK(); read_directory_recursive(dir, path, len, 0, simplify); + STOP_CLOCK(tv_read_directory); + } +#ifdef MEASURE_EXCLUDE + if (getenv("GIT_MEASURE_EXCLUDE")) { + fprintf(stderr, "treat_leading_path: %10.3f\n", + (float)tv_treat_leading_path / 1000000); + fprintf(stderr, "read_directory: %10.3f\n", + (float)tv_read_directory / 1000000); + fprintf(stderr, "+treat_one_path: %10.3f\n", + (float)tv_treat_one_path / 1000000); + fprintf(stderr, "++is_excluded: %10.3f\n", + (float)tv_is_excluded / 1000000); + fprintf(stderr, "+++prep_exclude: %10.3f\n", + (float)tv_prep_exclude / 1000000); + fprintf(stderr, "+++matching: %10.3f\n", + (float)tv_last_exclude_matching / 1000000); + fprintf(stderr, "++dir_exist: %10.3f\n", + (float)tv_directory_exists_in_index / 1000000); + fprintf(stderr, "++index_name_exists: %10.3f\n", + (float)tv_index_name_exists / 1000000); + fprintf(stderr, "lazy_init_name_hash: %10.3f\n", + (float)tv_lazy_init_name_hash / 1000000); + fprintf(stderr, "+simplify_away: %10.3f\n", + (float)tv_simplify_away / 1000000); + fprintf(stderr, "+dir_add_name: %10.3f\n", + (float)tv_dir_add_name / 1000000); + } +#endif free_simplify(simplify); qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name); qsort(dir->ignored, dir->ignored_nr, sizeof(struct dir_entry *), cmp_name); -- 1.8.1.2.536.gf441e6d -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html