danielsun1106 edited a comment on issue #1135: GROOVY-8298: Slow Performance 
Caused by Invoke Dynamic
URL: https://github.com/apache/groovy/pull/1135#issuecomment-570811643
 
 
   Jochen, the main idea can be described as the following code:
   
   ```java
   if (cacheHits(receiverCassName)) { // Try to find the cached MethodHandle
         // the main logic of `fromCache`
         MethodHandle mh = lruCache.get(receiverCassName); // find the cached 
MethodHandle again...
         return mh.invokeExact(...);
   } else { // fallback, and put the fallback methodhandle to the inline 
cache(LRU) for reuse
         // the main logic of `selectMethod`
         Selector selector = Selector.getSelector(...);
         selector.setCallSiteTarget();
         MethodHandle mh = 
selector.handle.asSpreader(...).asType(MethodType.methodType(Object.class, 
Object[].class));
         lruCache.put(receiverCassName, mh); // cache the methodhandle 
         return mh.invokeExact(...);
   }
   ```
   
   As the inline cache is implemented as LRU cache, and `cacheHits` and 
`fromCache` are executed in two steps(not atomic), so if `cacheHits` returns 
`true`(means cached methodhandle found), `fromCache` find the same cached 
methodhandle from LRU cache again, the result probably is `null` as cached 
methodhandle may be cleared according to the rule of LRU... I use `ThreadLocal` 
to avoid the above concurrent issue.
   
   Also, we have the inline cache for callsite, so `setTarget` can be avoided, 
which causes the poor performance as the GROOVY-8298 shown.
   
   >a call x.foo(y) may add a handle X#foo(Y1) in the cache, but if y changes 
to Y2 your cache will still return X#foo(Y1), even though y may not be an 
instance of Y1. You will have to check the argument types. 
   
   We cache the methodhandle with method type 
`MethodType.methodType(Object.class, Object[].class)`, so we will not encounter 
the issue, the following code runs well  ;-)
   ```groovy
   def same(String obj) { return obj }
   def same(int obj) { return obj }
   def same(float obj) { return obj }
   for (int i = 0; i < 100000; i++) {
       [1, 1.0f, '1.0'].each { same(it) }
   }
   ```
   (before tuning: 9s, after tuning: 6s, on my machine)
   
   ```groovy
   for (int i = 0; i < 100000; i++) {
       [1, 1.0f, '1.0'].each { it.toString() }
   }
   ```
   (before tuning: 6s, after tuning: 2s, on my machine)
   
   More strict performance tests will be done with JMH, I have no idea how to 
enable indy for performance tests for now...
   

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to