Re: Proxy.isProxyClass scalability

2013-04-29 Thread Aleksey Shipilev
On 04/27/2013 11:37 AM, Alan Bateman wrote:
 On 27/04/2013 00:13, Mandy Chung wrote:
 Peter,

 I have pushed the changeset:

 Changeset: 5e7ae178b24d
 Author:plevart
 Date:  2013-04-26 16:09 -0700
 URL:http://hg.openjdk.java.net/jdk8/tl/jdk/rev/5e7ae178b24d

 Mandy
 This is great work, thank you!

+1.

-Aleksey.

P.S. Dear Santa, please get more people like Peter in this project, please?


Re: Proxy.isProxyClass scalability

2013-04-27 Thread Alan Bateman

On 27/04/2013 00:13, Mandy Chung wrote:

Peter,

I have pushed the changeset:

Changeset: 5e7ae178b24d
Author:plevart
Date:  2013-04-26 16:09 -0700
URL:http://hg.openjdk.java.net/jdk8/tl/jdk/rev/5e7ae178b24d

Mandy

This is great work, thank you!

-Alan.



Re: Proxy.isProxyClass scalability

2013-04-26 Thread Peter Levart

Hi Mandy,

Just a note on null keys (1st level)...

On 04/25/2013 11:53 PM, Mandy Chung wrote:

Hi Peter,

This looks great.  I have imported your patch with slight modification 
in WeakCache:

http://cr.openjdk.java.net/~mchung/jdk8/webrevs/7123493/webrev.01/

I believe WeakCache.get(K, P) should throw NPE if key is null and I 
fixed that. 


The null key support is necessary to support bootstrap classloader as a 
key. It could be supported by a separate 2nd-level map internally 
(instead of using singleton NULL_KEY substitute Object), but the 
external API must support null. And as I can see the webrev at above URL 
still supports it.


I changed refQueue to be of type ReferenceQueueK rather than 
ReferenceQueueObject since CacheValue no longer added to the ref 
queue.  In the expungeStaleEntries method, change CacheKey? to 
CacheKeyK.  WeakCache.get(K, P) takes instance of K and P but 
subKeyFactory and valueFactory take superclasses of K and P - is that 
what you really want?  I have changed them to BiFunctionK,P, I 
also fixed a few typos and that's all.


It's just standard wildcards to allow functions with contra-varint 
parameters and co-variant returns. It's useful as a generic API but in 
our concrete usage doesn't have a value.


The performance improvement is significant and I want to push this 
version to jdk8/tl.  We can tune the memory usage in the future if 
that turns out to be an issue.  I don't have plan to backport to 
jdk7u-dev unless there are customers escalating this :)  This should 
be easy to convert without using BiFunction and Supplier and I will 
leave it as it is until there is a request to backport.


I keep Key2 class since jdk also creates a proxy of 2 interfaces and 
you have already implemented it.  If we think of a better way to 
replace the generation of the subkey in an optimized way, we could 
improve that in the future.  The first and second level maps 
maintained in the WeakCache have Object as the type for the key which 
I think we should look for a specific type (CacheKey and SubKey 
type).  To make the key of the first-level map to CacheKey would need 
to keep a separate cache for null key.  For the second-level map, the 
subkey type would need to be declared as a parameter type to 
WeakCache.  They are something that we should look at and clean up in 
the future if appropriate.  I think what you have is good work that 
shouldn't be delayed any further.


The CacheKey is only private and internal to WeekCache, so making the 
1st-level map's key as Object allows for NULL_KEY trick and makes logic 
more uniform. If bootstrap classloader is used a lot to define proxy 
classes, then a separate map can be viewed as a little speed-up for a 
special case though (saves one Map.get, but introduces complications 
with lazy instantiation - with AtomicReference perhaps). The sub-key as 
a type parameter would only have some value if we would want the user of 
WeakCache to constrain himself on the type of sub-keys returned by the 
supplied subKeyFunction - so the constraint (the type of sub-keys) would 
be specified together with the constrained function - at the WeakCache 
constructor call site. In our case we would have to instantiate it as 
Object (the common supertype of key0, Key1, Key2 and KeyX). The type 
parameter for sub-key has little value in general, since WeakCache only 
needs them to be Objects and sub-keys are never returned from the 
methods of the public API...




I'm running more tests.  If the above webrev looks fine with you, I'll 
push the changeset tomorrow.


thanks
Mandy


Fingers crossed.

Regards, Peter



On 4/25/13 8:40 AM, Peter Levart wrote:

Hi Mandy,

Here's another update that changes the sub-key back to 
WeakReferenceClass based:


http://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy-wc/webrev.05/index.html

On 04/25/2013 03:38 AM, Mandy Chung wrote:
I like this one too.  The mapping is straight forward and clean that 
avoids the fallback and post validation path. Let's proceed with 
this one.  It's good to optimize for the common case (1-interface). 
For 2 or more interfaces, we can improve the memory usage in the 
future when it turns out to be an issue.  I'm fine with the 
zero-interface proxy which is the current implementation too.


I made 3 straight-forward implementations of sub-keys:
- Key1 - single interface
- Key2 - two interfaces
- KeyX - any number of interfaces

The cache-structure size increment for each new cached proxy-class is 
(32 bit OOPS):


#of intfcs  original  patched
--    
 1   152  128(Key1)
 2   152  168(Key2), 208(KeyX)
 3   160  248(KeyX)
 4   160  280(KeyX)

...so you can decide if Key2 is worth having or not.



WeakCache.java
   The javadoc for the get(K,P) method - @throws RuntimeException 
and @throws Error are not needed here since any method being called 
in the implementation may throw unchecked exceptions.  There are 

Re: Proxy.isProxyClass scalability

2013-04-26 Thread Mandy Chung


On 4/25/2013 11:53 PM, Peter Levart wrote:
I believe WeakCache.get(K, P) should throw NPE if key is null and I 
fixed that. 




Oops... typo sorry for the confusion.- I meant WeakCache.containsKey(V 
value) should throw NPE if value is null.


Mandy


Re: Proxy.isProxyClass scalability

2013-04-26 Thread Peter Levart

On 04/26/2013 08:57 AM, Mandy Chung wrote:


On 4/25/2013 11:53 PM, Peter Levart wrote:
I believe WeakCache.get(K, P) should throw NPE if key is null and I 
fixed that. 




Oops... typo sorry for the confusion.- I meant WeakCache.containsKey(V 
value) should throw NPE if value is null.


I agree. Analogous to ConcurrentHashMap, for example.



Mandy




Re: Proxy.isProxyClass scalability

2013-04-26 Thread Mandy Chung

Peter,

I have pushed the changeset:

Changeset: 5e7ae178b24d
Author:plevart
Date:  2013-04-26 16:09 -0700
URL:http://hg.openjdk.java.net/jdk8/tl/jdk/rev/5e7ae178b24d

Mandy




Re: Proxy.isProxyClass scalability

2013-04-25 Thread Peter Levart

Hi Mandy,

Here's another update that changes the sub-key back to 
WeakReferenceClass based:


http://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy-wc/webrev.05/index.html


On 04/25/2013 03:38 AM, Mandy Chung wrote:
I like this one too.  The mapping is straight forward and clean that 
avoids the fallback and post validation path. Let's proceed with this 
one.  It's good to optimize for the common case (1-interface). For 2 
or more interfaces, we can improve the memory usage in the future when 
it turns out to be an issue.  I'm fine with the zero-interface proxy 
which is the current implementation too.


I made 3 straight-forward implementations of sub-keys:
- Key1 - single interface
- Key2 - two interfaces
- KeyX - any number of interfaces

The cache-structure size increment for each new cached proxy-class is 
(32 bit OOPS):


#of intfcs  original  patched
--    
 1   152  128(Key1)
 2   152  168(Key2), 208(KeyX)
 3   160  248(KeyX)
 4   160  280(KeyX)

...so you can decide if Key2 is worth having or not.



WeakCache.java
   The javadoc for the get(K,P) method - @throws RuntimeException and 
@throws Error are not needed here since any method being called in the 
implementation may throw unchecked exceptions. There are a couple 
places that checks if (reverseMap != null)  that check is not 
needed since it's always non-null.  But I'm fine if you keep it as it 
is - just wanted to mention it in case it was just leftover from the 
previous version.


Removed the unneeded @throws and reverseMap != null checks (the later 
was already removed in latest string-based webrev and I used that 
version here).




I think we're very close of getting this pushed.



Do you think this could also get backported to JDK7? The WeakCache uses 
two interfaces from java.util.function. Should we make private 
equivalents in this patch or do we leave that for the possible 
back-porting effort. I should note that JDK7's ConcurrentHashMap is not 
that space-efficient as proposed JDK8's, so space-usage would be 
different on JDK7...


Regards, Peter




thanks
Mandy




Re: Proxy.isProxyClass scalability

2013-04-25 Thread Mandy Chung

Hi Peter,

This looks great.  I have imported your patch with slight modification 
in WeakCache:

  http://cr.openjdk.java.net/~mchung/jdk8/webrevs/7123493/webrev.01/

I believe WeakCache.get(K, P) should throw NPE if key is null and I 
fixed that.  I changed refQueue to be of type ReferenceQueueK rather 
than ReferenceQueueObject since CacheValue no longer added to the ref 
queue.  In the expungeStaleEntries method, change CacheKey? to 
CacheKeyK.  WeakCache.get(K, P) takes instance of K and P but 
subKeyFactory and valueFactory take superclasses of K and P - is that 
what you really want?  I have changed them to BiFunctionK,P, I 
also fixed a few typos and that's all.


The performance improvement is significant and I want to push this 
version to jdk8/tl.  We can tune the memory usage in the future if that 
turns out to be an issue.  I don't have plan to backport to jdk7u-dev 
unless there are customers escalating this :)  This should be easy to 
convert without using BiFunction and Supplier and I will leave it as it 
is until there is a request to backport.


I keep Key2 class since jdk also creates a proxy of 2 interfaces and you 
have already implemented it.  If we think of a better way to replace the 
generation of the subkey in an optimized way, we could improve that in 
the future.  The first and second level maps maintained in the WeakCache 
have Object as the type for the key which I think we should look for a 
specific type (CacheKey and SubKey type).  To make the key of the 
first-level map to CacheKey would need to keep a separate cache for null 
key.  For the second-level map, the subkey type would need to be 
declared as a parameter type to WeakCache.  They are something that we 
should look at and clean up in the future if appropriate.  I think what 
you have is good work that shouldn't be delayed any further.


I'm running more tests.  If the above webrev looks fine with you, I'll 
push the changeset tomorrow.


thanks
Mandy

On 4/25/13 8:40 AM, Peter Levart wrote:

Hi Mandy,

Here's another update that changes the sub-key back to 
WeakReferenceClass based:


http://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy-wc/webrev.05/index.html

On 04/25/2013 03:38 AM, Mandy Chung wrote:
I like this one too.  The mapping is straight forward and clean that 
avoids the fallback and post validation path. Let's proceed with this 
one.  It's good to optimize for the common case (1-interface). For 2 
or more interfaces, we can improve the memory usage in the future 
when it turns out to be an issue.  I'm fine with the zero-interface 
proxy which is the current implementation too.


I made 3 straight-forward implementations of sub-keys:
- Key1 - single interface
- Key2 - two interfaces
- KeyX - any number of interfaces

The cache-structure size increment for each new cached proxy-class is 
(32 bit OOPS):


#of intfcs  original  patched
--    
 1   152  128(Key1)
 2   152  168(Key2), 208(KeyX)
 3   160  248(KeyX)
 4   160  280(KeyX)

...so you can decide if Key2 is worth having or not.



WeakCache.java
   The javadoc for the get(K,P) method - @throws RuntimeException and 
@throws Error are not needed here since any method being called in 
the implementation may throw unchecked exceptions.  There are a 
couple places that checks if (reverseMap != null)  that check is 
not needed since it's always non-null.  But I'm fine if you keep it 
as it is - just wanted to mention it in case it was just leftover 
from the previous version.


Removed the unneeded @throws and reverseMap != null checks (the later 
was already removed in latest string-based webrev and I used that 
version here).




I think we're very close of getting this pushed.



Do you think this could also get backported to JDK7? The WeakCache 
uses two interfaces from java.util.function. Should we make private 
equivalents in this patch or do we leave that for the possible 
back-porting effort. I should note that JDK7's ConcurrentHashMap is 
not that space-efficient as proposed JDK8's, so space-usage would be 
different on JDK7...


Regards, Peter




thanks
Mandy






Re: Proxy.isProxyClass scalability

2013-04-24 Thread Peter Levart

Hi Mandy,

On 04/24/2013 01:43 AM, Mandy Chung wrote:

Hi Peter,

Sorry for the delay.

On 4/20/2013 12:31 AM, Peter Levart wrote:

Hi Mandy,

I have another idea. Before jumping to implement it, I will first ask 
what do you think of it. For example:


- have an optimal interface names key calculated from interfaces.
- visibility of interfaces and other validations are pushed to 
slow-path (inside ProxyClassFactory.apply)
- the proxy Class object returned from WeakCache.get() is 
post-validated with a check like:


for (Class? intf : interfaces) {
if (!intf.isAssignableFrom(proxyClass)) {
throw new IllegalArgumentException();
}
}
// return post-validated proxyClass from getProxyClass0()...

I feel that Class.isAssignableFrom(Class) check could be much faster 
and that the only reason the check can fail is if some interface is 
not visible from the class loader.


Am I correct?


The isAssignableFrom check should be correct for well-behaved class 
loaders [1].  However, for non well-behaved class loaders, I'm not 
absolutely confident that this is right.  The case that I was 
concerned is when intf.isAssignableFrom(proxyClass) returns true but 
the proxy class doesn't implement the runtime types (i.e. given 
interfaces).   Precise check should be to validate if the given 
interfaces == the proxy interfaces implemented by the cached proxy 
class (i.e. proxyClass.getInterfaces()).


Really? This can happen? Could you describe a situation when?



Class.isAssignableFrom method checks if the proxy class is a subtype 
of the interface and no class loading/resolution involved.  It's 
definitely much cheaper than Class.forName which involves checking if 
a class is loaded (class loader delegation and class file search if 
not loaded - which is not the case you measure).


The existing implementation uses the interface names as the key to the 
per-loader proxy class cache.   I think we should use the Class?[] 
as the key (your webrev.02).   I have quickly modified the version I 
sent you (simply change the Key class to use Class?[] rather than 
String[] but didn't change the concurrent map cache to keep weak 
references) and the benchmark shows comparable speedup.


I just noticed the following (have been thinking of it already, but 
then forgot) in original code:


/*
 512  * Note that we need not worry about reaping the 
cache for
 513  * entries with cleared weak references because if a 
proxy class
 514  * has been garbage collected, its class loader will 
have been
 515  * garbage collected as well, so the entire cache 
will be reaped

 516  * from the loaderToCache map.
 517  */




Hmm... I think the original code has the class loader leak.  The 
WeakHashMapClassLoader, HashMapListString, Class keeps a weak 
reference to the ClassLoader but a strong reference to the cache of 
the proxy classes that are defined by that class loader.  The proxy 
classes are not GC'ed and thus the class loader is still kept alive.


Original code is actualy using the following structure: 
WeakHashMapClassLoader, HashMapListString, WeakReferenceClass

... so no ClassLoader leak here...

The TwoLevelWeakCache is an analogous structure: 
ConcurrentHashMapWeakReferenceClassLoader, ConcurrentHashMapSubKey, 
WeakReferenceClass


The point I was trying to make is that it is not needed to register a 
ReferenceQueue with WeakReferenceClass values and remove entries as 
they are cleared and enqueued, because they will not be cleared until 
the ClassLoader that defines the Class-es is GC-ed and the expunging 
logic can work solely on the grounds of cleared and enqueued 
WeakReferenceClassLoader keys, which is what my latest webrev using 
String-based sub-keys does (I have to update the other too).





Each ClassLoader maintains explicit hard-references to all Class 
objects for classes defined by the loader. So proxy Class object can 
not be GC-ed until the ClassLoader is GC-ed. So we need not register 
the CacheValue objects in WeakCache with a refQueue. The expunging of 
reverseMap entries is already performed with CacheKey when it is 
cleared and equeued. There's no harm as it is, since the clean-up is 
performed with all the checks and is idempotent, but it need not be 
done for ClassValue objects holding weak references to proxy Class 
objects.




As explained above, for the per-loader proxy class cache, both the key 
(interfaces) and the proxy class should be wrapped with weak reference.


Not the key (interfaces array) but the individual interface Class object 
- each has to be separately wrapped with a WeakReference. If you just do 
the WeakReferenceClass[] it will quickly be cleared since no-one is 
holding a strong reference to the array object.


The following webrev was an attempt in that direction (notice different 
name in URL: proxy-wc-wi - WeakCache-WeakInterfaces - I maintain 
separate numbering for webrevs in this branch):



Re: Proxy.isProxyClass scalability

2013-04-24 Thread Peter Levart


On 04/24/2013 07:33 AM, Mandy Chung wrote:

More comments in addition to what I replied earlier

On 4/23/2013 4:43 PM, Mandy Chung wrote:


Each ClassLoader maintains explicit hard-references to all Class 
objects for classes defined by the loader. So proxy Class object can 
not be GC-ed until the ClassLoader is GC-ed. 


AFAIU, a class loader will be GC'ed as long as there is no reference 
to any of its loaded classes.  The ClassLoader's internal vector of 
keeping the loaded classes is to prevent the classes from being GC'ed 
until the class loader is being GC'ed which will unload the classes.


So we should make the class loader and the proxy classes weak 
referenced so that they will be GC'ed properly.


That's right.



