ysr@777: /* ysr@777: * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. ysr@777: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ysr@777: * ysr@777: * This code is free software; you can redistribute it and/or modify it ysr@777: * under the terms of the GNU General Public License version 2 only, as ysr@777: * published by the Free Software Foundation. ysr@777: * ysr@777: * This code is distributed in the hope that it will be useful, but WITHOUT ysr@777: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ysr@777: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ysr@777: * version 2 for more details (a copy is included in the LICENSE file that ysr@777: * accompanied this code). ysr@777: * ysr@777: * You should have received a copy of the GNU General Public License version ysr@777: * 2 along with this work; if not, write to the Free Software Foundation, ysr@777: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ysr@777: * ysr@777: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, ysr@777: * CA 95054 USA or visit www.sun.com if you need additional information or ysr@777: * have any questions. ysr@777: * ysr@777: */ ysr@777: ysr@777: // Forward decl ysr@777: class ConcurrentG1RefineThread; ysr@777: class G1RemSet; ysr@777: ysr@777: // What to do after a yield: ysr@777: enum PostYieldAction { ysr@777: PYA_continue, // Continue the traversal ysr@777: PYA_restart, // Restart ysr@777: PYA_cancel // It's been completed by somebody else: cancel. ysr@777: }; ysr@777: ysr@777: class ConcurrentG1Refine { ysr@777: ConcurrentG1RefineThread* _cg1rThread; ysr@777: ysr@777: volatile jint _pya; ysr@777: PostYieldAction _last_pya; ysr@777: ysr@777: static bool _enabled; // Protected by G1ConcRefine_mon. ysr@777: unsigned _traversals; ysr@777: ysr@777: // Number of cards processed during last refinement traversal. ysr@777: unsigned _first_traversal; ysr@777: unsigned _last_cards_during; ysr@777: ysr@777: // The cache for card refinement. ysr@777: bool _use_cache; ysr@777: bool _def_use_cache; ysr@777: size_t _n_periods; ysr@777: size_t _total_cards; ysr@777: size_t _total_travs; ysr@777: ysr@777: unsigned char* _card_counts; ysr@777: unsigned _n_card_counts; ysr@777: const jbyte* _ct_bot; ysr@777: unsigned* _cur_card_count_histo; ysr@777: unsigned* _cum_card_count_histo; ysr@777: jbyte** _hot_cache; ysr@777: int _hot_cache_size; ysr@777: int _n_hot; ysr@777: int _hot_cache_idx; ysr@777: ysr@777: // Returns the count of this card after incrementing it. ysr@777: int add_card_count(jbyte* card_ptr); ysr@777: ysr@777: void print_card_count_histo_range(unsigned* histo, int from, int to, ysr@777: float& cum_card_pct, ysr@777: float& cum_travs_pct); ysr@777: public: ysr@777: ConcurrentG1Refine(); ysr@777: ~ConcurrentG1Refine(); ysr@777: ysr@777: void init(); // Accomplish some initialization that has to wait. ysr@777: ysr@777: // Enabled Conc refinement, waking up thread if necessary. ysr@777: void enable(); ysr@777: ysr@777: // Returns the number of traversals performed since this refiner was enabled. ysr@777: unsigned disable(); ysr@777: ysr@777: // Requires G1ConcRefine_mon to be held. ysr@777: bool enabled() { return _enabled; } ysr@777: ysr@777: // Returns only when G1 concurrent refinement has been enabled. ysr@777: void wait_for_ConcurrentG1Refine_enabled(); ysr@777: ysr@777: // Do one concurrent refinement pass over the card table. Returns "true" ysr@777: // if heuristics determine that another pass should be done immediately. ysr@777: bool refine(); ysr@777: ysr@777: // Indicate that an in-progress refinement pass should start over. ysr@777: void set_pya_restart(); ysr@777: // Indicate that an in-progress refinement pass should quit. ysr@777: void set_pya_cancel(); ysr@777: ysr@777: // Get the appropriate post-yield action. Also sets last_pya. ysr@777: PostYieldAction get_pya(); ysr@777: ysr@777: // The last PYA read by "get_pya". ysr@777: PostYieldAction get_last_pya(); ysr@777: ysr@777: bool do_traversal(); ysr@777: ysr@777: ConcurrentG1RefineThread* cg1rThread() { return _cg1rThread; } ysr@777: ysr@777: // If this is the first entry for the slot, writes into the cache and ysr@777: // returns NULL. If it causes an eviction, returns the evicted pointer. ysr@777: // Otherwise, its a cache hit, and returns NULL. ysr@777: jbyte* cache_insert(jbyte* card_ptr); ysr@777: ysr@777: // Process the cached entries. ysr@777: void clean_up_cache(int worker_i, G1RemSet* g1rs); ysr@777: ysr@777: // Discard entries in the hot cache. ysr@777: void clear_hot_cache() { ysr@777: _hot_cache_idx = 0; _n_hot = 0; ysr@777: } ysr@777: ysr@777: bool hot_cache_is_empty() { return _n_hot == 0; } ysr@777: ysr@777: bool use_cache() { return _use_cache; } ysr@777: void set_use_cache(bool b) { ysr@777: if (b) _use_cache = _def_use_cache; ysr@777: else _use_cache = false; ysr@777: } ysr@777: ysr@777: void clear_and_record_card_counts(); ysr@777: void print_final_card_counts(); ysr@777: };