diff options
author | Russell Belfer <rb@github.com> | 2014-02-11 14:45:37 -0800 |
---|---|---|
committer | Russell Belfer <rb@github.com> | 2014-04-17 14:43:45 -0700 |
commit | 40ed499039f887ebcb0b5badf0157519148398b8 (patch) | |
tree | abf8307b9960aed3eb6911fadc26bb0627b7ecf2 /tests/threads | |
parent | 3b4c401a38ce912d5be8c9bf4ab1c4912a4f08bd (diff) | |
download | libgit2-40ed499039f887ebcb0b5badf0157519148398b8.tar.gz |
Add diff threading tests and attr file cache locks
This adds a basic test of doing simultaneous diffs on multiple
threads and adds basic locking for the attr file cache because
that was the immediate problem that arose from these tests.
Diffstat (limited to 'tests/threads')
-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); +} |