4 Replies Latest reply: Oct 11, 2011 6:09 AM by Philippe Marschall RSS

TreeCache performance

Philippe Marschall Novice

We are evaluating migrating from JBoss Cache 1.4 to Infinispan 5.x . Since JBoss Cache 1.4 is tree based we plan to use infinispan-tree wich is more or less a drop in replacement and saves us from rewirting the code base.

 

However a unit test that would have previously taken 1.5 seconds now is in the 50 seconds range. That makes people a bit nervous. The test inserts 100000 elements in the cache and then accesses them. Below is the code that does the same (tested with 5.1.0.BETA1) and the profile output from YourKit. My interpretation is that copy on write kills us. Is this the case? Is there a way to change the configuration to get better performance? Do we somehow misuse the API?

 

public class TreeCachePerformance { 

  public static void main(String[] args) { 
    TreeCache<String, String> treeCache = createTreeCache(); 
    stressCache(treeCache); 
  } 

  static void stressCache(TreeCache<String, String> treeCache) { 
    int itemCount = 100000; 

    for (int i = 0; i < itemCount; i++) { 
      String s = "key" + i; 
      treeCache.put("prefix", s, s); 
    } 

    for (int i = 0; i < itemCount; i++) { 
      String s = "key" + i; 
      String v = treeCache.get("prefix", s); 
      if (!s.equals(v)) { 
        System.err.printf("expected %s but got %s%n", s, v); 
      } 
    } 
  } 

  static <K, V> TreeCache<K, V> createTreeCache() { 
    Configuration configuration = new Configuration(); 
    FluentConfiguration fluent = configuration.fluent(); 
    fluent.invocationBatching(); 
    fluent.eviction().strategy(EvictionStrategy.NONE).maxEntries(-1); 
    fluent.transactionManagerLookupClass(JBossStandaloneJTAManagerLookup.class); 
    fluent.transaction().transactionMode(TransactionMode.TRANSACTIONAL).lockingMode(LockingMode.OPTIMISTIC); 
    Cache<Object, Object> infinispanCache = new DefaultCacheManager(configuration).getCache(); 
    TreeCacheFactory factory = new TreeCacheFactory(); 
    return (TreeCache<K, V>) factory.createTreeCache(infinispanCache); 
  } 

}

 

