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>
This commit is contained in:
Karsten Blees 2013-04-15 21:13:35 +02:00 коммит произвёл Junio C Hamano
Родитель b07bc8c8c3
Коммит 8aaf8d7728
1 изменённых файлов: 11 добавлений и 27 удалений

38
dir.c
Просмотреть файл

@ -1066,28 +1066,6 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
return show_directory;
}
/*
* Decide what to do when we find a file while traversing the
* filesystem. Mostly two cases:
*
* 1. We are looking for ignored files
* (a) File is ignored, include it
* (b) File is in ignored path, include it
* (c) File is not ignored, exclude it
*
* 2. Other scenarios, include the file if not excluded
*
* Return 1 for exclude, 0 for include.
*/
static int treat_file(struct dir_struct *dir, struct strbuf *path, int exclude)
{
/* Always exclude indexed files */
if (index_name_exists(&the_index, path->buf, path->len, ignore_case))
return 1;
return exclude == !(dir->flags & DIR_SHOW_IGNORED);
}
/*
* This is an inexact early pruning of any recursive directory
* 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,
const struct path_simplify *simplify,
int dtype, struct dirent *de)
{
int exclude = is_excluded(dir, path->buf, &dtype);
int exclude;
if (dtype == DT_UNKNOWN)
dtype = get_dtype(de, path->buf, path->len);
/* Always exclude indexed files */
if (dtype != DT_DIR &&
cache_name_exists(path->buf, path->len, ignore_case))
return path_ignored;
exclude = is_excluded(dir, path->buf, &dtype);
if (exclude && (dir->flags & DIR_COLLECT_IGNORED)
&& exclude_matches_pathspec(path->buf, path->len, simplify))
dir_add_ignored(dir, path->buf, path->len);
@ -1223,9 +1210,6 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
if (exclude && !(dir->flags & DIR_SHOW_IGNORED))
return path_ignored;
if (dtype == DT_UNKNOWN)
dtype = get_dtype(de, path->buf, path->len);
switch (dtype) {
default:
return path_ignored;
@ -1242,7 +1226,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
break;
case DT_REG:
case DT_LNK:
if (treat_file(dir, path, exclude))
if (exclude == !(dir->flags & DIR_SHOW_IGNORED))
return path_ignored;
break;
}