ysr@777: /* xdono@1014: * Copyright 2001-2009 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: apetrusenko@984: class ConcurrentG1Refine: public CHeapObj { iveresov@1229: ConcurrentG1RefineThread** _threads; iveresov@1229: int _n_threads; 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@1325: assert(0 <= card_num && card_num < _max_n_card_counts, "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@1325: unsigned _n_card_counts; johnc@1325: johnc@1325: // The max number of buckets required for the number of johnc@1325: // cards for the entire reserved heap johnc@1325: unsigned _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@1325: static int _cc_cache_sizes[]; 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@1325: // Expands the array that holds the card counts to the next size up johnc@1325: void expand_card_count_cache(); johnc@1325: johnc@1325: // hash a given key (index of card_ptr) with the specified size johnc@1325: static unsigned int hash(size_t key, int size) { johnc@1325: 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@1325: unsigned ptr_2_card_num(jbyte* card_ptr) { johnc@1325: return (unsigned) (card_ptr - _ct_bot); johnc@1325: } johnc@1325: johnc@1325: jbyte* card_num_2_ptr(unsigned 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@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. ysr@777: void clean_up_cache(int worker_i, G1RemSet* g1rs); 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@1230: static size_t thread_num(); tonyp@1454: tonyp@1454: void print_worker_threads_on(outputStream* st) const; ysr@777: };