diff options
-rw-r--r-- | src/regress/lib/libc/qsort/qsort_test.c | 563 |
1 files changed, 421 insertions, 142 deletions
diff --git a/src/regress/lib/libc/qsort/qsort_test.c b/src/regress/lib/libc/qsort/qsort_test.c index 03d73216bd..8ab3d9f50d 100644 --- a/src/regress/lib/libc/qsort/qsort_test.c +++ b/src/regress/lib/libc/qsort/qsort_test.c | |||
@@ -35,13 +35,20 @@ | |||
35 | * M. D. McIlroy's "A Killer Adversary for Quicksort" | 35 | * M. D. McIlroy's "A Killer Adversary for Quicksort" |
36 | */ | 36 | */ |
37 | 37 | ||
38 | /* | ||
39 | * TODO: | ||
40 | * test with unaligned elements (char[]?) | ||
41 | */ | ||
38 | struct test_distribution { | 42 | struct test_distribution { |
39 | const char *name; | 43 | const char *name; |
40 | void (*fill)(int *x, int n, int m); | 44 | void (*fill)(void *x, int n, int m); |
41 | int (*test)(struct test_distribution *d, int n, int *x, int *y, int *z); | 45 | int (*test)(struct test_distribution *d, int n, void *x, void *y, void *z); |
46 | int (*cmp)(const void *v1, const void *v2); | ||
47 | int (*cmp_checked)(const void *v1, const void *v2); | ||
42 | }; | 48 | }; |
43 | 49 | ||
44 | #define min(a, b) (((a) < (b)) ? (a) : (b)) | 50 | #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) |
51 | #define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) | ||
45 | 52 | ||
46 | static size_t compares; | 53 | static size_t compares; |
47 | static size_t max_compares; | 54 | static size_t max_compares; |
@@ -52,7 +59,7 @@ static bool dump_table, timing, verbose; | |||
52 | extern int antiqsort(int n, int *a, int *ptr); | 59 | extern int antiqsort(int n, int *a, int *ptr); |
53 | 60 | ||
54 | static int | 61 | static int |
55 | cmp(const void *v1, const void *v2) | 62 | cmp_i(const void *v1, const void *v2) |
56 | { | 63 | { |
57 | const int a = *(const int *)v1; | 64 | const int a = *(const int *)v1; |
58 | const int b = *(const int *)v2; | 65 | const int b = *(const int *)v2; |
@@ -61,7 +68,7 @@ cmp(const void *v1, const void *v2) | |||
61 | } | 68 | } |
62 | 69 | ||
63 | static int | 70 | static int |
64 | cmp_checked(const void *v1, const void *v2) | 71 | cmp_checked_i(const void *v1, const void *v2) |
65 | { | 72 | { |
66 | const int a = *(const int *)v1; | 73 | const int a = *(const int *)v1; |
67 | const int b = *(const int *)v2; | 74 | const int b = *(const int *)v2; |
@@ -73,7 +80,49 @@ cmp_checked(const void *v1, const void *v2) | |||
73 | } | 80 | } |
74 | 81 | ||
75 | static int | 82 | static int |
76 | check_result(char *sub, int *got, int *expected, struct test_distribution *d, | 83 | cmp_ll(const void *v1, const void *v2) |
84 | { | ||
85 | const long long a = *(const long long *)v1; | ||
86 | const long long b = *(const long long *)v2; | ||
87 | |||
88 | return a > b ? 1 : a < b ? -1 : 0; | ||
89 | } | ||
90 | |||
91 | static int | ||
92 | cmp_checked_ll(const void *v1, const void *v2) | ||
93 | { | ||
94 | const long long a = *(const long long *)v1; | ||
95 | const long long b = *(const long long *)v2; | ||
96 | |||
97 | compares++; | ||
98 | if (compares > abrt_compares) | ||
99 | siglongjmp(cmpjmp, 1); | ||
100 | return a > b ? 1 : a < b ? -1 : 0; | ||
101 | } | ||
102 | |||
103 | static int | ||
104 | cmp_d(const void *v1, const void *v2) | ||
105 | { | ||
106 | const double a = *(const double *)v1; | ||
107 | const double b = *(const double *)v2; | ||
108 | |||
109 | return a > b ? 1 : a < b ? -1 : 0; | ||
110 | } | ||
111 | |||
112 | static int | ||
113 | cmp_checked_d(const void *v1, const void *v2) | ||
114 | { | ||
115 | const double a = *(const double *)v1; | ||
116 | const double b = *(const double *)v2; | ||
117 | |||
118 | compares++; | ||
119 | if (compares > abrt_compares) | ||
120 | siglongjmp(cmpjmp, 1); | ||
121 | return a > b ? 1 : a < b ? -1 : 0; | ||
122 | } | ||
123 | |||
124 | static int | ||
125 | check_result(char *sub, size_t es, char *got, char *expected, struct test_distribution *d, | ||
77 | int m, int n) | 126 | int m, int n) |
78 | { | 127 | { |
79 | int i; | 128 | int i; |
@@ -103,8 +152,10 @@ check_result(char *sub, int *got, int *expected, struct test_distribution *d, | |||
103 | } | 152 | } |
104 | 153 | ||
105 | for (i = 0; i < n; i++) { | 154 | for (i = 0; i < n; i++) { |
106 | if (got[i] != expected[i]) | 155 | if (memcmp(got, expected, es) != 0) |
107 | break; | 156 | break; |
157 | got += es; | ||
158 | expected += es; | ||
108 | } | 159 | } |
109 | if (i == n) | 160 | if (i == n) |
110 | return 0; | 161 | return 0; |
@@ -119,90 +170,228 @@ check_result(char *sub, int *got, int *expected, struct test_distribution *d, | |||
119 | return 1; | 170 | return 1; |
120 | } | 171 | } |
121 | 172 | ||
173 | #define FILL_SAWTOOTH(x, n, m) do { \ | ||
174 | int i; \ | ||
175 | \ | ||
176 | for (i = 0; i < n; i++) \ | ||
177 | x[i] = i % m; \ | ||
178 | } while (0) | ||
179 | |||
122 | static void | 180 | static void |
123 | fill_sawtooth(int *x, int n, int m) | 181 | fill_sawtooth_i(void *v, int n, int m) |
124 | { | 182 | { |
125 | int i; | 183 | int *x = v; |
184 | FILL_SAWTOOTH(x, n, m); | ||
185 | } | ||
126 | 186 | ||
127 | for (i = 0; i < n; i++) | 187 | static void |
128 | x[i] = i % m; | 188 | fill_sawtooth_ll(void *v, int n, int m) |
189 | { | ||
190 | long long *x = v; | ||
191 | FILL_SAWTOOTH(x, n, m); | ||
129 | } | 192 | } |
130 | 193 | ||
131 | static void | 194 | static void |
132 | fill_random(int *x, int n, int m) | 195 | fill_sawtooth_double(void *v, int n, int m) |
133 | { | 196 | { |
134 | int i; | 197 | double *x = v; |
198 | FILL_SAWTOOTH(x, n, m); | ||
199 | } | ||
200 | |||
201 | #define FILL_RANDOM(x, n, m) do { \ | ||
202 | int i; \ | ||
203 | \ | ||
204 | for (i = 0; i < n; i++) \ | ||
205 | x[i] = arc4random_uniform(m); \ | ||
206 | } while (0) | ||
135 | 207 | ||
136 | for (i = 0; i < n; i++) | 208 | |
137 | x[i] = arc4random_uniform(m); | 209 | static void |
210 | fill_random_i(void *v, int n, int m) | ||
211 | { | ||
212 | int *x = v; | ||
213 | FILL_RANDOM(x, n, m); | ||
138 | } | 214 | } |
139 | 215 | ||
140 | static void | 216 | static void |
141 | fill_stagger(int *x, int n, int m) | 217 | fill_random_ll(void *v, int n, int m) |
142 | { | 218 | { |
143 | int i; | 219 | long long *x = v; |
220 | FILL_RANDOM(x, n, m); | ||
221 | } | ||
144 | 222 | ||
145 | for (i = 0; i < n; i++) | 223 | static void |
146 | x[i] = (i * m + i) % n; | 224 | fill_random_double(void *v, int n, int m) |
225 | { | ||
226 | double *x = v; | ||
227 | FILL_RANDOM(x, n, m); | ||
147 | } | 228 | } |
148 | 229 | ||
230 | #define FILL_STAGGER(x, n, m) do { \ | ||
231 | int i; \ | ||
232 | \ | ||
233 | for (i = 0; i < n; i++) \ | ||
234 | x[i] = (i * m + i) % n; \ | ||
235 | } while (0) | ||
236 | |||
237 | |||
149 | static void | 238 | static void |
150 | fill_plateau(int *x, int n, int m) | 239 | fill_stagger_i(void *v, int n, int m) |
151 | { | 240 | { |
152 | int i; | 241 | int *x = v; |
242 | FILL_STAGGER(x, n, m); | ||
243 | } | ||
153 | 244 | ||
154 | for (i = 0; i < n; i++) | 245 | static void |
155 | x[i] = min(i, m); | 246 | fill_stagger_ll(void *v, int n, int m) |
247 | { | ||
248 | long long *x = v; | ||
249 | FILL_STAGGER(x, n, m); | ||
156 | } | 250 | } |
157 | 251 | ||
158 | static void | 252 | static void |
159 | fill_shuffle(int *x, int n, int m) | 253 | fill_stagger_double(void *v, int n, int m) |
160 | { | 254 | { |
161 | int i, j, k; | 255 | double *x = v; |
256 | FILL_STAGGER(x, n, m); | ||
257 | } | ||
258 | |||
259 | #define FILL_PLATEAU(x, n, m) do { \ | ||
260 | int i; \ | ||
261 | \ | ||
262 | for (i = 0; i < n; i++) \ | ||
263 | x[i] = MINIMUM(i, m); \ | ||
264 | } while (0) | ||
162 | 265 | ||
163 | for (i = 0, j = 0, k = 1; i < n; i++) | 266 | static void |
164 | x[i] = arc4random_uniform(m) ? (j += 2) : (k += 2); | 267 | fill_plateau_i(void *v, int n, int m) |
268 | { | ||
269 | int *x = v; | ||
270 | FILL_PLATEAU(x, n, m); | ||
165 | } | 271 | } |
166 | 272 | ||
167 | static void | 273 | static void |
168 | fill_bsd_killer(int *x, int n, int m) | 274 | fill_plateau_ll(void *v, int n, int m) |
169 | { | 275 | { |
170 | int i, k; | 276 | long long *x = v; |
277 | FILL_PLATEAU(x, n, m); | ||
278 | } | ||
171 | 279 | ||
172 | /* 4.4BSD insertion sort optimization killer, Mats Linander */ | 280 | static void |
173 | k = n / 2; | 281 | fill_plateau_double(void *v, int n, int m) |
174 | for (i = 0; i < n; i++) { | 282 | { |
175 | if (i < k) | 283 | double *x = v; |
176 | x[i] = k - i; | 284 | FILL_PLATEAU(x, n, m); |
177 | else if (i > k) | ||
178 | x[i] = n + k + 1 - i; | ||
179 | else | ||
180 | x[i] = k + 1; | ||
181 | } | ||
182 | } | 285 | } |
183 | 286 | ||
287 | #define FILL_SHUFFLE(x, n, m) do { \ | ||
288 | int i, j, k; \ | ||
289 | \ | ||
290 | for (i = 0, j = 0, k = 1; i < n; i++) \ | ||
291 | x[i] = arc4random_uniform(m) ? (j += 2) : (k += 2); \ | ||
292 | } while (0) | ||
293 | |||
184 | static void | 294 | static void |
185 | fill_med3_killer(int *x, int n, int m) | 295 | fill_shuffle_i(void *v, int n, int m) |
186 | { | 296 | { |
187 | int i, k; | 297 | int *x = v; |
298 | FILL_SHUFFLE(x, n, m); | ||
299 | } | ||
188 | 300 | ||
189 | /* | 301 | static void |
190 | * Median of 3 killer, as seen in David R Musser's | 302 | fill_shuffle_ll(void *v, int n, int m) |
191 | * "Introspective Sorting and Selection Algorithms" | 303 | { |
192 | */ | 304 | long long *x = v; |
193 | if (n & 1) { | 305 | FILL_SHUFFLE(x, n, m); |
194 | /* odd size, store last at end and make even. */ | 306 | } |
195 | x[n - 1] = n; | 307 | |
196 | n--; | 308 | static void |
197 | } | 309 | fill_shuffle_double(void *v, int n, int m) |
198 | k = n / 2; | 310 | { |
199 | for (i = 0; i < n; i++) { | 311 | double *x = v; |
200 | if (i & 1) { | 312 | FILL_SHUFFLE(x, n, m); |
201 | x[i] = k + x[i - 1]; | 313 | } |
202 | } else { | 314 | |
203 | x[i] = i + 1; | 315 | #define FILL_BSD_KILLER(x, n, m) do { \ |
204 | } | 316 | int i, k; \ |
205 | } | 317 | \ |
318 | /* 4.4BSD insertion sort optimization killer, Mats Linander */ \ | ||
319 | k = n / 2; \ | ||
320 | for (i = 0; i < n; i++) { \ | ||
321 | if (i < k) \ | ||
322 | x[i] = k - i; \ | ||
323 | else if (i > k) \ | ||
324 | x[i] = n + k + 1 - i; \ | ||
325 | else \ | ||
326 | x[i] = k + 1; \ | ||
327 | } \ | ||
328 | } while (0) | ||
329 | |||
330 | static void | ||
331 | fill_bsd_killer_i(void *v, int n, int m) | ||
332 | { | ||
333 | int *x = v; | ||
334 | FILL_BSD_KILLER(x, n, m); | ||
335 | |||
336 | } | ||
337 | |||
338 | static void | ||
339 | fill_bsd_killer_ll(void *v, int n, int m) | ||
340 | { | ||
341 | long long *x = v; | ||
342 | FILL_BSD_KILLER(x, n, m); | ||
343 | |||
344 | } | ||
345 | |||
346 | static void | ||
347 | fill_bsd_killer_double(void *v, int n, int m) | ||
348 | { | ||
349 | double *x = v; | ||
350 | FILL_BSD_KILLER(x, n, m); | ||
351 | |||
352 | } | ||
353 | |||
354 | #define FILL_MED3_KILLER(x, n, m) do { \ | ||
355 | int i, k; \ | ||
356 | \ | ||
357 | /* \ | ||
358 | * Median of 3 killer, as seen in David R Musser's \ | ||
359 | * "Introspective Sorting and Selection Algorithms" \ | ||
360 | */ \ | ||
361 | if (n & 1) { \ | ||
362 | /* odd size, store last at end and make even. */ \ | ||
363 | x[n - 1] = n; \ | ||
364 | n--; \ | ||
365 | } \ | ||
366 | k = n / 2; \ | ||
367 | for (i = 0; i < n; i++) { \ | ||
368 | if (i & 1) { \ | ||
369 | x[i] = k + x[i - 1]; \ | ||
370 | } else { \ | ||
371 | x[i] = i + 1; \ | ||
372 | } \ | ||
373 | } \ | ||
374 | } while (0) | ||
375 | |||
376 | static void | ||
377 | fill_med3_killer_i(void *v, int n, int m) | ||
378 | { | ||
379 | int *x = v; | ||
380 | FILL_MED3_KILLER(x, n, m); | ||
381 | } | ||
382 | |||
383 | static void | ||
384 | fill_med3_killer_ll(void *v, int n, int m) | ||
385 | { | ||
386 | long long *x = v; | ||
387 | FILL_MED3_KILLER(x, n, m); | ||
388 | } | ||
389 | |||
390 | static void | ||
391 | fill_med3_killer_double(void *v, int n, int m) | ||
392 | { | ||
393 | double *x = v; | ||
394 | FILL_MED3_KILLER(x, n, m); | ||
206 | } | 395 | } |
207 | 396 | ||
208 | static void | 397 | static void |
@@ -228,7 +417,7 @@ print_timing(struct test_distribution *d, char *sub, int m, int n, double elapse | |||
228 | } | 417 | } |
229 | 418 | ||
230 | static int | 419 | static int |
231 | do_test(struct test_distribution *d, char *sub, int m, int n, int *y, int *z) | 420 | do_test(struct test_distribution *d, char *sub, int m, int n, size_t es, void *y, void *z) |
232 | { | 421 | { |
233 | int ret = 0; | 422 | int ret = 0; |
234 | struct timespec before, after; | 423 | struct timespec before, after; |
@@ -246,7 +435,7 @@ do_test(struct test_distribution *d, char *sub, int m, int n, int *y, int *z) | |||
246 | } else { | 435 | } else { |
247 | if (timing) | 436 | if (timing) |
248 | clock_gettime(CLOCK_MONOTONIC, &before); | 437 | clock_gettime(CLOCK_MONOTONIC, &before); |
249 | qsort(y, n, sizeof(y[0]), cmp_checked); | 438 | qsort(y, n, es, d->cmp_checked); |
250 | if (timing) { | 439 | if (timing) { |
251 | double elapsed; | 440 | double elapsed; |
252 | clock_gettime(CLOCK_MONOTONIC, &after); | 441 | clock_gettime(CLOCK_MONOTONIC, &after); |
@@ -254,98 +443,162 @@ do_test(struct test_distribution *d, char *sub, int m, int n, int *y, int *z) | |||
254 | elapsed = after.tv_sec + after.tv_nsec / 1000000000.0; | 443 | elapsed = after.tv_sec + after.tv_nsec / 1000000000.0; |
255 | print_timing(d, sub, m, n, elapsed); | 444 | print_timing(d, sub, m, n, elapsed); |
256 | } | 445 | } |
257 | if (check_result(sub, y, z, d, m, n) != 0) | 446 | if (check_result(sub, es, y, z, d, m, n) != 0) |
258 | ret = 1; | 447 | ret = 1; |
259 | } | 448 | } |
260 | return ret; | 449 | return ret; |
261 | } | 450 | } |
262 | 451 | ||
452 | #define TEST_PERTURBED(d, n, x, y, z) do { \ | ||
453 | int i, j, m; \ | ||
454 | const int es = sizeof(x[0]); \ | ||
455 | \ | ||
456 | for (m = 1; m < 2 * n; m *= 2) { \ | ||
457 | /* Fill in x[n] modified by m */ \ | ||
458 | d->fill(x, n, m); \ | ||
459 | \ | ||
460 | /* Test on copy of x[] */ \ | ||
461 | for (i = 0; i < n; i++) \ | ||
462 | y[i] = z[i] = x[i]; \ | ||
463 | if (mergesort(z, n, es, d->cmp) != 0) \ | ||
464 | err(1, NULL); \ | ||
465 | if (do_test(d, "copy", m, n, es, y, z) != 0) \ | ||
466 | ret = 1; \ | ||
467 | \ | ||
468 | /* Test on reversed copy of x[] */ \ | ||
469 | for (i = 0, j = n - 1; i < n; i++, j--) \ | ||
470 | y[i] = z[i] = x[j]; \ | ||
471 | if (mergesort(z, n, es, d->cmp) != 0) \ | ||
472 | err(1, NULL); \ | ||
473 | if (do_test(d, "reversed", m, n, es, y, z) != 0) \ | ||
474 | ret = 1; \ | ||
475 | \ | ||
476 | /* Test with front half of x[] reversed */ \ | ||
477 | for (i = 0, j = (n / 2) - 1; i < n / 2; i++, j--) \ | ||
478 | y[i] = z[i] = x[j]; \ | ||
479 | for (; i < n; i++) \ | ||
480 | y[i] = z[i] = x[i]; \ | ||
481 | if (mergesort(z, n, es, d->cmp) != 0) \ | ||
482 | err(1, NULL); \ | ||
483 | if (do_test(d, "front reversed", m, n, es, y, z) != 0) \ | ||
484 | ret = 1; \ | ||
485 | \ | ||
486 | /* Test with back half of x[] reversed */ \ | ||
487 | for (i = 0; i < n / 2; i++) \ | ||
488 | y[i] = z[i] = x[i]; \ | ||
489 | for (j = n - 1; i < n; i++, j--) \ | ||
490 | y[i] = z[i] = x[j]; \ | ||
491 | if (mergesort(z, n, es, d->cmp) != 0) \ | ||
492 | err(1, NULL); \ | ||
493 | if (do_test(d, "back reversed", m, n, es, y, z) != 0) \ | ||
494 | ret = 1; \ | ||
495 | \ | ||
496 | /* Test on sorted copy of x[] */ \ | ||
497 | if (mergesort(x, n, es, d->cmp) != 0) \ | ||
498 | err(1, NULL); \ | ||
499 | for (i = 0; i < n; i++) \ | ||
500 | y[i] = x[i]; \ | ||
501 | if (do_test(d, "sorted", m, n, es, y, x) != 0) \ | ||
502 | ret = 1; \ | ||
503 | \ | ||
504 | /* Test with i%5 added to x[i] (dither) */ \ | ||
505 | for (i = 0, j = n - 1; i < n; i++, j--) \ | ||
506 | y[i] = z[i] = x[j] + (i % 5); \ | ||
507 | if (mergesort(z, n, es, d->cmp) != 0) \ | ||
508 | err(1, NULL); \ | ||
509 | if (do_test(d, "dithered", m, n, es, y, z) != 0) \ | ||
510 | ret = 1; \ | ||
511 | } \ | ||
512 | } while (0) | ||
513 | |||
263 | static int | 514 | static int |
264 | test_perturbed(struct test_distribution *d, int n, int *x, int *y, int *z) | 515 | test_perturbed_i(struct test_distribution *d, int n, void *vx, void *vy, void *vz) |
265 | { | 516 | { |
266 | int i, j, m; | 517 | int *x = vx; |
518 | int *y = vx; | ||
519 | int *z = vz; | ||
267 | int ret = 0; | 520 | int ret = 0; |
268 | 521 | ||
269 | for (m = 1; m < 2 * n; m *= 2) { | 522 | TEST_PERTURBED(d, n, x, y, z); |
270 | /* Fill in x[n] modified by m */ | 523 | return ret; |
271 | d->fill(x, n, m); | 524 | } |
272 | |||
273 | /* Test on copy of x[] */ | ||
274 | for (i = 0; i < n; i++) | ||
275 | y[i] = z[i] = x[i]; | ||
276 | if (mergesort(z, n, sizeof(z[0]), cmp) != 0) | ||
277 | err(1, NULL); | ||
278 | if (do_test(d, "copy", m, n, y, z) != 0) | ||
279 | ret = 1; | ||
280 | |||
281 | /* Test on reversed copy of x[] */ | ||
282 | for (i = 0, j = n - 1; i < n; i++, j--) | ||
283 | y[i] = z[i] = x[j]; | ||
284 | if (mergesort(z, n, sizeof(z[0]), cmp) != 0) | ||
285 | err(1, NULL); | ||
286 | if (do_test(d, "reversed", m, n, y, z) != 0) | ||
287 | ret = 1; | ||
288 | |||
289 | /* Test with front half of x[] reversed */ | ||
290 | for (i = 0, j = (n / 2) - 1; i < n / 2; i++, j--) | ||
291 | y[i] = z[i] = x[j]; | ||
292 | for (; i < n; i++) | ||
293 | y[i] = z[i] = x[i]; | ||
294 | if (mergesort(z, n, sizeof(z[0]), cmp) != 0) | ||
295 | err(1, NULL); | ||
296 | if (do_test(d, "front reversed", m, n, y, z) != 0) | ||
297 | ret = 1; | ||
298 | 525 | ||
299 | /* Test with back half of x[] reversed */ | 526 | static int |
300 | for (i = 0; i < n / 2; i++) | 527 | test_perturbed_ll(struct test_distribution *d, int n, void *vx, void *vy, void *vz) |
301 | y[i] = z[i] = x[i]; | 528 | { |
302 | for (j = n - 1; i < n; i++, j--) | 529 | long long *x = vx; |
303 | y[i] = z[i] = x[j]; | 530 | long long *y = vx; |
304 | if (mergesort(z, n, sizeof(z[0]), cmp) != 0) | 531 | long long *z = vz; |
305 | err(1, NULL); | 532 | int ret = 0; |
306 | if (do_test(d, "back reversed", m, n, y, z) != 0) | ||
307 | ret = 1; | ||
308 | 533 | ||
309 | /* Test on sorted copy of x[] */ | 534 | TEST_PERTURBED(d, n, x, y, z); |
310 | if (mergesort(x, n, sizeof(x[0]), cmp) != 0) | 535 | return ret; |
311 | err(1, NULL); | 536 | } |
312 | for (i = 0; i < n; i++) | ||
313 | y[i] = x[i]; | ||
314 | if (do_test(d, "sorted", m, n, y, x) != 0) | ||
315 | ret = 1; | ||
316 | 537 | ||
317 | /* Test with i%5 added to x[i] (dither) */ | 538 | static int |
318 | for (i = 0, j = n - 1; i < n; i++, j--) | 539 | test_perturbed_double(struct test_distribution *d, int n, void *vx, void *vy, void *vz) |
319 | y[i] = z[i] = x[j] + (i % 5); | 540 | { |
320 | if (mergesort(z, n, sizeof(z[0]), cmp) != 0) | 541 | double *x = vx; |
321 | err(1, NULL); | 542 | double *y = vx; |
322 | if (do_test(d, "front reversed", m, n, y, z) != 0) | 543 | double *z = vz; |
323 | ret = 1; | 544 | int ret = 0; |
324 | } | ||
325 | 545 | ||
546 | TEST_PERTURBED(d, n, x, y, z); | ||
326 | return ret; | 547 | return ret; |
327 | } | 548 | } |
328 | 549 | ||
329 | /* | 550 | /* |
330 | * Like test_perturbed() but because the input is tailored to cause | 551 | * Like TEST_PERTURBED but because the input is tailored to cause |
331 | * quicksort to go quadratic we don't perturb the input. | 552 | * quicksort to go quadratic we don't perturb the input. |
332 | */ | 553 | */ |
554 | #define TEST_SIMPLE(d, n, x, y, z) do { \ | ||
555 | int i, ret = 0; \ | ||
556 | \ | ||
557 | /* Fill in x[n] */ \ | ||
558 | d->fill(x, n, 0); \ | ||
559 | \ | ||
560 | /* Make a copy of x[] */ \ | ||
561 | for (i = 0; i < n; i++) \ | ||
562 | y[i] = z[i] = x[i]; \ | ||
563 | if (mergesort(z, n, sizeof(z[0]), d->cmp) != 0) \ | ||
564 | err(1, NULL); \ | ||
565 | if (do_test(d, NULL, 0, n, sizeof(x[0]), y, z) != 0) \ | ||
566 | ret = 1; \ | ||
567 | } while (0) | ||
568 | |||
333 | static int | 569 | static int |
334 | test_simple(struct test_distribution *d, int n, int *x, int *y, int *z) | 570 | test_simple_i(struct test_distribution *d, int n, void *vx, void *vy, void *vz) |
335 | { | 571 | { |
336 | int i, ret = 0; | 572 | int *x = vx; |
573 | int *y = vx; | ||
574 | int *z = vz; | ||
575 | int ret = 0; | ||
337 | 576 | ||
338 | /* Fill in x[n] */ | 577 | TEST_SIMPLE(d, n, x, y, z); |
339 | d->fill(x, n, 0); | 578 | return ret; |
579 | } | ||
340 | 580 | ||
341 | /* Make a copy of x[] */ | 581 | static int |
342 | for (i = 0; i < n; i++) | 582 | test_simple_ll(struct test_distribution *d, int n, void *vx, void *vy, void *vz) |
343 | y[i] = z[i] = x[i]; | 583 | { |
344 | if (mergesort(z, n, sizeof(z[0]), cmp) != 0) | 584 | long long *x = vx; |
345 | err(1, NULL); | 585 | long long *y = vx; |
346 | if (do_test(d, NULL, 0, n, y, z) != 0) | 586 | long long *z = vz; |
347 | ret = 1; | 587 | int ret = 0; |
348 | 588 | ||
589 | TEST_SIMPLE(d, n, x, y, z); | ||
590 | return ret; | ||
591 | } | ||
592 | |||
593 | static int | ||
594 | test_simple_double(struct test_distribution *d, int n, void *vx, void *vy, void *vz) | ||
595 | { | ||
596 | double *x = vx; | ||
597 | double *y = vx; | ||
598 | double *z = vz; | ||
599 | int ret = 0; | ||
600 | |||
601 | TEST_SIMPLE(d, n, x, y, z); | ||
349 | return ret; | 602 | return ret; |
350 | } | 603 | } |
351 | 604 | ||
@@ -354,9 +607,11 @@ test_simple(struct test_distribution *d, int n, int *x, int *y, int *z) | |||
354 | * We don't compare the results in this case. | 607 | * We don't compare the results in this case. |
355 | */ | 608 | */ |
356 | static int | 609 | static int |
357 | test_antiqsort(struct test_distribution *d, int n, int *x, int *y, int *z) | 610 | test_antiqsort(struct test_distribution *d, int n, void *vx, void *vy, void *vz) |
358 | { | 611 | { |
359 | struct timespec before, after; | 612 | struct timespec before, after; |
613 | int *x = vx; | ||
614 | int *y = vx; | ||
360 | int i, ret = 0; | 615 | int i, ret = 0; |
361 | 616 | ||
362 | /* | 617 | /* |
@@ -396,23 +651,38 @@ test_antiqsort(struct test_distribution *d, int n, int *x, int *y, int *z) | |||
396 | } | 651 | } |
397 | 652 | ||
398 | static struct test_distribution distributions[] = { | 653 | static struct test_distribution distributions[] = { |
399 | { "sawtooth", fill_sawtooth, test_perturbed }, | 654 | { "sawtooth_i", fill_sawtooth_i, test_perturbed_i, cmp_i, cmp_checked_i }, |
400 | { "random", fill_random, test_perturbed }, | 655 | { "sawtooth_ll", fill_sawtooth_ll, test_perturbed_ll, cmp_ll, cmp_checked_ll }, |
401 | { "stagger", fill_stagger, test_perturbed }, | 656 | { "sawtooth_d", fill_sawtooth_double, test_perturbed_double, cmp_d, cmp_checked_d }, |
402 | { "plateau", fill_plateau, test_perturbed }, | 657 | { "random_i", fill_random_i, test_perturbed_i, cmp_i, cmp_checked_i }, |
403 | { "shuffle", fill_shuffle, test_perturbed }, | 658 | { "random_ll", fill_random_ll, test_perturbed_ll, cmp_ll, cmp_checked_ll }, |
404 | { "bsd_killer", fill_bsd_killer, test_simple }, | 659 | { "random_d", fill_random_double, test_perturbed_double, cmp_d, cmp_checked_d }, |
405 | { "med3_killer", fill_med3_killer, test_simple }, | 660 | { "stagger_i", fill_stagger_i, test_perturbed_i, cmp_i, cmp_checked_i }, |
406 | { "antiqsort", NULL, test_antiqsort }, | 661 | { "stagger_ll", fill_stagger_ll, test_perturbed_ll, cmp_ll, cmp_checked_ll }, |
662 | { "stagger_d", fill_stagger_double, test_perturbed_double, cmp_d, cmp_checked_d }, | ||
663 | { "plateau_i", fill_plateau_i, test_perturbed_i, cmp_i, cmp_checked_i }, | ||
664 | { "plateau_ll", fill_plateau_ll, test_perturbed_ll, cmp_ll, cmp_checked_ll }, | ||
665 | { "plateau_d", fill_plateau_double, test_perturbed_double, cmp_d, cmp_checked_d }, | ||
666 | { "shuffle_i", fill_shuffle_i, test_perturbed_i, cmp_i, cmp_checked_i }, | ||
667 | { "shuffle_ll", fill_shuffle_ll, test_perturbed_ll, cmp_ll, cmp_checked_ll }, | ||
668 | { "shuffle_d", fill_shuffle_double, test_perturbed_double, cmp_d, cmp_checked_d }, | ||
669 | { "bsd_killer_i", fill_bsd_killer_i, test_simple_i, cmp_i, cmp_checked_i }, | ||
670 | { "bsd_killer_ll", fill_bsd_killer_ll, test_simple_ll, cmp_ll, cmp_checked_ll }, | ||
671 | { "bsd_killer_d", fill_bsd_killer_double, test_simple_double, cmp_d, cmp_checked_d }, | ||
672 | { "med3_killer_i", fill_med3_killer_i, test_simple_i, cmp_i, cmp_checked_i }, | ||
673 | { "med3_killer_ll", fill_med3_killer_ll, test_simple_ll, cmp_ll, cmp_checked_ll }, | ||
674 | { "med3_killer_d", fill_med3_killer_double, test_simple_double, cmp_d, cmp_checked_d }, | ||
675 | { "antiqsort", NULL, test_antiqsort, cmp_i, cmp_checked_i }, | ||
407 | { NULL } | 676 | { NULL } |
408 | }; | 677 | }; |
409 | 678 | ||
410 | static int | 679 | static int |
411 | run_tests(int n, const char *name) | 680 | run_tests(int n, const char *name) |
412 | { | 681 | { |
413 | int *x, *y, *z; | 682 | void *x, *y, *z; |
414 | int i, nlgn = 0; | 683 | int i, nlgn = 0; |
415 | int ret = 0; | 684 | int ret = 0; |
685 | size_t es; | ||
416 | struct test_distribution *d; | 686 | struct test_distribution *d; |
417 | 687 | ||
418 | /* | 688 | /* |
@@ -426,14 +696,16 @@ run_tests(int n, const char *name) | |||
426 | max_compares = nlgn * 1.5; | 696 | max_compares = nlgn * 1.5; |
427 | abrt_compares = nlgn * 10; | 697 | abrt_compares = nlgn * 10; |
428 | 698 | ||
429 | x = reallocarray(NULL, n, sizeof(x[0])); | 699 | /* Allocate enough space to store ints or doubles. */ |
430 | y = reallocarray(NULL, n, sizeof(y[0])); | 700 | es = MAXIMUM(sizeof(int), sizeof(double)); |
431 | z = reallocarray(NULL, n, sizeof(z[0])); | 701 | x = reallocarray(NULL, n, es); |
702 | y = reallocarray(NULL, n, es); | ||
703 | z = reallocarray(NULL, n, es); | ||
432 | if (x == NULL || y == NULL || z == NULL) | 704 | if (x == NULL || y == NULL || z == NULL) |
433 | err(1, NULL); | 705 | err(1, NULL); |
434 | 706 | ||
435 | for (d = distributions; d->name != NULL; d++) { | 707 | for (d = distributions; d->name != NULL; d++) { |
436 | if (name != NULL && strcmp(name, d->name) != 0) | 708 | if (name != NULL && strncmp(name, d->name, strlen(name)) != 0) |
437 | continue; | 709 | continue; |
438 | if (d->test(d, n, x, y, z) != 0) | 710 | if (d->test(d, n, x, y, z) != 0) |
439 | ret = 1; | 711 | ret = 1; |
@@ -456,6 +728,7 @@ int | |||
456 | main(int argc, char *argv[]) | 728 | main(int argc, char *argv[]) |
457 | { | 729 | { |
458 | char *nums[] = { "100", "1023", "1024", "1025", "4095", "4096", "4097" }; | 730 | char *nums[] = { "100", "1023", "1024", "1025", "4095", "4096", "4097" }; |
731 | struct test_distribution *d; | ||
459 | int ch, n, ret = 0; | 732 | int ch, n, ret = 0; |
460 | char *name = NULL; | 733 | char *name = NULL; |
461 | 734 | ||
@@ -465,6 +738,12 @@ main(int argc, char *argv[]) | |||
465 | dump_table = true; | 738 | dump_table = true; |
466 | break; | 739 | break; |
467 | case 'n': | 740 | case 'n': |
741 | for (d = distributions; d->name != NULL; d++) { | ||
742 | if (strncmp(optarg, d->name, strlen(optarg)) == 0) | ||
743 | break; | ||
744 | } | ||
745 | if (d->name == NULL) | ||
746 | errx(1, "unknown test %s", optarg); | ||
468 | name = optarg; | 747 | name = optarg; |
469 | break; | 748 | break; |
470 | case 't': | 749 | case 't': |