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)
38 #include <semaphore.h>
40 #include <mach/mach_init.h>
41 #include <mach/mach_error.h>
42 #include <mach/semaphore.h>
43 #include <mach/task.h>
53 #include "radixsort.h"
55 #define DEFAULT_SORT_FUNC_RADIXSORT mergesort
57 #define TINY_NODE(sl) ((sl)->tosort_num < 65)
58 #define SMALL_NODE(sl) ((sl)->tosort_num < 5)
60 /* are we sorting in reverse order ? */
61 static bool reverse_sort
;
63 /* sort sub-levels array size */
64 static const size_t slsz
= 256 * sizeof(struct sort_level
*);
66 /* one sort level structure */
69 struct sort_level
**sublevels
;
70 struct sort_list_item
**leaves
;
71 struct sort_list_item
**sorted
;
72 struct sort_list_item
**tosort
;
77 size_t start_position
;
83 /* stack of sort levels ready to be sorted */
85 struct level_stack
*next
;
86 struct sort_level
*sl
;
89 static struct level_stack
*g_ls
;
91 #if defined(SORT_THREADS)
92 /* stack guarding mutex */
93 static pthread_cond_t g_ls_cond
;
94 static pthread_mutex_t g_ls_mutex
;
96 /* counter: how many items are left */
97 static size_t sort_left
;
100 /* semaphore to count threads */
108 * Decrement items counter
111 sort_left_dec(size_t n
)
113 pthread_mutex_lock(&g_ls_mutex
);
115 if (sort_left
== 0 && nthreads
> 1)
116 pthread_cond_broadcast(&g_ls_cond
);
117 pthread_mutex_unlock(&g_ls_mutex
);
121 * Do we have something to sort ?
123 * This routine does not need to be locked.
130 ret
= (sort_left
> 0);
137 #define sort_left_dec(n)
139 #endif /* SORT_THREADS */
142 * Push sort level to the stack
145 push_ls(struct sort_level
*sl
)
147 struct level_stack
*new_ls
;
149 new_ls
= sort_malloc(sizeof(struct level_stack
));
152 #if defined(SORT_THREADS)
154 pthread_mutex_lock(&g_ls_mutex
);
160 #if defined(SORT_THREADS)
162 pthread_cond_signal(&g_ls_cond
);
165 #if defined(SORT_THREADS)
167 pthread_mutex_unlock(&g_ls_mutex
);
172 * Pop sort level from the stack (single-threaded style)
174 static inline struct sort_level
*
177 struct sort_level
*sl
;
180 struct level_stack
*saved_ls
;
192 #if defined(SORT_THREADS)
195 * Pop sort level from the stack (multi-threaded style)
197 static inline struct sort_level
*
200 struct level_stack
*saved_ls
;
201 struct sort_level
*sl
;
203 pthread_mutex_lock(&g_ls_mutex
);
215 if (have_sort_left() == 0)
217 pthread_cond_wait(&g_ls_cond
, &g_ls_mutex
);
220 pthread_mutex_unlock(&g_ls_mutex
);
227 #endif /* defined(SORT_THREADS) */
230 add_to_sublevel(struct sort_level
*sl
, struct sort_list_item
*item
, size_t indx
)
232 struct sort_level
*ssl
;
234 ssl
= sl
->sublevels
[indx
];
237 ssl
= sort_malloc(sizeof(struct sort_level
));
238 memset(ssl
, 0, sizeof(struct sort_level
));
240 ssl
->level
= sl
->level
+ 1;
241 sl
->sublevels
[indx
] = ssl
;
246 if (++(ssl
->tosort_num
) > ssl
->tosort_sz
) {
247 ssl
->tosort_sz
= ssl
->tosort_num
+ 128;
248 ssl
->tosort
= sort_realloc(ssl
->tosort
,
249 sizeof(struct sort_list_item
*) * (ssl
->tosort_sz
));
252 ssl
->tosort
[ssl
->tosort_num
- 1] = item
;
256 add_leaf(struct sort_level
*sl
, struct sort_list_item
*item
)
259 if (++(sl
->leaves_num
) > sl
->leaves_sz
) {
260 sl
->leaves_sz
= sl
->leaves_num
+ 128;
261 sl
->leaves
= sort_realloc(sl
->leaves
,
262 (sizeof(struct sort_list_item
*) * (sl
->leaves_sz
)));
264 sl
->leaves
[sl
->leaves_num
- 1] = item
;
268 get_wc_index(struct sort_list_item
*sli
, size_t level
)
270 const struct key_value
*kv
;
271 const struct bwstring
*bws
;
273 kv
= get_key_from_keys_array(&sli
->ka
, 0);
276 if ((BWSLEN(bws
) > level
))
277 return (unsigned char) BWS_GET(bws
,level
);
282 place_item(struct sort_level
*sl
, size_t item
)
284 struct sort_list_item
*sli
;
287 sli
= sl
->tosort
[item
];
288 c
= get_wc_index(sli
, sl
->level
);
293 add_to_sublevel(sl
, sli
, c
);
297 free_sort_level(struct sort_level
*sl
)
302 sort_free(sl
->leaves
);
305 sort_free(sl
->tosort
);
308 struct sort_level
*slc
;
313 for (size_t i
= 0; i
< sln
; ++i
) {
314 slc
= sl
->sublevels
[i
];
316 free_sort_level(slc
);
319 sort_free(sl
->sublevels
);
327 run_sort_level_next(struct sort_level
*sl
)
329 struct sort_level
*slc
;
330 size_t i
, sln
, tosort_num
;
333 sort_free(sl
->sublevels
);
334 sl
->sublevels
= NULL
;
337 switch (sl
->tosort_num
) {
341 sl
->sorted
[sl
->start_position
] = sl
->tosort
[0];
345 if (list_coll_offset(&(sl
->tosort
[0]), &(sl
->tosort
[1]),
347 sl
->sorted
[sl
->start_position
++] = sl
->tosort
[1];
348 sl
->sorted
[sl
->start_position
] = sl
->tosort
[0];
350 sl
->sorted
[sl
->start_position
++] = sl
->tosort
[0];
351 sl
->sorted
[sl
->start_position
] = sl
->tosort
[1];
357 if (TINY_NODE(sl
) || (sl
->level
> 15)) {
360 func
= get_list_call_func(sl
->level
);
362 sl
->leaves
= sl
->tosort
;
363 sl
->leaves_num
= sl
->tosort_num
;
364 sl
->leaves_sz
= sl
->leaves_num
;
365 sl
->leaves
= sort_realloc(sl
->leaves
,
366 (sizeof(struct sort_list_item
*) *
373 if (sort_opts_vals
.sflag
) {
374 if (mergesort(sl
->leaves
, sl
->leaves_num
,
375 sizeof(struct sort_list_item
*),
376 (int(*)(const void *, const void *)) func
) == -1)
378 err(2, "Radix sort error 3");
380 DEFAULT_SORT_FUNC_RADIXSORT(sl
->leaves
, sl
->leaves_num
,
381 sizeof(struct sort_list_item
*),
382 (int(*)(const void *, const void *)) func
);
384 memcpy(sl
->sorted
+ sl
->start_position
,
385 sl
->leaves
, sl
->leaves_num
*
386 sizeof(struct sort_list_item
*));
388 sort_left_dec(sl
->leaves_num
);
392 sl
->tosort_sz
= sl
->tosort_num
;
393 sl
->tosort
= sort_realloc(sl
->tosort
,
394 sizeof(struct sort_list_item
*) * (sl
->tosort_sz
));
399 sl
->sublevels
= sort_malloc(slsz
);
400 memset(sl
->sublevels
, 0, slsz
);
404 tosort_num
= sl
->tosort_num
;
405 for (i
= 0; i
< tosort_num
; ++i
)
408 sort_free(sl
->tosort
);
413 if (sl
->leaves_num
> 1) {
415 if (sort_opts_vals
.sflag
) {
416 mergesort(sl
->leaves
, sl
->leaves_num
,
417 sizeof(struct sort_list_item
*),
418 (int(*)(const void *, const void *)) list_coll
);
420 DEFAULT_SORT_FUNC_RADIXSORT(sl
->leaves
, sl
->leaves_num
,
421 sizeof(struct sort_list_item
*),
422 (int(*)(const void *, const void *)) list_coll
);
424 } else if (!sort_opts_vals
.sflag
&& sort_opts_vals
.complex_sort
) {
425 DEFAULT_SORT_FUNC_RADIXSORT(sl
->leaves
, sl
->leaves_num
,
426 sizeof(struct sort_list_item
*),
427 (int(*)(const void *, const void *)) list_coll_by_str_only
);
431 sl
->leaves_sz
= sl
->leaves_num
;
432 sl
->leaves
= sort_realloc(sl
->leaves
, (sizeof(struct sort_list_item
*) *
436 memcpy(sl
->sorted
+ sl
->start_position
, sl
->leaves
,
437 sl
->leaves_num
* sizeof(struct sort_list_item
*));
438 sl
->start_position
+= sl
->leaves_num
;
439 sort_left_dec(sl
->leaves_num
);
441 sort_free(sl
->leaves
);
448 for (i
= 0; i
< sln
; ++i
) {
449 slc
= sl
->sublevels
[i
];
452 slc
->sorted
= sl
->sorted
;
453 slc
->start_position
= sl
->start_position
;
454 sl
->start_position
+= slc
->tosort_num
;
456 run_sort_level_next(slc
);
459 sl
->sublevels
[i
] = NULL
;
468 for (i
= 0; i
< sln
; ++i
) {
470 slc
= sl
->sublevels
[n
];
473 slc
->sorted
= sl
->sorted
;
474 slc
->start_position
= sl
->start_position
;
475 sl
->start_position
+= slc
->tosort_num
;
477 run_sort_level_next(slc
);
480 sl
->sublevels
[n
] = NULL
;
484 memcpy(sl
->sorted
+ sl
->start_position
, sl
->leaves
,
485 sl
->leaves_num
* sizeof(struct sort_list_item
*));
486 sort_left_dec(sl
->leaves_num
);
494 * Single-threaded sort cycle
497 run_sort_cycle_st(void)
499 struct sort_level
*slc
;
506 run_sort_level_next(slc
);
510 #if defined(SORT_THREADS)
513 * Multi-threaded sort cycle
516 run_sort_cycle_mt(void)
518 struct sort_level
*slc
;
524 run_sort_level_next(slc
);
529 * Sort cycle thread (in multi-threaded mode)
532 sort_thread(void* arg
)
540 semaphore_signal(rmtsem
);
546 #endif /* defined(SORT_THREADS) */
549 run_top_sort_level(struct sort_level
*sl
)
551 struct sort_level
*slc
;
553 reverse_sort
= sort_opts_vals
.kflag
? keys
[0].sm
.rflag
:
554 default_sort_mods
->rflag
;
556 sl
->start_position
= 0;
558 sl
->sublevels
= sort_malloc(slsz
);
559 memset(sl
->sublevels
, 0, slsz
);
561 for (size_t i
= 0; i
< sl
->tosort_num
; ++i
)
564 if (sl
->leaves_num
> 1) {
566 if (sort_opts_vals
.sflag
) {
567 mergesort(sl
->leaves
, sl
->leaves_num
,
568 sizeof(struct sort_list_item
*),
569 (int(*)(const void *, const void *)) list_coll
);
571 DEFAULT_SORT_FUNC_RADIXSORT(sl
->leaves
, sl
->leaves_num
,
572 sizeof(struct sort_list_item
*),
573 (int(*)(const void *, const void *)) list_coll
);
575 } else if (!sort_opts_vals
.sflag
&& sort_opts_vals
.complex_sort
) {
576 DEFAULT_SORT_FUNC_RADIXSORT(sl
->leaves
, sl
->leaves_num
,
577 sizeof(struct sort_list_item
*),
578 (int(*)(const void *, const void *)) list_coll_by_str_only
);
583 memcpy(sl
->tosort
+ sl
->start_position
, sl
->leaves
,
584 sl
->leaves_num
* sizeof(struct sort_list_item
*));
585 sl
->start_position
+= sl
->leaves_num
;
586 sort_left_dec(sl
->leaves_num
);
588 for (size_t i
= 0; i
< sl
->sln
; ++i
) {
589 slc
= sl
->sublevels
[i
];
592 slc
->sorted
= sl
->tosort
;
593 slc
->start_position
= sl
->start_position
;
594 sl
->start_position
+= slc
->tosort_num
;
596 sl
->sublevels
[i
] = NULL
;
603 for (size_t i
= 0; i
< sl
->sln
; ++i
) {
606 slc
= sl
->sublevels
[n
];
609 slc
->sorted
= sl
->tosort
;
610 slc
->start_position
= sl
->start_position
;
611 sl
->start_position
+= slc
->tosort_num
;
613 sl
->sublevels
[n
] = NULL
;
617 memcpy(sl
->tosort
+ sl
->start_position
, sl
->leaves
,
618 sl
->leaves_num
* sizeof(struct sort_list_item
*));
620 sort_left_dec(sl
->leaves_num
);
623 #if defined(SORT_THREADS)
627 #if defined(SORT_THREADS)
631 for(i
= 0; i
< nthreads
; ++i
) {
635 pthread_attr_init(&attr
);
637 pthread_attr_setdetachstate(&attr
,
640 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
644 int res
= pthread_create(&pth
, &attr
,
648 if (errno
== EAGAIN
) {
659 pthread_attr_destroy(&attr
);
662 for(i
= 0; i
< nthreads
; ++i
)
666 semaphore_wait(rmtsem
);
669 #endif /* defined(SORT_THREADS) */
673 run_sort(struct sort_list_item
**base
, size_t nmemb
)
675 struct sort_level
*sl
;
677 #if defined(SORT_THREADS)
678 size_t nthreads_save
= nthreads
;
679 if (nmemb
< MT_SORT_THRESHOLD
)
683 pthread_mutexattr_t mattr
;
685 pthread_mutexattr_init(&mattr
);
687 pthread_mutexattr_settype(&mattr
, PTHREAD_MUTEX_ADAPTIVE_NP
);
690 pthread_mutex_init(&g_ls_mutex
, &mattr
);
691 pthread_cond_init(&g_ls_cond
, NULL
);
693 pthread_mutexattr_destroy(&mattr
);
696 sem_init(&mtsem
, 0, 0);
699 mach_port_t self
= mach_task_self();
700 kern_return_t ret
= semaphore_create(self
, &rmtsem
, SYNC_POLICY_FIFO
, 0);
701 if (ret
!= KERN_SUCCESS
) {
710 sl
= sort_malloc(sizeof(struct sort_level
));
711 memset(sl
, 0, sizeof(struct sort_level
));
714 sl
->tosort_num
= nmemb
;
715 sl
->tosort_sz
= nmemb
;
717 #if defined(SORT_THREADS)
721 run_top_sort_level(sl
);
725 #if defined(SORT_THREADS)
731 mach_port_t self
= mach_task_self();
732 semaphore_destroy(self
,rmtsem
);
735 pthread_mutex_destroy(&g_ls_mutex
);
737 nthreads
= nthreads_save
;
742 rxsort(struct sort_list_item
**base
, size_t nmemb
)
745 run_sort(base
, nmemb
);