Re: Question in understanding ClassValue better

2016-05-19 Thread Jochen Theodorou

On 19.05.2016 21:32, Peter Levart wrote:
[...]

a ClassValue instance can be thought of as a component of a compound
key. Together with a Class, they form a tuple (aClass, aClassValue) that
can be associated with an "associated value", AV. And yes, the AVs
associated with tuple containing a particular Class are strongly
reachable from that Class.


I see, I was mixing ClassValue and AV, I was more talking about AV, than 
ClassValue itself, though ClassValue surely plays an important role in 
here. Anyway, I am going for that AV is the value computed by aClassValue.


You said that the AV is strongly reachable from aClass. Can I further 
assume, that aClassValue is not strongly reachable from aClass? And that 
aClassValue can be collected independent of aClass? Can I further 
assume, that aClassValue can be collected even if AVs for it continue to 
exist?


[...]

An AV associated with a tuple (Integer.TYPE, aClassValue) -> AV can be
garbage collected. But only if aClassValue can be garbage collected 1st.


hmm... so in (aClass, aClassValue)->AV if aClassValue can be collected, 
AV can, but not the other way around... what about aClass? if nothing 
but AV is referencing aClass, can AV be garbage collected, even if 
aClassValue cannot? Can I extend your statement to AV can be collected 
only if either aClass or aClassValue can be garbage collected first?


Let us assume this is the case for now.


This is the most tricky part to get right in order to prevent leaks. If
in above example, aClassValue is reachable from the AV, then we have a
leak. The reachability of a ClassValue instance from the associated
value AV is not always obvious. One has to take into account the
following non-obvious references:

1 - each object instance has an implicit reference to its implementing class
2 - each class has a reference to its defining ClassLoader
3 - each ClassLoader has a reference to all classes defined by it
(except VM annonymous classes)
4 - each ClassLoader has a reference to all its predecessors (that it
delegates to)

Since a ClassValue instance is typically assigned to a static final
field, such instance is reachable from the class that declares the field.

I think you can get the picture from that.


yeah... that is actually problematic. Because if I keep no hard 
reference the ClassValue can be collected, even if the AVs still 
exist... meaning they would become unreachable. And if I keep one I have 
a memory leak... well more about in the program you have shown me later on.


[...]

Ok, let's set up the stage. If I understand you correctly, then:

Groovy runtime is loaded by whatever class loader is loading the
application (see the comment in MetaClass constructor if this is not
true).  This is either the ClassLoader.getSystemClassLoader() (the APP
class loader) if started from command line or for example Web App class
loader in a Web container.


Well, actually... if you start a script on the command line, the loader 
is a child to the app class loader, when used as library it could be the 
app loader (for example if the groovy program is precompiled) and in a 
tomcat like scenario it could be either the class loader for the web 
app, or the loader for all web apps. But let's go with the cases you 
mentioned first ;)



MetaClass(es) are objects implemented by Groovy runtime class(es). Let's
call them simply MetaClass.


good


Here's how I would do that:


public class MetaClass {

 // this list keeps MetaClass instances strongly reachable from the 
MetaClass
 // class(loader) since they are only weakly reachable from their associated
 // Class(es)
 private static final ArrayList META_CLASS_LIST = new 
ArrayList<>();

 // this WeakReference is constructed so that it keeps a strong reference
 // to a referent until releaseStrong() is called
 private static final class WeakEntry extends WeakReference {
 private final AtomicReference strong;

 WeakEntry(MetaClass mc) {
 super(mc);
 strong = new AtomicReference<>(mc);
 }

 boolean releaseStrong() {
 MetaClass mc = strong.get();
 return mc != null && strong.compareAndSet(mc, null);
 }
 }

 private static final ClassValue WEAK_ENTRY_CV =
 new ClassValue() {
 @Override
 protected WeakEntry computeValue(Class type) {
 return new WeakEntry(new MetaClass(type));
 }
 };

 // the public API
 public MetaClass getInstanceFor(Class type) {
 WeakEntry entry = WEAK_ENTRY_CV.get(type);
 MetaClass mc = entry.get();
 if (entry.releaseStrong()) {
 synchronized (META_CLASS_LIST) {
 META_CLASS_LIST.add(mc);
 }
 }
 return mc;
 }

