[utils] Explicitly check if the system has mincore instead of relying on mmap been...
[mono-project.git] / mono / unit-tests / test-conc-hashtable.c
blobed09d593b6ba19db889d7863654272b182737e14
1 /*
2 * test-conc-hashtable.c: Unit test for the concurrent hashtable.
4 * Copyright (C) 2014 Xamarin Inc
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License 2.0 as published by the Free Software Foundation;
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License 2.0 along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include "config.h"
22 #include "utils/mono-threads.h"
23 #include "utils/mono-conc-hashtable.h"
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28 #include <assert.h>
30 #include <pthread.h>
32 static int
33 single_writer_single_reader (void)
35 mono_mutex_t mutex;
36 MonoConcurrentHashTable *h;
37 int res = 0;
39 mono_mutex_init (&mutex);
40 h = mono_conc_hashtable_new (&mutex, NULL, NULL);
41 mono_conc_hashtable_insert (h, GUINT_TO_POINTER (10), GUINT_TO_POINTER (20));
42 mono_conc_hashtable_insert (h, GUINT_TO_POINTER (30), GUINT_TO_POINTER (40));
43 mono_conc_hashtable_insert (h, GUINT_TO_POINTER (50), GUINT_TO_POINTER (60));
44 mono_conc_hashtable_insert (h, GUINT_TO_POINTER (2), GUINT_TO_POINTER (3));
46 if (mono_conc_hashtable_lookup (h, GUINT_TO_POINTER (30)) != GUINT_TO_POINTER (40))
47 res = 1;
48 if (mono_conc_hashtable_lookup (h, GUINT_TO_POINTER (10)) != GUINT_TO_POINTER (20))
49 res = 2;
50 if (mono_conc_hashtable_lookup (h, GUINT_TO_POINTER (2)) != GUINT_TO_POINTER (3))
51 res = 3;
52 if (mono_conc_hashtable_lookup (h, GUINT_TO_POINTER (50)) != GUINT_TO_POINTER (60))
53 res = 4;
55 mono_conc_hashtable_destroy (h);
56 mono_mutex_destroy (&mutex);
57 if (res)
58 printf ("SERIAL TEST FAILED %d\n", res);
59 return res;
62 static MonoConcurrentHashTable *hash;
64 static void*
65 pw_sr_thread (void *arg)
67 int i, idx = 1000 * GPOINTER_TO_INT (arg);
68 mono_thread_info_attach ((gpointer)&arg);
70 for (i = 0; i < 1000; ++i)
71 mono_conc_hashtable_insert (hash, GINT_TO_POINTER (i + idx), GINT_TO_POINTER (i + 1));
72 return NULL;
75 static int
76 parallel_writer_single_reader (void)
78 pthread_t a,b,c;
79 mono_mutex_t mutex;
80 int i, j, res = 0;
82 mono_mutex_init (&mutex);
83 hash = mono_conc_hashtable_new (&mutex, NULL, NULL);
85 pthread_create (&a, NULL, pw_sr_thread, GINT_TO_POINTER (1));
86 pthread_create (&b, NULL, pw_sr_thread, GINT_TO_POINTER (2));
87 pthread_create (&c, NULL, pw_sr_thread, GINT_TO_POINTER (3));
89 pthread_join (a, NULL);
90 pthread_join (b, NULL);
91 pthread_join (c, NULL);
93 for (i = 0; i < 1000; ++i) {
94 for (j = 1; j < 4; ++j) {
95 if (mono_conc_hashtable_lookup (hash, GINT_TO_POINTER (j * 1000 + i)) != GINT_TO_POINTER (i + 1)) {
96 res = j + 1;
97 goto done;
102 done:
103 mono_conc_hashtable_destroy (hash);
104 mono_mutex_destroy (&mutex);
105 if (res)
106 printf ("PAR_WRITER_SINGLE_READER TEST FAILED %d\n", res);
107 return res;
111 static void*
112 pr_sw_thread (void *arg)
114 int i = 0, idx = 100 * GPOINTER_TO_INT (arg);
115 mono_thread_info_attach ((gpointer)&arg);
117 while (i < 100) {
118 gpointer res = mono_conc_hashtable_lookup (hash, GINT_TO_POINTER (i + idx + 1));
119 if (!res)
120 continue;
121 if (res != GINT_TO_POINTER ((i + idx) * 2 + 1))
122 return GINT_TO_POINTER (i);
123 ++i;
125 return NULL;
128 static int
129 single_writer_parallel_reader (void)
131 pthread_t a,b,c;
132 mono_mutex_t mutex;
133 gpointer ra, rb, rc;
134 int i, res = 0;
135 ra = rb = rc = GINT_TO_POINTER (1);
137 mono_mutex_init (&mutex);
138 hash = mono_conc_hashtable_new (&mutex, NULL, NULL);
140 pthread_create (&a, NULL, pr_sw_thread, GINT_TO_POINTER (0));
141 pthread_create (&b, NULL, pr_sw_thread, GINT_TO_POINTER (1));
142 pthread_create (&c, NULL, pr_sw_thread, GINT_TO_POINTER (2));
144 for (i = 0; i < 100; ++i) {
145 mono_conc_hashtable_insert (hash, GINT_TO_POINTER (i + 0 + 1), GINT_TO_POINTER ((i + 0) * 2 + 1));
146 mono_conc_hashtable_insert (hash, GINT_TO_POINTER (i + 100 + 1), GINT_TO_POINTER ((i + 100) * 2 + 1));
147 mono_conc_hashtable_insert (hash, GINT_TO_POINTER (i + 200 + 1), GINT_TO_POINTER ((i + 200) * 2 + 1));
150 pthread_join (a, &ra);
151 pthread_join (b, &rb);
152 pthread_join (c, &rc);
153 res = GPOINTER_TO_INT (ra) + GPOINTER_TO_INT (rb) + GPOINTER_TO_INT (rc);
155 mono_conc_hashtable_destroy (hash);
156 mono_mutex_destroy (&mutex);
157 if (res)
158 printf ("SINGLE_WRITER_PAR_READER TEST FAILED %d\n", res);
159 return res;
162 int running = 1;
164 static void*
165 pw_pr_r_thread (void *arg)
167 int key, val, i;
168 mono_thread_info_attach ((gpointer)&arg);
170 /* i will not be incremented as long as running is set to 1, this guarantee that
171 we loop over all the keys at least once after the writer threads have finished */
172 for (i = 0; i < 2; i += 1 - running) {
173 for (key = 1; key < 3 * 1000 + 1; key++) {
174 val = GPOINTER_TO_INT (mono_conc_hashtable_lookup (hash, GINT_TO_POINTER (key)));
176 if (!val)
177 continue;
178 if (key != val)
179 return GINT_TO_POINTER (key);
182 return NULL;
185 static void*
186 pw_pr_w_add_thread (void *arg)
188 int i, idx = 1000 * GPOINTER_TO_INT (arg);
190 mono_thread_info_attach ((gpointer)&arg);
192 for (i = idx; i < idx + 1000; i++)
193 mono_conc_hashtable_insert (hash, GINT_TO_POINTER (i + 1), GINT_TO_POINTER (i + 1));
194 return NULL;
197 static void*
198 pw_pr_w_del_thread (void *arg)
200 int i, idx = 1000 * GPOINTER_TO_INT (arg);
202 mono_thread_info_attach ((gpointer)&arg);
204 for (i = idx; i < idx + 1000; i++)
205 mono_conc_hashtable_remove (hash, GINT_TO_POINTER (i + 1));
206 return NULL;
209 static int
210 parallel_writer_parallel_reader (void)
212 pthread_t wa, wb, wc, ra, rb, rc;
213 mono_mutex_t mutex;
214 gpointer a, b, c;
215 int res = 0, i;
217 srand(time(NULL));
219 mono_mutex_init (&mutex);
220 hash = mono_conc_hashtable_new (&mutex, NULL, NULL);
222 for (i = 0; i < 2; i++) {
223 running = 1;
225 pthread_create (&ra, NULL, pw_pr_r_thread, NULL);
226 pthread_create (&rb, NULL, pw_pr_r_thread, NULL);
227 pthread_create (&rc, NULL, pw_pr_r_thread, NULL);
229 switch (i) {
230 case 0:
231 pthread_create (&wa, NULL, pw_pr_w_add_thread, GINT_TO_POINTER (0));
232 pthread_create (&wb, NULL, pw_pr_w_add_thread, GINT_TO_POINTER (1));
233 pthread_create (&wc, NULL, pw_pr_w_add_thread, GINT_TO_POINTER (2));
234 break;
235 case 1:
236 pthread_create (&wa, NULL, pw_pr_w_del_thread, GINT_TO_POINTER (0));
237 pthread_create (&wb, NULL, pw_pr_w_del_thread, GINT_TO_POINTER (1));
238 pthread_create (&wc, NULL, pw_pr_w_del_thread, GINT_TO_POINTER (2));
239 break;
242 pthread_join (wa, NULL);
243 pthread_join (wb, NULL);
244 pthread_join (wc, NULL);
246 running = 0;
248 pthread_join (ra, &a);
249 pthread_join (rb, &b);
250 pthread_join (rc, &c);
252 res += GPOINTER_TO_INT (a) + GPOINTER_TO_INT (b) + GPOINTER_TO_INT (c);
255 if (res)
256 printf ("PAR_WRITER_PAR_READER TEST FAILED %d %d %d\n", GPOINTER_TO_INT (a), GPOINTER_TO_INT (b), GPOINTER_TO_INT (c));
258 mono_conc_hashtable_destroy (hash);
259 mono_mutex_destroy (&mutex);
261 return res;
264 static void
265 benchmark_conc (void)
267 mono_mutex_t mutex;
268 MonoConcurrentHashTable *h;
269 int i, j;
271 mono_mutex_init (&mutex);
272 h = mono_conc_hashtable_new (&mutex, NULL, NULL);
274 for (i = 1; i < 10 * 1000; ++i)
275 mono_conc_hashtable_insert (h, GUINT_TO_POINTER (i), GUINT_TO_POINTER (i));
278 for (j = 0; j < 100000; ++j)
279 for (i = 1; i < 10 * 105; ++i)
280 mono_conc_hashtable_lookup (h, GUINT_TO_POINTER (i));
282 mono_conc_hashtable_destroy (h);
283 mono_mutex_destroy (&mutex);
287 static void
288 benchmark_glib (void)
290 GHashTable *h;
291 int i, j;
293 h = g_hash_table_new (NULL, NULL);
295 for (i = 1; i < 10 * 1000; ++i)
296 g_hash_table_insert (h, GUINT_TO_POINTER (i), GUINT_TO_POINTER (i));
299 for (j = 0; j < 100000; ++j)
300 for (i = 1; i < 10 * 105; ++i)
301 g_hash_table_lookup (h, GUINT_TO_POINTER (i));
303 g_hash_table_destroy (h);
307 main (void)
309 MonoThreadInfoCallbacks cb = { NULL };
310 int res = 0;
312 mono_threads_init (&cb, sizeof (MonoThreadInfo));
313 mono_thread_info_attach ((gpointer)&cb);
315 // benchmark_conc ();
316 // benchmark_glib ();
318 res += single_writer_single_reader ();
319 res += parallel_writer_single_reader ();
320 res += single_writer_parallel_reader ();
321 res += parallel_writer_parallel_reader ();
323 return res;