2 * UCW Library -- Testing the Old Sorter
4 * (c) 2007 Martin Mares <mj@ucw.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU Lesser General Public License.
11 #include "lib/getopt.h"
13 #include "lib/fastbuf.h"
14 #include "lib/hashfunc.h"
23 /*** Time measurement ***/
25 static timestamp_t timer;
38 log(L_INFO, "Test took %.3fs", get_timer(&timer) / 1000.);
41 /*** Simple 4-byte integer keys ***/
47 static inline int s1_compare(struct key1 *x, struct key1 *y)
53 #define SORT_KEY struct key1
54 #define SORT_PREFIX(x) s1_##x
56 #define SORT_OUTPUT_FB
61 #include "lib/sorter.h"
64 test_int(int mode, u64 size)
66 uns N = size ? nextprime(MIN(size/4, 0xffff0000)) : 0;
68 log(L_INFO, ">>> Integers (%s, N=%u)", ((char *[]) { "increasing", "decreasing", "random" })[mode], N);
70 struct fastbuf *f = bopen_tmp(65536);
71 for (uns i=0; i<N; i++)
72 bputl(f, (mode==0) ? i : (mode==1) ? N-1-i : ((u64)i * K + 17) % N);
79 SORT_XTRACE(2, "Verifying");
80 for (uns i=0; i<N; i++)
84 die("Discrepancy: %u instead of %u", j, i);
89 /*** Longer records with hashes (similar to Shepherd's index records) ***/
97 static inline int s3_compare(struct key3 *x, struct key3 *y)
99 /* FIXME: Maybe unroll manually? */
100 for (uns i=0; i<4; i++)
101 COMPARE(x->hash[i], y->hash[i]);
105 #define SORT_KEY struct key3
106 #define SORT_PREFIX(x) s3_##x
107 #define SORT_INPUT_FB
108 #define SORT_OUTPUT_FB
112 #include "lib/sorter.h"
115 gen_hash_key(int mode, struct key3 *k, uns i)
118 k->payload[0] = 7*i + 13;
119 k->payload[1] = 13*i + 19;
120 k->payload[2] = 19*i + 7;
125 k->hash[1] = k->payload[0];
126 k->hash[2] = k->payload[1];
127 k->hash[3] = k->payload[2];
131 k->hash[1] = k->payload[0];
132 k->hash[2] = k->payload[1];
133 k->hash[3] = k->payload[2];
136 struct MD5Context ctx;
138 MD5Update(&ctx, (byte*) &k->i, 4);
139 MD5Final((byte*) &k->hash, &ctx);
145 test_hashes(int mode, u64 size)
147 uns N = MIN(size / sizeof(struct key3), 0xffffffff);
148 log(L_INFO, ">>> Hashes (%s, N=%u)", ((char *[]) { "increasing", "decreasing", "random" })[mode], N);
149 struct key3 k, lastk;
151 struct fastbuf *f = bopen_tmp(65536);
153 for (uns i=0; i<N; i++)
155 gen_hash_key(mode, &k, i);
156 hash_sum += k.hash[3];
157 bwrite(f, &k, sizeof(k));
165 SORT_XTRACE(2, "Verifying");
166 for (uns i=0; i<N; i++)
168 int ok = breadb(f, &k, sizeof(k));
170 if (i && s3_compare(&k, &lastk) <= 0)
172 gen_hash_key(mode, &lastk, k.i);
173 if (memcmp(&k, &lastk, sizeof(k)))
175 hash_sum -= k.hash[3];
181 /*** Variable-length records (strings) with and without var-length data ***/
190 static inline int s4_fetch_key(struct fastbuf *f, struct key4 *x)
196 breadb(f, x->s, len);
200 static inline void s4_copy_data(struct fastbuf *i UNUSED, struct fastbuf *f, struct key4 *x)
203 bwrite(f, x->s, x->len);
206 static inline int s4_compare(struct key4 *x, struct key4 *y)
208 uns l = MIN(x->len, y->len);
209 int c = memcmp(x->s, y->s, l);
212 COMPARE(x->len, y->len);
216 static inline byte *s4_fetch_item(struct fastbuf *f UNUSED, struct key4 *x, byte *limit UNUSED)
218 return &x->s[x->len];
221 static inline void s4_store_item(struct fastbuf *f, struct key4 *x)
223 s4_copy_data(NULL, f, x);
226 #define SORT_KEY struct key4
227 #define SORT_PREFIX(x) s4_##x
228 #define SORT_INPUT_FB
229 #define SORT_OUTPUT_FB
232 #include "lib/sorter.h"
234 #define s4b_compare s4_compare
235 #define s4b_fetch_key s4_fetch_key
237 static inline uns s4_data_size(struct key4 *x)
239 return x->len ? (x->s[0] ^ 0xad) : 0;
242 static inline void s4b_copy_data(struct fastbuf *i, struct fastbuf *f, struct key4 *x)
245 bwrite(f, x->s, x->len);
246 bbcopy(i, f, s4_data_size(x));
249 static inline byte *s4b_fetch_item(struct fastbuf *f, struct key4 *x, byte *limit)
251 byte *d = &x->s[x->len];
252 if (d + s4_data_size(x) > limit)
254 breadb(f, d, s4_data_size(x));
255 return d + s4_data_size(x);
258 static inline void s4b_store_item(struct fastbuf *f, struct key4 *x)
261 bwrite(f, x->s, x->len + s4_data_size(x));
264 #define SORT_KEY struct key4
265 #define SORT_PREFIX(x) s4b_##x
266 #define SORT_INPUT_FB
267 #define SORT_OUTPUT_FB
270 #include "lib/sorter.h"
273 gen_key4(struct key4 *k)
275 k->len = random_max(KEY4_MAX);
276 for (uns i=0; i<k->len; i++)
281 gen_data4(byte *buf, uns len, uns h)
291 test_strings(uns mode, u64 size)
293 uns avg_item_size = KEY4_MAX/2 + 4 + (mode ? 128 : 0);
294 uns N = MIN(size / avg_item_size, 0xffffffff);
295 log(L_INFO, ">>> Strings %s(N=%u)", (mode ? "with data " : ""), N);
298 struct key4 k, lastk;
299 byte buf[256], buf2[256];
302 struct fastbuf *f = bopen_tmp(65536);
303 for (uns i=0; i<N; i++)
306 s4_copy_data(NULL, f, &k);
307 uns h = hash_block(k.s, k.len);
311 gen_data4(buf, s4_data_size(&k), h);
312 bwrite(f, buf, s4_data_size(&k));
318 f = (mode ? s4b_sort : s4_sort)(f);
321 SORT_XTRACE(2, "Verifying");
322 for (uns i=0; i<N; i++)
324 int ok = s4_fetch_key(f, &k);
326 uns h = hash_block(k.s, k.len);
327 if (mode && s4_data_size(&k))
329 ok = breadb(f, buf, s4_data_size(&k));
331 gen_data4(buf2, s4_data_size(&k), h);
332 ASSERT(!memcmp(buf, buf2, s4_data_size(&k)));
334 if (i && s4_compare(&k, &lastk) < 0)
346 run_test(uns i, u64 size)
351 test_int(0, size); break;
353 test_int(1, size); break;
355 test_int(2, size); break;
361 test_hashes(0, size); break;
363 test_hashes(1, size); break;
365 test_hashes(2, size); break;
367 test_strings(0, size); break;
369 test_strings(1, size); break;
375 main(int argc, char **argv)
382 while ((c = cf_getopt(argc, argv, CF_SHORT_OPTS "s:t:v", CF_NO_LONG_OPTS, NULL)) >= 0)
386 if (cf_parse_u64(optarg, &size))
399 fputs("Usage: sort-test [-v] [-s <size>] [-t <test>]\n", stderr);
408 for (uns i=0; i<TMAX; i++)