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 | |
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')
-rw-r--r-- | tests/clar_libgit2.h | 2 | ||||
-rw-r--r-- | tests/core/strmap.c | 72 | ||||
-rw-r--r-- | tests/threads/diff.c | 152 |
3 files changed, 188 insertions, 38 deletions
diff --git a/tests/clar_libgit2.h b/tests/clar_libgit2.h index c2489db38..d395bd66f 100644 --- a/tests/clar_libgit2.h +++ b/tests/clar_libgit2.h @@ -11,7 +11,7 @@ * * Use this wrapper around all `git_` library calls that return error codes! */ -#define cl_git_pass(expr) cl_git_pass_(expr, __FILE__, __LINE__) +#define cl_git_pass(expr) cl_git_pass_((expr), __FILE__, __LINE__) #define cl_git_pass_(expr, file, line) do { \ int _lg2_error; \ diff --git a/tests/core/strmap.c b/tests/core/strmap.c index f34a4f89f..a120f1feb 100644 --- a/tests/core/strmap.c +++ b/tests/core/strmap.c @@ -3,12 +3,22 @@ GIT__USE_STRMAP; +git_strmap *g_table; + +void test_core_strmap__initialize(void) +{ + cl_git_pass(git_strmap_alloc(&g_table)); + cl_assert(g_table != NULL); +} + +void test_core_strmap__cleanup(void) +{ + git_strmap_free(g_table); +} + void test_core_strmap__0(void) { - git_strmap *table = git_strmap_alloc(); - cl_assert(table != NULL); - cl_assert(git_strmap_num_entries(table) == 0); - git_strmap_free(table); + cl_assert(git_strmap_num_entries(g_table) == 0); } static void insert_strings(git_strmap *table, int count) @@ -37,21 +47,17 @@ void test_core_strmap__1(void) { int i; char *str; - git_strmap *table = git_strmap_alloc(); - cl_assert(table != NULL); - insert_strings(table, 20); + insert_strings(g_table, 20); - cl_assert(git_strmap_exists(table, "aaaaaaaaa")); - cl_assert(git_strmap_exists(table, "ggggggggg")); - cl_assert(!git_strmap_exists(table, "aaaaaaaab")); - cl_assert(!git_strmap_exists(table, "abcdefghi")); + cl_assert(git_strmap_exists(g_table, "aaaaaaaaa")); + cl_assert(git_strmap_exists(g_table, "ggggggggg")); + cl_assert(!git_strmap_exists(g_table, "aaaaaaaab")); + cl_assert(!git_strmap_exists(g_table, "abcdefghi")); i = 0; - git_strmap_foreach_value(table, str, { i++; free(str); }); + git_strmap_foreach_value(g_table, str, { i++; free(str); }); cl_assert(i == 20); - - git_strmap_free(table); } void test_core_strmap__2(void) @@ -59,44 +65,36 @@ void test_core_strmap__2(void) khiter_t pos; int i; char *str; - git_strmap *table = git_strmap_alloc(); - cl_assert(table != NULL); - insert_strings(table, 20); + insert_strings(g_table, 20); - cl_assert(git_strmap_exists(table, "aaaaaaaaa")); - cl_assert(git_strmap_exists(table, "ggggggggg")); - cl_assert(!git_strmap_exists(table, "aaaaaaaab")); - cl_assert(!git_strmap_exists(table, "abcdefghi")); + cl_assert(git_strmap_exists(g_table, "aaaaaaaaa")); + cl_assert(git_strmap_exists(g_table, "ggggggggg")); + cl_assert(!git_strmap_exists(g_table, "aaaaaaaab")); + cl_assert(!git_strmap_exists(g_table, "abcdefghi")); - cl_assert(git_strmap_exists(table, "bbbbbbbbb")); - pos = git_strmap_lookup_index(table, "bbbbbbbbb"); - cl_assert(git_strmap_valid_index(table, pos)); - cl_assert_equal_s(git_strmap_value_at(table, pos), "bbbbbbbbb"); - free(git_strmap_value_at(table, pos)); - git_strmap_delete_at(table, pos); + cl_assert(git_strmap_exists(g_table, "bbbbbbbbb")); + pos = git_strmap_lookup_index(g_table, "bbbbbbbbb"); + cl_assert(git_strmap_valid_index(g_table, pos)); + cl_assert_equal_s(git_strmap_value_at(g_table, pos), "bbbbbbbbb"); + free(git_strmap_value_at(g_table, pos)); + git_strmap_delete_at(g_table, pos); - cl_assert(!git_strmap_exists(table, "bbbbbbbbb")); + cl_assert(!git_strmap_exists(g_table, "bbbbbbbbb")); i = 0; - git_strmap_foreach_value(table, str, { i++; free(str); }); + git_strmap_foreach_value(g_table, str, { i++; free(str); }); cl_assert(i == 19); - - git_strmap_free(table); } void test_core_strmap__3(void) { int i; char *str; - git_strmap *table = git_strmap_alloc(); - cl_assert(table != NULL); - insert_strings(table, 10000); + insert_strings(g_table, 10000); i = 0; - git_strmap_foreach_value(table, str, { i++; free(str); }); + git_strmap_foreach_value(g_table, str, { i++; free(str); }); cl_assert(i == 10000); - - git_strmap_free(table); } 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); +} |