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