+-------------------------------------------------------------------------------------------------------------------+-----------------+ 
|                                                       Name                                                        |    Time (ms)    | 
+-------------------------------------------------------------------------------------------------------------------+-----------------+ 
|  +---<All threads>                                                                                                |  15'334  100 %  | 
|    |                                                                                                              |                 | 
|    +---com.acme.TreeCachePerformance.main(String[])                                                               |  15'334  100 %  | 
|      |                                                                                                            |                 | 
|      +---com.acme.TreeCachePerformance.stressCache(TreeCache)                                                     |  13'884   91 %  | 
|      | |                                                                                                          |                 | 
|      | +---org.infinispan.tree.TreeCacheImpl.put(String, Object, Object)                                          |  13'618   89 %  | 
|      | | |                                                                                                        |                 | 
|      | | +---org.infinispan.tree.TreeCacheImpl.put(Fqn, Object, Object)                                           |  13'462   88 %  | 
|      | | | |                                                                                                      |                 | 
|      | | | +---org.infinispan.atomic.AtomicHashMapProxy.put(Object, Object)                                       |  12'246   80 %  | 
|      | | | | |                                                                                                    |                 | 
|      | | | | +---org.infinispan.atomic.AtomicHashMapProxy.getDeltaMapForWrite(InvocationContext)                  |  12'214   80 %  | 
|      | | | | | |                                                                                                  |                 | 
|      | | | | | +---org.infinispan.atomic.AtomicHashMap.copyForWrite()                                             |  11'762   77 %  | 
|      | | | | | | |                                                                                                |                 | 
|      | | | | | | +---org.infinispan.util.FastCopyHashMap.clone()                                                  |  11'637   76 %  | 
|      | | | | | | | |                                                                                              |                 | 
|      | | | | | | | +---java.lang.Object.clone()                                                                   |  11'637   76 %  | 
|      | | | | | | |                                                                                                |                 | 
|      | | | | | | +---java.lang.Object.clone()                                                                     |     124    1 %  | 
|      | | | | | |                                                                                                  |                 | 
|      | | | | | +---org.infinispan.context.impl.AbstractInvocationContext.setFlags(Flag[])                         |     218    1 %  | 
|      | | | | | |                                                                                                  |                 | 
|      | | | | | +---org.infinispan.tree.CacheAdapter.put(Object, Object)                                           |     156    1 %  | 
|      | | | | | |                                                                                                  |                 | 
|      | | | | | +---org.infinispan.atomic.AtomicHashMapProxy.getDeltaMapForRead()                                  |      31    0 %  | 
|      | | | | | |                                                                                                  |                 | 
|      | | | | | +---org.infinispan.context.impl.LocalTxInvocationContext.lookupEntry(Object)                       |      31    0 %  | 
|      | | | | |                                                                                                    |                 | 
|      | | | | +---org.infinispan.atomic.AtomicHashMap.put(Object, Object)                                          |      15    0 %  | 
|      | | | | |                                                                                                    |                 | 
|      | | | | +---org.infinispan.context.TransactionalInvocationContextContainer.createInvocationContext(boolean)  |      15    0 %  | 
|      | | | |                                                                                                      |                 | 
|      | | | +---org.infinispan.batch.AutoBatchSupport.endAtomic()                                                  |     717    5 %  | 
|      | | | |                                                                                                      |                 | 
|      | | | +---org.infinispan.tree.TreeStructureSupport.createNodeInCache(Fqn)                                    |     374    2 %  | 
|      | | | |                                                                                                      |                 | 
|      | | | +---org.infinispan.batch.AutoBatchSupport.startAtomic()                                                |      93    1 %  | 
|      | | | |                                                                                                      |                 | 
|      | | | +---org.infinispan.tree.TreeStructureSupport.getAtomicMap(NodeKey)                                     |      31    0 %  | 
|      | | |                                                                                                        |                 | 
|      | | +---org.infinispan.tree.Fqn.fromString(String)                                                           |     156    1 %  | 
|      | |                                                                                                          |                 | 
|      | +---org.infinispan.tree.TreeCacheImpl.get(String, Object)                                                  |     249    2 %  | 
|      | |                                                                                                          |                 | 
|      | +---java.lang.StringBuilder.append(int)                                                                    |      15    0 %  | 
|      |                                                                                                            |                 | 
|      +---com.acme.TreeCachePerformance.createTreeCache()                                                          |   1'450    9 %  | 
+-------------------------------------------------------------------------------------------------------------------+-----------------+
  • 1. Re: TreeCache performance
    Galder Zamarreño Master

    I guess the issue is that you're making a note contain a lot of data, the node located in /prefix.

     

    You might want to change the test to store things under different subtrees in order to take advantage of two things:

    - Avoid overloading a node

    - Enable multiple nodes to be modified concurrently.

     

    So, maybe try something like:

     

    for (int i = 0; i < itemCount; i++) {
       String s = "key" + i;
       treeCache.put("prefix" + i, s, s);
    }
    

     

    If that's problematic, you can try some layering in the middle:

     

    for (int i = 0; i < itemCount; i++) {
       String s = "key" + i;
       treeCache.put("prefix-" + (i % 100) + "-" + i, s, s);
    }
    

     

    Obviously, the reading part would need to be adjusted accordingly.

     

    Btw, if what your code currently does is store all data in a single FQN, you might as well migrate to the basic Map API. You'll be much better off

  • 2. Re: TreeCache performance
    Philippe Marschall Novice

    I'm not looking for a way to make the test run faster, I'm looking for a way to make our code run faster.

     

    We don't store all the data in one FQN but they can get large (I don't have numbers).

     

    The code was running one or two orders of magitude faster with JBoss Cache 1.4 so I'm a bit suprised to see this performance. Rewriting the whole code base to use the Map API is not an option, that's why we use the tree cache in the first place.

  • 3. Re: TreeCache performance
    Galder Zamarreño Master

    Fair enough, an issue has been created to try to address this performance difference.

  • 4. Re: TreeCache performance
    Philippe Marschall Novice

    Thanks. Don't get me wrong, I'm fine with somewhat slower performance (I get that we should migrate) as long as it's in the same order of manitude.