dir.c: git-status: avoid is_excluded checks for tracked files
authorKarsten Blees <karsten.blees@gmail.com>
Mon, 15 Apr 2013 19:13:35 +0000 (21:13 +0200)
committerJunio C Hamano <gitster@pobox.com>
Mon, 15 Apr 2013 19:34:01 +0000 (12:34 -0700)
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>
dir.c
diff --git a/dir.c b/dir.c
index 47397600af6dcb1cd26557d5f58a81696a746fc4..9fc032fe3df6bfb617edee3bd11401380d5c43e0 100644 (file)
--- a/dir.c
+++ b/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;
        }