So we need not register the CacheValue objects in WeakCache with a 
refQueue. The expunging of reverseMap entries is already performed 
with CacheKey when it is cleared and equeued. There's no harm as it 
is, since the clean-up is performed with all the checks and is 
idempotent, but it need not be done for ClassValue objects holding 
weak references to proxy Class objects.



I actually think we don't need to make CacheKey as a weak reference 
but the CacheValue object should still be registered in the refQueue.  
The proxy class in the CacheValue implementing the given interfaces 
always reference the interfaces in the CacheKey and it means that the 
classes in the CacheKey will never be GC'ed before the proxy class.   
When there is no reference to the proxy class, it will be added to the 
reference queue.  Once the entry with the CacheValue holding the proxy 
class is expunged,  the interfaces will not be referenced in the cache.


But! If the interface in the sub-key (the CacheKey in WeakCache is the 
1st-level key and is a WeakReferenceClassLoader, the sub-key holds 
interfaces or interface names) happens to be loaded by the same 
ClassLoader as the proxy class, the ClassLoader will never be GC-ed and 
consequently the ClassValue will never be cleared and the entry will 
never be expunged... We have to wrap with a WeakReference:

- the ClassLoader
- each individual interface Class object
- proxy Class object

All 3 types of objects can have implicit or explicit strong references 
among them.


Regards, Peter



Does this make sense to you?
Mandy



As explained above, for the per-loader proxy class cache, both the 
key (interfaces) and the proxy class should be wrapped with weak 
reference.


In your revisions, you optimize for 0-interface and 1-interface proxy 
class.  What I hacked up earlier was just to use Class?[] as the 
key (need to make a copy of the array to prevent that being mutated 
during runtime) that is a simpler and straightforward 
implementation.  I didn't measure the footprint and compare the 
performance of your versions.  Have you seen any performance 
difference which led you to make the recent changes?


Mandy
[1] 
http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html#jvms-5.3






Re: Proxy.isProxyClass scalability

2013-04-24 Thread Peter Levart


On 04/24/2013 01:43 AM, Mandy Chung wrote:
Precise check should be to validate if the given interfaces == the 
proxy interfaces implemented by the cached proxy class (i.e. 
proxyClass.getInterfaces()).


Hi Mandy,

I will try to profile this approach as a post-validation and let you 
know the results.



Regards, Peter



Re: Proxy.isProxyClass scalability

2013-04-24 Thread Peter Levart

On 04/24/2013 09:16 AM, Peter Levart wrote:


On 04/24/2013 01:43 AM, Mandy Chung wrote:
Precise check should be to validate if the given interfaces == the 
proxy interfaces implemented by the cached proxy class (i.e. 
proxyClass.getInterfaces()).


Hi Mandy,

I will try to profile this approach as a post-validation and let you 
know the results.




Hi Mandy,

Here's the modified webrev using optimized String-based sub-keys and 
pos-validation of proxyClass using proxyClass.getInterfaces():


https://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy-wc/webrev.04/index.html

The benchmark results are the following:


Summary (4 Cores x 2 Threads i7 CPU):
   WeakCache+
ns/op  Strings key+
Test Threads Original  getIntfcs() post-valid.
===  ===  ===  ===
Proxy_getProxyClass1 2,453.77   565.96
   4 3,051.12   653.81
   8 5,113.27 1,174.33

Proxy_isProxyClassTrue 194.9641.47
   4 2,102.2941.57
   8 4,823.5071.80

Proxy_isProxyClassFalse186.59 1.36
   4 2,139.05 1.36
   8 4,639.17 2.72

Annotation_equals  1   222.86   195.39
   4 2,972.93   197.66
   8 9,658.96   338.62


...  not that bad, but not so great either, compared to Weakly 
referenced interfaces-based sub-key and no post-validation:


WeakCache+
Test Threads  ns/op Original  intfcs key
===  ===  == ===
Proxy_getProxyClass12,403.27 163.57
   43,039.01 211.70
   85,193.58 322.14

Proxy_isProxyClassTrue 1   95.02 41.23
   42,266.29 42.20
   84,782.29 72.21

Proxy_isProxyClassFalse1   95.02 1.36
   42,186.59 1.36
   84,891.15 2.72

Annotation_equals  1  240.10 194.61
   41,864.06 198.81
   88,639.20 342.90


Regards, Peter



Re: Proxy.isProxyClass scalability

2013-04-24 Thread Peter Levart

Hi Mandy,

I have noticed recently on the hotspot-runime-dev mailing list: 
RFR(XXS): 8012714: Assign the unique traceid directly to the Klass upon 
creation...


Could this be accessed from Java? It looks like a perfect key to 
identify a class within a JVM. Can it be represented as int or long? 
That would map to int[] or long[] as a sub-key in the WeakCache?...


Regards, Peter



Re: Proxy.isProxyClass scalability

2013-04-24 Thread Mandy Chung


On 4/23/2013 11:58 PM, Peter Levart wrote:
The isAssignableFrom check should be correct for well-behaved class 
loaders [1].  However, for non well-behaved class loaders, I'm not 
absolutely confident that this is right.  The case that I was 
concerned is when intf.isAssignableFrom(proxyClass) returns true but 
the proxy class doesn't implement the runtime types (i.e. given 
interfaces).   Precise check should be to validate if the given 
interfaces == the proxy interfaces implemented by the cached proxy 
class (i.e. proxyClass.getInterfaces()).


Really? This can happen? Could you describe a situation when?
Are you thinking of a situation like:

- intf1: pkg.Interface, loaded by classloader1
- intf2: pkg.SubInterface extends pkg.Interface, loaded by classloader1
- intf3: pkg.Interface extends pkg.SubInterface, loaded by 
classloader2 which is child of classloader1




Similar but classloader2 is non well-behaved classloader e.g. doesn't 
have relationship with classloader1; otherwise I don't think it's 
possible to define intf3 (classloader1.loadClass(pkg.Interface) should 
be resolved with intf1 instead (not its own defined pkg.Interface).


I haven't been able to identify such a case but I wasn't able to prove 
it not possible either as it is subject to non well-behaved class loader 
behavior :)


The isAssignableFrom method returns true not only if it's identical but 
also if it's a superinterface that a class implements.

Now you call:

proxy3 = Proxy.getProxyClass(classloader2, intf3);

followed by:

proxy1 = Proxy.getProxyClass(classloader2, intf1);

Is it possible that the second call succeeds and returns proxy1 == 
proxy3 ?


If it's possible to have intf1 and intf3 different runtime type of the 
same name, the second getProxyclass call would return proxy3 since 
intf1.isAssignableFrom(proxy3).What I'm not certain is - how would 
classloader2 be able to define intf3 with classloader1 defining intf1?  
We can't really predict how a non well-behaved class loader and thus I 
wouldn't exclude the possibility.


It seems that the key matching the list of interface names should 
already be a safe guard but we would need a proof for a name + 
isAssignableFrom is equivalent to that runtime type to determine its 
correctness with the consideration of all possible class loader 
behaviors that I don't have.  That's what my feedback was about.


Mandy


Re: Proxy.isProxyClass scalability

2013-04-24 Thread Mandy Chung

Hi Peter,

We both prefer the interface types as the subKey.See my comment 
inlined below.


On 4/23/2013 11:58 PM, Peter Levart wrote:

I developed two different approaches:

1. Key made of WeakReference-s to interface Class objects.
Strong points:
- no key aliasing, validation can be pushed entirely to slow-path
- quick and scalable
- less memory usage than original code for 0 and 1-interface proxies
Weak points:
- more memory usage for 2+ -interface proxies
Latest webrev:
http://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy-wc-wi/webrev.02/index.html
Comments:
  I like this one. If 2+ -interface proxies are relatively rare and 
you don't mind extra space consumption for them,  I would go with this 
approach.


I like this one too.  The mapping is straight forward and clean that 
avoids the fallback and post validation path. Let's proceed with this 
one.  It's good to optimize for the common case (1-interface). For 2 or 
more interfaces, we can improve the memory usage in the future when it 
turns out to be an issue.  I'm fine with the zero-interface proxy which 
is the current implementation too.




That's the sole reason for optimized: WekaRefereceClass - 
WeakReferenceClass - ... - WeakReferenceClass linked list 
instead of the WeakReferenceClass[] array approach. And it's not 
using any recursion for equals/hashCode, so the peformance is 
comparable to array approach and it doesn't suffer from 
StackOverflowExceptions for lots of interfaces.


I'm not objecting to build its own linked list but I'm not convinced if 
it's worth the extra complexity (although it's simple, this adds 
KeyNode, MidKeyNode, Key1, KeyX classes).  For 1-interface proxy, you 
can make it one single weak reference as you have right now.  I would 
simply think the array approach for 2+ interface proxy is preferable and 
the performance is comparable as you noted.  Did I miss any important 
reason you chose the linked list approach?  If not, let's do the simple 
approach that will help the future maintainers of this code.


The change in Proxy.java looks good to me with the comment about the 
array vs custom linked list.


WeakCache.java
   The javadoc for the get(K,P) method - @throws RuntimeException and 
@throws Error are not needed here since any method being called in the 
implementation may throw unchecked exceptions.  There are a couple 
places that checks if (reverseMap != null)  that check is not needed 
since it's always non-null.  But I'm fine if you keep it as it is - just 
wanted to mention it in case it was just leftover from the previous version.


I think we're very close of getting this pushed.

Below are my comments to follow up the discussion we had last night and 
this morning just for clarification.  We should be now on the same page.


Original code is actualy using the following structure: 
WeakHashMapClassLoader, HashMapListString, WeakReferenceClass

... so no ClassLoader leak here...



Oops... somehow I thought the original code didn't make a weak reference 
of the proxy class. I should have looked at the original code before I 
replied :(


The TwoLevelWeakCache is an analogous structure: 
ConcurrentHashMapWeakReferenceClassLoader, 
ConcurrentHashMapSubKey, WeakReferenceClass


The point I was trying to make is that it is not needed to register a 
ReferenceQueue with WeakReferenceClass values and remove entries as 
they are cleared and enqueued, because they will not be cleared until 
the ClassLoader that defines the Class-es is GC-ed and the expunging 
logic can work solely on the grounds of cleared and enqueued 
WeakReferenceClassLoader keys, which is what my latest webrev using 
String-based sub-keys does (I have to update the other too).


Agree.   That makes sense.   I got confused with CacheKey and the 
subkey.  I am now reading the WeakCache code closely.  You got it right 
that the key (defining ClassLoader), subkey (individual interfaces), and 
value (proxy class) have to be weakly referenced to ensure that classes 
loaded by any classloader cached as a key are not strongly reachable not 
causing the class loader leak.


Not the key (interfaces array) but the individual interface Class 
object - each has to be separately wrapped with a WeakReference. 


Sorry I should have been more precise - that's indeed what I meant.

thanks
Mandy


Re: Proxy.isProxyClass scalability

2013-04-23 Thread Peter Levart

On 04/23/2013 05:27 AM, Mandy Chung wrote:


On 4/21/2013 6:39 AM, Peter Levart wrote:

On 04/21/2013 04:52 AM, Mandy Chung wrote:

Hi Peter,

I want to give it some more thought and discuss with you next week.  
As for the zero number of interface, I think it's a bug and it 
should throw IAE if the given interfaces array is empty.   Thanks 
for finding it and I'll file a separate bug for that since it 
requires spec update/clarification.


I think it's a feature. It's useful, since it forwards Object methods 
to InvocationHandler (equals, hashCode, ...). Sometimes that's all 
you need.




Do you have specific use case or know any existing applications doing 
that?  What's the reason one would  prefer to create a proxy class 
with InvocationHandler rather than defining its own class that 
implements equals, hashCode, or toString() method?


I really don't have a use-case here. I can only think of a hypothetical 
case where one would already have an InvocationHandler capable of 
serving proxies for various interfaces, including equals/hashCode 
methods. Now to be able to re-use that logic for constructing keys for 
Maps, one could simply request a proxy with no interfaces. The fact is 
that currently this is allowed and although there might not be any 
usages, it doesn't hurt to allow it in the future and there's no 
performance cost supporting it. I think that not putting artificial 
constraints on API usage without a reason is a good design. It's similar 
in a way to some things in language, like for example the support for 
empty arrays. Why would anyone want to have an empty array?


Regards, Peter

P.S. What do you think of the latest webrev? I did some further 
simplifications to code (removed checks for reverseMap != null) and 
re-worded some javadocs. I can publish another webrev together with 
possible further changes when you review it.




Mandy




Re: Proxy.isProxyClass scalability

2013-04-23 Thread Mandy Chung


On 4/22/2013 11:24 PM, Peter Levart wrote:

On 04/23/2013 05:27 AM, Mandy Chung wrote:


On 4/21/2013 6:39 AM, Peter Levart wrote:

On 04/21/2013 04:52 AM, Mandy Chung wrote:

Hi Peter,

I want to give it some more thought and discuss with you next 
week.  As for the zero number of interface, I think it's a bug and 
it should throw IAE if the given interfaces array is empty.   
Thanks for finding it and I'll file a separate bug for that since 
it requires spec update/clarification.


I think it's a feature. It's useful, since it forwards Object 
methods to InvocationHandler (equals, hashCode, ...). Sometimes 
that's all you need.




Do you have specific use case or know any existing applications doing 
that?  What's the reason one would  prefer to create a proxy class 
with InvocationHandler rather than defining its own class that 
implements equals, hashCode, or toString() method?


I really don't have a use-case here. I can only think of a 
hypothetical case where one would already have an InvocationHandler 
capable of serving proxies for various interfaces, including 
equals/hashCode methods. Now to be able to re-use that logic for 
constructing keys for Maps, one could simply request a proxy with no 
interfaces. The fact is that currently this is allowed and although 
there might not be any usages, it doesn't hurt to allow it in the 
future and there's no performance cost supporting it. I think that not 
putting artificial constraints on API usage without a reason is a good 
design. 


I can't say for sure allowing to define a proxy class with no interface 
is a good design and thus I propose to file a separate issue to follow 
up and determine if there is any issue with and without such constraint 
(interfaces.length()  0 or not).  Yes - I am in a position not to allow 
creating a proxy class with no interface since that was not the original 
use case (for RMI).  But I see your point and we need to investigate 
before we decide one way or the other.  If we determine no need to 
constraint that, we can close that bug as will not fix.


It's similar in a way to some things in language, like for example the 
support for empty arrays. Why would anyone want to have an empty array?




I don't think the Proxy API can be compared with empty array language 
support :)



Regards, Peter

P.S. What do you think of the latest webrev? I did some further 
simplifications to code (removed checks for reverseMap != null) and 
re-worded some javadocs. I can publish another webrev together with 
possible further changes when you review it.




Sorry I didn't get the chance to look at your past 2 webrevs (I was 
distracted with higher priority tasks).


Mandy



Mandy






Re: Proxy.isProxyClass scalability

2013-04-23 Thread Mandy Chung

Hi Peter,

Sorry for the delay.

On 4/20/2013 12:31 AM, Peter Levart wrote:

Hi Mandy,

I have another idea. Before jumping to implement it, I will first ask 
what do you think of it. For example:


- have an optimal interface names key calculated from interfaces.
- visibility of interfaces and other validations are pushed to 
slow-path (inside ProxyClassFactory.apply)
- the proxy Class object returned from WeakCache.get() is 
post-validated with a check like:


for (Class? intf : interfaces) {
if (!intf.isAssignableFrom(proxyClass)) {
throw new IllegalArgumentException();
}
}
// return post-validated proxyClass from getProxyClass0()...

I feel that Class.isAssignableFrom(Class) check could be much faster 
and that the only reason the check can fail is if some interface is 
not visible from the class loader.


Am I correct?


The isAssignableFrom check should be correct for well-behaved class 
loaders [1].  However, for non well-behaved class loaders, I'm not 
absolutely confident that this is right.  The case that I was concerned 
is when intf.isAssignableFrom(proxyClass) returns true but the proxy 
class doesn't implement the runtime types (i.e. given interfaces).   
Precise check should be to validate if the given interfaces == the proxy 
interfaces implemented by the cached proxy class (i.e. 
proxyClass.getInterfaces()).


Class.isAssignableFrom method checks if the proxy class is a subtype of 
the interface and no class loading/resolution involved.  It's definitely 
much cheaper than Class.forName which involves checking if a class is 
loaded (class loader delegation and class file search if not loaded - 
which is not the case you measure).


