ysr@777: /* johnc@2713: * Copyright (c) 2001, 2011, Oracle and/or its affiliates. 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: * trims@1907: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA trims@1907: * or visit www.oracle.com if you need additional information or have any trims@1907: * questions. ysr@777: * ysr@777: */ ysr@777: stefank@2314: #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTG1REFINE_HPP stefank@2314: #define SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTG1REFINE_HPP stefank@2314: stefank@2314: #include "memory/allocation.hpp" stefank@2314: #include "memory/cardTableModRefBS.hpp" stefank@2314: #include "runtime/thread.hpp" stefank@2314: #include "utilities/globalDefinitions.hpp" stefank@2314: ysr@777: // Forward decl ysr@777: class ConcurrentG1RefineThread; ysr@777: class G1RemSet; ysr@777: zgu@3900: class ConcurrentG1Refine: public CHeapObj { iveresov@1229: ConcurrentG1RefineThread** _threads; iveresov@1229: int _n_threads; iveresov@1546: int _n_worker_threads; iveresov@1546: /* iveresov@1546: * The value of the update buffer queue length falls into one of 3 zones: iveresov@1546: * green, yellow, red. If the value is in [0, green) nothing is iveresov@1546: * done, the buffers are left unprocessed to enable the caching effect of the iveresov@1546: * dirtied cards. In the yellow zone [green, yellow) the concurrent refinement iveresov@1546: * threads are gradually activated. In [yellow, red) all threads are iveresov@1546: * running. If the length becomes red (max queue length) the mutators start iveresov@1546: * processing the buffers. iveresov@1546: * tonyp@1717: * There are some interesting cases (when G1UseAdaptiveConcRefinement tonyp@1717: * is turned off): iveresov@1546: * 1) green = yellow = red = 0. In this case the mutator will process all iveresov@1546: * buffers. Except for those that are created by the deferred updates iveresov@1546: * machinery during a collection. iveresov@1546: * 2) green = 0. Means no caching. Can be a good way to minimize the iveresov@1546: * amount of time spent updating rsets during a collection. iveresov@1546: */ iveresov@1546: int _green_zone; iveresov@1546: int _yellow_zone; iveresov@1546: int _red_zone; iveresov@1546: iveresov@1546: int _thread_threshold_step; iveresov@1546: iveresov@1546: // Reset the threshold step value based of the current zone boundaries. iveresov@1546: void reset_threshold_step(); johnc@1325: ysr@777: // The cache for card refinement. johnc@1325: bool _use_cache; johnc@1325: bool _def_use_cache; ysr@777: johnc@1325: size_t _n_periods; // Used as clearing epoch johnc@1325: johnc@1325: // An evicting cache of the number of times each card johnc@1325: // is accessed. Reduces, but does not eliminate, the amount johnc@1325: // of duplicated processing of dirty cards. johnc@1325: johnc@1325: enum SomePrivateConstants { johnc@1325: epoch_bits = 32, johnc@1325: card_num_shift = epoch_bits, johnc@1325: epoch_mask = AllBits, johnc@1325: card_num_mask = AllBits, johnc@1325: johnc@1325: // The initial cache size is approximately this fraction johnc@1325: // of a maximal cache (i.e. the size needed for all cards johnc@1325: // in the heap) johnc@1325: InitialCacheFraction = 512 johnc@1325: }; johnc@1325: johnc@1325: const static julong card_num_mask_in_place = johnc@1325: (julong) card_num_mask << card_num_shift; johnc@1325: johnc@1325: typedef struct { johnc@1325: julong _value; // | card_num | epoch | johnc@1325: } CardEpochCacheEntry; johnc@1325: johnc@1325: julong make_epoch_entry(unsigned int card_num, unsigned int epoch) { johnc@2713: assert(0 <= card_num && card_num < _max_cards, "Bounds"); johnc@1325: assert(0 <= epoch && epoch <= _n_periods, "must be"); johnc@1325: johnc@1325: return ((julong) card_num << card_num_shift) | epoch; johnc@1325: } johnc@1325: johnc@1325: unsigned int extract_epoch(julong v) { johnc@1325: return (v & epoch_mask); johnc@1325: } johnc@1325: johnc@1325: unsigned int extract_card_num(julong v) { johnc@1325: return (v & card_num_mask_in_place) >> card_num_shift; johnc@1325: } johnc@1325: johnc@1325: typedef struct { johnc@1325: unsigned char _count; johnc@1325: unsigned char _evict_count; johnc@1325: } CardCountCacheEntry; johnc@1325: johnc@1325: CardCountCacheEntry* _card_counts; johnc@1325: CardEpochCacheEntry* _card_epochs; johnc@1325: johnc@1325: // The current number of buckets in the card count cache johnc@2713: size_t _n_card_counts; johnc@1325: johnc@2713: // The number of cards for the entire reserved heap johnc@2713: size_t _max_cards; johnc@2713: johnc@2713: // The max number of buckets for the card counts and epochs caches. johnc@2713: // This is the maximum that the counts and epochs will grow to. johnc@2713: // It is specified as a fraction or percentage of _max_cards using johnc@2713: // G1MaxHotCardCountSizePercent. johnc@2713: size_t _max_n_card_counts; johnc@1325: johnc@1325: // Possible sizes of the cache: odd primes that roughly double in size. johnc@1325: // (See jvmtiTagMap.cpp). johnc@2713: enum { johnc@2713: MAX_CC_CACHE_INDEX = 15 // maximum index into the cache size array. johnc@2713: }; johnc@2713: johnc@2713: static size_t _cc_cache_sizes[MAX_CC_CACHE_INDEX]; johnc@1325: johnc@1325: // The index in _cc_cache_sizes corresponding to the size of johnc@1325: // _card_counts. johnc@1325: int _cache_size_index; johnc@1325: johnc@1325: bool _expand_card_counts; johnc@1325: johnc@1325: const jbyte* _ct_bot; johnc@1324: johnc@1324: jbyte** _hot_cache; johnc@1324: int _hot_cache_size; johnc@1324: int _n_hot; johnc@1324: int _hot_cache_idx; johnc@1324: johnc@1324: int _hot_cache_par_chunk_size; johnc@1324: volatile int _hot_cache_par_claimed_idx; ysr@777: johnc@1325: // Needed to workaround 6817995 johnc@1325: CardTableModRefBS* _ct_bs; johnc@1325: G1CollectedHeap* _g1h; johnc@1325: johnc@2713: // Helper routine for expand_card_count_cache(). johnc@2713: // The arrays used to hold the card counts and the epochs must have johnc@2713: // a 1:1 correspondence. Hence they are allocated and freed together. johnc@2713: // Returns true if the allocations of both the counts and epochs johnc@2713: // were successful; false otherwise. johnc@2713: bool allocate_card_count_cache(size_t n, johnc@2713: CardCountCacheEntry** counts, johnc@2713: CardEpochCacheEntry** epochs); johnc@2713: johnc@2713: // Expands the arrays that hold the card counts and epochs johnc@2713: // to the cache size at index. Returns true if the expansion/ johnc@2713: // allocation was successful; false otherwise. johnc@2713: bool expand_card_count_cache(int index); johnc@1325: johnc@1325: // hash a given key (index of card_ptr) with the specified size johnc@2713: static unsigned int hash(size_t key, size_t size) { johnc@2790: return (unsigned int) (key % size); johnc@1325: } johnc@1325: johnc@1325: // hash a given key (index of card_ptr) johnc@1325: unsigned int hash(size_t key) { johnc@1325: return hash(key, _n_card_counts); johnc@1325: } johnc@1325: johnc@2790: unsigned int ptr_2_card_num(jbyte* card_ptr) { johnc@2790: return (unsigned int) (card_ptr - _ct_bot); johnc@1325: } johnc@1325: johnc@2790: jbyte* card_num_2_ptr(unsigned int card_num) { johnc@1325: return (jbyte*) (_ct_bot + card_num); johnc@1325: } johnc@1325: ysr@777: // Returns the count of this card after incrementing it. johnc@1325: jbyte* add_card_count(jbyte* card_ptr, int* count, bool* defer); ysr@777: johnc@1325: // Returns true if this card is in a young region johnc@1325: bool is_young_card(jbyte* card_ptr); johnc@1325: ysr@777: public: ysr@777: ConcurrentG1Refine(); ysr@777: ~ConcurrentG1Refine(); ysr@777: ysr@777: void init(); // Accomplish some initialization that has to wait. iveresov@1229: void stop(); ysr@777: iveresov@1546: void reinitialize_threads(); iveresov@1546: iveresov@1229: // Iterate over the conc refine threads iveresov@1229: void threads_do(ThreadClosure *tc); 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. johnc@1325: jbyte* cache_insert(jbyte* card_ptr, bool* defer); ysr@777: ysr@777: // Process the cached entries. johnc@2060: void clean_up_cache(int worker_i, G1RemSet* g1rs, DirtyCardQueue* into_cset_dcq); ysr@777: johnc@1324: // Set up for parallel processing of the cards in the hot cache johnc@1324: void clear_hot_cache_claimed_index() { johnc@1324: _hot_cache_par_claimed_idx = 0; johnc@1324: } johnc@1324: 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(); iveresov@1230: iveresov@1546: static int thread_num(); tonyp@1454: tonyp@1454: void print_worker_threads_on(outputStream* st) const; iveresov@1546: iveresov@1546: void set_green_zone(int x) { _green_zone = x; } iveresov@1546: void set_yellow_zone(int x) { _yellow_zone = x; } iveresov@1546: void set_red_zone(int x) { _red_zone = x; } iveresov@1546: iveresov@1546: int green_zone() const { return _green_zone; } iveresov@1546: int yellow_zone() const { return _yellow_zone; } iveresov@1546: int red_zone() const { return _red_zone; } iveresov@1546: iveresov@1546: int total_thread_num() const { return _n_threads; } iveresov@1546: int worker_thread_num() const { return _n_worker_threads; } iveresov@1546: iveresov@1546: int thread_threshold_step() const { return _thread_threshold_step; } ysr@777: }; stefank@2314: stefank@2314: #endif // SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTG1REFINE_HPP