| 1 | /* |
| 2 | * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. |
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| 4 | * |
| 5 | * This code is free software; you can redistribute it and/or modify it |
| 6 | * under the terms of the GNU General Public License version 2 only, as |
| 7 | * published by the Free Software Foundation. |
| 8 | * |
| 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 12 | * version 2 for more details (a copy is included in the LICENSE file that |
| 13 | * accompanied this code). |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License version |
| 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
| 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| 18 | * |
| 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| 20 | * or visit www.oracle.com if you need additional information or have any |
| 21 | * questions. |
| 22 | * |
| 23 | */ |
| 24 | |
| 25 | #include "precompiled.hpp" |
| 26 | #include "classfile/stringTable.hpp" |
| 27 | #include "gc/shared/oopStorage.inline.hpp" |
| 28 | #include "gc/shared/oopStorageParState.inline.hpp" |
| 29 | #include "gc/shared/weakProcessor.inline.hpp" |
| 30 | #include "gc/shared/weakProcessorPhases.hpp" |
| 31 | #include "gc/shared/weakProcessorPhaseTimes.hpp" |
| 32 | #include "memory/allocation.inline.hpp" |
| 33 | #include "memory/iterator.hpp" |
| 34 | #include "prims/resolvedMethodTable.hpp" |
| 35 | #include "runtime/globals.hpp" |
| 36 | #include "utilities/macros.hpp" |
| 37 | |
| 38 | template <typename Container> |
| 39 | class OopsDoAndReportCounts { |
| 40 | public: |
| 41 | void operator()(BoolObjectClosure* is_alive, OopClosure* keep_alive, WeakProcessorPhase phase) { |
| 42 | Container::reset_dead_counter(); |
| 43 | |
| 44 | CountingSkippedIsAliveClosure<BoolObjectClosure, OopClosure> cl(is_alive, keep_alive); |
| 45 | WeakProcessorPhases::oop_storage(phase)->oops_do(&cl); |
| 46 | |
| 47 | Container::inc_dead_counter(cl.num_dead() + cl.num_skipped()); |
| 48 | Container::finish_dead_counter(); |
| 49 | } |
| 50 | }; |
| 51 | |
| 52 | void WeakProcessor::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive) { |
| 53 | FOR_EACH_WEAK_PROCESSOR_PHASE(phase) { |
| 54 | if (WeakProcessorPhases::is_serial(phase)) { |
| 55 | WeakProcessorPhases::processor(phase)(is_alive, keep_alive); |
| 56 | } else { |
| 57 | if (WeakProcessorPhases::is_stringtable(phase)) { |
| 58 | OopsDoAndReportCounts<StringTable>()(is_alive, keep_alive, phase); |
| 59 | } else if (WeakProcessorPhases::is_resolved_method_table(phase)){ |
| 60 | OopsDoAndReportCounts<ResolvedMethodTable>()(is_alive, keep_alive, phase); |
| 61 | } else { |
| 62 | WeakProcessorPhases::oop_storage(phase)->weak_oops_do(is_alive, keep_alive); |
| 63 | } |
| 64 | } |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | void WeakProcessor::oops_do(OopClosure* closure) { |
| 69 | AlwaysTrueClosure always_true; |
| 70 | weak_oops_do(&always_true, closure); |
| 71 | } |
| 72 | |
| 73 | uint WeakProcessor::ergo_workers(uint max_workers) { |
| 74 | // Ignore ParallelRefProcEnabled; that's for j.l.r.Reference processing. |
| 75 | if (ReferencesPerThread == 0) { |
| 76 | // Configuration says always use all the threads. |
| 77 | return max_workers; |
| 78 | } |
| 79 | |
| 80 | // One thread per ReferencesPerThread references (or fraction thereof) |
| 81 | // in the various OopStorage objects, bounded by max_threads. |
| 82 | // |
| 83 | // Serial phases are ignored in this calculation, because of the |
| 84 | // cost of running unnecessary threads. These phases are normally |
| 85 | // small or empty (assuming they are configured to exist at all), |
| 86 | // and development oriented, so not allocating any threads |
| 87 | // specifically for them is okay. |
| 88 | size_t ref_count = 0; |
| 89 | FOR_EACH_WEAK_PROCESSOR_OOP_STORAGE_PHASE(phase) { |
| 90 | ref_count += WeakProcessorPhases::oop_storage(phase)->allocation_count(); |
| 91 | } |
| 92 | |
| 93 | // +1 to (approx) round up the ref per thread division. |
| 94 | size_t nworkers = 1 + (ref_count / ReferencesPerThread); |
| 95 | nworkers = MIN2(nworkers, static_cast<size_t>(max_workers)); |
| 96 | return static_cast<uint>(nworkers); |
| 97 | } |
| 98 | |
| 99 | void WeakProcessor::Task::initialize() { |
| 100 | assert(_nworkers != 0, "must be" ); |
| 101 | assert(_phase_times == NULL || _nworkers <= _phase_times->max_threads(), |
| 102 | "nworkers (%u) exceeds max threads (%u)" , |
| 103 | _nworkers, _phase_times->max_threads()); |
| 104 | |
| 105 | if (_phase_times) { |
| 106 | _phase_times->set_active_workers(_nworkers); |
| 107 | } |
| 108 | |
| 109 | uint storage_count = WeakProcessorPhases::oop_storage_phase_count; |
| 110 | _storage_states = NEW_C_HEAP_ARRAY(StorageState, storage_count, mtGC); |
| 111 | |
| 112 | StorageState* states = _storage_states; |
| 113 | FOR_EACH_WEAK_PROCESSOR_OOP_STORAGE_PHASE(phase) { |
| 114 | OopStorage* storage = WeakProcessorPhases::oop_storage(phase); |
| 115 | new (states++) StorageState(storage, _nworkers); |
| 116 | } |
| 117 | StringTable::reset_dead_counter(); |
| 118 | ResolvedMethodTable::reset_dead_counter(); |
| 119 | } |
| 120 | |
| 121 | WeakProcessor::Task::Task(uint nworkers) : |
| 122 | _phase_times(NULL), |
| 123 | _nworkers(nworkers), |
| 124 | _serial_phases_done(WeakProcessorPhases::serial_phase_count), |
| 125 | _storage_states(NULL) |
| 126 | { |
| 127 | initialize(); |
| 128 | } |
| 129 | |
| 130 | WeakProcessor::Task::Task(WeakProcessorPhaseTimes* phase_times, uint nworkers) : |
| 131 | _phase_times(phase_times), |
| 132 | _nworkers(nworkers), |
| 133 | _serial_phases_done(WeakProcessorPhases::serial_phase_count), |
| 134 | _storage_states(NULL) |
| 135 | { |
| 136 | initialize(); |
| 137 | } |
| 138 | |
| 139 | WeakProcessor::Task::~Task() { |
| 140 | if (_storage_states != NULL) { |
| 141 | StorageState* states = _storage_states; |
| 142 | FOR_EACH_WEAK_PROCESSOR_OOP_STORAGE_PHASE(phase) { |
| 143 | states->StorageState::~StorageState(); |
| 144 | ++states; |
| 145 | } |
| 146 | FREE_C_HEAP_ARRAY(StorageState, _storage_states); |
| 147 | } |
| 148 | StringTable::finish_dead_counter(); |
| 149 | ResolvedMethodTable::finish_dead_counter(); |
| 150 | } |
| 151 | |
| 152 | void WeakProcessor::GangTask::work(uint worker_id) { |
| 153 | _erased_do_work(this, worker_id); |
| 154 | } |
| 155 | |