diff options
Diffstat (limited to 'tests/threads/diff.c')
-rw-r--r-- | tests/threads/diff.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/tests/threads/diff.c b/tests/threads/diff.c new file mode 100644 index 000000000..33afc58ac --- /dev/null +++ b/tests/threads/diff.c @@ -0,0 +1,152 @@ +#include "clar_libgit2.h" +#include "thread-utils.h" + +static git_repository *g_repo; +static git_tree *a, *b; +static git_atomic counts[4]; + +void test_threads_diff__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +static void run_in_parallel( + int repeats, int threads, void *(*func)(void *), + void (*before_test)(void), void (*after_test)(void)) +{ + int r, t, *id = git__calloc(threads, sizeof(int)); +#ifdef GIT_THREADS + git_thread *th = git__calloc(threads, sizeof(git_thread)); +#else + void *th = NULL; +#endif + + cl_assert(id != NULL && th != NULL); + + for (r = 0; r < repeats; ++r) { + g_repo = cl_git_sandbox_reopen(); /* reopen sandbox to flush caches */ + + if (before_test) before_test(); + + for (t = 0; t < threads; ++t) { + id[t] = t; +#ifdef GIT_THREADS + cl_git_pass(git_thread_create(&th[t], NULL, func, &id[t])); +#else + cl_assert(func(&id[t]) == &id[t]); +#endif + } + +#ifdef GIT_THREADS + for (t = 0; t < threads; ++t) + cl_git_pass(git_thread_join(th[t], NULL)); + memset(th, 0, threads * sizeof(git_thread)); +#endif + + if (after_test) after_test(); + } + + git__free(id); + git__free(th); +} + +static void setup_trees(void) +{ + cl_git_pass(git_revparse_single( + (git_object **)&a, g_repo, "0017bd4ab1^{tree}")); + cl_git_pass(git_revparse_single( + (git_object **)&b, g_repo, "26a125ee1b^{tree}")); + + memset(counts, 0, sizeof(counts)); +} + +#define THREADS 20 + +static void free_trees(void) +{ + git_tree_free(a); a = NULL; + git_tree_free(b); b = NULL; + + cl_assert_equal_i(288, git_atomic_get(&counts[0])); + cl_assert_equal_i(112, git_atomic_get(&counts[1])); + cl_assert_equal_i( 80, git_atomic_get(&counts[2])); + cl_assert_equal_i( 96, git_atomic_get(&counts[3])); +} + +static void *run_index_diffs(void *arg) +{ + int thread = *(int *)arg; + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff *diff = NULL; + size_t i; + int exp[4] = { 0, 0, 0, 0 }; + +// fprintf(stderr, "%d >>>\n", thread); + + switch (thread & 0x03) { + case 0: /* diff index to workdir */; + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + break; + case 1: /* diff tree 'a' to index */; + cl_git_pass(git_diff_tree_to_index(&diff, g_repo, a, NULL, &opts)); + break; + case 2: /* diff tree 'b' to index */; + cl_git_pass(git_diff_tree_to_index(&diff, g_repo, b, NULL, &opts)); + break; + case 3: /* diff index to workdir (explicit index) */; + { + git_index *idx; + cl_git_pass(git_repository_index(&idx, g_repo)); + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, idx, &opts)); + git_index_free(idx); + break; + } + } + +// fprintf(stderr, "%d <<<\n", thread); + + /* keep some diff stats to make sure results are as expected */ + + i = git_diff_num_deltas(diff); + git_atomic_add(&counts[0], (int32_t)i); + exp[0] = (int)i; + + while (i > 0) { + switch (git_diff_get_delta(diff, --i)->status) { + case GIT_DELTA_MODIFIED: exp[1]++; git_atomic_inc(&counts[1]); break; + case GIT_DELTA_ADDED: exp[2]++; git_atomic_inc(&counts[2]); break; + case GIT_DELTA_DELETED: exp[3]++; git_atomic_inc(&counts[3]); break; + default: break; + } + } + +// fprintf(stderr, "%2d: [%d] total %d (M %d A %d D %d)\n", +// thread, (int)(thread & 0x03), exp[0], exp[1], exp[2], exp[3]); + + switch (thread & 0x03) { + case 0: case 3: + cl_assert_equal_i(8, exp[0]); cl_assert_equal_i(4, exp[1]); + cl_assert_equal_i(0, exp[2]); cl_assert_equal_i(4, exp[3]); + break; + case 1: + cl_assert_equal_i(12, exp[0]); cl_assert_equal_i(3, exp[1]); + cl_assert_equal_i(7, exp[2]); cl_assert_equal_i(2, exp[3]); + break; + case 2: + cl_assert_equal_i(8, exp[0]); cl_assert_equal_i(3, exp[1]); + cl_assert_equal_i(3, exp[2]); cl_assert_equal_i(2, exp[3]); + break; + } + + git_diff_free(diff); + + return arg; +} + +void test_threads_diff__concurrent_diffs(void) +{ + g_repo = cl_git_sandbox_init("status"); + + run_in_parallel( + 20, 32, run_index_diffs, setup_trees, free_trees); +} |