<p dir="ltr">Hi John,</p>
<p dir="ltr">Wow, that's a giant heap! :)</p>
<p dir="ltr">I think G1ConcRSLogCacheSize needs to be validated to make sure it's <= 31; otherwise, I think you get undefined behavior on left shifting with it.</p>
<p dir="ltr">I don't think you need _def_use_cache -- can be replaced with G1ConcRSLogCacheSize > 0?</p>
<p dir="ltr">I'm sure this is due to my lack of G1 knowledge, but the concurrency control inside g1HotCardCache is a bit unclear.  There's a CAS to claim the region of cards, there's a HotCache lock for inserting a card.  However, reset_hot_cache() does a naked write of a few fields.  Are there any visibility and ordering constraints that need to be enforced? Do some of the stores need an OrderAccess barrier of some sort, depending on what's required? Sorry if I'm just missing it ...</p>

<p dir="ltr">I didn't finish looking at the rest yet so that's all I have for the moment.</p>
<p dir="ltr">Thanks<br></p>
<p dir="ltr">Sent from my phone</p>
<div class="gmail_quote">On Jan 15, 2013 6:32 PM, "John Cuthbertson" <<a href="mailto:john.cuthbertson@oracle.com">john.cuthbertson@oracle.com</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hi Everyone,<br>
<br>
Can I have a couple of people look over the changes for this CR - the webrev can be found at: <a href="http://cr.openjdk.java.net/~johnc/7176479/webrev.0/" target="_blank">http://cr.openjdk.java.net/~<u></u>johnc/7176479/webrev.0/</a><br>

<br>
Background:<br>
The issue here was that we were encoding the card index into the card counts table entries along with the GC number so that we could determine if the count associated with was valid. We had a check to ensure that the maximum card index could be encoded in an int. With such large heap size - the number of cards could not be encoded and so the check failed.<br>

<br>
The previous mechanism was an attempt to solve the problem of one thread arriving late to the actual GC work. The thread in question was being held up zeroing the card counts table at the start of the GC. The card counts table is used to determine which cards are being refined frequently. Once a card has been refined frequently enough, further refinements of that card are delayed by placing the card into a fixed size evicting table - the hot card cache. The card would then be refined when it was evicted from the hot card cache or when the cache was drained during the next GC.<br>

<br>
To solve the problem of zeroing we added an epoch (GC number) to the entries in the counts table and, eliminate the increase in footprint, we made the counts table into a cache which would expand if needed. This approach had some negatives: we might have to refine two cards during a single refinement operation, hashing the card, and performing CAS operations increasing the overhead of concurrent refinement. Also expanding the counts table during a GC incurred a penalty.<br>

<br>
This approach also limited the heap size to just under 1TB - which the systems team ran into.<br>
<br>
The new approach effectively undoes the previous mechanism and re-simplifies the card counts table.<br>
<br>
Summary of Changes:<br>
The hot card cache and card counts table have been moved from the concurrent refinement code into their own files.<br>
<br>
The hot card cache can now exist independently of whether the counts table exists. In this case refining a card once adds it to the hot card cache, i.e. all cards are treated as 'hot'.<br>
<br>
The interface to the hot card cache has been simplified - a simple query and a simple drain routine. This simplifies the calling code in g1RemSet.cpp and results in up to only a single card being refined for every call to "refine_card" instead of possibly two. This should reduce the overhead of concurrent refinement.<br>

<br>
The number of cards that the hot card cache can hold before cards start getting evicted is controlled by the flag G1ConcRSLogCacheSize, which is now product flag. The default value is 10 giving a hot card cache that can hold 1K cards.<br>

<br>
The card counts table has been greatly simplified. It is a simple array of counts how many times a card has been refined. The space for the table is now allocated from virtual memory instead of C heap. The space for the table is committed when the heap is initially committed and the spans the committed size of the heap. When the committed size of the heap is expanded, the counts table is also expanded to cover the newly expanded heap. If we fail to commit the memory for the counts table, cards that map to the uncommitted space will be treated as cold, i.e. they will be refined immediately. Having a simpler counts table also should reduce the overhead of concurrent refinement (there is no need to hash the card index and there are no CAS operations) Having a simpler interface will allow us to change the underlying data structure to an alternative that's perhaps more sparse in the future.<br>

<br>
During an incremental GC we no longer zero the entire counts table. We now zero the cards spanned by a region when the region is freed (i.e. when we free the collection set at the end of a GC and when we free regions at the end of a cleanup).  If a card was "hot" before a GC then we will consider it hot after the GC and the first refinement after the GC will insert the card into the hot card cache. Furthermore, since we don't refine cards in young regions, we only need to clear the counts associated with cards spanned by non-young regions.<br>

<br>
During a full GC we still discard the entries in the hot card cache and zero the counts for all the cards in the heap.<br>
<br>
Testing:<br>
GC Test suite with MaxTenuringThreshold=0 (to increase the amount of refinement) and a low IHOP value (to force cleanups).<br>
SPECjbb2005 with a 1.5TB heap size and 256GB young size, MaxTenuringThreshold=0 and a low IHOP value (1%). The systems team are continuing to test with very large heaps.<br>
<br>
</blockquote></div>