summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2014-04-28 14:04:29 -0700
committerRussell Belfer <rb@github.com>2014-05-02 09:21:32 -0700
commit240f4af321612a0fe4cf01aed75a8cb44173feb8 (patch)
treed92455ee46456a2de161b1128b0555e9a6e43401
parent6a1ca96e4193f79c16c6a71dd8b5d576acf22e91 (diff)
downloadlibgit2-240f4af321612a0fe4cf01aed75a8cb44173feb8.tar.gz
Add build option for diff internal statistics
-rw-r--r--CMakeLists.txt5
-rw-r--r--src/checkout.c3
-rw-r--r--src/diff.c79
-rw-r--r--src/diff.h7
-rw-r--r--src/diff_tform.c8
-rw-r--r--src/iterator.c10
-rw-r--r--src/iterator.h4
-rw-r--r--src/status.c8
-rw-r--r--src/util.h8
-rw-r--r--tests/diff/workdir.c12
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);