blob: 4842283f9ac1a7673072ef7670c4d9ddadc57a68 [file] [log] [blame]
/*
* Copyright (c) 2019, 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "gc/g1/g1CollectionSetCandidates.hpp"
#include "gc/g1/g1CollectionSetChooser.hpp"
#include "gc/g1/heapRegion.inline.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/growableArray.hpp"
G1CollectionCandidateList::G1CollectionCandidateList() : _candidates(2, mtGC) { }
void G1CollectionCandidateList::set(G1CollectionCandidateList::CandidateInfo* candidate_infos, uint num_infos) {
assert(_candidates.is_empty(), "must be");
GrowableArrayFromArray<G1CollectionCandidateList::CandidateInfo> a(candidate_infos, (int)num_infos);
_candidates.appendAll(&a);
}
void G1CollectionCandidateList::remove(G1CollectionCandidateRegionList* other) {
guarantee((uint)_candidates.length() >= other->length(), "must be");
if (other->length() == 0) {
// Nothing to remove or nothing in the original set.
return;
}
// Create a list from scratch, copying over the elements from the candidate
// list not in the other list. Finally deallocate and overwrite the old list.
int new_length = _candidates.length() - other->length();
GrowableArray<CandidateInfo> new_list(new_length, mtGC);
uint other_idx = 0;
for (uint candidate_idx = 0; candidate_idx < (uint)_candidates.length(); candidate_idx++) {
if ((other_idx == other->length()) || _candidates.at(candidate_idx)._r != other->at(other_idx)) {
new_list.append(_candidates.at(candidate_idx));
} else {
other_idx++;
}
}
_candidates.swap(&new_list);
verify();
assert(_candidates.length() == new_length, "must be %u %u", _candidates.length(), new_length);
}
void G1CollectionCandidateList::clear() {
_candidates.clear();
}
#ifndef PRODUCT
void G1CollectionCandidateList::verify() {
CandidateInfo* prev = nullptr;
for (uint i = 0; i < (uint)_candidates.length(); i++) {
CandidateInfo& ci = _candidates.at(i);
assert(prev == nullptr || prev->_gc_efficiency >= ci._gc_efficiency,
"Stored gc efficiency must be descending from region %u to %u",
prev->_r->hrm_index(), ci._r->hrm_index());
prev = &ci;
assert(ci._r->rem_set()->is_tracked(), "remset for region %u must be tracked", ci._r->hrm_index());
}
}
#endif
int G1CollectionCandidateList::compare(CandidateInfo* ci1, CandidateInfo* ci2) {
// Make sure that null entries are moved to the end.
if (ci1->_r == nullptr) {
if (ci2->_r == nullptr) {
return 0;
} else {
return 1;
}
} else if (ci2->_r == nullptr) {
return -1;
}
double gc_eff1 = ci1->_gc_efficiency;
double gc_eff2 = ci2->_gc_efficiency;
if (gc_eff1 > gc_eff2) {
return -1;
} if (gc_eff1 < gc_eff2) {
return 1;
} else {
return 0;
}
}
G1CollectionCandidateRegionList::G1CollectionCandidateRegionList() : _regions(2, mtGC) { }
void G1CollectionCandidateRegionList::append(HeapRegion* r) {
assert(!_regions.contains(r), "must be");
_regions.append(r);
}
void G1CollectionCandidateRegionList::remove_prefix(G1CollectionCandidateRegionList* other) {
#ifdef ASSERT
// Check that the given list is a prefix of this list.
int i = 0;
for (HeapRegion* r : *other) {
assert(_regions.at(i) == r, "must be in order, but element %d is not", i);
i++;
}
#endif
if (other->length() == 0) {
return;
}
_regions.remove_till(other->length());
}
HeapRegion* G1CollectionCandidateRegionList::at(uint index) {
return _regions.at(index);
}
void G1CollectionCandidateRegionList::clear() {
_regions.clear();
}
G1CollectionSetCandidates::G1CollectionSetCandidates() :
_marking_regions(),
_contains_map(nullptr),
_max_regions(0),
_last_marking_candidates_length(0)
{ }
G1CollectionSetCandidates::~G1CollectionSetCandidates() {
FREE_C_HEAP_ARRAY(CandidateOrigin, _contains_map);
}
bool G1CollectionSetCandidates::is_from_marking(HeapRegion* r) const {
assert(contains(r), "must be");
return _contains_map[r->hrm_index()] == CandidateOrigin::Marking;
}
void G1CollectionSetCandidates::initialize(uint max_regions) {
assert(_contains_map == nullptr, "already initialized");
_max_regions = max_regions;
_contains_map = NEW_C_HEAP_ARRAY(CandidateOrigin, max_regions, mtGC);
clear();
}
void G1CollectionSetCandidates::clear() {
_marking_regions.clear();
for (uint i = 0; i < _max_regions; i++) {
_contains_map[i] = CandidateOrigin::Invalid;
}
_last_marking_candidates_length = 0;
}
void G1CollectionSetCandidates::set_candidates_from_marking(G1CollectionCandidateList::CandidateInfo* candidate_infos,
uint num_infos) {
assert(_marking_regions.length() == 0, "must be empty before adding new ones");
verify();
_marking_regions.set(candidate_infos, num_infos);
for (uint i = 0; i < num_infos; i++) {
HeapRegion* r = candidate_infos[i]._r;
assert(!contains(r), "must not contain region %u", r->hrm_index());
_contains_map[r->hrm_index()] = CandidateOrigin::Marking;
}
_last_marking_candidates_length = num_infos;
verify();
}
void G1CollectionSetCandidates::remove(G1CollectionCandidateRegionList* other) {
_marking_regions.remove(other);
for (HeapRegion* r : *other) {
assert(contains(r), "must contain region %u", r->hrm_index());
_contains_map[r->hrm_index()] = CandidateOrigin::Invalid;
}
verify();
}
bool G1CollectionSetCandidates::is_empty() const {
return length() == 0;
}
bool G1CollectionSetCandidates::has_more_marking_candidates() const {
return _marking_regions.length() != 0;
}
#ifndef PRODUCT
void G1CollectionSetCandidates::verify_helper(G1CollectionCandidateList* list, uint& from_marking, CandidateOrigin* verify_map) {
list->verify();
for (uint i = 0; i < (uint)list->length(); i++) {
HeapRegion* r = list->at(i)._r;
if (is_from_marking(r)) {
from_marking++;
}
const uint hrm_index = r->hrm_index();
assert(_contains_map[hrm_index] == CandidateOrigin::Marking,
"must be %u is %u", hrm_index, (uint)_contains_map[hrm_index]);
assert(verify_map[hrm_index] == CandidateOrigin::Invalid, "already added");
verify_map[hrm_index] = CandidateOrigin::Verify;
}
}
void G1CollectionSetCandidates::verify() {
uint from_marking = 0;
CandidateOrigin* verify_map = NEW_C_HEAP_ARRAY(CandidateOrigin, _max_regions, mtGC);
for (uint i = 0; i < _max_regions; i++) {
verify_map[i] = CandidateOrigin::Invalid;
}
verify_helper(&_marking_regions, from_marking, verify_map);
assert(from_marking == marking_regions_length(), "must be");
// Check whether the _contains_map is consistent with the list.
for (uint i = 0; i < _max_regions; i++) {
assert(_contains_map[i] == verify_map[i] ||
(_contains_map[i] != CandidateOrigin::Invalid && verify_map[i] == CandidateOrigin::Verify),
"Candidate origin does not match for region %u, is %u but should be %u",
i,
static_cast<std::underlying_type<CandidateOrigin>::type>(_contains_map[i]),
static_cast<std::underlying_type<CandidateOrigin>::type>(verify_map[i]));
}
FREE_C_HEAP_ARRAY(CandidateOrigin, verify_map);
}
#endif
bool G1CollectionSetCandidates::contains(const HeapRegion* r) const {
const uint index = r->hrm_index();
assert(index < _max_regions, "must be");
return _contains_map[index] != CandidateOrigin::Invalid;
}
const char* G1CollectionSetCandidates::get_short_type_str(const HeapRegion* r) const {
static const char* type_strings[] = {
"Ci", // Invalid
"Cm", // Marking
"Cv" // Verification
};
uint8_t kind = static_cast<std::underlying_type<CandidateOrigin>::type>(_contains_map[r->hrm_index()]);
return type_strings[kind];
}