The existing implementation uses the interface names as the key to the 
per-loader proxy class cache.   I think we should use the Class?[] as 
the key (your webrev.02).   I have quickly modified the version I sent 
you (simply change the Key class to use Class?[] rather than String[] 
but didn't change the concurrent map cache to keep weak references) and 
the benchmark shows comparable speedup.


I just noticed the following (have been thinking of it already, but 
then forgot) in original code:


/*
 512  * Note that we need not worry about reaping the 
cache for
 513  * entries with cleared weak references because if a 
proxy class
 514  * has been garbage collected, its class loader will 
have been
 515  * garbage collected as well, so the entire cache 
will be reaped

 516  * from the loaderToCache map.
 517  */




Hmm... I think the original code has the class loader leak.  The 
WeakHashMapClassLoader, HashMapListString, Class keeps a weak 
reference to the ClassLoader but a strong reference to the cache of the 
proxy classes that are defined by that class loader.  The proxy classes 
are not GC'ed and thus the class loader is still kept alive.



Each ClassLoader maintains explicit hard-references to all Class 
objects for classes defined by the loader. So proxy Class object can 
not be GC-ed until the ClassLoader is GC-ed. So we need not register 
the CacheValue objects in WeakCache with a refQueue. The expunging of 
reverseMap entries is already performed with CacheKey when it is 
cleared and equeued. There's no harm as it is, since the clean-up is 
performed with all the checks and is idempotent, but it need not be 
done for ClassValue objects holding weak references to proxy Class 
objects.




As explained above, for the per-loader proxy class cache, both the key 
(interfaces) and the proxy class should be wrapped with weak reference.


In your revisions, you optimize for 0-interface and 1-interface proxy 
class.  What I hacked up earlier was just to use Class?[] as the key 
(need to make a copy of the array to prevent that being mutated during 
runtime) that is a simpler and straightforward implementation.  I didn't 
measure the footprint and compare the performance of your versions.  
Have you seen any performance difference which led you to make the 
recent changes?


Mandy
[1] http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html#jvms-5.3


Re: Proxy.isProxyClass scalability

2013-04-23 Thread Mandy Chung

More comments in addition to what I replied earlier

On 4/23/2013 4:43 PM, Mandy Chung wrote:


Each ClassLoader maintains explicit hard-references to all Class 
objects for classes defined by the loader. So proxy Class object can 
not be GC-ed until the ClassLoader is GC-ed. 


AFAIU, a class loader will be GC'ed as long as there is no reference to 
any of its loaded classes.  The ClassLoader's internal vector of keeping 
the loaded classes is to prevent the classes from being GC'ed until the 
class loader is being GC'ed which will unload the classes.


So we should make the class loader and the proxy classes weak referenced 
so that they will be GC'ed properly.


So we need not register the CacheValue objects in WeakCache with a 
refQueue. The expunging of reverseMap entries is already performed 
with CacheKey when it is cleared and equeued. There's no harm as it 
is, since the clean-up is performed with all the checks and is 
idempotent, but it need not be done for ClassValue objects holding 
weak references to proxy Class objects.



I actually think we don't need to make CacheKey as a weak reference but 
the CacheValue object should still be registered in the refQueue.  The 
proxy class in the CacheValue implementing the given interfaces always 
reference the interfaces in the CacheKey and it means that the classes 
in the CacheKey will never be GC'ed before the proxy class.   When there 
is no reference to the proxy class, it will be added to the reference 
queue.  Once the entry with the CacheValue holding the proxy class is 
expunged,  the interfaces will not be referenced in the cache.


Does this make sense to you?
Mandy



As explained above, for the per-loader proxy class cache, both the key 
(interfaces) and the proxy class should be wrapped with weak reference.


In your revisions, you optimize for 0-interface and 1-interface proxy 
class.  What I hacked up earlier was just to use Class?[] as the key 
(need to make a copy of the array to prevent that being mutated during 
runtime) that is a simpler and straightforward implementation.  I 
didn't measure the footprint and compare the performance of your 
versions.  Have you seen any performance difference which led you to 
make the recent changes?


Mandy
[1] 
http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html#jvms-5.3




Re: Proxy.isProxyClass scalability

2013-04-22 Thread Mandy Chung


On 4/21/2013 6:39 AM, Peter Levart wrote:

On 04/21/2013 04:52 AM, Mandy Chung wrote:

Hi Peter,

I want to give it some more thought and discuss with you next week.  
As for the zero number of interface, I think it's a bug and it should 
throw IAE if the given interfaces array is empty.   Thanks for 
finding it and I'll file a separate bug for that since it requires 
spec update/clarification.


I think it's a feature. It's useful, since it forwards Object methods 
to InvocationHandler (equals, hashCode, ...). Sometimes that's all you 
need.




Do you have specific use case or know any existing applications doing 
that?  What's the reason one would  prefer to create a proxy class with 
InvocationHandler rather than defining its own class that implements 
equals, hashCode, or toString() method?


Mandy


Re: Proxy.isProxyClass scalability

2013-04-21 Thread Peter Levart


On 04/21/2013 04:52 AM, Mandy Chung wrote:

Hi Peter,

I want to give it some more thought and discuss with you next week.  
As for the zero number of interface, I think it's a bug and it should 
throw IAE if the given interfaces array is empty. Thanks for finding 
it and I'll file a separate bug for that since it requires spec 
update/clarification.


I think it's a feature. It's useful, since it forwards Object methods to 
InvocationHandler (equals, hashCode, ...). Sometimes that's all you need.


Regards, Peter



Mandy

On 4/20/2013 12:31 AM, Peter Levart wrote:

Hi Mandy,

I have another idea. Before jumping to implement it, I will first ask 
what do you think of it. For example:


- have an optimal interface names key calculated from interfaces.
- visibility of interfaces and other validations are pushed to 
slow-path (inside ProxyClassFactory.apply)
- the proxy Class object returned from WeakCache.get() is 
post-validated with a check like:


for (Class? intf : interfaces) {
if (!intf.isAssignableFrom(proxyClass)) {
throw new IllegalArgumentException();
}
}
// return post-validated proxyClass from getProxyClass0()...

I feel that Class.isAssignableFrom(Class) check could be much faster 
and that the only reason the check can fail is if some interface is 
not visible from the class loader.


Am I correct?

Regards, Peter



On 04/19/2013 04:36 PM, Peter Levart wrote:

Hi Mandy,

On 04/19/2013 07:33 AM, Mandy Chung wrote:


https://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy-wc/webrev.02/index.html 

What about package-private in java.lang.reflect? It makes Proxy 
itself much easier to read. When we decide which way to go, I can 
remove the interface and only leave a single package-private class...




thanks.  Moving it to a single package-private classin 
java.lang.reflectand remove the interface sounds good.


Right.



I have merged your patch with the recent TL repo and did some clean 
up while reviewing it.  Some comments:
1. getProxyClass0 should validate the input interfaces and throw 
IAE if any illegal argument (e.g. interfaces are not visible to the 
given loader) before calling proxyClassCache.get(loader, 
interfaces). I moved back the validation code from 
ProxyClassFactory.apply to getProxyClass0.


Ops, you're right. There could be a request with interface(s) with 
same name(s) but loaded by different loader(s) and such code could 
return wrong pre-cached proxy class instead of throwing exception. 
Unfortunately, moving validation to slow-path was the cause of major 
performance and scalability improvement observed. With validation 
moved back to getProxyClass0 (in spite of using two-level 
WeakCache), we have the following performance (WeakCache#1):



Summary (4 Cores x 2 Threads i7 CPU):

Test Threads  ns/op Original WeakCache#1
===  ===  == ===
Proxy_getProxyClass12,403.27 2,174.51
   43,039.01 2,555.00
   85,193.58 4,273.42

Proxy_isProxyClassTrue 1   95.02 43.14
   42,266.29 43.23
   84,782.29 72.06

Proxy_isProxyClassFalse1   95.02 1.36
   42,186.59 1.36
   84,891.15 2.72

Annotation_equals  1  240.10 195.68
   41,864.06 201.41
   88,639.20 337.46

It's a little better than original getProxyClass(), but not much. 
The isProxyClass() and consequently Annotation.equals() are far 
better though. But as you might have guessed, I kind of solved that 
too...


My first attempt was to optimize the interface validation. Only the 
visibility part is necessary to be performed on fast-path. 
Uniqueness and other things can be performed on slow-path. With 
split-validation and hacks like:


private static final MethodHandle findLoadedClass0MH, 
findBootstrapClassMH;

private static final ClassLoader dummyCL = new ClassLoader() {};

static {
try {
Method method = 
ClassLoader.class.getDeclaredMethod(findLoadedClass0, String.class);

method.setAccessible(true);
findLoadedClass0MH = 
MethodHandles.lookup().unreflect(method);


method = 
ClassLoader.class.getDeclaredMethod(findBootstrapClass, 
String.class);

method.setAccessible(true);
findBootstrapClassMH = 
MethodHandles.lookup().unreflect(method);

} catch (NoSuchMethodException e) {
throw (Error) new 
NoSuchMethodError(e.getMessage()).initCause(e);

} catch (IllegalAccessException e) {
throw (Error) new 
IllegalAccessError(e.getMessage()).initCause(e);

}
}

static Class? findLoadedClass(ClassLoader loader, String name) {
try {
if 

Re: Proxy.isProxyClass scalability

2013-04-20 Thread Peter Levart

Hi Mandy,

I have another idea. Before jumping to implement it, I will first ask 
what do you think of it. For example:


- have an optimal interface names key calculated from interfaces.
- visibility of interfaces and other validations are pushed to slow-path 
(inside ProxyClassFactory.apply)
- the proxy Class object returned from WeakCache.get() is post-validated 
with a check like:


for (Class? intf : interfaces) {
if (!intf.isAssignableFrom(proxyClass)) {
throw new IllegalArgumentException();
}
}
// return post-validated proxyClass from getProxyClass0()...

I feel that Class.isAssignableFrom(Class) check could be much faster and 
that the only reason the check can fail is if some interface is not 
visible from the class loader.


Am I correct?

Regards, Peter



On 04/19/2013 04:36 PM, Peter Levart wrote:

Hi Mandy,

On 04/19/2013 07:33 AM, Mandy Chung wrote:


https://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy-wc/webrev.02/index.html 

What about package-private in java.lang.reflect? It makes Proxy 
itself much easier to read. When we decide which way to go, I can 
remove the interface and only leave a single package-private class...




thanks.  Moving it to a single package-private classin 
java.lang.reflectand remove the interface sounds good.


Right.



I have merged your patch with the recent TL repo and did some clean 
up while reviewing it.  Some comments:
1. getProxyClass0 should validate the input interfaces and throw IAE 
if any illegal argument (e.g. interfaces are not visible to the given 
loader) before calling proxyClassCache.get(loader, interfaces). I 
moved back the validation code from ProxyClassFactory.apply to 
getProxyClass0.


Ops, you're right. There could be a request with interface(s) with 
same name(s) but loaded by different loader(s) and such code could 
return wrong pre-cached proxy class instead of throwing exception. 
Unfortunately, moving validation to slow-path was the cause of major 
performance and scalability improvement observed. With validation 
moved back to getProxyClass0 (in spite of using two-level WeakCache), 
we have the following performance (WeakCache#1):



Summary (4 Cores x 2 Threads i7 CPU):

Test Threads  ns/op Original WeakCache#1
===  ===  == ===
Proxy_getProxyClass12,403.27 2,174.51
   43,039.01 2,555.00
   85,193.58 4,273.42

Proxy_isProxyClassTrue 1   95.02 43.14
   42,266.29 43.23
   84,782.29 72.06

Proxy_isProxyClassFalse1   95.02 1.36
   42,186.59 1.36
   84,891.15 2.72

Annotation_equals  1  240.10 195.68
   41,864.06 201.41
   88,639.20 337.46

It's a little better than original getProxyClass(), but not much. The 
isProxyClass() and consequently Annotation.equals() are far better 
though. But as you might have guessed, I kind of solved that too...


My first attempt was to optimize the interface validation. Only the 
visibility part is necessary to be performed on fast-path. 
Uniqueness and other things can be performed on slow-path. With 
split-validation and hacks like:


private static final MethodHandle findLoadedClass0MH, 
findBootstrapClassMH;

private static final ClassLoader dummyCL = new ClassLoader() {};

static {
try {
Method method = 
ClassLoader.class.getDeclaredMethod(findLoadedClass0, String.class);

method.setAccessible(true);
findLoadedClass0MH = 
MethodHandles.lookup().unreflect(method);


method = 
ClassLoader.class.getDeclaredMethod(findBootstrapClass, String.class);

method.setAccessible(true);
findBootstrapClassMH = 
MethodHandles.lookup().unreflect(method);

} catch (NoSuchMethodException e) {
throw (Error) new 
NoSuchMethodError(e.getMessage()).initCause(e);

} catch (IllegalAccessException e) {
throw (Error) new 
IllegalAccessError(e.getMessage()).initCause(e);

}
}

static Class? findLoadedClass(ClassLoader loader, String name) {
try {
if (VM.isSystemDomainLoader(loader)) {
return (Class?) 
findBootstrapClassMH.invokeExact(dummyCL, name);

} else {
return (Class?) 
findLoadedClass0MH.invokeExact(loader, name);

}
} catch (RuntimeException | Error e) {
throw e;
} catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}


... using findLoadedClass(loader, intf.getName()) and only doing 
Class.forName(intf.getName(), false, loader) if the former returned 
null ... I managed to reclaim some 

Re: Proxy.isProxyClass scalability

2013-04-20 Thread Peter Levart

On 04/20/2013 09:31 AM, Peter Levart wrote:

Hi Mandy,

I have another idea. Before jumping to implement it, I will first ask 
what do you think of it. For example:


- have an optimal interface names key calculated from interfaces.
- visibility of interfaces and other validations are pushed to 
slow-path (inside ProxyClassFactory.apply)
- the proxy Class object returned from WeakCache.get() is 
post-validated with a check like:


for (Class? intf : interfaces) {
if (!intf.isAssignableFrom(proxyClass)) {
throw new IllegalArgumentException();
}
}
// return post-validated proxyClass from getProxyClass0()...


I just did it:

http://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy-wc/webrev.03/index.html

I also incorporated the expunging optimization that I talked about in 
one of previous mails.


And the keys, composed of interface names, are now more space-friendly too:
- a key for 0 interface proxy is a singleton Object
- a key for 1 interface proxy is the name of the interface itself (an 
already interned String)
- a key for 2 interface proxy is a special class with 2 references to 
interned Strings
- a key for 3+ interface proxy is a special class wrapping an array of 
interned Strings


The performance is screaming again (WeakCache+post-validation):


ns/op   WeakCache+ WeakCache+
Test Threads Original   pre-valid. post-valid.
===  ===  ===  === ===
Proxy_getProxyClass1 2,420.99 2,258.00   211.04
   4 3,075.39 2,644.26   282.93
   8 5,374.45 5,159.71   432.14

Proxy_isProxyClassTrue 197.75 45.3742.67
   4 2,505.92 42.5942.77
   8 5,042.61 75.4473.20

Proxy_isProxyClassFalse189.20 1.40 1.40
   4 2,548.61 1.40 1.40
   8 4,901.56 2.82 2.80

Annotation_equals  1   224.39 201.82   202.97
   4 2,046.21 200.61   204.89
   8 3,564.78 347.27   344.57


And the space savings are now even greater. Patched code is always 
better space-wise. The savings are:


32 bit addressing:

- 56 bytes per proxy class implementing 1 interface
- 32 bytes per proxy class implementing 2 interfaces
- 16 bytes per proxy class implementing 3 or more interfaces

64 bit addressing:

- 80 bytes per proxy class implementing 1 interface
- 56 bytes per proxy class implementing 2 interfaces
- 24 bytes per proxy class implementing 3 or more interfaces


Regards, Peter


P.S. Details:

32 bit addressing:


   ** Original j.l.r.Proxy
   ** 0 interfaces / proxy class

   class proxy   size of  delta to
 loaders   classescaches  prev.ln.
      
   0 0   400   400
   1 1   760   360
   2 9  1072   312
      

   ** Original j.l.r.Proxy
   ** 1 interfaces / proxy class

   class proxy   size of  delta to
 loaders   classescaches  prev.ln.
      
   0 0   400   400
   1 1   768   368
   1 2   920   152
   1 3  1072   152
   1 4  1224   152
   1 5  1376   152
   1 6  1528   152
   1 7  1680   152
   1 8  1832   152
   2 9  2152   320
   210  2304   152
   211  2456   152
   212  2672   216
   213  2824   152
   214  2976   152
   215  3128   152
   216  3280   152
      

   ** Original j.l.r.Proxy
   ** 2 interfaces / proxy class

   class proxy   size of  delta to
 loaders   classescaches  prev.ln.
      
   0 0   400   400
   1 1   768   368
   1 2   920   152
   1 3  1072   152
   1 4  1224   152
   1 5  1376   152
   1 6  1528   152
   1 7  1680   152
   1 8  1832   152
   2 9  2152   320
   210  2304   152
   211  2456   152
   212  2672   216
   213  2824   152
   214  2976   152
   215  3128   152
   216  3280   152
      

   ** Original j.l.r.Proxy
   ** 3 interfaces / proxy class

   

Re: Proxy.isProxyClass scalability

2013-04-19 Thread Peter Levart

Hi Mandy,

On 04/19/2013 07:33 AM, Mandy Chung wrote:


https://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy-wc/webrev.02/index.html 

What about package-private in java.lang.reflect? It makes Proxy 
itself much easier to read. When we decide which way to go, I can 
remove the interface and only leave a single package-private class...




thanks.  Moving it to a single package-private classin 
java.lang.reflectand remove the interface sounds good.


Right.



I have merged your patch with the recent TL repo and did some clean up 
while reviewing it.  Some comments:
1. getProxyClass0 should validate the input interfaces and throw IAE 
if any illegal argument (e.g. interfaces are not visible to the given 
loader) before calling proxyClassCache.get(loader, interfaces). I 
moved back the validation code from ProxyClassFactory.apply to 
getProxyClass0.


Ops, you're right. There could be a request with interface(s) with same 
name(s) but loaded by different loader(s) and such code could return 
wrong pre-cached proxy class instead of throwing exception. 
Unfortunately, moving validation to slow-path was the cause of major 
performance and scalability improvement observed. With validation moved 
back to getProxyClass0 (in spite of using two-level WeakCache), we have 
the following performance (WeakCache#1):



Summary (4 Cores x 2 Threads i7 CPU):

Test Threads  ns/op Original WeakCache#1
===  ===  == ===
Proxy_getProxyClass12,403.27 2,174.51
   43,039.01 2,555.00
   85,193.58 4,273.42

Proxy_isProxyClassTrue 1   95.02 43.14
   42,266.29 43.23
   84,782.29 72.06

Proxy_isProxyClassFalse1   95.02 1.36
   42,186.59 1.36
   84,891.15 2.72

Annotation_equals  1  240.10 195.68
   41,864.06 201.41
   88,639.20 337.46

It's a little better than original getProxyClass(), but not much. The 
isProxyClass() and consequently Annotation.equals() are far better 
though. But as you might have guessed, I kind of solved that too...


My first attempt was to optimize the interface validation. Only the 
visibility part is necessary to be performed on fast-path. Uniqueness 
and other things can be performed on slow-path. With split-validation 
and hacks like:


private static final MethodHandle findLoadedClass0MH, 
findBootstrapClassMH;

private static final ClassLoader dummyCL = new ClassLoader() {};

static {
try {
Method method = 
ClassLoader.class.getDeclaredMethod(findLoadedClass0, String.class);

method.setAccessible(true);
findLoadedClass0MH = MethodHandles.lookup().unreflect(method);

method = 
ClassLoader.class.getDeclaredMethod(findBootstrapClass, String.class);

method.setAccessible(true);
findBootstrapClassMH = 
MethodHandles.lookup().unreflect(method);

} catch (NoSuchMethodException e) {
throw (Error) new 
NoSuchMethodError(e.getMessage()).initCause(e);

} catch (IllegalAccessException e) {
throw (Error) new 
IllegalAccessError(e.getMessage()).initCause(e);

}
}

static Class? findLoadedClass(ClassLoader loader, String name) {
try {
if (VM.isSystemDomainLoader(loader)) {
return (Class?) 
findBootstrapClassMH.invokeExact(dummyCL, name);

} else {
return (Class?) 
findLoadedClass0MH.invokeExact(loader, name);

}
} catch (RuntimeException | Error e) {
throw e;
} catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}


... using findLoadedClass(loader, intf.getName()) and only doing 
Class.forName(intf.getName(), false, loader) if the former returned null 
... I managed to reclaim some performance (WeakCache#1+):



Test Threads  ns/op Original  WeakCache#1 WeakCache#1+
===  ===  == ===  
Proxy_getProxyClass12,403.27 2,174.51  1,589.36
   43,039.01 2,555.00  1,929.11
   85,193.58 4,273.42  3,409.77


...but that was still not very satisfactory.

I modified the KeyFactory to create keys that weakly-reference interface 
Class objects and implement hashCode/equals in terms of comparing those 
Class objects. With such keys, no false aliasing can occur and the whole 
validation can be pushed back to slow-path. I tried hard to create keys 
with as little space overhead as possible:



Re: Proxy.isProxyClass scalability

2013-04-19 Thread Peter Levart

On 04/19/2013 04:36 PM, Peter Levart wrote:


http://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy-wc-wi/webrev.01/index.html 





Hi Mandy,

I changed the copyright header of WeakCache to GPLv2 with ClassPath 
exception and corrected a minor formatting inconsistency:


http://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy-wc-wi/webrev.02/index.html

Regards, Peter



Re: Proxy.isProxyClass scalability

2013-04-19 Thread Peter Levart

Hi Mandy,

I just noticed the following (have been thinking of it already, but then 
forgot) in original code:


/*
 512  * Note that we need not worry about reaping the cache for
 513  * entries with cleared weak references because if a proxy 
class
 514  * has been garbage collected, its class loader will have been
 515  * garbage collected as well, so the entire cache will be 
reaped
 516  * from the loaderToCache map.
 517  */


Each ClassLoader maintains explicit hard-references to all Class objects 
for classes defined by the loader. So proxy Class object can not be 
GC-ed until the ClassLoader is GC-ed. So we need not register the 
CacheValue objects in WeakCache with a refQueue. The expunging of 
reverseMap entries is already performed with CacheKey when it is cleared 
and equeued. There's no harm as it is, since the clean-up is performed 
with all the checks and is idempotent, but it need not be done for 
ClassValue objects holding weak references to proxy Class objects.


I'll do that change to WeakCache in next webrev together with any other 
possible changes that might be needed.


Regards, Peter


On 04/19/2013 05:43 PM, Peter Levart wrote:

On 04/19/2013 04:36 PM, Peter Levart wrote:


http://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy-wc-wi/webrev.01/index.html 





Hi Mandy,

I changed the copyright header of WeakCache to GPLv2 with ClassPath 
exception and corrected a minor formatting inconsistency:


http://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy-wc-wi/webrev.02/index.html 



Regards, Peter





Re: Proxy.isProxyClass scalability

2013-04-18 Thread Mandy Chung

Hi Peter,

On 4/17/13 7:18 AM, Peter Levart wrote:
As expected, the Proxy.getProxyClass() is yet a little slower than 
with FlattenedWeakCache, but still much faster than original Proxy 
implementation. Another lookup in the ConcurrentHashMap and another 
indirection have a price, but we also get something in return - space.



[...]
So we loose approx. 32 bytes (32bit addresses) or 48 bytes (64 bit 
addresses) for each proxy class compared to original code when using 
FlattenedWeakCache, but we gain 8 bytes (32 bit or 64 bit addresses) 
for each proxy class cached compared to original code when using 
TwoLevelWeakCache. So which to favour, space or time?


With TwoLevelWeakCache, there is a step of 108 bytes (32bit 
addresses) when new ClassLoader is encoutered (new 2nd level 
ConcurrentHashMap is allocated and new entry added to 1st level CHM. 
There's no such step in FlattenedWeakCache (modulo the steps when 
the CHMs are itself resized). So we roughly have 108 bytes wasted for 
each new ClassLoader encountered with TwoLevelWeakCache vs. 
FlattenedWeakCache, but we also have 40 bytes spared for each proxy 
class cached. TwoLevelWeakCache starts to pay off if there are at 
least 3 proxy classes defined per ClassLoader in average.





Thanks for the detailed measurement and analysis.  Although the extra 
lookup on the per-loader cache incurs additional overhead on 
Proxy.getProxyClass, it still shows 10x speed on your performance 
measurement result which is very good.


Since the performance improvement is significant on both approaches, the 
memory saving would be the desirable choice.Especially Java SE 8 
profiles [1] can run on small devices and we should be cautious about 
the space and speed tradeoff.I'll support going for per-loader cache 
(i.e. two-level weak cache).


Another point - Proxies are used in the JDK to implement annotations, 
java.beans.EventHandler, JMX MXBeans mapping, JMX MBean proxies, 
Invocable interface by script engines, and RMI/serialization.   JAXWS 
also uses proxies to support @javax.xml.bind.annotation.XmlElement. For 
the case of annotations and JMX, the number of generated proxy classes 
would typically not be a couple that depends on what interfaces 
application define. In EE environment, there will be many class loaders 
running. It'd be better to prepare to work the moderate number, if not 
high, of proxy classes and multiple loaders case.




https://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy-wc/webrev.02/index.html
What about package-private in java.lang.reflect? It makes Proxy itself 
much easier to read. When we decide which way to go, I can remove the 
interface and only leave a single package-private class...




thanks.  Moving it to a single package-private classin 
java.lang.reflectand remove the interface sounds good.


I have merged your patch with the recent TL repo and did some clean up 
while reviewing it.  Some comments:
1. getProxyClass0 should validate the input interfaces and throw IAE if 
any illegal argument (e.g. interfaces are not visible to the given 
loader) before calling proxyClassCache.get(loader, interfaces). I moved 
back the validation code from ProxyClassFactory.apply to getProxyClass0.
2. I did some cleanup to restore some original comments to make the 
diffs clearer where the change is.
3. I removed the newInstance method which is dead code after my previous 
code.  Since we are in this code, I took the chance to clean that up and 
also change a couple for-loop to use for-each.


I have put the merged and slightly modified Proxy.java and webrev at:
http://cr.openjdk.java.net/~mchung/jdk8/webrevs/7123493/webrev.00/

We will use this bug for your contribution:
   7123493 : (proxy) Proxy.getProxyClass doesn't scale under high load

For the weak cache class, since it's for proxy implementation use, I 
suggest to take out the supportContainsValueOperation flagas it always 
keeps the reverse map for isProxyClass lookup.


You can simply call Objects.requireNonNull(param) instead of 
requireNonNull(param, param-name) since the proxy implementation 
should have made sure the argument is non-null.


Formatting nits:

  68 Object cacheKey = CacheKey.valueOf(
  69 key,
  70 refQueue
  71 );

should be: all in one line or line break on a long-line.  Same for
method signature.

 237 void expungeFrom(
 238 ConcurrentMap?, ? extends ConcurrentMap?, ? map,
 239 ConcurrentMap?, Boolean reverseMap
 240 );

should be:

void expungeFrom(ConcurrentMap?, ? extends ConcurrentMap?, ? map,
 ConcurrentMap?, Boolean reverseMap);

so that it'll be more consistent with the existing code.  I'll do a
detailed review on the weak cache class as you will finalize the code
per the decision to go with the two-level weak cache.

Thanks again for the good work.

Mandy
[1] http://openjdk.java.net/jeps/161


Re: Proxy.isProxyClass scalability

2013-04-17 Thread Peter Levart

Hi Mandy,

Here's the updated webrev:

https://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy-wc/webrev.02/index.html

This adds TwoLevelWeakCache to the scene with following performance 
compared to other alternatives:


Summary (4 Cores x 2 Threads i7 CPU):

Test Threads  ns/op Original Patch(CL field)  
FlattenedWeakCache  TwoLevelWeakCache
===  ===  == ===  
==  =
Proxy_getProxyClass1 2,403.27   163.70  
206.88 252.89
   4 3,039.01   202.77  
303.38 327.62
   8 5,193.58   314.47  
442.58 510.63


Proxy_isProxyClassTrue 1 95.0210.78   
41.85  42.03
   4 2,266.29
10.80   42.32  42.07
   8 4,782.29
20.53   72.29  69.25


Proxy_isProxyClassFalse1 95.02 1.36
1.36   1.36
   4 2,186.59 
1.361.37   1.40
   8 4,891.15 
2.722.94   2.72


Annotation_equals  1 240.10   152.29  
193.27 200.45
   4 1,864.06   153.81  
195.60 202.45
   8 8,639.20   262.09  
384.72 338.70



As expected, the Proxy.getProxyClass() is yet a little slower than with 
FlattenedWeakCache, but still much faster than original Proxy 
implementation. Another lookup in the ConcurrentHashMap and another 
indirection have a price, but we also get something in return - space.


This is all obtained on latest lambda build (with new segment-less 
ConcurrentHashMap). I also added another ClassLoader to see what happens 
when the 2nd is added to the cache:


# Original Proxy, 32 bit addressing

class proxy size of   delta to
loaders   classes   cachesprev.ln.
      
   0 0   400   400
   1 1   768   368
   1 2   920   152
   1 3  1072   152
   1 4  1224   152
   1 5  1376   152
   1 6  1528   152
   1 7  1680   152
   1 8  1832   152
   1 9  1984   152
   110  2136   152
   211  2456   320
   212  2672   216
   213  2824   152
   214  2976   152
   215  3128   152
   216  3280   152
   217  3432   152
   218  3584   152
   219  3736   152
   220  3888   152

# Original Proxy, 64 bit addressing

class proxy size of   delta to
loaders   classes   cachesprev.ln.
      
   0 0   632   632
   1 1  1216   584
   1 2  1448   232
   1 3  1680   232
   1 4  1912   232
   1 5  2144   232
   1 6  2376   232
   1 7  2608   232
   1 8  2840   232
   1 9  3072   232
   110  3304   232
   211  3832   528
   212  4192   360
   213  4424   232
   214  4656   232
   215  4888   232
   216  5120   232
   217  5352   232
   218  5584   232
   219  5816   232
   220  6048   232

# Patched Proxy (FlattenedWeakCache), 32 bit addressing

class proxy size of   delta to
loaders   classes   cachesprev.ln.
      
   0 0   240   240
   1 1   584   344
   1 2   768   184
   1 3   952   184
   1 4  1136   184
   1 5  1320   184
   1 6  1504   184
   1 7  1688   184
   1 8  1872   184
   1 9  2056   184
   110  2240   184
   211  2424   184
   212  2736   312
   213  2920   184
   214  3104   184
   215  3288   184
   216  3472   184
   217  3656   184
   218  3840   184
   2

Re: Proxy.isProxyClass scalability

2013-04-16 Thread Peter Levart

Hi Mandy,

I prepared a preview variant of j.l.r.Proxy using WeakCache (turned into 
an interface and a special FlattenedWeakCache implementation in 
anticipation to create another variant using two-levels of 
ConcurrentHashMaps for backing storage, but with same API) just to 
compare performance:


https://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy-wc/webrev.01/index.html

As the values (Class objects of proxy classes) must be wrapped in a 
WeakReference, the same instance of WeakReference can be re-used as a 
key in another ConcurrentHashMap to implement quick look-up for 
Proxy.isProxyClass() method eliminating the need to use ClassValue, 
which is quite space-hungry.


Comparing the performance, here's a summary of all 3 variants (original, 
patched using a field in ClassLoader and this variant):



Summary (4 Cores x 2 Threads i7 CPU):

Test Threads  ns/op Original  Patched (CL field)  
Patched (WeakCache)
===  ===  == ==  
===
Proxy_getProxyClass1 2,403.27  
163.70   206.88
   4 3,039.01  
202.77   303.38
   8 5,193.58  
314.47   442.58


Proxy_isProxyClassTrue 1 95.02   
10.7841.85
   4 2,266.29   
10.8042.32
   8 4,782.29   
20.5372.29


Proxy_isProxyClassFalse1 95.02
1.36 1.36
   4 2,186.59
1.36 1.37
   8 4,891.15
2.72 2.94


Annotation_equals  1 240.10  
152.29   193.27
   4 1,864.06  
153.81   195.60
   8 8,639.20  
262.09   384.72



The improvement is still quite satisfactory, although a little slower 
than the direct-field variant. The scalability is the same as with 
direct-field variant.


Space consumption of cache structure, calculated as deep-size of the 
structure, ignoring interned Strings, Class and ClassLoader objects 
unsing single non-bootstrap ClassLoader for defining the proxy classes 
and using 32 bit addressing is the following:


original Proxy code:

proxy size of   delta to
classes   cachesprev.ln.
    
   0   400   400
   1   768   368
   2   920   152
   3  1072   152
   4  1224   152
   5  1376   152
   6  1528   152
   7  1680   152
   8  1832   152
   9  1984   152
  10  2136   152

Proxy patched with the variant using FlattenedWeakCache, run on current 
JDK8/tl tip (still uses old ConcurrentHashMap implementation with segments):


proxy size of   delta to
classes   cachesprev.ln.
    
   0   560   560
   1   936   376
   2  1312   376
   3  1688   376
   4  2064   376
   5  2352   288
   6  2728   376
   7  3016   288
   8  3392   376
   9  3592   200
  10  3872   280

...and the same with current JDK8/lambda tip (using new segment-less 
ConcurrentHashMap):


proxy size of   delta to
classes   cachesprev.ln.
    
   0   240   240
   1   584   344
   2   768   184
   3   952   184
   4  1136   184
   5  1320   184
   6  1504   184
   7  1688   184
   8  1872   184
   9  2056   184
  10  2240   184


So with new ConcurrentHashMap the patched Proxy uses about 32 bytes more 
per proxy class.



Is this satisfactory or should we also try a variant with two-levels of 
ConcurrentHashMaps?



Regards, Peter


P.S. Comment to your comment in-line...

On 04/16/2013 12:58 AM, Mandy Chung wrote:


On 4/13/2013 2:59 PM, Peter Levart wrote:




I also devised an alternative caching mechanism with scalability in 
mind which uses WeakReferences for keys (for example ClassLoader) 
and values (for example Class) that could be used in this situation 
in case adding a field to ClassLoader is not an option:




I would also consider any alternative to avoid adding the 
proxyClassCache field in ClassLoader as Alan commented previously.


My observation of the typical usage of proxies is to use the 
interface's class loader to define the proxy class. So is it 
necessary to maintain a per-loader cache?  The per-loader cache maps 
from the interface names to a proxy class defined by one loader. I 
would think it's reasonable to assume 

Re: Proxy.isProxyClass scalability

2013-04-16 Thread Mandy Chung

On 4/16/2013 7:18 AM, Peter Levart wrote:

Hi Mandy,

I prepared a preview variant of j.l.r.Proxy using WeakCache (turned 
into an interface and a special FlattenedWeakCache implementation in 
anticipation to create another variant using two-levels of 
ConcurrentHashMaps for backing storage, but with same API) just to 
compare performance:


https://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy-wc/webrev.01/index.html




thanks for getting this prototype done quickly.

As the values (Class objects of proxy classes) must be wrapped in a 
WeakReference, the same instance of WeakReference can be re-used as a 
key in another ConcurrentHashMap to implement quick look-up for 
Proxy.isProxyClass() method eliminating the need to use ClassValue, 
which is quite space-hungry.




I also think maintaining another ConcurrentHashMap is a good replacement 
with the use of ClassValue to avoid its memory overhead.


Comparing the performance, here's a summary of all 3 variants 
(original, patched using a field in ClassLoader and this variant):


[...]

The improvement is still quite satisfactory, although a little slower 
than the direct-field variant. The scalability is the same as with 
direct-field variant.




Agree - the improvement is quite good.

Space consumption of cache structure, calculated as deep-size of the 
structure, ignoring interned Strings, Class and ClassLoader objects 
unsing single non-bootstrap ClassLoader for defining the proxy classes 
and using 32 bit addressing is the following:


[...]

So with new ConcurrentHashMap the patched Proxy uses about 32 bytes 
more per proxy class.


Is this satisfactory or should we also try a variant with two-levels 
of ConcurrentHashMaps?




The overhead seems okay to trade off the scalability.

Since you have prepared for doing another variant, it'd be good to 
compare two prototypes if this doesn't bring too much work :)  I would 
imagine that there might be slight difference in your measurement when 
comparing with proxies defined by a single class loader but the code 
might be simpler (might not be if you keep the same API but different 
implementation).


Regardless of which approach to use - you have added a general purpose 
WeakCache and the implementation class in the sun.misc package.  While 
it's good to have such class for other jdk class to use, I am more 
comfortable in keeping it as a private class for proxy implementation to 
use.  We need existing applications to migrate away from sun.misc and 
other private APIs to prepare for modularization.


Nits: can you wrap the lines around 80 columns including comments? 
try-catch-finally statements need some formatting fixes.  Our convention 
is to have 'catch', or 'finally' following the closing bracket '}' in 
the same line.  Your editor breaks 'catch' or 'finally' into the next line.




Even without SecurityManager installed the performance of native 
getClassLoader0 was a hog. I don't know why? Isn't there an implicit 
reference to defining ClassLoader from every Class object?


That's right - it looks for the caller class only if the security 
manager is installed.   The defining class loader is kept in the VM's 
Klass object (language-level Class instance representation in the VM) 
and there is no computation needed to obtain a defining class loader of 
a given Class object.  I can only think of the Java - native 
transition overhead that could be one factor. Class.getClassLoader0 is 
not intrinsified.  I'll find out (others on this mailing list may 
probably know).


Mandy


Re: Proxy.isProxyClass scalability

2013-04-15 Thread Mandy Chung


On 4/13/2013 2:59 PM, Peter Levart wrote:




I also devised an alternative caching mechanism with scalability in 
mind which uses WeakReferences for keys (for example ClassLoader) 
and values (for example Class) that could be used in this situation 
in case adding a field to ClassLoader is not an option:




I would also consider any alternative to avoid adding the 
proxyClassCache field in ClassLoader as Alan commented previously.


My observation of the typical usage of proxies is to use the 
interface's class loader to define the proxy class. So is it 
necessary to maintain a per-loader cache?  The per-loader cache maps 
from the interface names to a proxy class defined by one loader. I 
would think it's reasonable to assume the number of loaders to define 
proxy class with the same set of interfaces is small.  What if we 
make the cache as interface names as the key to a set of proxy 
class suppliers that can have only one proxy class per one unique 
defining loader.  If the proxy class is being generated i.e. 
ProxyClassFactory supplier, the loader is available for comparison. 
When there are more than one matching proxy classes, it would have to 
iterate all in the set.


I would assume yes, proxy class for a particular set of interfaces is 
typically defined by one classloader only. But the API allows to 
specify different loaders as long as the interfaces implemented by 
proxy class are visible from the loader that defines the proxy 
class. If we're talking about interface names - as opposed to 
interfaces - then the possibility that a particular set of interface 
names would want to be used to define proxy classes with different 
loaders is even bigger, since an interface name can refer to different 
interfaces with same name (think of interfaces deployed as part of an 
app in an application server, say a set of annotations used by 
different apps but deployed as part of each individual app).




Agree.  I was tempted to consider making weak reference to the interface 
classes as the key but in any case the overhead of 
Class.getClassLoader() is still a performance hog.   Let's move forward 
with the alternative you propose.


The scheme you're proposing might be possible, though not simple: The 
factory SupplierClass would become a FunctionClassLoader, Class 
and would have to maintain it's own set of cached proxy classes. There 
would be a single ConcurrentMapListString, FunctionClassLoader, 
Class to map sets of interface names to factory Functions, but the 
cached classes in a particular factory Function would still have to be 
weakly referenced. I see some difficulties in implementing such a scheme:
- expunging cleared WeakReferences could only reliably clear the cache 
inside each factory Function but removing the entry from the map of  
factory Functions when last proxy class for a particular set of 
interface names is expunged  would become a difficult task if not 
impossible with all the scalability constraints in mind (just thinking 
about concurrent requests into same factory Function where one is 
requesting new proxy class and the other is expunging cleared 
WeakReference which represents the last element in the set of cached 
proxy classes).
- one of my past ideas of implementing scalable Proxy.isProxyClass() 
was to maintain a SetClass in each ClassLoader populated with all 
the proxy classes defined by a particular ClassLoader. Benchmarking 
such solution showed that Class.getClassLoader() is a peformance hog, 
so I scraped it in favor of ClassValueBoolean that is now 
incorporated in the patch. In order to choose the right proxy class 
from the set of proxy classes inside a particular factory Function, 
the Class.getClassLoader() method would have to be used, or entries 
would have to (weakly) reference a particular ClassLoader associated 
with each proxy class.




Thanks for reminding me your earlier prototype.  I suspect the cost of 
Class.getClassLoader() is due to its lookup of the caller class every 
time it's called.


Considering all that, such solution starts to look unappealing. It 
might even be more space-hungry then the presented WeakCache.


WeakCache is currently the following:

ConcurrentMapWeakReferenceWithInterfaceNamesClassLoader, 
WeakReferenceClass


another alternative would be:

ConcurrentMapWeakReferenceClassLoader, 
ConcurrentMapInterfaceNames, WeakReferenceClass


...which might need a little less space than WeakCache (only one 
WeakReference per proxy class + one per ClassLoader instead of two 
WeakReferences per proxy class) but would require two map lookups 
during fast-path retrieval. It might not be performance critical and 
the expunging could be performed easily too.




I am fine with either of these alternatives.  As you noted, the latter 
one would save little bit of memory for the cases when several proxy 
classes are defined per loader e.g. one per each annotation type.


Mandy


Re: Proxy.isProxyClass scalability

2013-04-13 Thread Peter Levart

Hi Mandy,

On 04/12/2013 11:31 PM, Mandy Chung wrote:

Hi Peter,

Thank you for rebasing the patch. This is very good work and I hope to 
make time to work with you to get your patch to jdk8 over the next 
couple weeks.


I hope I can be of assistance,



On 4/10/2013 5:35 AM, Peter Levart wrote:

Hi Alan,

I have prepared new webrev of the patch rebased to current tip of 
jdk8/tl repo:


https://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy/webrev.04/index.html 




[...]


I also devised an alternative caching mechanism with scalability in 
mind which uses WeakReferences for keys (for example ClassLoader) and 
values (for example Class) that could be used in this situation in 
case adding a field to ClassLoader is not an option:




I would also consider any alternative to avoid adding the 
proxyClassCache field in ClassLoader as Alan commented previously.


My observation of the typical usage of proxies is to use the 
interface's class loader to define the proxy class. So is it necessary 
to maintain a per-loader cache?  The per-loader cache maps from the 
interface names to a proxy class defined by one loader. I would think 
it's reasonable to assume the number of loaders to define proxy class 
with the same set of interfaces is small.  What if we make the cache 
as interface names as the key to a set of proxy class suppliers that 
can have only one proxy class per one unique defining loader.  If the 
proxy class is being generated i.e. ProxyClassFactory supplier, the 
loader is available for comparison. When there are more than one 
matching proxy classes, it would have to iterate all in the set.


I would assume yes, proxy class for a particular set of interfaces is 
typically defined by one classloader only. But the API allows to specify 
different loaders as long as the interfaces implemented by proxy class 
are visible from the loader that defines the proxy class. If we're 
talking about interface names - as opposed to interfaces - then the 
possibility that a particular set of interface names would want to be 
used to define proxy classes with different loaders is even bigger, 
since an interface name can refer to different interfaces with same name 
(think of interfaces deployed as part of an app in an application 
server, say a set of annotations used by different apps but deployed as 
part of each individual app).


The scheme you're proposing might be possible, though not simple: The 
factory SupplierClass would become a FunctionClassLoader, Class and 
would have to maintain it's own set of cached proxy classes. There would 
be a single ConcurrentMapListString, FunctionClassLoader, Class to 
map sets of interface names to factory Functions, but the cached classes 
in a particular factory Function would still have to be weakly 
referenced. I see some difficulties in implementing such a scheme:
- expunging cleared WeakReferences could only reliably clear the cache 
inside each factory Function but removing the entry from the map of  
factory Functions when last proxy class for a particular set of 
interface names is expunged  would become a difficult task if not 
impossible with all the scalability constraints in mind (just thinking 
about concurrent requests into same factory Function where one is 
requesting new proxy class and the other is expunging cleared 
WeakReference which represents the last element in the set of cached 
proxy classes).
- one of my past ideas of implementing scalable Proxy.isProxyClass() was 
to maintain a SetClass in each ClassLoader populated with all the 
proxy classes defined by a particular ClassLoader. Benchmarking such 
solution showed that Class.getClassLoader() is a peformance hog, so I 
scraped it in favor of ClassValueBoolean that is now incorporated in 
the patch. In order to choose the right proxy class from the set of 
proxy classes inside a particular factory Function, the 
Class.getClassLoader() method would have to be used, or entries would 
have to (weakly) reference a particular ClassLoader associated with each 
proxy class.


Considering all that, such solution starts to look unappealing. It might 
even be more space-hungry then the presented WeakCache.


WeakCache is currently the following:

ConcurrentMapWeakReferenceWithInterfaceNamesClassLoader, 
WeakReferenceClass


another alternative would be:

ConcurrentMapWeakReferenceClassLoader, ConcurrentMapInterfaceNames, 
WeakReferenceClass


...which might need a little less space than WeakCache (only one 
WeakReference per proxy class + one per ClassLoader instead of two 
WeakReferences per proxy class) but would require two map lookups during 
fast-path retrieval. It might not be performance critical and the 
expunging could be performed easily too.



Regards, Peter



This alternative is sub-optimal than the per-loader cache. I'd be 
interested in your thought of this alternative and any rough idea of 
the performance difference with and without the per-loader cache 
approach for the 

Re: Proxy.isProxyClass scalability

2013-04-12 Thread Mandy Chung

Hi Peter,

Thank you for rebasing the patch. This is very good work and I hope to 
make time to work with you to get your patch to jdk8 over the next 
couple weeks.


On 4/10/2013 5:35 AM, Peter Levart wrote:

Hi Alan,

I have prepared new webrev of the patch rebased to current tip of 
jdk8/tl repo:


https://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy/webrev.04/index.html 




[...]


I also devised an alternative caching mechanism with scalability in 
mind which uses WeakReferences for keys (for example ClassLoader) and 
values (for example Class) that could be used in this situation in 
case adding a field to ClassLoader is not an option:




I would also consider any alternative to avoid adding the 
proxyClassCache field in ClassLoader as Alan commented previously.


My observation of the typical usage of proxies is to use the interface's 
class loader to define the proxy class. So is it necessary to maintain a 
per-loader cache?  The per-loader cache maps from the interface names to 
a proxy class defined by one loader. I would think it's reasonable to 
assume the number of loaders to define proxy class with the same set of 
interfaces is small.  What if we make the cache as interface names as 
the key to a set of proxy class suppliers that can have only one proxy 
class per one unique defining loader.  If the proxy class is being 
generated i.e. ProxyClassFactory supplier, the loader is available for 
comparison. When there are more than one matching proxy classes, it 
would have to iterate all in the set.


This alternative is sub-optimal than the per-loader cache. I'd be 
interested in your thought of this alternative and any rough idea of the 
performance difference with and without the per-loader cache approach 
for the annotation case.


Coding convention: we use /** ... */ for javadoc and /*...*/ or // for 
comments.  Your patch uses /**...*/ style as comments that need fixing.  
The style you have for

   try {
   }
   catch {
   }
   finally {
   }

Mandy

https://github.com/plevart/jdk8-tl/blob/proxy/test/src/test/WeakCache.java 




Regards, Peter






Re: Proxy.isProxyClass scalability

2013-04-10 Thread Peter Levart

Hi Alan,

I have prepared new webrev of the patch rebased to current tip of 
jdk8/tl repo:


https://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy/webrev.04/index.html

I noticed there were quite a few changes to the j.l.r.Proxy in the 
meanwhile regarding new security checks. But @CallerSensitive changes 
seem not to have been pushed yet.


Anyway, I have also simplified the caching logic a bit so that it's now 
easier to reason about it's correctness. I have re-run the performance 
benchmarks that are still very favourable:


https://raw.github.com/plevart/jdk8-tl/proxy/test/proxy_benchmark_results.txt

Proxy.getProxyClass(): is almost 15x faster single-threaded with same or 
even slightly better scalability
Proxy.isProxyClass() == true: is about 9x faster for single-threaded 
execution and much more scalable
Proxy.isProxyClass() == false: is about 1600x faster single-threaded and 
infinitely scalable

Annotation.equals(): is 1.6x faster single-threaded and much more scalable

I also devised an alternative caching mechanism with scalability in mind 
which uses WeakReferences for keys (for example ClassLoader) and values 
(for example Class) that could be used in this situation in case adding 
a field to ClassLoader is not an option:


https://github.com/plevart/jdk8-tl/blob/proxy/test/src/test/WeakCache.java


Regards, Peter


On 01/28/2013 05:13 PM, Peter Levart wrote:

Hi Alan,

I prepared the variant with lazy initialization of ConcurrentHashMaps 
per ClassLoader and performance measurements show no differences. So 
here's this variant:


* http://dl.dropbox.com/u/101777488/jdk8-tl/proxy/webrev.03/index.html

I also checked the ClassLoader layout and as it happens the additional 
pointer slot increases the ClassLoader object size by 8 bytes in both 
addressing modes: 32bit and 64bit. But that's a small overhead 
compared to for example the deep-size of AppClassLoader at the 
beginning of the main method: 14648 bytes (32bit) / 22432 bytes (64bit).


Regards, Peter

On 01/28/2013 01:57 PM, Peter Levart wrote:

On 01/28/2013 12:49 PM, Alan Bateman wrote:

On 25/01/2013 17:55, Peter Levart wrote:


:

The solution is actually very simple. I just want to validate my 
reasoning before jumping to implement it:


- for solving scalability of getProxyClass cache, a field with a 
reference to ConcurrentHashMapListString, Class? extends 
Proxy is added to j.l.ClassLoader
- for solving scalability of isProxyClass, a field with a reference 
to ConcurrentHashMapClass? extends Proxy, Boolean is added to 
j.l.ClassLoader
I haven't had time to look very closely as your more recent changes 
(you are clearly doing very good work here). The only thing I wonder 
if whether it would be possible to avoid adding to ClassLoader. I 
can't say what percentage of frameworks and applications use proxies 
but it would be nice if the impact on applications that don't use 
proxies is zero.

Hi Alan,

Hm, well. Any application that uses run-time annotations, is 
implicitly using Proxies. But I agree that there are applications 
that don't use either. Such applications usually don't use many 
ClassLoaders either. Applications that use many ClassLoaders are 
typically application servers or applications written for modular 
systems (such as OSGI or NetBeans) and all those applications are 
also full of runtime annotations nowadays. So a typical application 
that does not use neither Proxies nor runtime annotations is composed 
of bootstrap classloader, AppClassLoader and ExtClassLoader. The 
ConcurrentHashMap for the bootstrap classloader is hosted by 
j.l.r.Proxy class and is only initialized when the j.l.r.Proxy class 
is initialized - so in this case never. The overhead for such 
applications is therefore an empty ConcurrentHashMap instance plus 
the overhead for a pointer slot in the ClassLoader object multiplied 
by the number of ClassLoaders (typically 2). An empty 
ConcurrentHashMap in JDK8 is only pre-allocating a single internal 
Segment:


java.util.concurrent.ConcurrentHashMap@642b6fc7(48 bytes) {
  keySet: null
  values: null
  hashSeed: int
  segmentMask: int
  segmentShift: int
  segments: 
java.util.concurrent.ConcurrentHashMap$Segment[16]@8e1dfb1(80 bytes) {

java.util.concurrent.ConcurrentHashMap$Segment@2524e205(40 bytes) {
  sync: 
java.util.concurrent.locks.ReentrantLock$NonfairSync@17feafba(32 
bytes) {

exclusiveOwnerThread: null
head: null
tail: null
state: int
  }-(32 deep bytes)
  table: 
java.util.concurrent.ConcurrentHashMap$HashEntry[2]@1c3aacb4(24 bytes) {

null
null
  }-(24 deep bytes)
  count: int
  modCount: int
  threshold: int
  loadFactor: float
}-(96 deep bytes)
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
  }-(176 deep bytes)
  keySet: null
  entrySet: null
  values: null
}-(224 deep bytes)

...therefore the overhead is 

Re: Proxy.isProxyClass scalability

2013-04-10 Thread Mandy Chung


On 4/10/2013 5:35 AM, Peter Levart wrote:

Hi Alan,

I have prepared new webrev of the patch rebased to current tip of 
jdk8/tl repo:


https://dl.dropboxusercontent.com/u/101777488/jdk8-tl/proxy/webrev.04/index.html 



I noticed there were quite a few changes to the j.l.r.Proxy in the 
meanwhile regarding new security checks. But @CallerSensitive changes 
seem not to have been pushed yet.




This has been waiting for the VM support which is now in jdk8/hotspot.  
Once TL is synced up jdk8 master (soon be this week), I'll push the changes.


Anyway, I have also simplified the caching logic a bit so that it's 
now easier to reason about it's correctness. I have re-run the 
performance benchmarks that are still very favourable:


https://raw.github.com/plevart/jdk8-tl/proxy/test/proxy_benchmark_results.txt 



Proxy.getProxyClass(): is almost 15x faster single-threaded with same 
or even slightly better scalability
Proxy.isProxyClass() == true: is about 9x faster for single-threaded 
execution and much more scalable
Proxy.isProxyClass() == false: is about 1600x faster single-threaded 
and infinitely scalable
Annotation.equals(): is 1.6x faster single-threaded and much more 
scalable


That's great improvement.  I have another patch in Proxy coming out for 
review soon.   When I get several urgent things on my plate done, I'll 
take a look at your patch and get back to you this week hopefully.


Mandy



I also devised an alternative caching mechanism with scalability in 
mind which uses WeakReferences for keys (for example ClassLoader) and 
values (for example Class) that could be used in this situation in 
case adding a field to ClassLoader is not an option:


https://github.com/plevart/jdk8-tl/blob/proxy/test/src/test/WeakCache.java 




Regards, Peter


On 01/28/2013 05:13 PM, Peter Levart wrote:

Hi Alan,

I prepared the variant with lazy initialization of ConcurrentHashMaps 
per ClassLoader and performance measurements show no differences. So 
here's this variant:


* http://dl.dropbox.com/u/101777488/jdk8-tl/proxy/webrev.03/index.html

I also checked the ClassLoader layout and as it happens the 
additional pointer slot increases the ClassLoader object size by 8 
bytes in both addressing modes: 32bit and 64bit. But that's a small 
overhead compared to for example the deep-size of AppClassLoader at 
the beginning of the main method: 14648 bytes (32bit) / 22432 bytes 
(64bit).


Regards, Peter

On 01/28/2013 01:57 PM, Peter Levart wrote:

On 01/28/2013 12:49 PM, Alan Bateman wrote:

On 25/01/2013 17:55, Peter Levart wrote:


:

The solution is actually very simple. I just want to validate my 
reasoning before jumping to implement it:


- for solving scalability of getProxyClass cache, a field with a 
reference to ConcurrentHashMapListString, Class? extends 
Proxy is added to j.l.ClassLoader
- for solving scalability of isProxyClass, a field with a 
reference to ConcurrentHashMapClass? extends Proxy, Boolean is 
added to j.l.ClassLoader
I haven't had time to look very closely as your more recent changes 
(you are clearly doing very good work here). The only thing I 
wonder if whether it would be possible to avoid adding to 
ClassLoader. I can't say what percentage of frameworks and 
applications use proxies but it would be nice if the impact on 
applications that don't use proxies is zero.

Hi Alan,

Hm, well. Any application that uses run-time annotations, is 
implicitly using Proxies. But I agree that there are applications 
that don't use either. Such applications usually don't use many 
ClassLoaders either. Applications that use many ClassLoaders are 
typically application servers or applications written for modular 
systems (such as OSGI or NetBeans) and all those applications are 
also full of runtime annotations nowadays. So a typical application 
that does not use neither Proxies nor runtime annotations is 
composed of bootstrap classloader, AppClassLoader and 
ExtClassLoader. The ConcurrentHashMap for the bootstrap classloader 
is hosted by j.l.r.Proxy class and is only initialized when the 
j.l.r.Proxy class is initialized - so in this case never. The 
overhead for such applications is therefore an empty 
ConcurrentHashMap instance plus the overhead for a pointer slot in 
the ClassLoader object multiplied by the number of ClassLoaders 
(typically 2). An empty ConcurrentHashMap in JDK8 is only 
pre-allocating a single internal Segment:


java.util.concurrent.ConcurrentHashMap@642b6fc7(48 bytes) {
  keySet: null
  values: null
  hashSeed: int
  segmentMask: int
  segmentShift: int
  segments: 
java.util.concurrent.ConcurrentHashMap$Segment[16]@8e1dfb1(80 bytes) {

java.util.concurrent.ConcurrentHashMap$Segment@2524e205(40 bytes) {
  sync: 
java.util.concurrent.locks.ReentrantLock$NonfairSync@17feafba(32 
bytes) {

exclusiveOwnerThread: null
head: null
tail: null
state: int
  }-(32 deep bytes)
  table: 

Re: Proxy.isProxyClass scalability

2013-04-08 Thread Peter Levart

Hi Alan,

Is this still being considered? Recently there were some changes in the 
j.l.r.Proxy (the @CallerSensitive annotation), so my final webrev of the 
patch will have to be rebased. Do you still think we should not add new 
fields to ClassLoader? I have some ideas how to do it without adding a 
field to ClassLoader but for the price of some additional space overhead 
for each Proxy class produced. On the other hand I think that in the 
future, more platform-internal data structures would want to be 
attached to ClassLoaders so perhaps a single ConcurrentHashMap per 
ClassLoader could be re-used for different purposes by using distinct 
(never-equal) keys for each purpose (fox example, the lambda metafactory 
currently does not do any caching for it's own spun SAM proxy classes or 
CallSite objects, but could benefit quite a bit from doing so).


Regards, Peter

On 01/28/2013 05:13 PM, Peter Levart wrote:

Hi Alan,

I prepared the variant with lazy initialization of ConcurrentHashMaps 
per ClassLoader and performance measurements show no differences. So 
here's this variant:


* http://dl.dropbox.com/u/101777488/jdk8-tl/proxy/webrev.03/index.html

I also checked the ClassLoader layout and as it happens the additional 
pointer slot increases the ClassLoader object size by 8 bytes in both 
addressing modes: 32bit and 64bit. But that's a small overhead 
compared to for example the deep-size of AppClassLoader at the 
beginning of the main method: 14648 bytes (32bit) / 22432 bytes (64bit).


Regards, Peter

On 01/28/2013 01:57 PM, Peter Levart wrote:

On 01/28/2013 12:49 PM, Alan Bateman wrote:

On 25/01/2013 17:55, Peter Levart wrote:


:

The solution is actually very simple. I just want to validate my 
reasoning before jumping to implement it:


- for solving scalability of getProxyClass cache, a field with a 
reference to ConcurrentHashMapListString, Class? extends 
Proxy is added to j.l.ClassLoader
- for solving scalability of isProxyClass, a field with a reference 
to ConcurrentHashMapClass? extends Proxy, Boolean is added to 
j.l.ClassLoader
I haven't had time to look very closely as your more recent changes 
(you are clearly doing very good work here). The only thing I wonder 
if whether it would be possible to avoid adding to ClassLoader. I 
can't say what percentage of frameworks and applications use proxies 
but it would be nice if the impact on applications that don't use 
proxies is zero.

Hi Alan,

Hm, well. Any application that uses run-time annotations, is 
implicitly using Proxies. But I agree that there are applications 
that don't use either. Such applications usually don't use many 
ClassLoaders either. Applications that use many ClassLoaders are 
typically application servers or applications written for modular 
systems (such as OSGI or NetBeans) and all those applications are 
also full of runtime annotations nowadays. So a typical application 
that does not use neither Proxies nor runtime annotations is composed 
of bootstrap classloader, AppClassLoader and ExtClassLoader. The 
ConcurrentHashMap for the bootstrap classloader is hosted by 
j.l.r.Proxy class and is only initialized when the j.l.r.Proxy class 
is initialized - so in this case never. The overhead for such 
applications is therefore an empty ConcurrentHashMap instance plus 
the overhead for a pointer slot in the ClassLoader object multiplied 
by the number of ClassLoaders (typically 2). An empty 
ConcurrentHashMap in JDK8 is only pre-allocating a single internal 
Segment:


java.util.concurrent.ConcurrentHashMap@642b6fc7(48 bytes) {
  keySet: null
  values: null
  hashSeed: int
  segmentMask: int
  segmentShift: int
  segments: 
java.util.concurrent.ConcurrentHashMap$Segment[16]@8e1dfb1(80 bytes) {

java.util.concurrent.ConcurrentHashMap$Segment@2524e205(40 bytes) {
  sync: 
java.util.concurrent.locks.ReentrantLock$NonfairSync@17feafba(32 
bytes) {

exclusiveOwnerThread: null
head: null
tail: null
state: int
  }-(32 deep bytes)
  table: 
java.util.concurrent.ConcurrentHashMap$HashEntry[2]@1c3aacb4(24 bytes) {

null
null
  }-(24 deep bytes)
  count: int
  modCount: int
  threshold: int
  loadFactor: float
}-(96 deep bytes)
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
  }-(176 deep bytes)
  keySet: null
  entrySet: null
  values: null
}-(224 deep bytes)

...therefore the overhead is approx. 224+4 = 228 bytes (on 32 bit 
pointer environments) per ClassLoader. In typical application (with 2 
ClassLoader objects) this amounts to approx. 456 bytes.


Is 456 bytes overhead too much?

If it is, I could do lazy initialization of per-classloader CHM 
instances, but then the fast-path would incur a little additional 
penalty (not to be taken seriously though).


Regards, Peter

P.S. I was inspecting the ClassValue internal implementation. This is 
a very nice 

Re: Proxy.isProxyClass scalability

2013-01-28 Thread Alan Bateman

On 25/01/2013 17:55, Peter Levart wrote:


:

The solution is actually very simple. I just want to validate my 
reasoning before jumping to implement it:


- for solving scalability of getProxyClass cache, a field with a 
reference to ConcurrentHashMapListString, Class? extends Proxy 
is added to j.l.ClassLoader
- for solving scalability of isProxyClass, a field with a reference to 
ConcurrentHashMapClass? extends Proxy, Boolean is added to 
j.l.ClassLoader
I haven't had time to look very closely as your more recent changes (you 
are clearly doing very good work here). The only thing I wonder if 
whether it would be possible to avoid adding to ClassLoader. I can't say 
what percentage of frameworks and applications use proxies but it would 
be nice if the impact on applications that don't use proxies is zero.


-Alan


Re: Proxy.isProxyClass scalability

2013-01-28 Thread Peter Levart

On 01/28/2013 12:49 PM, Alan Bateman wrote:

On 25/01/2013 17:55, Peter Levart wrote:


:

The solution is actually very simple. I just want to validate my 
reasoning before jumping to implement it:


- for solving scalability of getProxyClass cache, a field with a 
reference to ConcurrentHashMapListString, Class? extends Proxy 
is added to j.l.ClassLoader
- for solving scalability of isProxyClass, a field with a reference 
to ConcurrentHashMapClass? extends Proxy, Boolean is added to 
j.l.ClassLoader
I haven't had time to look very closely as your more recent changes 
(you are clearly doing very good work here). The only thing I wonder 
if whether it would be possible to avoid adding to ClassLoader. I 
can't say what percentage of frameworks and applications use proxies 
but it would be nice if the impact on applications that don't use 
proxies is zero.

Hi Alan,

Hm, well. Any application that uses run-time annotations, is implicitly 
using Proxies. But I agree that there are applications that don't use 
either. Such applications usually don't use many ClassLoaders either. 
Applications that use many ClassLoaders are typically application 
servers or applications written for modular systems (such as OSGI or 
NetBeans) and all those applications are also full of runtime 
annotations nowadays. So a typical application that does not use neither 
Proxies nor runtime annotations is composed of bootstrap classloader, 
AppClassLoader and ExtClassLoader. The ConcurrentHashMap for the 
bootstrap classloader is hosted by j.l.r.Proxy class and is only 
initialized when the j.l.r.Proxy class is initialized - so in this case 
never. The overhead for such applications is therefore an empty 
ConcurrentHashMap instance plus the overhead for a pointer slot in the 
ClassLoader object multiplied by the number of ClassLoaders (typically 
2). An empty ConcurrentHashMap in JDK8 is only pre-allocating a single 
internal Segment:


java.util.concurrent.ConcurrentHashMap@642b6fc7(48 bytes) {
  keySet: null
  values: null
  hashSeed: int
  segmentMask: int
  segmentShift: int
  segments: 
java.util.concurrent.ConcurrentHashMap$Segment[16]@8e1dfb1(80 bytes) {

java.util.concurrent.ConcurrentHashMap$Segment@2524e205(40 bytes) {
  sync: 
java.util.concurrent.locks.ReentrantLock$NonfairSync@17feafba(32 bytes) {

exclusiveOwnerThread: null
head: null
tail: null
state: int
  }-(32 deep bytes)
  table: 
java.util.concurrent.ConcurrentHashMap$HashEntry[2]@1c3aacb4(24 bytes) {

null
null
  }-(24 deep bytes)
  count: int
  modCount: int
  threshold: int
  loadFactor: float
}-(96 deep bytes)
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
  }-(176 deep bytes)
  keySet: null
  entrySet: null
  values: null
}-(224 deep bytes)

...therefore the overhead is approx. 224+4 = 228 bytes (on 32 bit 
pointer environments) per ClassLoader. In typical application (with 2 
ClassLoader objects) this amounts to approx. 456 bytes.


Is 456 bytes overhead too much?

If it is, I could do lazy initialization of per-classloader CHM 
instances, but then the fast-path would incur a little additional 
penalty (not to be taken seriously though).


Regards, Peter

P.S. I was inspecting the ClassValue internal implementation. This is a 
very nice piece of Java code. Without using any Unsafe magic, it 
provides a perfect performant an scalable map of lazily initialized 
independent data structures associated with Class instances. There's 
nothing special about ClassValue/ClassValueMap that would tie it to 
Class instances. In fact I think the ClassValueMap could be made generic 
so it could be reused for implementing a ClasLoaderValue, for example. 
This would provide a more performant and scalable alternative to using 
WeakHashMapClassLoader, ... wrapped by synchronized wrappers for other 
uses.
If anything like that happens in the future, the proposed patch can be 
quickly adapted to using that infrastructure instead of a direct 
reference in the ClassLoader.




-Alan




Re: Proxy.isProxyClass scalability

2013-01-28 Thread Peter Levart

Hi Alan,

I prepared the variant with lazy initialization of ConcurrentHashMaps 
per ClassLoader and performance measurements show no differences. So 
here's this variant:


* http://dl.dropbox.com/u/101777488/jdk8-tl/proxy/webrev.03/index.html

I also checked the ClassLoader layout and as it happens the additional 
pointer slot increases the ClassLoader object size by 8 bytes in both 
addressing modes: 32bit and 64bit. But that's a small overhead compared 
to for example the deep-size of AppClassLoader at the beginning of the 
main method: 14648 bytes (32bit) / 22432 bytes (64bit).


Regards, Peter

On 01/28/2013 01:57 PM, Peter Levart wrote:

On 01/28/2013 12:49 PM, Alan Bateman wrote:

On 25/01/2013 17:55, Peter Levart wrote:


:

The solution is actually very simple. I just want to validate my 
reasoning before jumping to implement it:


- for solving scalability of getProxyClass cache, a field with a 
reference to ConcurrentHashMapListString, Class? extends Proxy 
is added to j.l.ClassLoader
- for solving scalability of isProxyClass, a field with a reference 
to ConcurrentHashMapClass? extends Proxy, Boolean is added to 
j.l.ClassLoader
I haven't had time to look very closely as your more recent changes 
(you are clearly doing very good work here). The only thing I wonder 
if whether it would be possible to avoid adding to ClassLoader. I 
can't say what percentage of frameworks and applications use proxies 
but it would be nice if the impact on applications that don't use 
proxies is zero.

Hi Alan,

Hm, well. Any application that uses run-time annotations, is 
implicitly using Proxies. But I agree that there are applications that 
don't use either. Such applications usually don't use many 
ClassLoaders either. Applications that use many ClassLoaders are 
typically application servers or applications written for modular 
systems (such as OSGI or NetBeans) and all those applications are also 
full of runtime annotations nowadays. So a typical application that 
does not use neither Proxies nor runtime annotations is composed of 
bootstrap classloader, AppClassLoader and ExtClassLoader. The 
ConcurrentHashMap for the bootstrap classloader is hosted by 
j.l.r.Proxy class and is only initialized when the j.l.r.Proxy class 
is initialized - so in this case never. The overhead for such 
applications is therefore an empty ConcurrentHashMap instance plus the 
overhead for a pointer slot in the ClassLoader object multiplied by 
the number of ClassLoaders (typically 2). An empty ConcurrentHashMap 
in JDK8 is only pre-allocating a single internal Segment:


java.util.concurrent.ConcurrentHashMap@642b6fc7(48 bytes) {
  keySet: null
  values: null
  hashSeed: int
  segmentMask: int
  segmentShift: int
  segments: 
java.util.concurrent.ConcurrentHashMap$Segment[16]@8e1dfb1(80 bytes) {

java.util.concurrent.ConcurrentHashMap$Segment@2524e205(40 bytes) {
  sync: 
java.util.concurrent.locks.ReentrantLock$NonfairSync@17feafba(32 bytes) {

exclusiveOwnerThread: null
head: null
tail: null
state: int
  }-(32 deep bytes)
  table: 
java.util.concurrent.ConcurrentHashMap$HashEntry[2]@1c3aacb4(24 bytes) {

null
null
  }-(24 deep bytes)
  count: int
  modCount: int
  threshold: int
  loadFactor: float
}-(96 deep bytes)
null
null
null
null
null
null
null
null
null
null
null
null
null
null
null
  }-(176 deep bytes)
  keySet: null
  entrySet: null
  values: null
}-(224 deep bytes)

...therefore the overhead is approx. 224+4 = 228 bytes (on 32 bit 
pointer environments) per ClassLoader. In typical application (with 2 
ClassLoader objects) this amounts to approx. 456 bytes.


Is 456 bytes overhead too much?

If it is, I could do lazy initialization of per-classloader CHM 
instances, but then the fast-path would incur a little additional 
penalty (not to be taken seriously though).


Regards, Peter

P.S. I was inspecting the ClassValue internal implementation. This is 
a very nice piece of Java code. Without using any Unsafe magic, it 
provides a perfect performant an scalable map of lazily initialized 
independent data structures associated with Class instances. There's 
nothing special about ClassValue/ClassValueMap that would tie it to 
Class instances. In fact I think the ClassValueMap could be made 
generic so it could be reused for implementing a ClasLoaderValue, for 
example. This would provide a more performant and scalable alternative 
to using WeakHashMapClassLoader, ... wrapped by synchronized 
wrappers for other uses.
If anything like that happens in the future, the proposed patch can be 
quickly adapted to using that infrastructure instead of a direct 
reference in the ClassLoader.




-Alan






Re: Proxy.isProxyClass scalability

2013-01-25 Thread Peter Levart

On 01/25/2013 06:35 AM, David Holmes wrote:

On 25/01/2013 2:36 AM, Peter Levart wrote:

On 01/24/2013 04:45 PM, Peter Levart wrote:


Is there really no existing alignment gap in j.l.Class layout that a
boolean can slide into?


There might be, I will check.

All instance fields in j.l.Class are either references or ints.


Instance are also 8-byte aligned though so does that leave any slop 
where an extra field would not make an actual difference. (I should 
know the answer to that after the ReflectionData changes but don't 
recall.)


Note: I have not looked at this, just considering the add a field 
aspect of it.


David


Here's what the Unsafe reports about current layout of j.l.Class 
(ReflectionData changes already taken into account):


32 bit pointers:

java.lang.Class instance field offsets:

  Field Type   Field Name Offset
  -- -- --
 Constructor cachedConstructor 12
   Class newInstanceCallerCache 16
  String name 20
   SoftReference reflectionData 24
 ClassRepository genericInfo 28
Object[] enumConstants 32
 Map enumConstantDirectory 36
 Map annotations 40
 Map declaredAnnotations 44
  AnnotationType annotationType 48
   ClassValueMap classValueMap 52
 int classRedefinedCount 80
 int lastAnnotationsRedefinedCount 84

java.lang.String static field offsets:

  Field Type   Field Name Offset
  -- -- --
 ObjectStreamField[] serialPersistentFields 96
  Comparator CASE_INSENSITIVE_ORDER100
long serialVersionUID104
 int HASHING_SEED112


64 bit pointers:

java.lang.Class instance field offsets:

  Field Type   Field Name Offset
  -- -- --
 Constructor cachedConstructor 16
   Class newInstanceCallerCache 24
  String name 32
   SoftReference reflectionData 40
 ClassRepository genericInfo 48
Object[] enumConstants 56
 Map enumConstantDirectory 64
 Map annotations 72
 Map declaredAnnotations 80
  AnnotationType annotationType 88
   ClassValueMap classValueMap 96
 int classRedefinedCount128
 int lastAnnotationsRedefinedCount132

java.lang.String static field offsets:

  Field Type   Field Name Offset
  -- -- --
 ObjectStreamField[] serialPersistentFields144
  Comparator CASE_INSENSITIVE_ORDER152
long serialVersionUID160
 int HASHING_SEED168


If I add a boolean instance field isProxy to j.l.Class the report 
changes to:


32 bit pointers:

java.lang.Class instance field offsets:

  Field Type   Field Name Offset
  -- -- --
 Constructor cachedConstructor 12
   Class newInstanceCallerCache 16
  String name 20
   SoftReference reflectionData 24
 ClassRepository genericInfo 28
Object[] enumConstants 32
 Map enumConstantDirectory 36
 Map annotations 40
 Map declaredAnnotations 44
  AnnotationType annotationType 48
   ClassValueMap classValueMap 52
 int classRedefinedCount 80
 int lastAnnotationsRedefinedCount 84
 boolean isProxy 96

java.lang.String static field offsets:

  Field Type   Field Name Offset
  -- -- --
 ObjectStreamField[] serialPersistentFields104
  Comparator CASE_INSENSITIVE_ORDER108
long serialVersionUID112
 int HASHING_SEED120


64 bit pointers:

java.lang.Class instance field offsets:

  Field Type   Field Name Offset
  -- -- --
 Constructor cachedConstructor 16
   Class newInstanceCallerCache 24
  String name 32
   SoftReference reflectionData 40
 ClassRepository genericInfo 48
Object[] enumConstants 56
 Map enumConstantDirectory 64
 Map annotations 72
 Map declaredAnnotations 80
  

Re: Proxy.isProxyClass scalability

2013-01-25 Thread Vitaly Davidovich
That's unfortunate.  Can you steal a bit in one of the int fields? E.g.
lastAnnotationsRedefinedCount surely doesn't need the full range right? :)

Sent from my phone
On Jan 25, 2013 11:02 AM, Peter Levart peter.lev...@gmail.com wrote:

 On 01/25/2013 06:35 AM, David Holmes wrote:

 On 25/01/2013 2:36 AM, Peter Levart wrote:

 On 01/24/2013 04:45 PM, Peter Levart wrote:


 Is there really no existing alignment gap in j.l.Class layout that a
 boolean can slide into?

  There might be, I will check.

 All instance fields in j.l.Class are either references or ints.


 Instance are also 8-byte aligned though so does that leave any slop where
 an extra field would not make an actual difference. (I should know the
 answer to that after the ReflectionData changes but don't recall.)

 Note: I have not looked at this, just considering the add a field
 aspect of it.

 David


 Here's what the Unsafe reports about current layout of j.l.Class
 (ReflectionData changes already taken into account):

 32 bit pointers:

 java.lang.Class instance field offsets:

   Field Type   Field Name Offset
   -- -- --
  Constructor cachedConstructor 12
Class newInstanceCallerCache 16
   String name 20
SoftReference reflectionData 24
  ClassRepository genericInfo 28
 Object[] enumConstants 32
  Map enumConstantDirectory 36
  Map annotations 40
  Map declaredAnnotations 44
   AnnotationType annotationType 48
ClassValueMap classValueMap 52
  int classRedefinedCount 80
  int lastAnnotationsRedefinedCount 84

 java.lang.String static field offsets:

   Field Type   Field Name Offset
   -- -- --
  ObjectStreamField[] serialPersistentFields 96
   Comparator CASE_INSENSITIVE_ORDER100
 long serialVersionUID104
  int HASHING_SEED112


 64 bit pointers:

 java.lang.Class instance field offsets:

   Field Type   Field Name Offset
   -- -- --
  Constructor cachedConstructor 16
Class newInstanceCallerCache 24
   String name 32
SoftReference reflectionData 40
  ClassRepository genericInfo 48
 Object[] enumConstants 56
  Map enumConstantDirectory 64
  Map annotations 72
  Map declaredAnnotations 80
   AnnotationType annotationType 88
ClassValueMap classValueMap 96
  int classRedefinedCount128
  int lastAnnotationsRedefinedCount132

 java.lang.String static field offsets:

   Field Type   Field Name Offset
   -- -- --
  ObjectStreamField[] serialPersistentFields144
   Comparator CASE_INSENSITIVE_ORDER152
 long serialVersionUID160
  int HASHING_SEED168


 If I add a boolean instance field isProxy to j.l.Class the report
 changes to:

 32 bit pointers:

 java.lang.Class instance field offsets:

   Field Type   Field Name Offset
   -- -- --
  Constructor cachedConstructor 12
Class newInstanceCallerCache 16
   String name 20
SoftReference reflectionData 24
  ClassRepository genericInfo 28
 Object[] enumConstants 32
  Map enumConstantDirectory 36
  Map annotations 40
  Map declaredAnnotations 44
   AnnotationType annotationType 48
ClassValueMap classValueMap 52
  int classRedefinedCount 80
  int lastAnnotationsRedefinedCount 84
  boolean isProxy 96

 java.lang.String static field offsets:

   Field Type   Field Name Offset
   -- -- --
  ObjectStreamField[] serialPersistentFields104
   Comparator CASE_INSENSITIVE_ORDER108
 long serialVersionUID112
  int HASHING_SEED120


 64 bit pointers:

 java.lang.Class instance field offsets:

   Field Type   Field Name Offset
   -- -- --
  Constructor cachedConstructor 16
Class newInstanceCallerCache 24
   

Re: Proxy.isProxyClass scalability

2013-01-25 Thread Aleksey Shipilev
On 01/25/2013 08:02 PM, Peter Levart wrote:
 On 01/25/2013 06:35 AM, David Holmes wrote:
 On 25/01/2013 2:36 AM, Peter Levart wrote:
 On 01/24/2013 04:45 PM, Peter Levart wrote:
 ...so it seems that in both cases, adding a boolean to j.l.Class wastes
 8 bytes per Class object :-(

Seems to be the case, we are hitting the 8-byte alignment boundary.

java-object-layout [1] on jdk7u12:

$ java -jar ~/projects/java-object-layout/target/java-object-layout.jar
java.lang.Class
Running 64-bit HotSpot VM.
Using compressed references with 3-bit shift.
Objects are 8 bytes aligned.

java.lang.Class
 offset  sizetype description
  012 (assumed to be the object header)
 12 4 Constructor Class.cachedConstructor
 16 4   Class Class.newInstanceCallerCache
 20 4  String Class.name
 24 4   SoftReference Class.declaredFields
 28 4   SoftReference Class.publicFields
 32 4   SoftReference Class.declaredMethods
 36 4   SoftReference Class.publicMethods
 40 4   SoftReference Class.declaredConstructors
 44 4   SoftReference Class.publicConstructors
 48 4   SoftReference Class.declaredPublicFields
 52 4   SoftReference Class.declaredPublicMethods
 56 4 ClassRepository Class.genericInfo
 60 4Object[] Class.enumConstants
 64 4 Map Class.enumConstantDirectory
 68 4 Map Class.annotations
 72 4 Map Class.declaredAnnotations
 76 4  AnnotationType Class.annotationType
 80 4   ClassValueMap Class.classValueMap
 8412 (alignment/padding gap)
 96 4 int Class.classRedefinedCount
100 4 int Class.lastRedefinedCount
104   (object boundary, size estimate)

But, otherwise, can't we use java.lang.ClassValue to associate this flag
with each class?

-Aleksey.

[1] https://github.com/shipilev/java-field-layout



Re: Proxy.isProxyClass scalability

2013-01-25 Thread Peter Levart

Hi David,

I was surprised to see Usafe report these offsets. See below:

java.lang.Class *instance* field offsets:

  Field Type   Field Name Offset
  -- -- --
 Constructor cachedConstructor 12
   Class newInstanceCallerCache 16
  String name 20
   SoftReference reflectionData 24
 ClassRepository genericInfo 28
Object[] enumConstants 32
 Map enumConstantDirectory 36
 Map annotations 40
 Map declaredAnnotations 44
  AnnotationType annotationType 48
   ClassValueMap classValueMap *52*


Why the *24 bytes* gap between /classValueMap/ and /classRedefinedCount/ 
fields?


 int classRedefinedCount *80*
 int lastAnnotationsRedefinedCount 84

java.lang.String *static* field offsets:

  Field Type   Field Name Offset
  -- -- --
 ObjectStreamField[] serialPersistentFields 96
  Comparator CASE_INSENSITIVE_ORDER100
long serialVersionUID104
 int HASHING_SEED112


The 64 bit pointers variant:

java.lang.Class instance field offsets:

  Field Type   Field Name Offset
  -- -- --
 Constructor cachedConstructor 16
   Class newInstanceCallerCache 24
  String name 32
   SoftReference reflectionData 40
 ClassRepository genericInfo 48
Object[] enumConstants 56
 Map enumConstantDirectory 64
 Map annotations 72
 Map declaredAnnotations 80
  AnnotationType annotationType 88
   ClassValueMap classValueMap *96*

*24 bytes* gap here too!

 int classRedefinedCount *128*
 int lastAnnotationsRedefinedCount132

java.lang.String static field offsets:

  Field Type   Field Name Offset
  -- -- --
 ObjectStreamField[] serialPersistentFields144
  Comparator CASE_INSENSITIVE_ORDER152
long serialVersionUID160
 int HASHING_SEED168


Might it be that the classRedefinedCount field offset is fixed somehow 
in VM, since the VM has to update it? Should there be VM changes also to 
accomodate ReflectionData changes? Are there VM fields inserted here 
that don't have a Java mapping?


Regards, Peter



Re: Proxy.isProxyClass scalability

2013-01-25 Thread Peter Levart

On 01/25/2013 05:34 PM, Aleksey Shipilev wrote:

On 01/25/2013 08:02 PM, Peter Levart wrote:

On 01/25/2013 06:35 AM, David Holmes wrote:

On 25/01/2013 2:36 AM, Peter Levart wrote:

On 01/24/2013 04:45 PM, Peter Levart wrote:

...so it seems that in both cases, adding a boolean to j.l.Class wastes
8 bytes per Class object :-(

Seems to be the case, we are hitting the 8-byte alignment boundary.

java-object-layout [1] on jdk7u12:

$ java -jar ~/projects/java-object-layout/target/java-object-layout.jar
java.lang.Class
Running 64-bit HotSpot VM.
Using compressed references with 3-bit shift.
Objects are 8 bytes aligned.

java.lang.Class
  offset  sizetype description
   012 (assumed to be the object header)
  12 4 Constructor Class.cachedConstructor
  16 4   Class Class.newInstanceCallerCache
  20 4  String Class.name
  24 4   SoftReference Class.declaredFields
  28 4   SoftReference Class.publicFields
  32 4   SoftReference Class.declaredMethods
  36 4   SoftReference Class.publicMethods
  40 4   SoftReference Class.declaredConstructors
  44 4   SoftReference Class.publicConstructors
  48 4   SoftReference Class.declaredPublicFields
  52 4   SoftReference Class.declaredPublicMethods
  56 4 ClassRepository Class.genericInfo
  60 4Object[] Class.enumConstants
  64 4 Map Class.enumConstantDirectory
  68 4 Map Class.annotations
  72 4 Map Class.declaredAnnotations
  76 4  AnnotationType Class.annotationType
  80 4   ClassValueMap Class.classValueMap
  8412 (alignment/padding gap)

What's this? why 12 bytes?

  96 4 int Class.classRedefinedCount
 100 4 int Class.lastRedefinedCount
 104   (object boundary, size estimate)

But, otherwise, can't we use java.lang.ClassValue to associate this flag
with each class?

-Aleksey.

[1] https://github.com/shipilev/java-field-layout





Re: Proxy.isProxyClass scalability

2013-01-25 Thread Peter Levart

On 01/25/2013 05:34 PM, Aleksey Shipilev wrote:

But, otherwise, can't we use java.lang.ClassValue to associate this flag
with each class?
That is my proposed patch. It tries to be space saving and does not 
associate the flag with each class, but only with each subclass of 
java.lang.reflect.Proxy.


Regards, Peter



Re: Proxy.isProxyClass scalability

2013-01-25 Thread Aleksey Shipilev
On 01/25/2013 08:37 PM, Peter Levart wrote:
 On 01/25/2013 05:34 PM, Aleksey Shipilev wrote:
   80 4   ClassValueMap Class.classValueMap
   8412 (alignment/padding gap)
 What's this? why 12 bytes?
   96 4 int Class.classRedefinedCount

Beats me, some voodoo VM magic? This is what Unsafe reports anyway. Your
data have the same gap (though not immediately evident because you don't
calculate the offset differences).

-Aleksey.


Re: Proxy.isProxyClass scalability

2013-01-25 Thread Aleksey Shipilev
On 01/25/2013 08:40 PM, Peter Levart wrote:
 On 01/25/2013 05:34 PM, Aleksey Shipilev wrote:
 But, otherwise, can't we use java.lang.ClassValue to associate this flag
 with each class?
 That is my proposed patch. It tries to be space saving and does not
 associate the flag with each class, but only with each subclass of
 java.lang.reflect.Proxy.

Ah, I see. Sorry, I wasn't following the thread carefully. Cramming the
boolean field into j.l.Class when we have ClassValue does not seem worth
considering.

-Aleksey.



Re: Proxy.isProxyClass scalability

2013-01-25 Thread Peter Levart

On 01/25/2013 05:42 PM, Aleksey Shipilev wrote:

On 01/25/2013 08:37 PM, Peter Levart wrote:

On 01/25/2013 05:34 PM, Aleksey Shipilev wrote:

   80 4   ClassValueMap Class.classValueMap
   8412 (alignment/padding gap)

What's this? why 12 bytes?

   96 4 int Class.classRedefinedCount

Beats me, some voodoo VM magic? This is what Unsafe reports anyway. Your
data have the same gap (though not immediately evident because you don't
calculate the offset differences).

-Aleksey.
j.l.Class seems to be very special with it's own layout lo(ma)gic. For 
example, I copied the source of j.l.Class into j.l.MyClass and 
chopped-out all the methods, which gives the following (32 bit pointers):


java.lang.MyClass instance field offsets:

  Field Type   Field Name Offset
  -- -- --
* int classRedefinedCount 12**
** int lastAnnotationsRedefinedCount 16*
 Constructor cachedConstructor 20
   Class newInstanceCallerCache 24
  String name 28
   SoftReference reflectionData 32
 ClassRepository genericInfo 36
Object[] enumConstants 40
 Map enumConstantDirectory 44
 Map annotations 48
 Map declaredAnnotations 52
  AnnotationType annotationType 56
   ClassValueMap classValueMap 60

the primitive fields come before pointers whereas in j.l.Class:

java.lang.Class instance field offsets:

  Field Type   Field Name Offset
  -- -- --
 Constructor cachedConstructor 12
   Class newInstanceCallerCache 16
  String name 20
   SoftReference reflectionData 24
 ClassRepository genericInfo 28
Object[] enumConstants 32
 Map enumConstantDirectory 36
 Map annotations 40
 Map declaredAnnotations 44
  AnnotationType annotationType 48
   ClassValueMap classValueMap 52
* int classRedefinedCount 80**
** int lastAnnotationsRedefinedCount 84*

...they come after the pointers and the first one has a strange alignment...


Regards, Peter





Re: Proxy.isProxyClass scalability

2013-01-25 Thread Peter Levart

Hi David,

I think I already have a kind of answer. You wrote it in RFR: 8005232 
(JEP-149) Class Instance size reduction:


On 01/06/2013 11:46 PM, David Holmes wrote:
In Java 8, using a 32-bit example, a java.lang.Class instance is 112 
bytes consisting of:


- 8 byte object header
- 20 declared fields (mostly references, some int)
*- 5 injected fields (3 references, 2 ints) *

That gives: 8 + (20*4) +(5*4) = 108 bytes. But as we need 8-byte 
alignment that increases to 112 bytes. 


Regards, Peter


On 01/25/2013 05:34 PM, Peter Levart wrote:

Hi David,

I was surprised to see Usafe report these offsets. See below:

java.lang.Class *instance* field offsets:

  Field Type   Field Name Offset
  -- -- --
 Constructor cachedConstructor 12
   Class newInstanceCallerCache 16
  String name 20
   SoftReference reflectionData 24
 ClassRepository genericInfo 28
Object[] enumConstants 32
 Map enumConstantDirectory 36
 Map annotations 40
 Map declaredAnnotations 44
  AnnotationType annotationType 48
   ClassValueMap classValueMap *52*


Why the *24 bytes* gap between /classValueMap/ and 
/classRedefinedCount/ fields?


 int classRedefinedCount *80*
 int lastAnnotationsRedefinedCount 84

java.lang.String *static* field offsets:

  Field Type   Field Name Offset
  -- -- --
 ObjectStreamField[] serialPersistentFields 96
  Comparator CASE_INSENSITIVE_ORDER100
long serialVersionUID104
 int HASHING_SEED112


The 64 bit pointers variant:

java.lang.Class instance field offsets:

  Field Type   Field Name Offset
  -- -- --
 Constructor cachedConstructor 16
   Class newInstanceCallerCache 24
  String name 32
   SoftReference reflectionData 40
 ClassRepository genericInfo 48
Object[] enumConstants 56
 Map enumConstantDirectory 64
 Map annotations 72
 Map declaredAnnotations 80
  AnnotationType annotationType 88
   ClassValueMap classValueMap *96*

*24 bytes* gap here too!

 int classRedefinedCount *128*
 int lastAnnotationsRedefinedCount132

java.lang.String static field offsets:

  Field Type   Field Name Offset
  -- -- --
 ObjectStreamField[] serialPersistentFields144
  Comparator CASE_INSENSITIVE_ORDER152
long serialVersionUID160
 int HASHING_SEED168


Might it be that the classRedefinedCount field offset is fixed 
somehow in VM, since the VM has to update it? Should there be VM 
changes also to accomodate ReflectionData changes? Are there VM fields 
inserted here that don't have a Java mapping?


Regards, Peter





Re: Proxy.isProxyClass scalability

2013-01-25 Thread Peter Levart

On 01/24/2013 03:34 PM, Peter Levart wrote:

On 01/24/2013 03:10 PM, Alan Bateman wrote:

On 24/01/2013 13:49, Peter Levart wrote:

Should I file a RFE first?
Sorry I don't have time at the moment to study the proposed patch but 
just to mention that it has come up a few times, its just that it 
never bubbled up to the top of anyone's list. Here's the bug tracking 
it:


http://bugs.sun.com/view_bug.do?bug_id=7123493

-Alan.
I belive that is another bottleneck. It is mentioning the 
Proxy.getProxyClass method which also uses synchronization for 
maintaining a cache of proxy classes by request parameters. I could as 
well try to fix this too in the same patch if there is interest.


Regards, Peter



Hi Alan, David,

I thought about the ways to fix Proxy.isProxyClass() scalability and the 
Proxy.getProxyClass() scalability. While they are different methods, 
each with it's own data structure, I think that both problems can be 
solved with a single solution and that solution does not involve neither 
adding fields to j.l.Class nor ClassValue.


The solution is actually very simple. I just want to validate my 
reasoning before jumping to implement it:


- for solving scalability of getProxyClass cache, a field with a 
reference to ConcurrentHashMapListString, Class? extends Proxy is 
added to j.l.ClassLoader
- for solving scalability of isProxyClass, a field with a reference to 
ConcurrentHashMapClass? extends Proxy, Boolean is added to 
j.l.ClassLoader


Both maps hold strong references to Class objects, but only for the 
classes that are loaded by the ClassLoader that references them. Each 
ClassLoader already holds a strong reference to all the Class objects 
for the classes that were loaded by it in a Vector. Holding another 
reference does not present any problem, right?


I think this would be the best solution and it would solve both 
scalability problems of j.l.Proxy in one go.


Am I missing something?

Regards, Peter



Re: Proxy.isProxyClass scalability

2013-01-25 Thread David Holmes

Right - I was going to ask if those tools took into account injected fields.

David

On 26/01/2013 3:32 AM, Peter Levart wrote:

Hi David,

I think I already have a kind of answer. You wrote it in RFR: 8005232
(JEP-149) Class Instance size reduction:

On 01/06/2013 11:46 PM, David Holmes wrote:

In Java 8, using a 32-bit example, a java.lang.Class instance is 112
bytes consisting of:

- 8 byte object header
- 20 declared fields (mostly references, some int)
*- 5 injected fields (3 references, 2 ints) *

That gives: 8 + (20*4) +(5*4) = 108 bytes. But as we need 8-byte
alignment that increases to 112 bytes.


Regards, Peter


On 01/25/2013 05:34 PM, Peter Levart wrote:

Hi David,

I was surprised to see Usafe report these offsets. See below:

java.lang.Class *instance* field offsets:

Field Type Field Name Offset
-- -- --
Constructor cachedConstructor 12
Class newInstanceCallerCache 16
String name 20
SoftReference reflectionData 24
ClassRepository genericInfo 28
Object[] enumConstants 32
Map enumConstantDirectory 36
Map annotations 40
Map declaredAnnotations 44
AnnotationType annotationType 48
ClassValueMap classValueMap *52*


Why the *24 bytes* gap between /classValueMap/ and
/classRedefinedCount/ fields?

int classRedefinedCount *80*
int lastAnnotationsRedefinedCount 84

java.lang.String *static* field offsets:

Field Type Field Name Offset
-- -- --
ObjectStreamField[] serialPersistentFields 96
Comparator CASE_INSENSITIVE_ORDER 100
long serialVersionUID 104
int HASHING_SEED 112


The 64 bit pointers variant:

java.lang.Class instance field offsets:

Field Type Field Name Offset
-- -- --
Constructor cachedConstructor 16
Class newInstanceCallerCache 24
String name 32
SoftReference reflectionData 40
ClassRepository genericInfo 48
Object[] enumConstants 56
Map enumConstantDirectory 64
Map annotations 72
Map declaredAnnotations 80
AnnotationType annotationType 88
ClassValueMap classValueMap *96*

*24 bytes* gap here too!

int classRedefinedCount *128*
int lastAnnotationsRedefinedCount 132

java.lang.String static field offsets:

Field Type Field Name Offset
-- -- --
ObjectStreamField[] serialPersistentFields 144
Comparator CASE_INSENSITIVE_ORDER 152
long serialVersionUID 160
int HASHING_SEED 168


Might it be that the classRedefinedCount field offset is fixed
somehow in VM, since the VM has to update it? Should there be VM
changes also to accomodate ReflectionData changes? Are there VM fields
inserted here that don't have a Java mapping?

Regards, Peter





Re: Proxy.isProxyClass scalability

2013-01-24 Thread Alan Bateman

On 24/01/2013 13:49, Peter Levart wrote:

Should I file a RFE first?
Sorry I don't have time at the moment to study the proposed patch but 
just to mention that it has come up a few times, its just that it never 
bubbled up to the top of anyone's list. Here's the bug tracking it:


http://bugs.sun.com/view_bug.do?bug_id=7123493

-Alan.


Re: Proxy.isProxyClass scalability

2013-01-24 Thread Peter Levart

On 01/24/2013 03:10 PM, Alan Bateman wrote:

On 24/01/2013 13:49, Peter Levart wrote:

Should I file a RFE first?
Sorry I don't have time at the moment to study the proposed patch but 
just to mention that it has come up a few times, its just that it 
never bubbled up to the top of anyone's list. Here's the bug tracking it:


http://bugs.sun.com/view_bug.do?bug_id=7123493

-Alan.
I belive that is another bottleneck. It is mentioning the 
Proxy.getProxyClass method which also uses synchronization for 
maintaining a cache of proxy classes by request parameters. I could as 
well try to fix this too in the same patch if there is interest.


Regards, Peter



Re: Proxy.isProxyClass scalability

2013-01-24 Thread Vitaly Davidovich
Peter,

I know this was brought up on your c-i mailing list thread, but it really
feels like a new boolean field in j.l.Class is the cleaner solution (and
infinitely scalable and doesn't require bookkeeping in the Proxy class).
Is there really no existing alignment gap in j.l.Class layout that a
boolean can slide into?

Sent from my phone
On Jan 24, 2013 9:35 AM, Peter Levart peter.lev...@gmail.com wrote:

 On 01/24/2013 03:10 PM, Alan Bateman wrote:

 On 24/01/2013 13:49, Peter Levart wrote:

 Should I file a RFE first?

 Sorry I don't have time at the moment to study the proposed patch but
 just to mention that it has come up a few times, its just that it never
 bubbled up to the top of anyone's list. Here's the bug tracking it:

 http://bugs.sun.com/view_bug.**do?bug_id=7123493http://bugs.sun.com/view_bug.do?bug_id=7123493

 -Alan.

 I belive that is another bottleneck. It is mentioning the
 Proxy.getProxyClass method which also uses synchronization for maintaining
 a cache of proxy classes by request parameters. I could as well try to fix
 this too in the same patch if there is interest.

 Regards, Peter




Re: Proxy.isProxyClass scalability

2013-01-24 Thread Peter Levart

On 01/24/2013 03:40 PM, Vitaly Davidovich wrote:


Peter,

I know this was brought up on your c-i mailing list thread, but it 
really feels like a new boolean field in j.l.Class is the cleaner 
solution (and infinitely scalable and doesn't require bookkeeping in 
the Proxy class).  Is there really no existing alignment gap in 
j.l.Class layout that a boolean can slide into?


There might be, I will check. The ClassValue is scalable too (check the 
benchmarks), and bookkeeping is performed in the 
ClassValue.ClassValueMap that is referenced from the Class - not in the 
Proxy class. Unfortunately the j.l.r.Proxy class is in another package 
from j.l.Class, so the solution with a simple boolean field would 
require JavaLangAccess or Unsafe acrobatics.


Another thing is this separate bug:

http://bugs.sun.com/view_bug.do?bug_id=7123493

To solve it, a reference field in j.l.ClassLoader or a hypothetical 
ClassLoaderValue implementation would be required. I looked at the bug 
reporter's solution (ConcurrentProxy). He guards the 
WeakHashMapClassLoader, ... with a ReadWriteLock:


/*
* Find or create the proxy class cache for the class loader.
*/
MapObject,ReferenceClass cache;
try{
loaderToCacheLock.readLock().lock();
cache = loaderToCache.get(loader);
}finally{
loaderToCacheLock.readLock().unlock();
}
// window of opportunity here between locks that would result in 
duplicate put(..) call

if (cache == null) {
try{
loaderToCacheLock.writeLock().lock();
cache = new ConcurrentHashMapObject,ReferenceClass();
loaderToCache.put(loader, cache);
}finally{
loaderToCacheLock.writeLock().unlock();
}
}


That code is broken twice. First, it is not double-checking the 
existence of cache in the writeLock guarded section. That's not so 
serious and could be fixed.
The other fault is using ReadWriteLock.readLock() to guard the 
WeakHashMap.get(). This is dangerous, since WeakHashMap.get() is a 
mutating method (expunging stale entries).


I don't think fixing this bug without either:
- new field in ClassLoader or
- ClassLoaderValue or
- WeakConcurrentHashMap

...is possible. Since we don't have the later two at the moment, the 
best bet for it unfortunately seems to be the first solution.


Regards, Peter


Sent from my phone

On Jan 24, 2013 9:35 AM, Peter Levart peter.lev...@gmail.com 
mailto:peter.lev...@gmail.com wrote:


On 01/24/2013 03:10 PM, Alan Bateman wrote:

On 24/01/2013 13:49, Peter Levart wrote:

Should I file a RFE first?

Sorry I don't have time at the moment to study the proposed
patch but just to mention that it has come up a few times, its
just that it never bubbled up to the top of anyone's list.
Here's the bug tracking it:

http://bugs.sun.com/view_bug.do?bug_id=7123493

-Alan.

I belive that is another bottleneck. It is mentioning the
Proxy.getProxyClass method which also uses synchronization for
maintaining a cache of proxy classes by request parameters. I
could as well try to fix this too in the same patch if there is
interest.

Regards, Peter





Re: Proxy.isProxyClass scalability

2013-01-24 Thread Vitaly Davidovich
The boolean seems better from an intent standpoint as well - all this wants
to do is tag a Class as having been internally generated by the proxy.
This information is present at the point of generation, obviously (and the
new. field can be marked final).  Doing the tagging via indirection
(ClassValue or otherwise) feels circuitous.  If the new boolean would
actually increase footprint, then OK - tagging via indirection to avoid
footprint increase for a relatively uncommon thing seems worthwhile.

I'm not that familiar with ClassValue but I don't doubt it scales better
than a synch map, and it may scale well enough for the expected usage.
But a read of a final field is obviously the best case.

Are there any downsides to using ClassValue? That is, what could go wrong?

Thanks

Sent from my phone
On Jan 24, 2013 10:46 AM, Peter Levart peter.lev...@gmail.com wrote:

  On 01/24/2013 03:40 PM, Vitaly Davidovich wrote:

 Peter,

 I know this was brought up on your c-i mailing list thread, but it really
 feels like a new boolean field in j.l.Class is the cleaner solution (and
 infinitely scalable and doesn't require bookkeeping in the Proxy class).
 Is there really no existing alignment gap in j.l.Class layout that a
 boolean can slide into?

 There might be, I will check. The ClassValue is scalable too (check the
 benchmarks), and bookkeeping is performed in the ClassValue.ClassValueMap
 that is referenced from the Class - not in the Proxy class. Unfortunately
 the j.l.r.Proxy class is in another package from j.l.Class, so the solution
 with a simple boolean field would require JavaLangAccess or Unsafe
 acrobatics.

 Another thing is this separate bug:

  http://bugs.sun.com/view_bug.do?bug_id=7123493

 To solve it, a reference field in j.l.ClassLoader or a hypothetical
 ClassLoaderValue implementation would be required. I looked at the bug
 reporter's solution (ConcurrentProxy). He guards the
 WeakHashMapClassLoader, ... with a ReadWriteLock:

 /*
  * Find or create the proxy class cache for the class loader.
  */
 MapObject,ReferenceClass cache;
 try{
 loaderToCacheLock.readLock().lock();
 cache = loaderToCache.get(loader);
 }finally{
 loaderToCacheLock.readLock().unlock();
 }
 // window of opportunity here between locks that would result in 
 duplicate put(..) call
 if (cache == null) {
 try{
 loaderToCacheLock.writeLock().lock();
 
 nbsp;   cache = new ConcurrentHashMapObject,ReferenceClass();
 loaderToCache.put(loader, cache);
 }finally{
   
 nbsp; loaderToCacheLock.writeLock().unlock();
 }
 }


 That code is broken twice. First, it is not double-checking the existence
 of cache in the writeLock guarded section. That's not so serious and could
 be fixed.
 The other fault is using ReadWriteLock.readLock() to guard the
 WeakHashMap.get(). This is dangerous, since WeakHashMap.get() is a mutating
 method (expunging stale entries).

 I don't think fixing this bug without either:
 - new field in ClassLoader or
 - ClassLoaderValue or
 - WeakConcurrentHashMap

 ...is possible. Since we don't have the later two at the moment, the best
 bet for it unfortunately seems to be the first solution.

 Regards, Peter

  Sent from my phone
 On Jan 24, 2013 9:35 AM, Peter Levart peter.lev...@gmail.com wrote:

 On 01/24/2013 03:10 PM, Alan Bateman wrote:

 On 24/01/2013 13:49, Peter Levart wrote:

 Should I file a RFE first?

 Sorry I don't have time at the moment to study the proposed patch but
 just to mention that it has come up a few times, its just that it never
 bubbled up to the top of anyone's list. Here's the bug tracking it:

 http://bugs.sun.com/view_bug.do?bug_id=7123493

 -Alan.

 I belive that is another bottleneck. It is mentioning the
 Proxy.getProxyClass method which also uses synchronization for maintaining
 a cache of proxy classes by request parameters. I could as well try to fix
 this too in the same patch if there is interest.

 Regards, Peter





Re: Proxy.isProxyClass scalability

2013-01-24 Thread Peter Levart

On 01/24/2013 04:45 PM, Peter Levart wrote:


Is there really no existing alignment gap in j.l.Class layout that a 
boolean can slide into?



There might be, I will check.

All instance fields in j.l.Class are either references or ints.

Regards, Peter


Re: Proxy.isProxyClass scalability

2013-01-24 Thread David Holmes

On 25/01/2013 2:36 AM, Peter Levart wrote:

On 01/24/2013 04:45 PM, Peter Levart wrote:


Is there really no existing alignment gap in j.l.Class layout that a
boolean can slide into?


There might be, I will check.

All instance fields in j.l.Class are either references or ints.


Instance are also 8-byte aligned though so does that leave any slop 
where an extra field would not make an actual difference. (I should know 
the answer to that after the ReflectionData changes but don't recall.)


Note: I have not looked at this, just considering the add a field 
aspect of it.


David


Regards, Peter