Re: [9, 8u40] RFR (M): 8057020: LambdaForm caches should support eviction
Just one more thought... In lines: 358 } else if (stale 0 k.get() == null) { 359 stale = i; // remember 1st stale entry index 360 } ...an index to 1st stale entry is remembered while scanning the array so that at the end, instead of always allocating new slot, an existing slot can be re-used. This has an inadvertent effect on the lifetime of SoftReference(s) that are touched in the process (LRU policy of cleaning). Here we see that an additional method like SoftReference.isPresent() that didn't touch the access time, would be helpful. Regards, Peter On 12/06/2014 01:30 PM, Peter Levart wrote: (Sorry for a re-send, forgot to include core-libs-dev)... Hi Vladimir, First, just a nit. I think that in LambdaFormEditor: 289 private LambdaForm putInCache(Transform key, LambdaForm form) { 290 key = key.withResult(form); 291 for (int pass = 0; ; pass++) { 292 Object c = lambdaForm.transformCache; 293 if (c instanceof ConcurrentHashMap) { 294 @SuppressWarnings(unchecked) 295 ConcurrentHashMapTransform,Transform m = (ConcurrentHashMapTransform,Transform) c; 296 Transform k = m.putIfAbsent(key, key); 297 if (k == null) return form; 298 LambdaForm result = k.get(); 299 if (result != null) { 300 return result; 301 } else { 302 if (m.replace(key, k, key)) { 303 return form; 304 } else { 305 continue; 306 } 307 } 308 } 309 assert(pass == 0); 310 synchronized (lambdaForm) { 311 c = lambdaForm.transformCache; 312 if (c instanceof ConcurrentHashMap) 313 continue; ... 372 lambdaForm.transformCache = c = m; ^^^ put assignment to 'c' back in 373 // The second iteration will update for this query, concurrently. 374 continue; ...you could move the assignment to 'c' in line 292 out of for loop and put it back in line 372, since once 'c' is instance of CHM, lambdaForm.transformCache never changes again and if 'c' is not CHM yet, it is re-assigned in lines 311 and 372 before next loop. Am I right? Now what scares me (might be that I don't have an intimacy with LambdaForm class like you do). There is a situation where you publish LambdaForm instances via data race. One form of LambdaForm.transformCache is an array of Transform objects (the other two forms are not problematic). Transform class has all fields final except the 'referent' field of SoftReference, which holds a LambdaForm instance. In the following line: 377 ta[idx] = key; ...you publish Transform object to an element of array with relaxed write, and in the following lines: 271 } else { 272 Transform[] ta = (Transform[])c; 273 for (int i = 0; i ta.length; i++) { 274 Transform t = ta[i]; 275 if (t == null) break; 276 if (t.equals(key)) { k = t; break; } 277 } 278 } 279 assert(k == null || key.equals(k)); 280 return (k != null) ? k.get() : null; ...you obtain the element of the array with no synchronization and a relaxed read and might return a non-null referent (the LambdaForm) which is then returned as an interned instance. So can LambdaForm instances be published via data races without fear that they would appear half-initialized? That's what I didn't know when I used a lazySet coupled with volatile get to access array elements in my version: http://cr.openjdk.java.net/~plevart/misc/LambdaFormEditor.WeakCache/webrev.01/ Regards, Peter On 12/03/2014 12:45 PM, Vladimir Ivanov wrote: Aleksey, thanks for the review. I haven't tried -XX:SoftRefLRUPolicyMSPerMB=0, but I did extensive testing on Octane/Nashorn with multiple low -Xmx levels + frequent Full GCs (8060147 [1] was the result of those experiments) and stress tested cache eviction with jdk/java/lang/invoke/LFCache tests in long running mode. Best regards, Vladimir Ivanov [1] https://bugs.openjdk.java.net/browse/JDK-8060147 On 12/3/14, 3:11 PM, Aleksey Shipilev wrote: On 12/01/2014 07:58 PM, Vladimir Ivanov wrote: http://cr.openjdk.java.net/~vlivanov/8057020/webrev.00/ https://bugs.openjdk.java.net/browse/JDK-8057020 Looks okay, although the cache management logic gives me a headache after the vacation. I thought I spotted a few bugs, but those were only false positives. The fix is to use SoftReferences to keep LambdaForms alive as long as possible, but avoid throwing OOME until the caches are evicted. I
Re: [9, 8u40] RFR (M): 8057020: LambdaForm caches should support eviction
On Dec 6, 2014, at 1:30 PM, Peter Levart peter.lev...@gmail.com wrote: Now what scares me (might be that I don't have an intimacy with LambdaForm class like you do). There is a situation where you publish LambdaForm instances via data race. One form of LambdaForm.transformCache is an array of Transform objects (the other two forms are not problematic). Transform class has all fields final except the 'referent' field of SoftReference, which holds a LambdaForm instance. In the following line: 377 ta[idx] = key; ...you publish Transform object to an element of array with relaxed write, and in the following lines: 271 } else { 272 Transform[] ta = (Transform[])c; 273 for (int i = 0; i ta.length; i++) { 274 Transform t = ta[i]; 275 if (t == null) break; 276 if (t.equals(key)) { k = t; break; } 277 } 278 } 279 assert(k == null || key.equals(k)); 280 return (k != null) ? k.get() : null; ...you obtain the element of the array with no synchronization and a relaxed read and might return a non-null referent (the LambdaForm) which is then returned as an interned instance. Transform still has final fields, thus when constructing a Transform using key.withResult(form)) i don't think hotspot will reorder the store of the referent, or dependent stores, so that they occur after publication of the key element into the Transform[] array. So i think things are also are ok between putInCache and getInCache. So can LambdaForm instances be published via data races without fear that they would appear half-initialized? AFAICT yes. LambdaForm has final/stable fields and i presume it does not leak in the constructor (even when compiling on construction). See also MethodHandle.updateForm for rare cases where the lambda form of a MethodHandle is updated. Paul. That's what I didn't know when I used a lazySet coupled with volatile get to access array elements in my version: http://cr.openjdk.java.net/~plevart/misc/LambdaFormEditor.WeakCache/webrev.01/ Regards, Peter
Re: [9, 8u40] RFR (M): 8057020: LambdaForm caches should support eviction
Peter, Thanks for looking into that and for you initial prototype! So WeakReferences did not hold LambdaForms long enough even with strong back-reference from LambdaForm to the lambda form 'this' was derived from? So final derived LambdaForms (leaves) are not kept referenced from the code? Or did back-references keep intermediate LambdaForms in cache for too long (forever?) and you wanted them to be evicted too? Regarding back references, my main concern was footprint. In some corner cases, LambdaFormEditor chain can become very long and I wanted to allow unloading of unused LambdaForms. Also, there's another major source of method handles - MethodTypeForm - where most of the LambdaFormEditor chains root. It should be cleared as well to avoid memory exhaustion. Regarding WeakReferences, my experiments showed that cache hit rate degrades significantly when they are used (30x more instantiated LambdaForms- from 1-3k to 30k-60k on Octane/Nashorn). So, SoftReferences look like a good fit. Best regards, Vladimir Ivanov
Re: [9, 8u40] RFR (M): 8057020: LambdaForm caches should support eviction
Peter, Just one more thought... In lines: 358 } else if (stale 0 k.get() == null) { 359 stale = i; // remember 1st stale entry index 360 } ...an index to 1st stale entry is remembered while scanning the array so that at the end, instead of always allocating new slot, an existing slot can be re-used. This has an inadvertent effect on the lifetime of SoftReference(s) that are touched in the process (LRU policy of cleaning). Here we see that an additional method like SoftReference.isPresent() that didn't touch the access time, would be helpful. Good point! However, I don't think that cache eviction policy matters for LabmdaForms. On average, there are very limited number of LambdaForm (up to 8k on Octane/Nashorn in single VM mode). So, in normal situation there should be no need to clear the caches. It's there mostly for correctness - avoid OOME in some corner cases (e.g. random enumeration of method handles). Best regards, Vladimir Ivanov Regards, Peter On 12/06/2014 01:30 PM, Peter Levart wrote: (Sorry for a re-send, forgot to include core-libs-dev)... Hi Vladimir, First, just a nit. I think that in LambdaFormEditor: 289 private LambdaForm putInCache(Transform key, LambdaForm form) { 290 key = key.withResult(form); 291 for (int pass = 0; ; pass++) { 292 Object c = lambdaForm.transformCache; 293 if (c instanceof ConcurrentHashMap) { 294 @SuppressWarnings(unchecked) 295 ConcurrentHashMapTransform,Transform m = (ConcurrentHashMapTransform,Transform) c; 296 Transform k = m.putIfAbsent(key, key); 297 if (k == null) return form; 298 LambdaForm result = k.get(); 299 if (result != null) { 300 return result; 301 } else { 302 if (m.replace(key, k, key)) { 303 return form; 304 } else { 305 continue; 306 } 307 } 308 } 309 assert(pass == 0); 310 synchronized (lambdaForm) { 311 c = lambdaForm.transformCache; 312 if (c instanceof ConcurrentHashMap) 313 continue; ... 372 lambdaForm.transformCache = c = m; ^^^ put assignment to 'c' back in 373 // The second iteration will update for this query, concurrently. 374 continue; ...you could move the assignment to 'c' in line 292 out of for loop and put it back in line 372, since once 'c' is instance of CHM, lambdaForm.transformCache never changes again and if 'c' is not CHM yet, it is re-assigned in lines 311 and 372 before next loop. Am I right? Now what scares me (might be that I don't have an intimacy with LambdaForm class like you do). There is a situation where you publish LambdaForm instances via data race. One form of LambdaForm.transformCache is an array of Transform objects (the other two forms are not problematic). Transform class has all fields final except the 'referent' field of SoftReference, which holds a LambdaForm instance. In the following line: 377 ta[idx] = key; ...you publish Transform object to an element of array with relaxed write, and in the following lines: 271 } else { 272 Transform[] ta = (Transform[])c; 273 for (int i = 0; i ta.length; i++) { 274 Transform t = ta[i]; 275 if (t == null) break; 276 if (t.equals(key)) { k = t; break; } 277 } 278 } 279 assert(k == null || key.equals(k)); 280 return (k != null) ? k.get() : null; ...you obtain the element of the array with no synchronization and a relaxed read and might return a non-null referent (the LambdaForm) which is then returned as an interned instance. So can LambdaForm instances be published via data races without fear that they would appear half-initialized? That's what I didn't know when I used a lazySet coupled with volatile get to access array elements in my version: http://cr.openjdk.java.net/~plevart/misc/LambdaFormEditor.WeakCache/webrev.01/ Regards, Peter On 12/03/2014 12:45 PM, Vladimir Ivanov wrote: Aleksey, thanks for the review. I haven't tried -XX:SoftRefLRUPolicyMSPerMB=0, but I did extensive testing on Octane/Nashorn with multiple low -Xmx levels + frequent Full GCs (8060147 [1] was the result of those experiments) and stress tested cache eviction with jdk/java/lang/invoke/LFCache tests in long running mode. Best regards, Vladimir Ivanov [1] https://bugs.openjdk.java.net/browse/JDK-8060147 On 12/3/14, 3:11 PM, Aleksey Shipilev wrote: On 12/01/2014 07:58 PM, Vladimir Ivanov wrote:
Re: [9, 8u40] RFR (M): 8057020: LambdaForm caches should support eviction
On 12/08/2014 09:09 PM, Vladimir Ivanov wrote: Peter, Just one more thought... In lines: 358 } else if (stale 0 k.get() == null) { 359 stale = i; // remember 1st stale entry index 360 } ...an index to 1st stale entry is remembered while scanning the array so that at the end, instead of always allocating new slot, an existing slot can be re-used. This has an inadvertent effect on the lifetime of SoftReference(s) that are touched in the process (LRU policy of cleaning). Here we see that an additional method like SoftReference.isPresent() that didn't touch the access time, would be helpful. Good point! However, I don't think that cache eviction policy matters for LabmdaForms. On average, there are very limited number of LambdaForm (up to 8k on Octane/Nashorn in single VM mode). So, in normal situation there should be no need to clear the caches. It's there mostly for correctness - avoid OOME in some corner cases (e.g. random enumeration of method handles). Yes, there's nothing wrong. It's just that some LambdaForms can get longer lifetime than they deserve (according to strict LRU policy), but the unreferenced ones should all be released before OOME is thrown anyway. Regards, Peter Best regards, Vladimir Ivanov Regards, Peter On 12/06/2014 01:30 PM, Peter Levart wrote: (Sorry for a re-send, forgot to include core-libs-dev)... Hi Vladimir, First, just a nit. I think that in LambdaFormEditor: 289 private LambdaForm putInCache(Transform key, LambdaForm form) { 290 key = key.withResult(form); 291 for (int pass = 0; ; pass++) { 292 Object c = lambdaForm.transformCache; 293 if (c instanceof ConcurrentHashMap) { 294 @SuppressWarnings(unchecked) 295 ConcurrentHashMapTransform,Transform m = (ConcurrentHashMapTransform,Transform) c; 296 Transform k = m.putIfAbsent(key, key); 297 if (k == null) return form; 298 LambdaForm result = k.get(); 299 if (result != null) { 300 return result; 301 } else { 302 if (m.replace(key, k, key)) { 303 return form; 304 } else { 305 continue; 306 } 307 } 308 } 309 assert(pass == 0); 310 synchronized (lambdaForm) { 311 c = lambdaForm.transformCache; 312 if (c instanceof ConcurrentHashMap) 313 continue; ... 372 lambdaForm.transformCache = c = m; ^^^ put assignment to 'c' back in 373 // The second iteration will update for this query, concurrently. 374 continue; ...you could move the assignment to 'c' in line 292 out of for loop and put it back in line 372, since once 'c' is instance of CHM, lambdaForm.transformCache never changes again and if 'c' is not CHM yet, it is re-assigned in lines 311 and 372 before next loop. Am I right? Now what scares me (might be that I don't have an intimacy with LambdaForm class like you do). There is a situation where you publish LambdaForm instances via data race. One form of LambdaForm.transformCache is an array of Transform objects (the other two forms are not problematic). Transform class has all fields final except the 'referent' field of SoftReference, which holds a LambdaForm instance. In the following line: 377 ta[idx] = key; ...you publish Transform object to an element of array with relaxed write, and in the following lines: 271 } else { 272 Transform[] ta = (Transform[])c; 273 for (int i = 0; i ta.length; i++) { 274 Transform t = ta[i]; 275 if (t == null) break; 276 if (t.equals(key)) { k = t; break; } 277 } 278 } 279 assert(k == null || key.equals(k)); 280 return (k != null) ? k.get() : null; ...you obtain the element of the array with no synchronization and a relaxed read and might return a non-null referent (the LambdaForm) which is then returned as an interned instance. So can LambdaForm instances be published via data races without fear that they would appear half-initialized? That's what I didn't know when I used a lazySet coupled with volatile get to access array elements in my version: http://cr.openjdk.java.net/~plevart/misc/LambdaFormEditor.WeakCache/webrev.01/ Regards, Peter On 12/03/2014 12:45 PM, Vladimir Ivanov wrote: Aleksey, thanks for the review. I haven't tried -XX:SoftRefLRUPolicyMSPerMB=0, but I did extensive testing on Octane/Nashorn with multiple low -Xmx levels + frequent Full GCs (8060147 [1] was the result of those experiments) and stress tested
Re: [9, 8u40] RFR (M): 8057020: LambdaForm caches should support eviction
(Sorry for a re-send, forgot to include core-libs-dev)... Hi Vladimir, First, just a nit. I think that in LambdaFormEditor: 289 private LambdaForm putInCache(Transform key, LambdaForm form) { 290 key = key.withResult(form); 291 for (int pass = 0; ; pass++) { 292 Object c = lambdaForm.transformCache; 293 if (c instanceof ConcurrentHashMap) { 294 @SuppressWarnings(unchecked) 295 ConcurrentHashMapTransform,Transform m = (ConcurrentHashMapTransform,Transform) c; 296 Transform k = m.putIfAbsent(key, key); 297 if (k == null) return form; 298 LambdaForm result = k.get(); 299 if (result != null) { 300 return result; 301 } else { 302 if (m.replace(key, k, key)) { 303 return form; 304 } else { 305 continue; 306 } 307 } 308 } 309 assert(pass == 0); 310 synchronized (lambdaForm) { 311 c = lambdaForm.transformCache; 312 if (c instanceof ConcurrentHashMap) 313 continue; ... 372 lambdaForm.transformCache = c = m; ^^^ put assignment to 'c' back in 373 // The second iteration will update for this query, concurrently. 374 continue; ...you could move the assignment to 'c' in line 292 out of for loop and put it back in line 372, since once 'c' is instance of CHM, lambdaForm.transformCache never changes again and if 'c' is not CHM yet, it is re-assigned in lines 311 and 372 before next loop. Am I right? Now what scares me (might be that I don't have an intimacy with LambdaForm class like you do). There is a situation where you publish LambdaForm instances via data race. One form of LambdaForm.transformCache is an array of Transform objects (the other two forms are not problematic). Transform class has all fields final except the 'referent' field of SoftReference, which holds a LambdaForm instance. In the following line: 377 ta[idx] = key; ...you publish Transform object to an element of array with relaxed write, and in the following lines: 271 } else { 272 Transform[] ta = (Transform[])c; 273 for (int i = 0; i ta.length; i++) { 274 Transform t = ta[i]; 275 if (t == null) break; 276 if (t.equals(key)) { k = t; break; } 277 } 278 } 279 assert(k == null || key.equals(k)); 280 return (k != null) ? k.get() : null; ...you obtain the element of the array with no synchronization and a relaxed read and might return a non-null referent (the LambdaForm) which is then returned as an interned instance. So can LambdaForm instances be published via data races without fear that they would appear half-initialized? That's what I didn't know when I used a lazySet coupled with volatile get to access array elements in my version: http://cr.openjdk.java.net/~plevart/misc/LambdaFormEditor.WeakCache/webrev.01/ Regards, Peter On 12/03/2014 12:45 PM, Vladimir Ivanov wrote: Aleksey, thanks for the review. I haven't tried -XX:SoftRefLRUPolicyMSPerMB=0, but I did extensive testing on Octane/Nashorn with multiple low -Xmx levels + frequent Full GCs (8060147 [1] was the result of those experiments) and stress tested cache eviction with jdk/java/lang/invoke/LFCache tests in long running mode. Best regards, Vladimir Ivanov [1] https://bugs.openjdk.java.net/browse/JDK-8060147 On 12/3/14, 3:11 PM, Aleksey Shipilev wrote: On 12/01/2014 07:58 PM, Vladimir Ivanov wrote: http://cr.openjdk.java.net/~vlivanov/8057020/webrev.00/ https://bugs.openjdk.java.net/browse/JDK-8057020 Looks okay, although the cache management logic gives me a headache after the vacation. I thought I spotted a few bugs, but those were only false positives. The fix is to use SoftReferences to keep LambdaForms alive as long as possible, but avoid throwing OOME until the caches are evicted. I experimented with WeakReferences, but it doesn't hold LambdaForms for long enough: LambdaForm cache hit rate degrades significantly and it negatively affects application startup and warmup, since every instantiated LambdaForm is precompiled to bytecode before usage. Testing: jdk/java/lang/invoke/LFCache in stress mode + jck (api/java_lang/invoke), jdk/java/lang/invoke, jdk/java/util/streams, octane SoftReferences are tricky in the way they can get suddenly drop the referent, and normal testing would not catch it (e.g. the normal operation would reclaim softrefs under your feet almost never). Does this code survive with -XX:SoftRefLRUPolicyMSPerMB=0? Thanks, -Aleksey.
Re: [9, 8u40] RFR (M): 8057020: LambdaForm caches should support eviction
On 12/01/2014 05:58 PM, Vladimir Ivanov wrote: http://cr.openjdk.java.net/~vlivanov/8057020/webrev.00/ https://bugs.openjdk.java.net/browse/JDK-8057020 There are 2 major LambdaForm caches: LambdaFormEditor-based and MethodTypeForm. The former is per-LambdaForm and the latter is per method type erased to basic types. The problem is that these caches don't support eviction, so they can hold LambdaForms forever. Usually, it's not a problem since an application has very limited number of unique erased method types (e.g. on Octane/Nashorn it varies 1,5-3k shapes). The fix is to use SoftReferences to keep LambdaForms alive as long as possible, but avoid throwing OOME until the caches are evicted. I experimented with WeakReferences, but it doesn't hold LambdaForms for long enough: LambdaForm cache hit rate degrades significantly and it negatively affects application startup and warmup, since every instantiated LambdaForm is precompiled to bytecode before usage. Testing: jdk/java/lang/invoke/LFCache in stress mode + jck (api/java_lang/invoke), jdk/java/lang/invoke, jdk/java/util/streams, octane Thanks! Best regards, Vladimir Ivanov Hi Vladimir, So WeakReferences did not hold LambdaForms long enough even with strong back-reference from LambdaForm to the lambda form 'this' was derived from? So final derived LambdaForms (leaves) are not kept referenced from the code? Or did back-references keep intermediate LambdaForms in cache for too long (forever?) and you wanted them to be evicted too? Regards, Peter
Re: [9, 8u40] RFR (M): 8057020: LambdaForm caches should support eviction
Paul, John, thanks! Best regards, Vladimir Ivanov On 12/3/14, 10:38 AM, John Rose wrote: Reviewed. I sympathize with Paul's gnarly comment. Nice bit of stream-ology (rheology) in the test code. Regarding: On Dec 2, 2014, at 8:20 AM, Vladimir Ivanov vladimir.x.iva...@oracle.com wrote: In src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java 366 lambdaForm.transformCache = c = ta; Do you need to set c? It's a local variable and by this point the method should return rather than loop. I did it mostly as a cleanup. Now I think that it doesn't help much. Removed (+ similar change in another place). The c = bit can be viewed as a bug-stopper. It prevents a later expression (if introduced in a future change) from accidentally using 'c' and getting an out-of-date value. A better bug-stopper would be a declaration that c is dead as of this point, and cannot be used any more, but the language does not support that. I don't mind seeing the assignment deleted. — John On Dec 1, 2014, at 8:58 AM, Vladimir Ivanov vladimir.x.iva...@oracle.com wrote: http://cr.openjdk.java.net/~vlivanov/8057020/webrev.00/ https://bugs.openjdk.java.net/browse/JDK-8057020
Re: [9, 8u40] RFR (M): 8057020: LambdaForm caches should support eviction
Aleksey, thanks for the review. I haven't tried -XX:SoftRefLRUPolicyMSPerMB=0, but I did extensive testing on Octane/Nashorn with multiple low -Xmx levels + frequent Full GCs (8060147 [1] was the result of those experiments) and stress tested cache eviction with jdk/java/lang/invoke/LFCache tests in long running mode. Best regards, Vladimir Ivanov [1] https://bugs.openjdk.java.net/browse/JDK-8060147 On 12/3/14, 3:11 PM, Aleksey Shipilev wrote: On 12/01/2014 07:58 PM, Vladimir Ivanov wrote: http://cr.openjdk.java.net/~vlivanov/8057020/webrev.00/ https://bugs.openjdk.java.net/browse/JDK-8057020 Looks okay, although the cache management logic gives me a headache after the vacation. I thought I spotted a few bugs, but those were only false positives. The fix is to use SoftReferences to keep LambdaForms alive as long as possible, but avoid throwing OOME until the caches are evicted. I experimented with WeakReferences, but it doesn't hold LambdaForms for long enough: LambdaForm cache hit rate degrades significantly and it negatively affects application startup and warmup, since every instantiated LambdaForm is precompiled to bytecode before usage. Testing: jdk/java/lang/invoke/LFCache in stress mode + jck (api/java_lang/invoke), jdk/java/lang/invoke, jdk/java/util/streams, octane SoftReferences are tricky in the way they can get suddenly drop the referent, and normal testing would not catch it (e.g. the normal operation would reclaim softrefs under your feet almost never). Does this code survive with -XX:SoftRefLRUPolicyMSPerMB=0? Thanks, -Aleksey.
Re: [9, 8u40] RFR (M): 8057020: LambdaForm caches should support eviction
Thanks, Paul! Updated webrev in place. On Dec 1, 2014, at 5:58 PM, Vladimir Ivanov vladimir.x.iva...@oracle.com wrote: http://cr.openjdk.java.net/~vlivanov/8057020/webrev.00/ https://bugs.openjdk.java.net/browse/JDK-8057020 That LambdaFormEditor.putInCache method just got more gnarly :-) Generally looks good. In src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java 366 lambdaForm.transformCache = c = ta; Do you need to set c? It's a local variable and by this point the method should return rather than loop. I did it mostly as a cleanup. Now I think that it doesn't help much. Removed (+ similar change in another place). In test/java/lang/invoke/LFCaching/LambdaFormTestCase.java 55 private static final ListGarbageCollectorMXBean gcInfo; 56 57 private static long gcCount() { 58 return gcInfo.stream() 59 .map(GarbageCollectorMXBean::getCollectionCount) 60 .reduce(0L, Long::sum); 61 } You can do: gcInfo.stream().mapToLong(GarbageCollectorMXBean::getCollectionCount).sum(); Good point. Updated. Best regards, Vladimir Ivanov Paul. There are 2 major LambdaForm caches: LambdaFormEditor-based and MethodTypeForm. The former is per-LambdaForm and the latter is per method type erased to basic types. The problem is that these caches don't support eviction, so they can hold LambdaForms forever. Usually, it's not a problem since an application has very limited number of unique erased method types (e.g. on Octane/Nashorn it varies 1,5-3k shapes). The fix is to use SoftReferences to keep LambdaForms alive as long as possible, but avoid throwing OOME until the caches are evicted. I experimented with WeakReferences, but it doesn't hold LambdaForms for long enough: LambdaForm cache hit rate degrades significantly and it negatively affects application startup and warmup, since every instantiated LambdaForm is precompiled to bytecode before usage. Testing: jdk/java/lang/invoke/LFCache in stress mode + jck (api/java_lang/invoke), jdk/java/lang/invoke, jdk/java/util/streams, octane Thanks! Best regards, Vladimir Ivanov ___ mlvm-dev mailing list mlvm-...@openjdk.java.net http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev ___ mlvm-dev mailing list mlvm-...@openjdk.java.net http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
Re: [9, 8u40] RFR (M): 8057020: LambdaForm caches should support eviction
On Dec 2, 2014, at 5:20 PM, Vladimir Ivanov vladimir.x.iva...@oracle.com wrote: Thanks, Paul! Updated webrev in place. +1. Paul.
Re: [9, 8u40] RFR (M): 8057020: LambdaForm caches should support eviction
Reviewed. I sympathize with Paul's gnarly comment. Nice bit of stream-ology (rheology) in the test code. Regarding: On Dec 2, 2014, at 8:20 AM, Vladimir Ivanov vladimir.x.iva...@oracle.com wrote: In src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java 366 lambdaForm.transformCache = c = ta; Do you need to set c? It's a local variable and by this point the method should return rather than loop. I did it mostly as a cleanup. Now I think that it doesn't help much. Removed (+ similar change in another place). The c = bit can be viewed as a bug-stopper. It prevents a later expression (if introduced in a future change) from accidentally using 'c' and getting an out-of-date value. A better bug-stopper would be a declaration that c is dead as of this point, and cannot be used any more, but the language does not support that. I don't mind seeing the assignment deleted. — John On Dec 1, 2014, at 8:58 AM, Vladimir Ivanov vladimir.x.iva...@oracle.com wrote: http://cr.openjdk.java.net/~vlivanov/8057020/webrev.00/ https://bugs.openjdk.java.net/browse/JDK-8057020
[9, 8u40] RFR (M): 8057020: LambdaForm caches should support eviction
http://cr.openjdk.java.net/~vlivanov/8057020/webrev.00/ https://bugs.openjdk.java.net/browse/JDK-8057020 There are 2 major LambdaForm caches: LambdaFormEditor-based and MethodTypeForm. The former is per-LambdaForm and the latter is per method type erased to basic types. The problem is that these caches don't support eviction, so they can hold LambdaForms forever. Usually, it's not a problem since an application has very limited number of unique erased method types (e.g. on Octane/Nashorn it varies 1,5-3k shapes). The fix is to use SoftReferences to keep LambdaForms alive as long as possible, but avoid throwing OOME until the caches are evicted. I experimented with WeakReferences, but it doesn't hold LambdaForms for long enough: LambdaForm cache hit rate degrades significantly and it negatively affects application startup and warmup, since every instantiated LambdaForm is precompiled to bytecode before usage. Testing: jdk/java/lang/invoke/LFCache in stress mode + jck (api/java_lang/invoke), jdk/java/lang/invoke, jdk/java/util/streams, octane Thanks! Best regards, Vladimir Ivanov