 MetaClass(Class type) {
 // derive it from 'type', but don't reference it
 // strongly if Groovy runtime is loaded by a parent
 // class loader 

Re: Question in understanding ClassValue better

2016-05-19 Thread Peter Levart

A small correction...


On 05/19/2016 09:32 PM, Peter Levart wrote:

// the public API
public MetaClass getInstanceFor(Class type) {


This should of course read:

 // the public API
public *static* MetaClass getInstanceFor(Class type) {


Regards, Peter

___
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev


Re: Question in understanding ClassValue better

2016-05-19 Thread Peter Levart

Hi Jochen,

I'll try to answer your questions as profoundly as I can...


On 05/19/2016 04:27 PM, Jochen Theodorou wrote:

Hi,

at the beginning of this year I had an exchange with Peter Lavart 
about JDK-8136353 (see 
http://mail.openjdk.java.net/pipermail/mlvm-dev/2016-January/006563.html), 
and that is probably based on wrong assumptions. But I must confess I 
still have trouble understanding ClassValue semantics. And since the 
ClassValue problem in Groovy came up again, I though I make another 
try based on a list of assumptions and asking if they are wrong or right


1) ClassValue can be basically understood as a strong reference of a 
class to a class value


a ClassValue instance can be thought of as a component of a compound 
key. Together with a Class, they form a tuple (aClass, aClassValue) that 
can be associated with an "associated value", AV. And yes, the AVs 
associated with tuple containing a particular Class are strongly 
reachable from that Class.


2) a ClassValue associated with a system class (for example 
Integer.TYPE) is never garbage collected


An AV associated with a tuple (Integer.TYPE, aClassValue) -> AV can be 
garbage collected. But only if aClassValue can be garbage collected 1st. 
This is the most tricky part to get right in order to prevent leaks. If 
in above example, aClassValue is reachable from the AV, then we have a 
leak. The reachability of a ClassValue instance from the associated 
value AV is not always obvious. One has to take into account the 
following non-obvious references:


1 - each object instance has an implicit reference to its implementing class
2 - each class has a reference to its defining ClassLoader
3 - each ClassLoader has a reference to all classes defined by it 
(except VM annonymous classes)
4 - each ClassLoader has a reference to all its predecessors (that it 
delegates to)


Since a ClassValue instance is typically assigned to a static final 
field, such instance is reachable from the class that declares the field.


I think you can get the picture from that.

3) a ClassValue from a different loader than the system loader, 
associated with a system class, will prevent that loader to unload


You mean an instance of a ClassValue subclass loaded by a non-system 
class loader? I don't think this matters much. Any object instance with 
a runtime class that is not a system class, while being reachable, holds 
the non-system ClassLoader non-reclaimable (this follows from the 1st 
and 2nd rules of non-obvious references above)


a ClassValue instance is not associated with a Class. (aClass, 
aClassValue) tuple is associated with an associated value AV. Such 
association is implemented in a way where aClassValue is not strongly 
reachable from aClass BECAUSE OF THE ASSOCIATION ITSELF, if that is what 
you wanted to know.


4) a ClassValue referencing to the class it is associated with, does 
not prevent the collection of that class


An association (aClass, aClassValue) -> AV is implemented in a way where 
aClass is not strongly reachable from aClassValue BECAUSE OF THE 
ASSOCIATION ITSELF. It can still be reachable because of other 
non-obvious references mentioned above.




Point 2 and 3 are kind of problematic for me and I wish them wrong, 
but they would follow from 1. The exchange with Peter makes me think 
assumption 4 is wrong... just I don't understand why.


If those assumptions are right, then I actually wonder in what cases I 
should use ClassValue without causing memory leaks. What I wanted to 
use it for is to associate a meta class with every class I need a meta 
class for. This includes system classes. If 3 is right, then doing so 
would prevent the Groovy runtime from being unloaded. Even if the meta 
classes are able to unload, the implementation of the ClassValue would 
still be there. And since that comes from the same loader, that loaded 
the runtime, that loader will stay. Now loading and (trying to) unload 
the Groovy runtime countless times would end up in a OOME at some 
point (permgen problem in older JDKs). And even if I would do 
something else for class from the standard loaders, I would still get 
into trouble on for example Tomcat. Not to forget that having two 
parallel structures for this raises the question as of why to use 
ClassValue at all.


I think what it boils down to in the end is: When (under what 
conditions) for what to use ClassValue at all.


bye Jochen



Ok, let's set up the stage. If I understand you correctly, then:

Groovy runtime is loaded by whatever class loader is loading the 
application (see the comment in MetaClass constructor if this is not 
true). This is either the ClassLoader.getSystemClassLoader() (the APP 
class loader) if started from command line or for example Web App class 
loader in a Web container.


MetaClass(es) are objects implemented by Groovy runtime class(es). Let's 
call them simply MetaClass.



Here's how I would do that:


public class MetaClass {

// this list keeps 

Question in understanding ClassValue better

2016-05-19 Thread Jochen Theodorou

Hi,

at the beginning of this year I had an exchange with Peter Lavart about 
JDK-8136353 (see 
http://mail.openjdk.java.net/pipermail/mlvm-dev/2016-January/006563.html), 
and that is probably based on wrong assumptions. But I must confess I 
still have trouble understanding ClassValue semantics. And since the 
ClassValue problem in Groovy came up again, I though I make another try 
based on a list of assumptions and asking if they are wrong or right


1) ClassValue can be basically understood as a strong reference of a 
class to a class value
2) a ClassValue associated with a system class (for example 
Integer.TYPE) is never garbage collected
3) a ClassValue from a different loader than the system loader, 
associated with a system class, will prevent that loader to unload
4) a ClassValue referencing to the class it is associated with, does not 
prevent the collection of that class


