Re: [9, 8u40] RFR (M): 8057020: LambdaForm caches should support eviction

2014-12-08 Thread Peter Levart

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

2014-12-08 Thread Paul Sandoz
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

2014-12-08 Thread Vladimir Ivanov

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

2014-12-08 Thread Vladimir Ivanov

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

2014-12-08 Thread Peter Levart


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

2014-12-06 Thread Peter Levart

(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

2014-12-05 Thread Peter Levart

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

2014-12-03 Thread Vladimir Ivanov

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

2014-12-03 Thread Vladimir Ivanov

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

2014-12-02 Thread Vladimir Ivanov

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

2014-12-02 Thread Paul Sandoz

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

2014-12-02 Thread John Rose
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

2014-12-01 Thread Vladimir Ivanov

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