]> git.proxmox.com Git - libgit2.git/blame - tests/threads/diff.c
Minor tree cache speedups
[libgit2.git] / tests / threads / diff.c
CommitLineData
40ed4990
RB
1#include "clar_libgit2.h"
2#include "thread-utils.h"
3
8a2834d3
RB
4static git_repository *_repo;
5static git_tree *_a, *_b;
6static git_atomic _counts[4];
7static int _check_counts;
40ed4990
RB
8
9void test_threads_diff__cleanup(void)
10{
11 cl_git_sandbox_cleanup();
12}
13
14static void run_in_parallel(
15 int repeats, int threads, void *(*func)(void *),
16 void (*before_test)(void), void (*after_test)(void))
17{
18 int r, t, *id = git__calloc(threads, sizeof(int));
19#ifdef GIT_THREADS
20 git_thread *th = git__calloc(threads, sizeof(git_thread));
3816debc 21 cl_assert(th != NULL);
40ed4990
RB
22#else
23 void *th = NULL;
24#endif
25
3816debc 26 cl_assert(id != NULL);
40ed4990
RB
27
28 for (r = 0; r < repeats; ++r) {
8a2834d3 29 _repo = cl_git_sandbox_reopen(); /* reopen sandbox to flush caches */
40ed4990
RB
30
31 if (before_test) before_test();
32
33 for (t = 0; t < threads; ++t) {
34 id[t] = t;
35#ifdef GIT_THREADS
36 cl_git_pass(git_thread_create(&th[t], NULL, func, &id[t]));
37#else
38 cl_assert(func(&id[t]) == &id[t]);
39#endif
40 }
41
42#ifdef GIT_THREADS
43 for (t = 0; t < threads; ++t)
44 cl_git_pass(git_thread_join(th[t], NULL));
45 memset(th, 0, threads * sizeof(git_thread));
46#endif
47
48 if (after_test) after_test();
49 }
50
51 git__free(id);
52 git__free(th);
53}
54
55static void setup_trees(void)
56{
57 cl_git_pass(git_revparse_single(
8a2834d3 58 (git_object **)&_a, _repo, "0017bd4ab1^{tree}"));
40ed4990 59 cl_git_pass(git_revparse_single(
8a2834d3 60 (git_object **)&_b, _repo, "26a125ee1b^{tree}"));
40ed4990 61
8a2834d3 62 memset(_counts, 0, sizeof(_counts));
40ed4990
RB
63}
64
65#define THREADS 20
66
67static void free_trees(void)
68{
8a2834d3
RB
69 git_tree_free(_a); _a = NULL;
70 git_tree_free(_b); _b = NULL;
71
72 if (_check_counts) {
73 cl_assert_equal_i(288, git_atomic_get(&_counts[0]));
74 cl_assert_equal_i(112, git_atomic_get(&_counts[1]));
75 cl_assert_equal_i( 80, git_atomic_get(&_counts[2]));
76 cl_assert_equal_i( 96, git_atomic_get(&_counts[3]));
77 }
40ed4990
RB
78}
79
80static void *run_index_diffs(void *arg)
81{
82 int thread = *(int *)arg;
83 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
84 git_diff *diff = NULL;
85 size_t i;
86 int exp[4] = { 0, 0, 0, 0 };
87
40ed4990
RB
88 switch (thread & 0x03) {
89 case 0: /* diff index to workdir */;
8a2834d3 90 cl_git_pass(git_diff_index_to_workdir(&diff, _repo, NULL, &opts));
40ed4990
RB
91 break;
92 case 1: /* diff tree 'a' to index */;
8a2834d3 93 cl_git_pass(git_diff_tree_to_index(&diff, _repo, _a, NULL, &opts));
40ed4990
RB
94 break;
95 case 2: /* diff tree 'b' to index */;
8a2834d3 96 cl_git_pass(git_diff_tree_to_index(&diff, _repo, _b, NULL, &opts));
40ed4990
RB
97 break;
98 case 3: /* diff index to workdir (explicit index) */;
99 {
100 git_index *idx;
8a2834d3
RB
101 cl_git_pass(git_repository_index(&idx, _repo));
102 cl_git_pass(git_diff_index_to_workdir(&diff, _repo, idx, &opts));
40ed4990
RB
103 git_index_free(idx);
104 break;
105 }
106 }
107
40ed4990
RB
108 /* keep some diff stats to make sure results are as expected */
109
110 i = git_diff_num_deltas(diff);
8a2834d3 111 git_atomic_add(&_counts[0], (int32_t)i);
40ed4990
RB
112 exp[0] = (int)i;
113
114 while (i > 0) {
115 switch (git_diff_get_delta(diff, --i)->status) {
8a2834d3
RB
116 case GIT_DELTA_MODIFIED: exp[1]++; git_atomic_inc(&_counts[1]); break;
117 case GIT_DELTA_ADDED: exp[2]++; git_atomic_inc(&_counts[2]); break;
118 case GIT_DELTA_DELETED: exp[3]++; git_atomic_inc(&_counts[3]); break;
40ed4990
RB
119 default: break;
120 }
121 }
122
40ed4990
RB
123 switch (thread & 0x03) {
124 case 0: case 3:
125 cl_assert_equal_i(8, exp[0]); cl_assert_equal_i(4, exp[1]);
126 cl_assert_equal_i(0, exp[2]); cl_assert_equal_i(4, exp[3]);
127 break;
128 case 1:
129 cl_assert_equal_i(12, exp[0]); cl_assert_equal_i(3, exp[1]);
130 cl_assert_equal_i(7, exp[2]); cl_assert_equal_i(2, exp[3]);
131 break;
132 case 2:
133 cl_assert_equal_i(8, exp[0]); cl_assert_equal_i(3, exp[1]);
134 cl_assert_equal_i(3, exp[2]); cl_assert_equal_i(2, exp[3]);
135 break;
136 }
137
138 git_diff_free(diff);
139
140 return arg;
141}
142
143void test_threads_diff__concurrent_diffs(void)
144{
8a2834d3
RB
145 _repo = cl_git_sandbox_init("status");
146 _check_counts = 1;
40ed4990
RB
147
148 run_in_parallel(
149 20, 32, run_index_diffs, setup_trees, free_trees);
150}
8a2834d3
RB
151
152static void *run_index_diffs_with_modifier(void *arg)
153{
154 int thread = *(int *)arg;
155 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
156 git_diff *diff = NULL;
157 git_index *idx = NULL;
158
159 cl_git_pass(git_repository_index(&idx, _repo));
160
161 /* have first thread altering the index as we go */
162 if (thread == 0) {
163 int i;
164
165 for (i = 0; i < 300; ++i) {
166 switch (i & 0x03) {
167 case 0: (void)git_index_add_bypath(idx, "new_file"); break;
168 case 1: (void)git_index_remove_bypath(idx, "modified_file"); break;
169 case 2: (void)git_index_remove_bypath(idx, "new_file"); break;
170 case 3: (void)git_index_add_bypath(idx, "modified_file"); break;
171 }
172 git_thread_yield();
173 }
174
175 git_index_free(idx);
176 return arg;
177 }
178
179 /* only use explicit index in this test to prevent reloading */
180
181 switch (thread & 0x03) {
182 case 0: /* diff index to workdir */;
183 cl_git_pass(git_diff_index_to_workdir(&diff, _repo, idx, &opts));
184 break;
185 case 1: /* diff tree 'a' to index */;
186 cl_git_pass(git_diff_tree_to_index(&diff, _repo, _a, idx, &opts));
187 break;
188 case 2: /* diff tree 'b' to index */;
189 cl_git_pass(git_diff_tree_to_index(&diff, _repo, _b, idx, &opts));
190 break;
191 case 3: /* diff index to workdir reversed */;
192 opts.flags |= GIT_DIFF_REVERSE;
193 cl_git_pass(git_diff_index_to_workdir(&diff, _repo, idx, &opts));
194 break;
195 }
196
197 /* results will be unpredictable with index modifier thread running */
198
199 git_diff_free(diff);
200 git_index_free(idx);
201
202 return arg;
203}
204
205void test_threads_diff__with_concurrent_index_modified(void)
206{
207 _repo = cl_git_sandbox_init("status");
208 _check_counts = 0;
209
210 run_in_parallel(
211 20, 32, run_index_diffs_with_modifier, setup_trees, free_trees);
212}