2 * Copyright (C) 2012 Oleg Moskalenko <mom040267@gmail.com>
3 * Copyright (C) 2012 Gabor Kovesdan <gabor@FreeBSD.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
35 #if defined(SORT_THREADS)
37 #include <semaphore.h>
46 #include "radixsort.h"
48 #define DEFAULT_SORT_FUNC_RADIXSORT mergesort
50 #define TINY_NODE(sl) ((sl)->tosort_num < 65)
51 #define SMALL_NODE(sl) ((sl)->tosort_num < 5)
53 /* are we sorting in reverse order ? */
54 static bool reverse_sort;
56 /* sort sub-levels array size */
57 static const size_t slsz = 256 * sizeof(struct sort_level*);
59 /* one sort level structure */
62 struct sort_level **sublevels;
63 struct sort_list_item **leaves;
64 struct sort_list_item **sorted;
65 struct sort_list_item **tosort;
70 size_t start_position;
76 /* stack of sort levels ready to be sorted */
78 struct level_stack *next;
79 struct sort_level *sl;
82 static struct level_stack *g_ls;
84 #if defined(SORT_THREADS)
85 /* stack guarding mutex */
86 static pthread_cond_t g_ls_cond;
87 static pthread_mutex_t g_ls_mutex;
89 /* counter: how many items are left */
90 static size_t sort_left;
93 /* semaphore to count threads */
97 * Decrement items counter
100 sort_left_dec(size_t n)
102 pthread_mutex_lock(&g_ls_mutex);
104 if (sort_left == 0 && nthreads > 1)
105 pthread_cond_broadcast(&g_ls_cond);
106 pthread_mutex_unlock(&g_ls_mutex);
110 * Do we have something to sort ?
112 * This routine does not need to be locked.
119 ret = (sort_left > 0);
126 #define sort_left_dec(n)
128 #endif /* SORT_THREADS */
131 * Push sort level to the stack
134 push_ls(struct sort_level* sl)
136 struct level_stack *new_ls;
138 new_ls = sort_malloc(sizeof(struct level_stack));
141 #if defined(SORT_THREADS)
143 pthread_mutex_lock(&g_ls_mutex);
149 #if defined(SORT_THREADS)
151 pthread_cond_signal(&g_ls_cond);
154 #if defined(SORT_THREADS)
156 pthread_mutex_unlock(&g_ls_mutex);
161 * Pop sort level from the stack (single-threaded style)
163 static inline struct sort_level*
166 struct sort_level *sl;
169 struct level_stack *saved_ls;
181 #if defined(SORT_THREADS)
184 * Pop sort level from the stack (multi-threaded style)
186 static inline struct sort_level*
189 struct level_stack *saved_ls;
190 struct sort_level *sl;
192 pthread_mutex_lock(&g_ls_mutex);
204 if (have_sort_left() == 0)
206 pthread_cond_wait(&g_ls_cond, &g_ls_mutex);
209 pthread_mutex_unlock(&g_ls_mutex);
216 #endif /* defined(SORT_THREADS) */
219 add_to_sublevel(struct sort_level *sl, struct sort_list_item *item, size_t indx)
221 struct sort_level *ssl;
223 ssl = sl->sublevels[indx];
226 ssl = sort_malloc(sizeof(struct sort_level));
227 memset(ssl, 0, sizeof(struct sort_level));
229 ssl->level = sl->level + 1;
230 sl->sublevels[indx] = ssl;
235 if (++(ssl->tosort_num) > ssl->tosort_sz) {
236 ssl->tosort_sz = ssl->tosort_num + 128;
237 ssl->tosort = sort_realloc(ssl->tosort,
238 sizeof(struct sort_list_item*) * (ssl->tosort_sz));
241 ssl->tosort[ssl->tosort_num - 1] = item;
245 add_leaf(struct sort_level *sl, struct sort_list_item *item)
248 if (++(sl->leaves_num) > sl->leaves_sz) {
249 sl->leaves_sz = sl->leaves_num + 128;
250 sl->leaves = sort_realloc(sl->leaves,
251 (sizeof(struct sort_list_item*) * (sl->leaves_sz)));
253 sl->leaves[sl->leaves_num - 1] = item;
257 get_wc_index(struct sort_list_item *sli, size_t level)
259 const struct bwstring *bws;
261 bws = sli->ka.key[0].k;
263 if ((BWSLEN(bws) > level))
264 return (unsigned char) BWS_GET(bws,level);
269 place_item(struct sort_level *sl, size_t item)
271 struct sort_list_item *sli;
274 sli = sl->tosort[item];
275 c = get_wc_index(sli, sl->level);
280 add_to_sublevel(sl, sli, c);
284 free_sort_level(struct sort_level *sl)
289 sort_free(sl->leaves);
292 sort_free(sl->tosort);
295 struct sort_level *slc;
300 for (size_t i = 0; i < sln; ++i) {
301 slc = sl->sublevels[i];
303 free_sort_level(slc);
306 sort_free(sl->sublevels);
314 run_sort_level_next(struct sort_level *sl)
316 struct sort_level *slc;
317 size_t i, sln, tosort_num;
320 sort_free(sl->sublevels);
321 sl->sublevels = NULL;
324 switch (sl->tosort_num){
328 sl->sorted[sl->start_position] = sl->tosort[0];
332 if (list_coll_offset(&(sl->tosort[0]), &(sl->tosort[1]),
334 sl->sorted[sl->start_position++] = sl->tosort[1];
335 sl->sorted[sl->start_position] = sl->tosort[0];
337 sl->sorted[sl->start_position++] = sl->tosort[0];
338 sl->sorted[sl->start_position] = sl->tosort[1];
344 if (TINY_NODE(sl) || (sl->level > 15)) {
347 func = get_list_call_func(sl->level);
349 sl->leaves = sl->tosort;
350 sl->leaves_num = sl->tosort_num;
351 sl->leaves_sz = sl->leaves_num;
352 sl->leaves = sort_realloc(sl->leaves,
353 (sizeof(struct sort_list_item *) *
360 if (sort_opts_vals.sflag) {
361 if (mergesort(sl->leaves, sl->leaves_num,
362 sizeof(struct sort_list_item *),
363 (int(*)(const void *, const void *)) func) == -1)
365 err(2, "Radix sort error 3");
367 DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num,
368 sizeof(struct sort_list_item *),
369 (int(*)(const void *, const void *)) func);
371 memcpy(sl->sorted + sl->start_position,
372 sl->leaves, sl->leaves_num *
373 sizeof(struct sort_list_item*));
375 sort_left_dec(sl->leaves_num);
379 sl->tosort_sz = sl->tosort_num;
380 sl->tosort = sort_realloc(sl->tosort,
381 sizeof(struct sort_list_item*) * (sl->tosort_sz));
386 sl->sublevels = sort_malloc(slsz);
387 memset(sl->sublevels, 0, slsz);
391 tosort_num = sl->tosort_num;
392 for (i = 0; i < tosort_num; ++i)
395 sort_free(sl->tosort);
400 if (sl->leaves_num > 1) {
402 if (sort_opts_vals.sflag) {
403 mergesort(sl->leaves, sl->leaves_num,
404 sizeof(struct sort_list_item *),
405 (int(*)(const void *, const void *)) list_coll);
407 DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num,
408 sizeof(struct sort_list_item *),
409 (int(*)(const void *, const void *)) list_coll);
411 } else if (!sort_opts_vals.sflag && sort_opts_vals.complex_sort) {
412 DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num,
413 sizeof(struct sort_list_item *),
414 (int(*)(const void *, const void *)) list_coll_by_str_only);
418 sl->leaves_sz = sl->leaves_num;
419 sl->leaves = sort_realloc(sl->leaves, (sizeof(struct sort_list_item *) *
423 memcpy(sl->sorted + sl->start_position, sl->leaves,
424 sl->leaves_num * sizeof(struct sort_list_item*));
425 sl->start_position += sl->leaves_num;
426 sort_left_dec(sl->leaves_num);
428 sort_free(sl->leaves);
435 for (i = 0; i < sln; ++i) {
436 slc = sl->sublevels[i];
439 slc->sorted = sl->sorted;
440 slc->start_position = sl->start_position;
441 sl->start_position += slc->tosort_num;
443 run_sort_level_next(slc);
446 sl->sublevels[i] = NULL;
455 for (i = 0; i < sln; ++i) {
457 slc = sl->sublevels[n];
460 slc->sorted = sl->sorted;
461 slc->start_position = sl->start_position;
462 sl->start_position += slc->tosort_num;
464 run_sort_level_next(slc);
467 sl->sublevels[n] = NULL;
471 memcpy(sl->sorted + sl->start_position, sl->leaves,
472 sl->leaves_num * sizeof(struct sort_list_item*));
473 sort_left_dec(sl->leaves_num);
481 * Single-threaded sort cycle
484 run_sort_cycle_st(void)
486 struct sort_level *slc;
493 run_sort_level_next(slc);
497 #if defined(SORT_THREADS)
500 * Multi-threaded sort cycle
503 run_sort_cycle_mt(void)
505 struct sort_level *slc;
511 run_sort_level_next(slc);
516 * Sort cycle thread (in multi-threaded mode)
519 sort_thread(void* arg)
527 #endif /* defined(SORT_THREADS) */
530 run_top_sort_level(struct sort_level *sl)
532 struct sort_level *slc;
534 reverse_sort = sort_opts_vals.kflag ? keys[0].sm.rflag :
535 default_sort_mods->rflag;
537 sl->start_position = 0;
539 sl->sublevels = sort_malloc(slsz);
540 memset(sl->sublevels, 0, slsz);
542 for (size_t i = 0; i < sl->tosort_num; ++i)
545 if (sl->leaves_num > 1) {
547 if (sort_opts_vals.sflag) {
548 mergesort(sl->leaves, sl->leaves_num,
549 sizeof(struct sort_list_item *),
550 (int(*)(const void *, const void *)) list_coll);
552 DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num,
553 sizeof(struct sort_list_item *),
554 (int(*)(const void *, const void *)) list_coll);
556 } else if (!sort_opts_vals.sflag && sort_opts_vals.complex_sort) {
557 DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num,
558 sizeof(struct sort_list_item *),
559 (int(*)(const void *, const void *)) list_coll_by_str_only);
564 memcpy(sl->tosort + sl->start_position, sl->leaves,
565 sl->leaves_num * sizeof(struct sort_list_item*));
566 sl->start_position += sl->leaves_num;
567 sort_left_dec(sl->leaves_num);
569 for (size_t i = 0; i < sl->sln; ++i) {
570 slc = sl->sublevels[i];
573 slc->sorted = sl->tosort;
574 slc->start_position = sl->start_position;
575 sl->start_position += slc->tosort_num;
577 sl->sublevels[i] = NULL;
584 for (size_t i = 0; i < sl->sln; ++i) {
587 slc = sl->sublevels[n];
590 slc->sorted = sl->tosort;
591 slc->start_position = sl->start_position;
592 sl->start_position += slc->tosort_num;
594 sl->sublevels[n] = NULL;
598 memcpy(sl->tosort + sl->start_position, sl->leaves,
599 sl->leaves_num * sizeof(struct sort_list_item*));
601 sort_left_dec(sl->leaves_num);
604 #if defined(SORT_THREADS)
608 #if defined(SORT_THREADS)
612 for(i = 0; i < nthreads; ++i) {
616 pthread_attr_init(&attr);
617 pthread_attr_setdetachstate(&attr, PTHREAD_DETACHED);
620 int res = pthread_create(&pth, &attr,
624 if (errno == EAGAIN) {
631 pthread_attr_destroy(&attr);
634 for (i = 0; i < nthreads; ++i)
637 #endif /* defined(SORT_THREADS) */
641 run_sort(struct sort_list_item **base, size_t nmemb)
643 struct sort_level *sl;
645 #if defined(SORT_THREADS)
646 size_t nthreads_save = nthreads;
647 if (nmemb < MT_SORT_THRESHOLD)
651 pthread_mutexattr_t mattr;
653 pthread_mutexattr_init(&mattr);
654 pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_ADAPTIVE_NP);
656 pthread_mutex_init(&g_ls_mutex, &mattr);
657 pthread_cond_init(&g_ls_cond, NULL);
659 pthread_mutexattr_destroy(&mattr);
661 sem_init(&mtsem, 0, 0);
666 sl = sort_malloc(sizeof(struct sort_level));
667 memset(sl, 0, sizeof(struct sort_level));
670 sl->tosort_num = nmemb;
671 sl->tosort_sz = nmemb;
673 #if defined(SORT_THREADS)
677 run_top_sort_level(sl);
681 #if defined(SORT_THREADS)
684 pthread_mutex_destroy(&g_ls_mutex);
686 nthreads = nthreads_save;
691 rxsort(struct sort_list_item **base, size_t nmemb)
694 run_sort(base, nmemb);