Point 2 and 3 are kind of problematic for me and I wish them wrong, but 
they would follow from 1. The exchange with Peter makes me think 
assumption 4 is wrong... just I don't understand why.


If those assumptions are right, then I actually wonder in what cases I 
should use ClassValue without causing memory leaks. What I wanted to use 
it for is to associate a meta class with every class I need a meta class 
for. This includes system classes. If 3 is right, then doing so would 
prevent the Groovy runtime from being unloaded. Even if the meta classes 
are able to unload, the implementation of the ClassValue would still be 
there. And since that comes from the same loader, that loaded the 
runtime, that loader will stay. Now loading and (trying to) unload the 
Groovy runtime countless times would end up in a OOME at some point 
(permgen problem in older JDKs). And even if I would do something else 
for class from the standard loaders, I would still get into trouble on 
for example Tomcat. Not to forget that having two parallel structures 
for this raises the question as of why to use ClassValue at all.


I think what it boils down to in the end is: When (under what 
conditions) for what to use ClassValue at all.


bye Jochen
___
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev


Re: ClassValue perf?

2016-05-19 Thread Aleksey Shipilev
On 05/19/2016 03:32 PM, Michael Haupt wrote:
> It may well be that running the bechmark so few times does not deliver a
> stable enough result. I'd like Aleksey to comment on this: is adopting
> Peter's code worthwhile given it improves on footprint and reduces code
> size and complexity?

Eh, if you pose the question like that, the answer is obviously "yes". I
like how Peter's version strips down the ClassValue impl.

But, looking at the data, it would seem we are regressing randomAccess
with low classValueCount?

Benchmark (cCount)  (cvCount)   Mode  CntScoreError  Units

# result-plain.txt
randomAccess  1024  1   avgt   1018.375 ±  0.046  ns/op
randomAccess  1024  4   avgt   1026.755 ±  0.018  ns/op
randomAccess  1024 16   avgt   1026.263 ±  0.024  ns/op
randomAccess  1024256   avgt   1053.543 ±  0.419  ns/op

# result-plevart-03.txt
randomAccess  1024  1   avgt   1023.315 ±  0.053  ns/op
randomAccess  1024  4   avgt   1028.323 ±  0.053  ns/op
randomAccess  1024 16   avgt   1029.514 ±  0.070  ns/op
randomAccess  1024256   avgt   1045.339 ±  0.035  ns/op

This seems to go the other direction Michael was pursuing: optimizing
the single-value case. Seems even more pronunciated on low classCount.

I'd be more happy if we can at least not regress the performance. If
there is a cleaner implementation with the same perf characteristics,
I'd be inclined to accept it, of course.

> I agree regarding whether there's a point in optimising for single-value
> storage whilst maintaining full flexibility. In a scenario where it is
> known that only one value will be associated with a class, it's better
> to use static fields.

Specialized solutions that can use the knowledge about the external
condition would always win, given enough effort. The improvements in
shared infrastructure are still very welcome, because they break the
chicken-and-egg problem: you would not use a shared API if it is slow,
and you would not optimize shared API because nobody uses it.

Thanks,
-Aleksey



signature.asc
Description: OpenPGP digital signature
___
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev


Re: ClassValue perf?

