8333133: Simplify QuickSort::sort

Reviewed-by: shade, dholmes
This commit is contained in:
Kim Barrett 2024-06-26 05:15:36 +00:00
parent c66f785fb6
commit 25c3845be2
11 changed files with 33 additions and 125 deletions

View File

@ -568,7 +568,7 @@ Array<ModuleEntry*>* ModuleEntryTable::allocate_archived_entries() {
if (n > 1) {
// Always allocate in the same order to produce deterministic archive.
QuickSort::sort(archived_modules->data(), n, (_sort_Fn)compare_module_by_name, true);
QuickSort::sort(archived_modules->data(), n, compare_module_by_name);
}
for (int i = 0; i < n; i++) {
archived_modules->at_put(i, archived_modules->at(i)->allocate_archived_entry());

View File

@ -300,7 +300,8 @@ Array<PackageEntry*>* PackageEntryTable::allocate_archived_entries() {
_table.iterate_all(grab);
if (n > 1) {
QuickSort::sort(archived_packages->data(), n, (_sort_Fn)compare_package_by_name, true);
// Always allocate in the same order to produce deterministic archive.
QuickSort::sort(archived_packages->data(), n, compare_package_by_name);
}
for (int i = 0; i < n; i++) {
archived_packages->at_put(i, archived_packages->at(i)->allocate_archived_entry());

View File

@ -604,7 +604,7 @@ void CompilationMemoryStatistic::print_all_by_size(outputStream* st, bool human_
st->print_cr("(%d/%d)", num, _the_table->number_of_entries());
}
if (num > 0) {
QuickSort::sort(filtered, num, diff_entries_by_size, false);
QuickSort::sort(filtered, num, diff_entries_by_size);
// Now print. Has to happen under lock protection too, since entries may be changed.
for (int i = 0; i < num; i ++) {
filtered[i]->print_on(st, human_readable);

View File

@ -383,7 +383,7 @@ void G1CollectionSet::finalize_old_part(double time_remaining_ms) {
double non_young_end_time_sec = os::elapsedTime();
phase_times()->record_non_young_cset_choice_time_ms((non_young_end_time_sec - non_young_start_time_sec) * 1000.0);
QuickSort::sort(_collection_set_regions, _collection_set_cur_length, compare_region_idx, true);
QuickSort::sort(_collection_set_regions, _collection_set_cur_length, compare_region_idx);
}
void G1CollectionSet::move_candidates_to_collection_set(G1CollectionCandidateRegionList* regions) {

View File

@ -359,8 +359,7 @@ class G1RefineBufferedCards : public StackObj {
void sort_cards(size_t start_index) {
QuickSort::sort(&_node_buffer[start_index],
_node_buffer_capacity - start_index,
compare_cards,
false);
compare_cards);
}
// Returns the index to the first clean card in the buffer.

View File

@ -97,7 +97,7 @@ void ShenandoahAdaptiveHeuristics::choose_collection_set_from_regiondata(Shenand
byte_size_in_proper_unit(min_garbage), proper_unit_for_byte_size(min_garbage));
// Better select garbage-first regions
QuickSort::sort<RegionData>(data, (int)size, compare_by_garbage, false);
QuickSort::sort(data, size, compare_by_garbage);
size_t cur_cset = 0;
size_t cur_garbage = 0;

View File

@ -322,7 +322,7 @@ void LogSelection::suggest_similar_matching(outputStream* out) const {
// Sort found suggestions to suggest the best one first
SimilarityComparator sc(*this);
QuickSort::sort(suggestions, nsuggestions, sc, false);
QuickSort::sort(suggestions, nsuggestions, sc);
out->print("Did you mean any of the following?");
for (size_t i = 0; i < nsuggestions; i++) {

View File

@ -1733,7 +1733,7 @@ void Method::sort_methods(Array<Method*>* methods, bool set_idnums, method_compa
}
{
NoSafepointVerifier nsv;
QuickSort::sort(methods->data(), length, func, /*idempotent=*/false);
QuickSort::sort(methods->data(), length, func);
}
// Reset method ordering
if (set_idnums) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,25 +26,23 @@
#define SHARE_UTILITIES_QUICKSORT_HPP
#include "memory/allStatic.hpp"
#include "runtime/globals.hpp"
#include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp"
class QuickSort : AllStatic {
private:
template<class T>
static void swap(T* array, size_t x, size_t y) {
T tmp = array[x];
array[x] = array[y];
array[y] = tmp;
static void swap_elements(T* array, size_t x, size_t y) {
swap(array[x], array[y]);
}
// As pivot we use the median of the first, last and middle elements.
// We swap in these three values at the right place in the array. This
// means that this method not only returns the index of the pivot
// element. It also alters the array so that:
// We swap these three values as needed so that
// array[first] <= array[middle] <= array[last]
// A side effect of this is that arrays of length <= 3 are sorted.
// As a result, the first and last elements are placed in the proper
// partition, and arrays of length <= 3 are sorted.
// The middle index is returned, designating that element as the pivot.
template<class T, class C>
static size_t find_pivot(T* array, size_t length, C comparator) {
assert(length > 1, "length of array must be > 0");
@ -53,20 +51,20 @@ class QuickSort : AllStatic {
size_t last_index = length - 1;
if (comparator(array[0], array[middle_index]) > 0) {
swap(array, 0, middle_index);
swap_elements(array, 0, middle_index);
}
if (comparator(array[0], array[last_index]) > 0) {
swap(array, 0, last_index);
swap_elements(array, 0, last_index);
}
if (comparator(array[middle_index], array[last_index]) > 0) {
swap(array, middle_index, last_index);
swap_elements(array, middle_index, last_index);
}
// Now the value in the middle of the array is the median
// of the fist, last and middle values. Use this as pivot.
// of the first, last and middle values. Use this as pivot.
return middle_index;
}
template<bool idempotent, class T, class C>
template<class T, class C>
static size_t partition(T* array, size_t pivot, size_t length, C comparator) {
size_t left_index = 0;
size_t right_index = length - 1;
@ -74,27 +72,22 @@ class QuickSort : AllStatic {
for ( ; true; ++left_index, --right_index) {
for ( ; comparator(array[left_index], pivot_val) < 0; ++left_index) {
assert(left_index < length, "reached end of partition");
assert(left_index < (length - 1), "reached end of partition");
}
for ( ; comparator(array[right_index], pivot_val) > 0; --right_index) {
assert(right_index > 0, "reached start of partition");
}
if (left_index < right_index) {
if (!idempotent || comparator(array[left_index], array[right_index]) != 0) {
swap(array, left_index, right_index);
}
swap_elements(array, left_index, right_index);
} else {
return right_index;
}
}
ShouldNotReachHere();
return 0;
}
template<bool idempotent, class T, class C>
static void inner_sort(T* array, size_t length, C comparator) {
public:
template<class T, class C>
static void sort(T* array, size_t length, C comparator) {
if (length < 2) {
return;
}
@ -103,28 +96,11 @@ class QuickSort : AllStatic {
// arrays up to length 3 will be sorted after finding the pivot
return;
}
size_t split = partition<idempotent>(array, pivot, length, comparator);
size_t split = partition(array, pivot, length, comparator);
size_t first_part_length = split + 1;
inner_sort<idempotent>(array, first_part_length, comparator);
inner_sort<idempotent>(&array[first_part_length], length - first_part_length, comparator);
}
public:
// The idempotent parameter prevents the sort from
// reordering a previous valid sort by not swapping
// fields that compare as equal. This requires extra
// calls to the comparator, so the performance
// impact depends on the comparator.
template<class T, class C>
static void sort(T* array, size_t length, C comparator, bool idempotent) {
// Switch "idempotent" from function parameter to template parameter
if (idempotent) {
inner_sort<true>(array, length, comparator);
} else {
inner_sort<false>(array, length, comparator);
}
sort(array, first_part_length, comparator);
sort(&array[first_part_length], length - first_part_length, comparator);
}
};
#endif // SHARE_UTILITIES_QUICKSORT_HPP

View File

@ -461,7 +461,7 @@ public:
*to_release[i] = nullptr;
}
if (sorted) {
QuickSort::sort(to_release, nrelease, PointerCompare(), false);
QuickSort::sort(to_release, nrelease, PointerCompare());
}
storage().release(to_release, nrelease);

View File

@ -48,23 +48,11 @@ static bool compare_arrays(int* actual, int* expected, size_t length) {
}
template <class C>
static bool sort_and_compare(int* arrayToSort, int* expectedResult, size_t length, C comparator, bool idempotent = false) {
QuickSort::sort(arrayToSort, length, comparator, idempotent);
static bool sort_and_compare(int* arrayToSort, int* expectedResult, size_t length, C comparator) {
QuickSort::sort(arrayToSort, length, comparator);
return compare_arrays(arrayToSort, expectedResult, length);
}
static int test_even_odd_comparator(int a, int b) {
bool a_is_odd = ((a % 2) == 1);
bool b_is_odd = ((b % 2) == 1);
if (a_is_odd == b_is_odd) {
return 0;
}
if (a_is_odd) {
return -1;
}
return 1;
}
extern "C" {
static int test_stdlib_comparator(const void* a, const void* b) {
int ai = *(int*)a;
@ -126,50 +114,6 @@ TEST(QuickSort, quicksort) {
int expected_array[] = {6,7,8,8,9,9,11,11,13,21,22,24,24,25,27,27,28,31,32,39,40,40,40,41,44,46,51,55,56,59,64,64,65,69,71,74,75,75,76,78,81,82};
EXPECT_TRUE(sort_and_compare(test_array, expected_array, 42, test_comparator));
}
{
int test_array[] = {2,8,1,4};
int expected_array[] = {1,4,2,8};
EXPECT_TRUE(sort_and_compare(test_array, expected_array, 4, test_even_odd_comparator));
}
}
TEST(QuickSort, idempotent) {
{
// An array of lenght 3 is only sorted by find_pivot. Make sure that it is idempotent.
int test_array[] = {1, 4, 8};
int expected_array[] = {1, 4, 8};
EXPECT_TRUE(sort_and_compare(test_array, expected_array, 3, test_even_odd_comparator, true));
}
{
int test_array[] = {1, 7, 9, 4, 8, 2};
int expected_array[] = {1, 7, 9, 4, 8, 2};
EXPECT_TRUE(sort_and_compare(test_array, expected_array, 6, test_even_odd_comparator, true));
}
{
int test_array[] = {1, 9, 7, 4, 2, 8};
int expected_array[] = {1, 9, 7, 4, 2, 8};
EXPECT_TRUE(sort_and_compare(test_array, expected_array, 6, test_even_odd_comparator, true));
}
{
int test_array[] = {7, 9, 1, 2, 8, 4};
int expected_array[] = {7, 9, 1, 2, 8, 4};
EXPECT_TRUE(sort_and_compare(test_array, expected_array, 6, test_even_odd_comparator, true));
}
{
int test_array[] = {7, 1, 9, 2, 4, 8};
int expected_array[] = {7, 1, 9, 2, 4, 8};
EXPECT_TRUE(sort_and_compare(test_array, expected_array, 6, test_even_odd_comparator, true));
}
{
int test_array[] = {9, 1, 7, 4, 8, 2};
int expected_array[] = {9, 1, 7, 4, 8, 2};
EXPECT_TRUE(sort_and_compare(test_array, expected_array, 6, test_even_odd_comparator, true));
}
{
int test_array[] = {9, 7, 1, 4, 2, 8};
int expected_array[] = {9, 7, 1, 4, 2, 8};
EXPECT_TRUE(sort_and_compare(test_array, expected_array, 6, test_even_odd_comparator, true));
}
}
TEST(QuickSort, random) {
@ -186,18 +130,6 @@ TEST(QuickSort, random) {
// Compare sorting to stdlib::qsort()
qsort(expected_array, length, sizeof(int), test_stdlib_comparator);
EXPECT_TRUE(sort_and_compare(test_array, expected_array, length, test_comparator));
// Make sure sorting is idempotent.
// Both test_array and expected_array are sorted by the test_comparator.
// Now sort them once with the test_even_odd_comparator. Then sort the
// test_array one more time with test_even_odd_comparator and verify that
// it is idempotent.
QuickSort::sort(expected_array, length, test_even_odd_comparator, true);
QuickSort::sort(test_array, length, test_even_odd_comparator, true);
EXPECT_TRUE(compare_arrays(test_array, expected_array, length));
QuickSort::sort(test_array, length, test_even_odd_comparator, true);
EXPECT_TRUE(compare_arrays(test_array, expected_array, length));
FREE_C_HEAP_ARRAY(int, test_array);
FREE_C_HEAP_ARRAY(int, expected_array);
}