diff options
-rw-r--r-- | CMakeLists.txt | 5 | ||||
-rw-r--r-- | src/checkout.c | 3 | ||||
-rw-r--r-- | src/diff.c | 79 | ||||
-rw-r--r-- | src/diff.h | 7 | ||||
-rw-r--r-- | src/diff_tform.c | 8 | ||||
-rw-r--r-- | src/iterator.c | 10 | ||||
-rw-r--r-- | src/iterator.h | 4 | ||||
-rw-r--r-- | src/status.c | 8 | ||||
-rw-r--r-- | src/util.h | 8 | ||||
-rw-r--r-- | tests/diff/workdir.c | 12 |
10 files changed, 96 insertions, 48 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 884c9bcf1..83e03d6cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,7 @@ OPTION( ANDROID "Build for android NDK" OFF ) OPTION( USE_ICONV "Link with and use iconv library" OFF ) OPTION( USE_SSH "Link with libssh to enable SSH support" ON ) OPTION( VALGRIND "Configure build for valgrind" OFF ) +OPTION( PERF_STATS "Internally track performance data" OFF ) IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") SET( USE_ICONV ON ) @@ -352,6 +353,10 @@ IF (THREADSAFE) ADD_DEFINITIONS(-DGIT_THREADS) ENDIF() +IF (PERF_STATS) + ADD_DEFINITIONS(-DGIT_PERF) +ENDIF() + ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64) # Collect sourcefiles diff --git a/src/checkout.c b/src/checkout.c index bc976b854..93d6bc9c5 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -185,8 +185,7 @@ static bool checkout_is_workdir_modified( return true; if (git_diff__oid_for_file( - data->repo, wditem->path, wditem->mode, - wditem->file_size, &oid) < 0) + &oid, data->diff, wditem->path, wditem->mode, wditem->file_size) < 0) return false; return (git_oid__cmp(&baseitem->id, &oid) != 0); diff --git a/src/diff.c b/src/diff.c index 4b6fbe25a..aa880650a 100644 --- a/src/diff.c +++ b/src/diff.c @@ -510,26 +510,31 @@ void git_diff_addref(git_diff *diff) } int git_diff__oid_for_file( - git_repository *repo, + git_oid *out, + git_diff *diff, const char *path, uint16_t mode, - git_off_t size, - git_oid *oid) + git_off_t size) { - int result = 0; + int error = 0; git_buf full_path = GIT_BUF_INIT; + git_filter_list *fl = NULL; + + memset(out, 0, sizeof(*out)); if (git_buf_joinpath( - &full_path, git_repository_workdir(repo), path) < 0) + &full_path, git_repository_workdir(diff->repo), path) < 0) return -1; if (!mode) { struct stat st; - if (p_stat(path, &st) < 0) { - giterr_set(GITERR_OS, "Could not stat '%s'", path); - result = -1; - goto cleanup; + GIT_PERF_INC(diff->stat_calls); + + if (p_stat(full_path.ptr, &st) < 0) { + error = git_path_set_error(errno, path, "stat"); + git_buf_free(&full_path); + return error; } mode = st.st_mode; @@ -540,46 +545,43 @@ int git_diff__oid_for_file( if (S_ISGITLINK(mode)) { git_submodule *sm; - memset(oid, 0, sizeof(*oid)); + GIT_PERF_INC(diff->submodule_lookups); - if (!git_submodule_lookup(&sm, repo, path)) { + if (!git_submodule_lookup(&sm, diff->repo, path)) { const git_oid *sm_oid = git_submodule_wd_id(sm); if (sm_oid) - git_oid_cpy(oid, sm_oid); + git_oid_cpy(out, sm_oid); git_submodule_free(sm); } else { /* if submodule lookup failed probably just in an intermediate * state where some init hasn't happened, so ignore the error */ giterr_clear(); - memset(oid, 0, sizeof(*oid)); } } else if (S_ISLNK(mode)) { - result = git_odb__hashlink(oid, full_path.ptr); + GIT_PERF_INC(diff->oid_calculations); + error = git_odb__hashlink(out, full_path.ptr); } else if (!git__is_sizet(size)) { giterr_set(GITERR_OS, "File size overflow (for 32-bits) on '%s'", path); - result = -1; - } else { - git_filter_list *fl = NULL; - - result = git_filter_list_load(&fl, repo, NULL, path, GIT_FILTER_TO_ODB); - if (!result) { - int fd = git_futils_open_ro(full_path.ptr); - if (fd < 0) - result = fd; - else { - result = git_odb__hashfd_filtered( - oid, fd, (size_t)size, GIT_OBJ_BLOB, fl); - p_close(fd); - } - - git_filter_list_free(fl); + error = -1; + } else if (!(error = git_filter_list_load( + &fl, diff->repo, NULL, path, GIT_FILTER_TO_ODB))) + { + int fd = git_futils_open_ro(full_path.ptr); + if (fd < 0) + error = fd; + else { + GIT_PERF_INC(diff->oid_calculations); + error = git_odb__hashfd_filtered( + out, fd, (size_t)size, GIT_OBJ_BLOB, fl); + p_close(fd); } + + git_filter_list_free(fl); } -cleanup: git_buf_free(&full_path); - return result; + return error; } static bool diff_time_eq( @@ -617,6 +619,8 @@ static int maybe_modified_submodule( ign == GIT_SUBMODULE_IGNORE_ALL) return 0; + GIT_PERF_INC(diff->submodule_lookups); + if ((error = git_submodule_lookup( &sub, diff->repo, info->nitem->path)) < 0) { @@ -748,8 +752,8 @@ static int maybe_modified( */ if (status == GIT_DELTA_MODIFIED && git_oid_iszero(&nitem->id)) { if (git_oid_iszero(&noid)) { - if ((error = git_diff__oid_for_file(diff->repo, - nitem->path, nitem->mode, nitem->file_size, &noid)) < 0) + if ((error = git_diff__oid_for_file(&noid, + diff, nitem->path, nitem->mode, nitem->file_size)) < 0) return error; } @@ -914,6 +918,8 @@ static int handle_unmatched_new_item( delta_type = GIT_DELTA_ADDED; else if (nitem->mode == GIT_FILEMODE_COMMIT) { + GIT_PERF_INC(diff->submodule_lookups); + /* ignore things that are not actual submodules */ if (git_submodule_lookup(NULL, info->repo, nitem->path) != 0) { giterr_clear(); @@ -1066,6 +1072,11 @@ int git_diff__from_iterators( error = 0; } + GIT_PERF_ADD(diff->stat_calls, old_iter->stat_calls); + GIT_PERF_ADD(diff->stat_calls, new_iter->stat_calls); + GIT_PERF_ADD(diff->submodule_lookups, old_iter->submodule_lookups); + GIT_PERF_ADD(diff->submodule_lookups, new_iter->submodule_lookups); + cleanup: if (!error) *diff_ptr = diff; diff --git a/src/diff.h b/src/diff.h index aae8fbff1..491fc4667 100644 --- a/src/diff.h +++ b/src/diff.h @@ -62,6 +62,11 @@ struct git_diff { git_iterator_type_t old_src; git_iterator_type_t new_src; uint32_t diffcaps; +#ifdef GIT_PERF + size_t stat_calls; + size_t oid_calculations; + size_t submodule_lookups; +#endif int (*strcomp)(const char *, const char *); int (*strncomp)(const char *, const char *, size_t); @@ -90,7 +95,7 @@ extern int git_diff_delta__format_file_header( int oid_strlen); extern int git_diff__oid_for_file( - git_repository *, const char *, uint16_t, git_off_t, git_oid *); + git_oid *oit, git_diff *, const char *, uint16_t, git_off_t); extern int git_diff__from_iterators( git_diff **diff_ptr, diff --git a/src/diff_tform.c b/src/diff_tform.c index 97fbc2883..a2dab0ae2 100644 --- a/src/diff_tform.c +++ b/src/diff_tform.c @@ -574,14 +574,14 @@ static int similarity_measure( if (exact_match) { if (git_oid_iszero(&a_file->id) && diff->old_src == GIT_ITERATOR_TYPE_WORKDIR && - !git_diff__oid_for_file(diff->repo, a_file->path, - a_file->mode, a_file->size, &a_file->id)) + !git_diff__oid_for_file(&a_file->id, + diff, a_file->path, a_file->mode, a_file->size)) a_file->flags |= GIT_DIFF_FLAG_VALID_ID; if (git_oid_iszero(&b_file->id) && diff->new_src == GIT_ITERATOR_TYPE_WORKDIR && - !git_diff__oid_for_file(diff->repo, b_file->path, - b_file->mode, b_file->size, &b_file->id)) + !git_diff__oid_for_file(&b_file->id, + diff, b_file->path, b_file->mode, b_file->size)) b_file->flags |= GIT_DIFF_FLAG_VALID_ID; } diff --git a/src/iterator.c b/src/iterator.c index ef27fa71f..5e668b50c 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -1017,6 +1017,8 @@ static int fs_iterator__expand_dir(fs_iterator *fi) return GIT_ENOTFOUND; } + GIT_PERF_ADD(fi->base.stat_calls, ff->entries.length); + fs_iterator__seek_frame_start(fi, ff); ff->next = fi->stack; @@ -1304,9 +1306,11 @@ static int workdir_iterator__enter_dir(fs_iterator *fi) /* convert submodules to GITLINK and remove trailing slashes */ git_vector_foreach(&ff->entries, pos, entry) { - if (S_ISDIR(entry->st.st_mode) && - git_submodule__is_submodule(fi->base.repo, entry->path)) - { + if (!S_ISDIR(entry->st.st_mode)) + continue; + + GIT_PERF_INC(fi->base.submodule_lookups); + if (git_submodule__is_submodule(fi->base.repo, entry->path)) { entry->st.st_mode = GIT_FILEMODE_COMMIT; entry->path_len--; entry->path[entry->path_len] = '\0'; diff --git a/src/iterator.h b/src/iterator.h index ba9c1e486..2968b8c0c 100644 --- a/src/iterator.h +++ b/src/iterator.h @@ -53,6 +53,10 @@ struct git_iterator { char *end; int (*prefixcomp)(const char *str, const char *prefix); unsigned int flags; +#ifdef GIT_PERF + size_t stat_calls; + size_t submodule_lookups; +#endif }; extern int git_iterator_for_nothing( diff --git a/src/status.c b/src/status.c index c4b990a84..e1f8e06ae 100644 --- a/src/status.c +++ b/src/status.c @@ -81,15 +81,15 @@ static unsigned int workdir_delta2status( if (git_oid_iszero(&idx2wd->old_file.id) && diff->old_src == GIT_ITERATOR_TYPE_WORKDIR && !git_diff__oid_for_file( - diff->repo, idx2wd->old_file.path, idx2wd->old_file.mode, - idx2wd->old_file.size, &idx2wd->old_file.id)) + &idx2wd->old_file.id, diff, idx2wd->old_file.path, + idx2wd->old_file.mode, idx2wd->old_file.size)) idx2wd->old_file.flags |= GIT_DIFF_FLAG_VALID_ID; if (git_oid_iszero(&idx2wd->new_file.id) && diff->new_src == GIT_ITERATOR_TYPE_WORKDIR && !git_diff__oid_for_file( - diff->repo, idx2wd->new_file.path, idx2wd->new_file.mode, - idx2wd->new_file.size, &idx2wd->new_file.id)) + &idx2wd->new_file.id, diff, idx2wd->new_file.path, + idx2wd->new_file.mode, idx2wd->new_file.size)) idx2wd->new_file.flags |= GIT_DIFF_FLAG_VALID_ID; if (!git_oid_equal(&idx2wd->old_file.id, &idx2wd->new_file.id)) diff --git a/src/util.h b/src/util.h index 6fb2dc0f4..be7a16ef8 100644 --- a/src/util.h +++ b/src/util.h @@ -436,4 +436,12 @@ GIT_INLINE(double) git__timer(void) #endif +#ifdef GIT_PERF +# define GIT_PERF_INC(counter) (counter)++ +# define GIT_PERF_ADD(counter,val) (counter) += (val) +#else +# define GIT_PERF_INC(counter) 0 +# define GIT_PERF_ADD(counter,val) 0 +#endif + #endif /* INCLUDE_util_h__ */ diff --git a/tests/diff/workdir.c b/tests/diff/workdir.c index 6128e820e..03a3ff418 100644 --- a/tests/diff/workdir.c +++ b/tests/diff/workdir.c @@ -2,6 +2,11 @@ #include "diff_helpers.h" #include "repository.h" +#ifdef GIT_PERF +/* access to diff usage statistics */ +# include "diff.h" +#endif + static git_repository *g_repo = NULL; void test_diff_workdir__initialize(void) @@ -58,6 +63,13 @@ void test_diff_workdir__to_index(void) cl_assert_equal_i(5, exp.line_ctxt); cl_assert_equal_i(4, exp.line_adds); cl_assert_equal_i(5, exp.line_dels); + +#ifdef GIT_PERF + cl_assert_equal_sz( + 13 /* in root */ + 3 /* in subdir */, diff->stat_calls); + cl_assert_equal_sz(9, diff->oid_calculations); + cl_assert_equal_sz(2, diff->submodule_lookups); +#endif } git_diff_free(diff); |