dir.c: git-status: avoid is_excluded checks for tracked files

Checking if a file is in the index is much faster (hashtable lookup) than checking if the file is excluded (linear search over exclude patterns). Skip is_excluded checks for files: move the cache_name_exists check from treat_file to treat_one_path and return early if the file is tracked. This can safely be done as all other code paths also return path_ignored for tracked files, and dir_add_ignored skips tracked files as well. There's just one line left in treat_file, so move this to treat_one_path as well. Here's some performance data for git-status from the linux and WebKit repos (best of 10 runs on a Debian Linux on SSD, core.preloadIndex=true): | status | status --ignored | linux | WebKit | linux | WebKit -------+-------+--------+-------+--------- before | 0.218 | 1.583 | 0.321 | 2.579 after | 0.156 | 0.988 | 0.202 | 1.279 gain | 1.397 | 1.602 | 1.589 | 2.016 Signed-off-by: Karsten Blees <blees@dcon.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Karsten Blees committed Apr 15, 2013 at 21:13 UTC 8aaf8d7728e8ac50cbf6bcad05b6e896d4e69e0b
1 file changed +11 -27
dir.c
+11 -27
@@ -1066,28 +1066,6 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
1066 return show_directory;
1067 }
1068
1069 -/*
1070 - * Decide what to do when we find a file while traversing the
1071 - * filesystem. Mostly two cases:
1072 - *
1073 - * 1. We are looking for ignored files
1074 - * (a) File is ignored, include it
1075 - * (b) File is in ignored path, include it
1076 - * (c) File is not ignored, exclude it
1077 - *
1078 - * 2. Other scenarios, include the file if not excluded
1079 - *
1080 - * Return 1 for exclude, 0 for include.
1081 - */
1082 -static int treat_file(struct dir_struct *dir, struct strbuf *path, int exclude)
1083 -{
1084 - /* Always exclude indexed files */
1085 - if (index_name_exists(&the_index, path->buf, path->len, ignore_case))
1086 - return 1;
1087 -
1088 - return exclude == !(dir->flags & DIR_SHOW_IGNORED);
1089 -}
1090 -
1069 /*
1070 * This is an inexact early pruning of any recursive directory
1071 * reading - if the path cannot possibly be in the pathspec,
@@ -1211,7 +1189,16 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
1189 const struct path_simplify *simplify,
1190 int dtype, struct dirent *de)
1191 {
1214 - int exclude = is_excluded(dir, path->buf, &dtype);
1192 + int exclude;
1193 + if (dtype == DT_UNKNOWN)
1194 + dtype = get_dtype(de, path->buf, path->len);
1195 +
1196 + /* Always exclude indexed files */
1197 + if (dtype != DT_DIR &&
1198 + cache_name_exists(path->buf, path->len, ignore_case))
1199 + return path_ignored;
1200 +
1201 + exclude = is_excluded(dir, path->buf, &dtype);
1202 if (exclude && (dir->flags & DIR_COLLECT_IGNORED)
1203 && exclude_matches_pathspec(path->buf, path->len, simplify))
1204 dir_add_ignored(dir, path->buf, path->len);
@@ -1223,9 +1210,6 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
1210 if (exclude && !(dir->flags & DIR_SHOW_IGNORED))
1211 return path_ignored;
1212
1226 - if (dtype == DT_UNKNOWN)
1227 - dtype = get_dtype(de, path->buf, path->len);
1228 -
1213 switch (dtype) {
1214 default:
1215 return path_ignored;
@@ -1242,7 +1226,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
1226 break;
1227 case DT_REG:
1228 case DT_LNK:
1245 - if (treat_file(dir, path, exclude))
1229 + if (exclude == !(dir->flags & DIR_SHOW_IGNORED))
1230 return path_ignored;
1231 break;
1232 }