Proxy.[isProxyClass|getProxyClass] scalability

Peter Levart peter.levart at gmail.com
Sun Jan 27 14:34:24 UTC 2013


Hi again,

By simple rearrangement of code in Proxy.getProxyClass (moved the 
parameters validation to slow-path) I managed to speed-up the fast-path 
getProxyClass so that now it's raw speed is 40x the speed of current 
getProxyClass method:

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

Here are quick measurements (only for i7 this time):

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

Regards, Peter

On 01/27/2013 02:32 PM, Peter Levart wrote:
> Hi Alan, David,
>
> I think I have a solution for scalability problems of 
> java.lang.reflect.Proxy:
>
> * http://dl.dropbox.com/u/101777488/jdk8-tl/proxy/webrev.01/index.html
>
> I designed it along the lines mentioned in previous mail (see below). 
> First I thought that both caches (a cache mapping request parameters 
> of Proxy.getProxyClass to a proxy Class and a cache for resolving the 
> Proxy.isProxyClass method) could be placed inside the j.l.ClassLoader. 
> And they actually could. I tried this and it worked correctly, but the 
> raw (single-threaded) performance of Proxy.isProxyClass was half the 
> performance of current JDK8 isProxyClass method that way. The main 
> performance hog I identified was the Class.getClassLoader() method. 
> This method delegates to a native JVM method after checking the 
> callers permissions. So the plan to keep the isProxyClass cache inside 
> the ClassLoader failed. But then the ClassValue solution that I 
> proposed in previous revision works beautifully and fast, so I kept 
> this solution for isProxyClass cache. The ThreadLocal trick to 
> initialize the ClassValue for a particular proxy class is necessary 
> because ClassValue does not have a put() method. It does have 
> actually, but it's package private and the comment suggests that it 
> might not be there forever:
>
>     // Possible functionality for JSR 292 MR 1
>     /*public*/ void put(Class<?> type, T value) {
>         ClassValueMap map = getMap(type);
>         map.changeEntry(this, value);
>     }
>
> I could use the JavaLangAccess to access it from Proxy code though, so 
> this is another refinement that is possible and would eliminate the 
> need for ThreadLocal trick.
> The cache for getProxyClass method on the other hand is most naturally 
> hosted by j.l.ClassLoader and that's where I put it in the proposed 
> patch. Currently the cross-package access to it is implemented using 
> Unsafe, but the performance aspect is not so critical that It couldn't 
> be changed to using JavaLangAccess instead if desired.
> I did some performance testing too. Here are the results taken on 3 
> different systems (i7 Linux PC, Raspberry Pi and Sun-Blade-T6320 
> Solaris machine):
>
> * 
> https://raw.github.com/plevart/jdk8-tl/proxy/test/proxy_benchmark_results.txt
>
> These are the test sources i used:
>
> * 
> https://github.com/plevart/jdk8-tl/blob/proxy/test/src/test/ProxyBenchmarkTest.java
> * 
> https://github.com/plevart/micro-bench/blob/master/src/si/pele/microbench/TestRunner.java
>
> Results show scalability and raw performance improvements for both 
> critical Proxy methods.
>
> So what do you think?
>
>
> Regards, Peter
>
>
> On 01/25/2013 06:55 PM, Peter Levart wrote:
>> 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 ConcurrentHashMap<List<String>, Class<? extends Proxy>> 
>> is added to j.l.ClassLoader
>> - for solving scalability of isProxyClass, a field with a reference 
>> to ConcurrentHashMap<Class<? 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
>>
>




More information about the core-libs-dev mailing list