Commit 240f4af3 by Russell Belfer

Add build option for diff internal statistics

parent 6a1ca96e
...@@ -37,6 +37,7 @@ OPTION( ANDROID "Build for android NDK" OFF ) ...@@ -37,6 +37,7 @@ OPTION( ANDROID "Build for android NDK" OFF )
OPTION( USE_ICONV "Link with and use iconv library" OFF ) OPTION( USE_ICONV "Link with and use iconv library" OFF )
OPTION( USE_SSH "Link with libssh to enable SSH support" ON ) OPTION( USE_SSH "Link with libssh to enable SSH support" ON )
OPTION( VALGRIND "Configure build for valgrind" OFF ) OPTION( VALGRIND "Configure build for valgrind" OFF )
OPTION( PERF_STATS "Internally track performance data" OFF )
IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
SET( USE_ICONV ON ) SET( USE_ICONV ON )
...@@ -352,6 +353,10 @@ IF (THREADSAFE) ...@@ -352,6 +353,10 @@ IF (THREADSAFE)
ADD_DEFINITIONS(-DGIT_THREADS) ADD_DEFINITIONS(-DGIT_THREADS)
ENDIF() ENDIF()
IF (PERF_STATS)
ADD_DEFINITIONS(-DGIT_PERF)
ENDIF()
ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64) ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64)
# Collect sourcefiles # Collect sourcefiles
......
...@@ -185,8 +185,7 @@ static bool checkout_is_workdir_modified( ...@@ -185,8 +185,7 @@ static bool checkout_is_workdir_modified(
return true; return true;
if (git_diff__oid_for_file( if (git_diff__oid_for_file(
data->repo, wditem->path, wditem->mode, &oid, data->diff, wditem->path, wditem->mode, wditem->file_size) < 0)
wditem->file_size, &oid) < 0)
return false; return false;
return (git_oid__cmp(&baseitem->id, &oid) != 0); return (git_oid__cmp(&baseitem->id, &oid) != 0);
......
...@@ -510,26 +510,31 @@ void git_diff_addref(git_diff *diff) ...@@ -510,26 +510,31 @@ void git_diff_addref(git_diff *diff)
} }
int git_diff__oid_for_file( int git_diff__oid_for_file(
git_repository *repo, git_oid *out,
git_diff *diff,
const char *path, const char *path,
uint16_t mode, uint16_t mode,
git_off_t size, git_off_t size)
git_oid *oid)
{ {
int result = 0; int error = 0;
git_buf full_path = GIT_BUF_INIT; git_buf full_path = GIT_BUF_INIT;
git_filter_list *fl = NULL;
memset(out, 0, sizeof(*out));
if (git_buf_joinpath( if (git_buf_joinpath(
&full_path, git_repository_workdir(repo), path) < 0) &full_path, git_repository_workdir(diff->repo), path) < 0)
return -1; return -1;
if (!mode) { if (!mode) {
struct stat st; struct stat st;
if (p_stat(path, &st) < 0) { GIT_PERF_INC(diff->stat_calls);
giterr_set(GITERR_OS, "Could not stat '%s'", path);
result = -1; if (p_stat(full_path.ptr, &st) < 0) {
goto cleanup; error = git_path_set_error(errno, path, "stat");
git_buf_free(&full_path);
return error;
} }
mode = st.st_mode; mode = st.st_mode;
...@@ -540,46 +545,43 @@ int git_diff__oid_for_file( ...@@ -540,46 +545,43 @@ int git_diff__oid_for_file(
if (S_ISGITLINK(mode)) { if (S_ISGITLINK(mode)) {
git_submodule *sm; 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); const git_oid *sm_oid = git_submodule_wd_id(sm);
if (sm_oid) if (sm_oid)
git_oid_cpy(oid, sm_oid); git_oid_cpy(out, sm_oid);
git_submodule_free(sm); git_submodule_free(sm);
} else { } else {
/* if submodule lookup failed probably just in an intermediate /* if submodule lookup failed probably just in an intermediate
* state where some init hasn't happened, so ignore the error * state where some init hasn't happened, so ignore the error
*/ */
giterr_clear(); giterr_clear();
memset(oid, 0, sizeof(*oid));
} }
} else if (S_ISLNK(mode)) { } 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)) { } else if (!git__is_sizet(size)) {
giterr_set(GITERR_OS, "File size overflow (for 32-bits) on '%s'", path); giterr_set(GITERR_OS, "File size overflow (for 32-bits) on '%s'", path);
result = -1; error = -1;
} else { } else if (!(error = git_filter_list_load(
git_filter_list *fl = NULL; &fl, diff->repo, NULL, path, GIT_FILTER_TO_ODB)))
{
result = git_filter_list_load(&fl, repo, NULL, path, GIT_FILTER_TO_ODB); int fd = git_futils_open_ro(full_path.ptr);
if (!result) { if (fd < 0)
int fd = git_futils_open_ro(full_path.ptr); error = fd;
if (fd < 0) else {
result = fd; GIT_PERF_INC(diff->oid_calculations);
else { error = git_odb__hashfd_filtered(
result = git_odb__hashfd_filtered( out, fd, (size_t)size, GIT_OBJ_BLOB, fl);
oid, fd, (size_t)size, GIT_OBJ_BLOB, fl); p_close(fd);
p_close(fd);
}
git_filter_list_free(fl);
} }
git_filter_list_free(fl);
} }
cleanup:
git_buf_free(&full_path); git_buf_free(&full_path);
return result; return error;
} }
static bool diff_time_eq( static bool diff_time_eq(
...@@ -617,6 +619,8 @@ static int maybe_modified_submodule( ...@@ -617,6 +619,8 @@ static int maybe_modified_submodule(
ign == GIT_SUBMODULE_IGNORE_ALL) ign == GIT_SUBMODULE_IGNORE_ALL)
return 0; return 0;
GIT_PERF_INC(diff->submodule_lookups);
if ((error = git_submodule_lookup( if ((error = git_submodule_lookup(
&sub, diff->repo, info->nitem->path)) < 0) { &sub, diff->repo, info->nitem->path)) < 0) {
...@@ -748,8 +752,8 @@ static int maybe_modified( ...@@ -748,8 +752,8 @@ static int maybe_modified(
*/ */
if (status == GIT_DELTA_MODIFIED && git_oid_iszero(&nitem->id)) { if (status == GIT_DELTA_MODIFIED && git_oid_iszero(&nitem->id)) {
if (git_oid_iszero(&noid)) { if (git_oid_iszero(&noid)) {
if ((error = git_diff__oid_for_file(diff->repo, if ((error = git_diff__oid_for_file(&noid,
nitem->path, nitem->mode, nitem->file_size, &noid)) < 0) diff, nitem->path, nitem->mode, nitem->file_size)) < 0)
return error; return error;
} }
...@@ -914,6 +918,8 @@ static int handle_unmatched_new_item( ...@@ -914,6 +918,8 @@ static int handle_unmatched_new_item(
delta_type = GIT_DELTA_ADDED; delta_type = GIT_DELTA_ADDED;
else if (nitem->mode == GIT_FILEMODE_COMMIT) { else if (nitem->mode == GIT_FILEMODE_COMMIT) {
GIT_PERF_INC(diff->submodule_lookups);
/* ignore things that are not actual submodules */ /* ignore things that are not actual submodules */
if (git_submodule_lookup(NULL, info->repo, nitem->path) != 0) { if (git_submodule_lookup(NULL, info->repo, nitem->path) != 0) {
giterr_clear(); giterr_clear();
...@@ -1066,6 +1072,11 @@ int git_diff__from_iterators( ...@@ -1066,6 +1072,11 @@ int git_diff__from_iterators(
error = 0; 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: cleanup:
if (!error) if (!error)
*diff_ptr = diff; *diff_ptr = diff;
......
...@@ -62,6 +62,11 @@ struct git_diff { ...@@ -62,6 +62,11 @@ struct git_diff {
git_iterator_type_t old_src; git_iterator_type_t old_src;
git_iterator_type_t new_src; git_iterator_type_t new_src;
uint32_t diffcaps; 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 (*strcomp)(const char *, const char *);
int (*strncomp)(const char *, const char *, size_t); int (*strncomp)(const char *, const char *, size_t);
...@@ -90,7 +95,7 @@ extern int git_diff_delta__format_file_header( ...@@ -90,7 +95,7 @@ extern int git_diff_delta__format_file_header(
int oid_strlen); int oid_strlen);
extern int git_diff__oid_for_file( 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( extern int git_diff__from_iterators(
git_diff **diff_ptr, git_diff **diff_ptr,
......
...@@ -574,14 +574,14 @@ static int similarity_measure( ...@@ -574,14 +574,14 @@ static int similarity_measure(
if (exact_match) { if (exact_match) {
if (git_oid_iszero(&a_file->id) && if (git_oid_iszero(&a_file->id) &&
diff->old_src == GIT_ITERATOR_TYPE_WORKDIR && diff->old_src == GIT_ITERATOR_TYPE_WORKDIR &&
!git_diff__oid_for_file(diff->repo, a_file->path, !git_diff__oid_for_file(&a_file->id,
a_file->mode, a_file->size, &a_file->id)) diff, a_file->path, a_file->mode, a_file->size))
a_file->flags |= GIT_DIFF_FLAG_VALID_ID; a_file->flags |= GIT_DIFF_FLAG_VALID_ID;
if (git_oid_iszero(&b_file->id) && if (git_oid_iszero(&b_file->id) &&
diff->new_src == GIT_ITERATOR_TYPE_WORKDIR && diff->new_src == GIT_ITERATOR_TYPE_WORKDIR &&
!git_diff__oid_for_file(diff->repo, b_file->path, !git_diff__oid_for_file(&b_file->id,
b_file->mode, b_file->size, &b_file->id)) diff, b_file->path, b_file->mode, b_file->size))
b_file->flags |= GIT_DIFF_FLAG_VALID_ID; b_file->flags |= GIT_DIFF_FLAG_VALID_ID;
} }
......
...@@ -1017,6 +1017,8 @@ static int fs_iterator__expand_dir(fs_iterator *fi) ...@@ -1017,6 +1017,8 @@ static int fs_iterator__expand_dir(fs_iterator *fi)
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
} }
GIT_PERF_ADD(fi->base.stat_calls, ff->entries.length);
fs_iterator__seek_frame_start(fi, ff); fs_iterator__seek_frame_start(fi, ff);
ff->next = fi->stack; ff->next = fi->stack;
...@@ -1304,9 +1306,11 @@ static int workdir_iterator__enter_dir(fs_iterator *fi) ...@@ -1304,9 +1306,11 @@ static int workdir_iterator__enter_dir(fs_iterator *fi)
/* convert submodules to GITLINK and remove trailing slashes */ /* convert submodules to GITLINK and remove trailing slashes */
git_vector_foreach(&ff->entries, pos, entry) { git_vector_foreach(&ff->entries, pos, entry) {
if (S_ISDIR(entry->st.st_mode) && if (!S_ISDIR(entry->st.st_mode))
git_submodule__is_submodule(fi->base.repo, entry->path)) 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->st.st_mode = GIT_FILEMODE_COMMIT;
entry->path_len--; entry->path_len--;
entry->path[entry->path_len] = '\0'; entry->path[entry->path_len] = '\0';
......
...@@ -53,6 +53,10 @@ struct git_iterator { ...@@ -53,6 +53,10 @@ struct git_iterator {
char *end; char *end;
int (*prefixcomp)(const char *str, const char *prefix); int (*prefixcomp)(const char *str, const char *prefix);
unsigned int flags; unsigned int flags;
#ifdef GIT_PERF
size_t stat_calls;
size_t submodule_lookups;
#endif
}; };
extern int git_iterator_for_nothing( extern int git_iterator_for_nothing(
......
...@@ -81,15 +81,15 @@ static unsigned int workdir_delta2status( ...@@ -81,15 +81,15 @@ static unsigned int workdir_delta2status(
if (git_oid_iszero(&idx2wd->old_file.id) && if (git_oid_iszero(&idx2wd->old_file.id) &&
diff->old_src == GIT_ITERATOR_TYPE_WORKDIR && diff->old_src == GIT_ITERATOR_TYPE_WORKDIR &&
!git_diff__oid_for_file( !git_diff__oid_for_file(
diff->repo, idx2wd->old_file.path, idx2wd->old_file.mode, &idx2wd->old_file.id, diff, idx2wd->old_file.path,
idx2wd->old_file.size, &idx2wd->old_file.id)) idx2wd->old_file.mode, idx2wd->old_file.size))
idx2wd->old_file.flags |= GIT_DIFF_FLAG_VALID_ID; idx2wd->old_file.flags |= GIT_DIFF_FLAG_VALID_ID;
if (git_oid_iszero(&idx2wd->new_file.id) && if (git_oid_iszero(&idx2wd->new_file.id) &&
diff->new_src == GIT_ITERATOR_TYPE_WORKDIR && diff->new_src == GIT_ITERATOR_TYPE_WORKDIR &&
!git_diff__oid_for_file( !git_diff__oid_for_file(
diff->repo, idx2wd->new_file.path, idx2wd->new_file.mode, &idx2wd->new_file.id, diff, idx2wd->new_file.path,
idx2wd->new_file.size, &idx2wd->new_file.id)) idx2wd->new_file.mode, idx2wd->new_file.size))
idx2wd->new_file.flags |= GIT_DIFF_FLAG_VALID_ID; idx2wd->new_file.flags |= GIT_DIFF_FLAG_VALID_ID;
if (!git_oid_equal(&idx2wd->old_file.id, &idx2wd->new_file.id)) if (!git_oid_equal(&idx2wd->old_file.id, &idx2wd->new_file.id))
......
...@@ -436,4 +436,12 @@ GIT_INLINE(double) git__timer(void) ...@@ -436,4 +436,12 @@ GIT_INLINE(double) git__timer(void)
#endif #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__ */ #endif /* INCLUDE_util_h__ */
...@@ -2,6 +2,11 @@ ...@@ -2,6 +2,11 @@
#include "diff_helpers.h" #include "diff_helpers.h"
#include "repository.h" #include "repository.h"
#ifdef GIT_PERF
/* access to diff usage statistics */
# include "diff.h"
#endif
static git_repository *g_repo = NULL; static git_repository *g_repo = NULL;
void test_diff_workdir__initialize(void) void test_diff_workdir__initialize(void)
...@@ -58,6 +63,13 @@ void test_diff_workdir__to_index(void) ...@@ -58,6 +63,13 @@ void test_diff_workdir__to_index(void)
cl_assert_equal_i(5, exp.line_ctxt); cl_assert_equal_i(5, exp.line_ctxt);
cl_assert_equal_i(4, exp.line_adds); cl_assert_equal_i(4, exp.line_adds);
cl_assert_equal_i(5, exp.line_dels); 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); git_diff_free(diff);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment