From a044787846f7b6628db703545bf40523b353f60d Mon Sep 17 00:00:00 2001 From: Richard Thier Date: Wed, 15 Dec 2021 03:14:35 +0100 Subject: [PATCH] finally again a real optimization and API for reusal - even faster for non-reused --- magyarsort.h | 123 ++++++++++++++++++++++++++++++++++++++++--- simd-sort/speed.cpp | 1 + simd-sort/speed_avx2 | Bin 92216 -> 96816 bytes test.cpp | 2 + ypsu.cpp | 4 ++ 5 files changed, 123 insertions(+), 7 deletions(-) diff --git a/magyarsort.h b/magyarsort.h index d7413b3..5c6fab1 100644 --- a/magyarsort.h +++ b/magyarsort.h @@ -216,17 +216,38 @@ namespace MagyarSort { }; - /** + /* * Sort the given array (in-place sorting) with the given size. * * Rem.: If you use the VectorGiverWithReuse please remind yourself to Gc() it time-to-time! * + * Beware: GC needs to happen on all threads that use us! + * * @param arr The array to sort. Result will be in the same array - as sorted. * @param size The lenght of the array. - * @param VectorGiver is either VectorGiverHeap or VectorGiverWithReuse. Have Give(size_t size, ...) returning value or ref. + * @param REUSE OPTIONAL: When true, we reuse the array instead of always gettin' and releasin' from da heap. + * @param GC OPTIONAL: When true, we garbage collect memory from previous sorts if REUSE is true. + * @param GC_WITHOUT_SORT OPTIONAL: When true, we "just GC" but do not sort in case of GC is true. */ - //template - inline void sort(uint32_t arr[], size_t size) noexcept { + template + inline void __attribute__((always_inline)) sort_impl(uint32_t arr[], size_t size) noexcept { + // Most funny optimization is this multiply here :-) + // + // Literally.. come on.. this makes it nearly a compile-time, macro-like + // ifdef-like thing as we avoid memory allocations of size BUT also we + // optimize the first call for sort when we REUSE the array so size is fine! + static thread_local std::vector arc(size * REUSE); + + // "Garbage-collection" + if(GC) { + arc = std::vector(); + // This must be implemented, because we can only access + // the static in our function body so this is the "way". + if(GC_WITHOUT_SORT) { + return; + } + } + // Holds "digit" occurences, prefix sums, whatevers // First "DIGIT_RANGE" elem is for MSB "DIGITS", last is for LSB static thread_local size_t radics[DIGITS * DIGIT_RANGE]; @@ -250,10 +271,19 @@ namespace MagyarSort { // above already anyways... // Regular radix sort needs a copy, see: https://www.youtube.com/watch?v=ujb2CIWE8zY + // But instead of the below, we do a trickery... + // //std::vector arc(size); //auto arc = VectorGiver::Give(size); // "auto" is needed for this to perform well with some givers! - static thread_local std::vector arc(size); - arc.resize(size); // JHP + // + // Rem.: The branch is optimized out in compile time! + if(REUSE) { + arc.resize(size); + } else { + // Must not be .clean() !!! + // We must regain memory of previous! + arc = std::move(std::vector(size)); + } uint32_t *from = arr; uint32_t *to = &arc[0]; @@ -262,11 +292,90 @@ namespace MagyarSort { // With an other API we could spare this copy if we can delete original arr and return ptr or something... // I am fine with this... this is not my main idea anyways, just little ILP tweak to regular radix sort - //if(to != arr) { // <- logically, but bad they are already swapped here!!! BEWARE + //if(to != arr) // <- logically, but bad they are already swapped here!!! BEWARE if(from != arr) { // <- in reality this is what we want because of last swap happened anyways! memcpy(arr, from, size); } } + + /** + * Garbage collect reused data structures from last call. + * + * This is optimized and is a NO-OP if MAGYAR_SORT_DEFAULT_REUSE is not defined! + * - unless you use the FORCE! May it be with you if you need it. + * + * @param FORCE OPTIONAL: When true, the gc happens even if MAGYAR_SORT_DEFAULT_REUSE is not defined! + */ + template + inline void gc() noexcept { + if(FORCE) { + // Only GC-ing + MagyarSort::sort_impl(nullptr, 0); + } else { +#ifdef MAGYAR_SORT_DEFAULT_REUSE + // Only GC-ing + MagyarSort::sort_impl(nullptr, 0); +#endif + } + } + + /** + * Sort the given array (in-place sorting) with the given size. + * + * Rem.: Please remind yourself to cc() from time-to-time! + * Rem.: Thread-safe to use! + * + * Beware: MagyarSort::gc(); needs to happen on all threads that use this variant otherwise memory leaks away! + * Please mind the "true" template parameter that forces the GC even when sort by default not reuses... + * + * @param arr The array to sort. Result will be in the same array - as sorted. + * @param size The lenght of the array. + * @param GC OPTIONAL: When true, we garbage collect before this sort - so cached memory size will be "size" elems. + */ + template + inline void __attribute__((always_inline)) sort_reuse(uint32_t arr[], size_t size) noexcept { + // Reuse the temporary vectors across runs + // This results in much less heap allocations and much faster on gcc + // and also a bit faster on clang too. + MagyarSort::sort_impl(arr, size); + } + + /** + * Sort the given array (in-place sorting) with the given size. + * + * Rem.: Thread-safe to use! + * + * Beware: MagyarSort::gc(); needs to happen on all threads that use this variant otherwise memory leaks away! + * + * @param arr The array to sort. Result will be in the same array - as sorted. + * @param size The lenght of the array. + */ + inline void __attribute__((always_inline)) sort_no_reuse(uint32_t arr[], size_t size) noexcept { + // We use the heap once per every call... + // This is safer and we do not need garbage collecting + MagyarSort::sort_impl(arr, size); + } + + /* + * Sort the given array (in-place sorting) with the given size. + * + * Rem.: If you use the VectorGiverWithReuse please remind yourself to Gc() it time-to-time! + * + * Beware: MagyarSort::gc(); should be called after "sort bursts" (consecutive fast sorts of when you need memory + * on all threads that use this variant otherwise memory leaks away as biggest sorted array keeps being in ram! + * This depends on the config #define MAGYAR_SORT_DEFAULT_REUSE is defined or not. Define and you get reuse + * and if you get reuse you can call multiple sorts with reused temporary buffers that you gc() afterwards! + * + * @param arr The array to sort. Result will be in the same array - as sorted. + * @param size The lenght of the array. + */ + inline void sort(uint32_t arr[], size_t size) noexcept { +#ifdef MAGYAR_SORT_DEFAULT_REUSE + MagyarSort::sort_reuse(arr, size); +#else + MagyarSort::sort_no_reuse(arr, size); +#endif + } }; #endif diff --git a/simd-sort/speed.cpp b/simd-sort/speed.cpp index aa58089..c60c1b4 100644 --- a/simd-sort/speed.cpp +++ b/simd-sort/speed.cpp @@ -14,6 +14,7 @@ #include "quicksort-all.cpp" #include "avx2-altquicksort.h" //#include "avx2-nate-quicksort.cpp" +#define MAGYAR_SORT_DEFAULT_REUSE #include "../magyarsort.h" // mine #include "avx2-natenodutch-quicksort.h" #define USE_RDTSC // undef to get measurments in seconds diff --git a/simd-sort/speed_avx2 b/simd-sort/speed_avx2 index 6bbb97af765ae7642175b092dcfdf2809fbc5db4..cb8adebd36a8834dee9207f8609ae94a0379768a 100755 GIT binary patch literal 96816 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 #include #include // std::sort + +#define MAGYAR_SORT_DEFAULT_REUSE #include "magyarsort.h" #ifdef SKA_SORT diff --git a/ypsu.cpp b/ypsu.cpp index 1d11e51..859887c 100644 --- a/ypsu.cpp +++ b/ypsu.cpp @@ -11,7 +11,11 @@ #include #include #include "ska_sort.hpp" + + + #define MAGYAR_SORT_DEFAULT_REUSE #include "magyarsort.h" + std::map results; std::map worst; void measure(const std::string &inputtype, const std::string &name,