2016-05-19 Thread Michael Haupt
Hi Peter,thank you. As some background info, the machine I'm running the benchmarks on is a 32-core Xeon.Results of running your latest benchmarks with unmodified 9-dev and your two patches (02, 03) are attached. Overall, it seems your solution 03 is a bit slower than 02, and 02 shines especially in the expunging benchmark, but also for random access with large numbers of classes and class values. It appears to be somewhat slower than the unmodified case, though.It may well be that running the bechmark so few times does not deliver a stable enough result. I'd like Aleksey to comment on this: is adopting Peter's code worthwhile given it improves on footprint and reduces code size and complexity?I agree regarding whether there's a point in optimising for single-value storage whilst maintaining full flexibility. In a scenario where it is known that only one value will be associated with a class, it's better to use static fields.Best,MichaelBenchmark (classCount)  (classValueCount)  
(classValuesPerPart)  (classesPerPart)   (impl)  (partitions)  Mode  Cnt 
ScoreError  Units
ClassValueBench.randomAccess   128  1   
N/A   N/A  unknown   N/A  avgt   1010.190 
±  0.014  ns/op
ClassValueBench.randomAccess   128  4   
N/A   N/A  unknown   N/A  avgt   1012.000 
±  0.164  ns/op
ClassValueBench.randomAccess   128 16   
N/A   N/A  unknown   N/A  avgt   1016.131 
±  0.026  ns/op
ClassValueBench.randomAccess   128256   
N/A   N/A  unknown   N/A  avgt   1024.267 
±  0.065  ns/op
ClassValueBench.randomAccess  1024  1   
N/A   N/A  unknown   N/A  avgt   1018.375 
±  0.046  ns/op
ClassValueBench.randomAccess  1024  4   
N/A   N/A  unknown   N/A  avgt   1026.755 
±  0.018  ns/op
ClassValueBench.randomAccess  1024 16   
N/A   N/A  unknown   N/A  avgt   1026.263 
±  0.024  ns/op
ClassValueBench.randomAccess  1024256   
N/A   N/A  unknown   N/A  avgt   1053.543 
±  0.419  ns/op
ClassValueBench.sequentialAccess   128  1   
N/A   N/A  unknown   N/A  avgt   1011.063 
±  0.077  ns/op
ClassValueBench.sequentialAccess   128  4   
N/A   N/A  unknown   N/A  avgt   10 9.384 
±  0.033  ns/op
ClassValueBench.sequentialAccess   128 16   
N/A   N/A  unknown   N/A  avgt   1010.534 
±  0.036  ns/op
ClassValueBench.sequentialAccess   128256   
N/A   N/A  unknown   N/A  avgt   1018.038 
±  0.119  ns/op
ClassValueBench.sequentialAccess  1024  1   
N/A   N/A  unknown   N/A  avgt   1014.862 
±  0.013  ns/op
ClassValueBench.sequentialAccess  1024  4   
N/A   N/A  unknown   N/A  avgt   1011.586 
±  0.027  ns/op
ClassValueBench.sequentialAccess  1024 16   
N/A   N/A  unknown   N/A  avgt   10 8.949 
±  0.116  ns/op
ClassValueBench.sequentialAccess  1024256   
N/A   N/A  unknown   N/A  avgt   1043.170 
±  0.074  ns/op
ClassValueExpungeBench.redeployPartition   N/AN/A   
  8  1024  unknown16ss   16   130.911 
± 10.815  ms/op
ClassValueExpungeBench.redeployPartition   N/AN/A   
  8  4096  unknown16ss   16   435.190 
± 32.679  ms/op
ClassValueExpungeBench.redeployPartition   N/AN/A   
 64  1024  unknown16ss   16   569.942 
± 68.902  ms/op
ClassValueExpungeBench.redeployPartition   N/AN/A   
 64  4096  unknown16ss   16  1485.027 
± 91.200  ms/op
Benchmark (classCount)  (classValueCount)  
(classValuesPerPart)  (classesPerPart)   (impl)  (partitions)  Mode  Cnt
ScoreError  Units
ClassValueBench.randomAccess   128  1   
N/A   N/A  unknown   N/A  avgt   10   

Re: ClassValue perf?

2016-05-19 Thread Michael Haupt
Hi Christian,

> Am 06.05.2016 um 22:35 schrieb Christian Thalinger 
> :
>> Given that one concern with this issue, next to reducing footprint, was to 
>> optimise for the single-value case, I'm still a bit hesitant even though the 
>> sheer amount of code reduction is impressive. I'll evaluate further.
> 
> The main motivation to optimize for the single-value use case is Graal but 
> it’s not super important.  Graal solved this issue in a different way and 
> it’s questionable Graal would go back using ClassValue so don’t worry too 
> much about it.

IIRC Graal has adopted static field storage for its single-value case. Beating 
that with a solution that has to have the flexibility of multiple values as 
well? Fat chance. :-)

Thanks for confirming,

Michael

-- 

 
Dr. Michael Haupt | Principal Member of Technical Staff
Phone: +49 331 200 7277 | Fax: +49 331 200 7561
Oracle Java Platform Group | LangTools Team | Nashorn
Oracle Deutschland B.V. & Co. KG | Schiffbauergasse 14 | 14467 Potsdam, Germany

ORACLE Deutschland B.V. & Co. KG | Hauptverwaltung: Riesstraße 25, D-80992 
München
Registergericht: Amtsgericht München, HRA 95603

Komplementärin: ORACLE Deutschland Verwaltung B.V. | Hertogswetering 163/167, 
3543 AS Utrecht, Niederlande
Handelsregister der Handelskammer Midden-Nederland, Nr. 30143697
Geschäftsführer: Alexander van der Ven, Jan Schultheiss, Val Maher
  Oracle is committed to developing 
practices and products that help protect the environment

___
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev