Commit d97ba7f6744012fb51127d5313543a10c5a60e43

Jeff Hostetler 2015-02-06T15:45:59

Large merge perf test.

diff --git a/tests/perf/helper__perf__do_merge.c b/tests/perf/helper__perf__do_merge.c
new file mode 100644
index 0000000..0022185
--- /dev/null
+++ b/tests/perf/helper__perf__do_merge.c
@@ -0,0 +1,78 @@
+#include "clar_libgit2.h"
+#include "helper__perf__do_merge.h"
+#include "helper__perf__timer.h"
+
+static git_repository * g_repo;
+
+void perf__do_merge(const char *fixture,
+					const char *test_name,
+					const char *id_a,
+					const char *id_b)
+{
+	git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT;
+	git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT;
+	git_merge_options merge_opts = GIT_MERGE_OPTIONS_INIT;
+	git_oid oid_a;
+	git_oid oid_b;
+	git_reference *ref_branch_a = NULL;
+	git_reference *ref_branch_b = NULL;
+	git_commit *commit_a = NULL;
+	git_commit *commit_b = NULL;
+	git_annotated_commit *annotated_commits[1] = { NULL };
+	perf_timer t_total = PERF_TIMER_INIT;
+	perf_timer t_clone = PERF_TIMER_INIT;
+	perf_timer t_checkout = PERF_TIMER_INIT;
+	perf_timer t_merge = PERF_TIMER_INIT;
+
+	perf__timer__start(&t_total);
+
+	checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
+	clone_opts.checkout_opts = checkout_opts;
+	cl_git_pass(git_signature_now(&clone_opts.signature, "Me", "foo@example.com"));
+
+	perf__timer__start(&t_clone);
+	cl_git_pass(git_clone(&g_repo, fixture, test_name, &clone_opts));
+	perf__timer__stop(&t_clone);
+	
+	git_oid_fromstr(&oid_a, id_a);
+	cl_git_pass(git_commit_lookup(&commit_a, g_repo, &oid_a));
+	cl_git_pass(git_branch_create(&ref_branch_a, g_repo,
+								  "A", commit_a,
+								  0, NULL, NULL));
+
+	perf__timer__start(&t_checkout);
+	cl_git_pass(git_checkout_tree(g_repo, (git_object*)commit_a, &checkout_opts));
+	perf__timer__stop(&t_checkout);
+
+	cl_git_pass(git_repository_set_head(g_repo,
+										git_reference_name(ref_branch_a),
+										NULL, NULL));
+
+	git_oid_fromstr(&oid_b, id_b);
+	cl_git_pass(git_commit_lookup(&commit_b, g_repo, &oid_b));
+	cl_git_pass(git_branch_create(&ref_branch_b, g_repo,
+								  "B", commit_b,
+								  0, NULL, NULL));
+
+	cl_git_pass(git_annotated_commit_lookup(&annotated_commits[0], g_repo, &oid_b));
+
+	perf__timer__start(&t_merge);
+	cl_git_pass(git_merge(g_repo,
+						  (const git_annotated_commit **)annotated_commits, 1,
+						  &merge_opts, &checkout_opts));
+	perf__timer__stop(&t_merge);
+
+	git_reference_free(ref_branch_a);
+	git_reference_free(ref_branch_b);
+	git_commit_free(commit_a);
+	git_commit_free(commit_b);
+	git_annotated_commit_free(annotated_commits[0]);
+	git_repository_free(g_repo);
+
+	perf__timer__stop(&t_total);
+
+	perf__timer__report(&t_clone, "%s: clone", test_name);
+	perf__timer__report(&t_checkout, "%s: checkout", test_name);
+	perf__timer__report(&t_merge, "%s: merge", test_name);
+	perf__timer__report(&t_total, "%s: total", test_name);
+}
diff --git a/tests/perf/helper__perf__do_merge.h b/tests/perf/helper__perf__do_merge.h
new file mode 100644
index 0000000..4a4723d
--- /dev/null
+++ b/tests/perf/helper__perf__do_merge.h
@@ -0,0 +1,4 @@
+void perf__do_merge(const char *fixture,
+					const char *test_name,
+					const char *id_a,
+					const char *id_b);
diff --git a/tests/perf/helper__perf__timer.c b/tests/perf/helper__perf__timer.c
new file mode 100644
index 0000000..8a7ed09
--- /dev/null
+++ b/tests/perf/helper__perf__timer.c
@@ -0,0 +1,73 @@
+#include "clar_libgit2.h"
+#include "helper__perf__timer.h"
+
+#if defined(GIT_WIN32)
+
+void perf__timer__start(perf_timer *t)
+{
+	QueryPerformanceCounter(&t->time_started);
+}
+
+void perf__timer__stop(perf_timer *t)
+{
+	LARGE_INTEGER time_now;
+	QueryPerformanceCounter(&time_now);
+
+	t->sum.QuadPart += (time_now.QuadPart - t->time_started.QuadPart);
+}
+
+void perf__timer__report(perf_timer *t, const char *fmt, ...)
+{
+	va_list arglist;
+	LARGE_INTEGER freq;
+	double fraction;
+
+	QueryPerformanceFrequency(&freq);
+
+	fraction = ((double)t->sum.QuadPart) / ((double)freq.QuadPart);
+
+	printf("%10.3f: ", fraction);
+
+	va_start(arglist, fmt);
+	vprintf(fmt, arglist);
+	va_end(arglist);
+
+	printf("\n");
+}
+
+#else
+
+#include <sys/time.h>
+
+static uint32_t now_in_ms(void)
+{
+	struct timeval now;
+	gettimeofday(&now, NULL);
+	return (uint32_t)((now.tv_sec * 1000) + (now.tv_usec / 1000));
+}
+
+void perf__timer__start(perf_timer *t)
+{
+	t->time_started = now_in_ms();
+}
+
+void perf__timer__stop(perf_timer *t)
+{
+	uint32_t now = now_in_ms();
+	t->sum += (now - t->time_started);
+}
+
+void perf__timer__report(perf_timer *t, const char *fmt, ...)
+{
+	va_list arglist;
+
+	printf("%10.3f: ", ((double)t->sum) / 1000);
+
+	va_start(arglist, fmt);
+	vprintf(fmt, arglist);
+	va_end(arglist);
+
+	printf("\n");
+}
+
+#endif
diff --git a/tests/perf/helper__perf__timer.h b/tests/perf/helper__perf__timer.h
new file mode 100644
index 0000000..5aff4b1
--- /dev/null
+++ b/tests/perf/helper__perf__timer.h
@@ -0,0 +1,27 @@
+#if defined(GIT_WIN32)
+
+struct perf__timer
+{
+	LARGE_INTEGER sum;
+	LARGE_INTEGER time_started;
+};
+
+#define PERF_TIMER_INIT {0}
+
+#else
+
+struct perf__timer
+{
+	uint32_t sum;
+	uint32_t time_started;
+};
+
+#define PERF_TIMER_INIT {0}
+
+#endif
+
+typedef struct perf__timer perf_timer;
+
+void perf__timer__start(perf_timer *t);
+void perf__timer__stop(perf_timer *t);
+void perf__timer__report(perf_timer *t, const char *fmt, ...);
diff --git a/tests/perf/merge.c b/tests/perf/merge.c
new file mode 100644
index 0000000..b2ef082
--- /dev/null
+++ b/tests/perf/merge.c
@@ -0,0 +1,44 @@
+#include "clar_libgit2.h"
+#include "helper__perf__do_merge.h"
+
+/* This test requires a large repo with many files.
+ * It doesn't care about the contents, just the size.
+ * 
+ * For now, we use the LibGit2 repo containing the
+ * source tree because it is already here.
+ *
+ * `find . | wc -l` reports 5128.
+ * 
+ */
+#define SRC_REPO (cl_fixture("../.."))
+
+/* We need 2 arbitrary commits within that repo
+ * that have a large number of changed files.
+ * Again, we don't care about the actual contents,
+ * just the size.
+ *
+ * For now, we use these public branches:
+ * maint/v0.21 d853fb9f24e0fe63b3dce9fbc04fd9cfe17a030b Always checkout with case sensitive iterator
+ * maint/v0.22 1ce9ea3ba9b4fa666602d52a5281d41a482cc58b checkout tests: cleanup realpath impl on Win32
+ *
+ */
+#define ID_BRANCH_A "d853fb9f24e0fe63b3dce9fbc04fd9cfe17a030b"
+#define ID_BRANCH_B "1ce9ea3ba9b4fa666602d52a5281d41a482cc58b"
+
+
+void test_perf_merge__initialize(void)
+{
+}
+
+void test_perf_merge__cleanup(void)
+{
+}
+
+void test_perf_merge__m1(void)
+{
+#if 1
+	cl_skip();
+#else
+	perf__do_merge(SRC_REPO, "m1", ID_BRANCH_A, ID_BRANCH_B);
+#endif
+}