#77 Dramatic Performance Degradation with Interfaces

closed
None
7
2007-03-26
2007-03-20
No

Setting:

SourceClass implements IF

If mapping is done with Class, 1000 invocations take 344ms, if Mapping is done with Interface 1000 invocations take 8282ms.

The processing time cumulates with each invocation.

Problem: (All Applies to Dozer 3.0)

In Mappingprocessor line 224, the class-mapping is determined:

//Now check for super class mappings as a convenience -assuming for now that super class mappings are at the same level
List parentFieldNames = null;
if (parentClassMap == null) {
// check for super classes
List superClasses = checkForSuperTypeMapping(sourceClass, destClass);
// check for interfaces
superClasses.addAll(classMapFinder.findInterfaceMappings(this.customMappings, sourceClass, destClass));
if (superClasses != null && superClasses.size() > 0) {
parentFieldNames = processSuperTypeMapping(superClasses, sourceObj, destObj, sourceClass, parentFieldMap);
}
}

superClasses is taken from cache (line 228) and Interfaces are added in line 230. As this is a List and the cached value is not copied, in every invocation the same Interface-Mapping is added again (would not occur with a HastSet instead of an ArrayList). As this is a reference to the cached List, the cached value grows as well.

Solution:

Change Type of superClasses to Set (so duplicates aren't added) if this is possible, or do a defense copying of the cached value.

Discussion

  • Mika Goeckel

    Mika Goeckel - 2007-03-20

    Logged In: YES
    user_id=306614
    Originator: YES

    The Problem only occurs if the object has got a parent object (Like ApplicationUser <- Subscriber in Dozer tests)
    Here's a performance comparison (see Testcase attached)

    20.03.2007 13:55:53 net.sf.dozer.util.mapping.InterfacePerformanceTest testInterface
    INFO: Execution of 1 iterations times ApplicationUser = 0 Subscriber = 0
    20.03.2007 13:55:53 net.sf.dozer.util.mapping.InterfacePerformanceTest testInterface
    INFO: Execution of 2 iterations times ApplicationUser = 0 Subscriber = 0
    20.03.2007 13:55:53 net.sf.dozer.util.mapping.InterfacePerformanceTest testInterface
    INFO: Execution of 4 iterations times ApplicationUser = 0 Subscriber = 0
    20.03.2007 13:55:53 net.sf.dozer.util.mapping.InterfacePerformanceTest testInterface
    INFO: Execution of 8 iterations times ApplicationUser = 16 Subscriber = 16
    20.03.2007 13:55:53 net.sf.dozer.util.mapping.InterfacePerformanceTest testInterface
    INFO: Execution of 16 iterations times ApplicationUser = 0 Subscriber = 31
    20.03.2007 13:55:53 net.sf.dozer.util.mapping.InterfacePerformanceTest testInterface
    INFO: Execution of 32 iterations times ApplicationUser = 16 Subscriber = 46
    20.03.2007 13:55:53 net.sf.dozer.util.mapping.InterfacePerformanceTest testInterface
    INFO: Execution of 64 iterations times ApplicationUser = 0 Subscriber = 94
    20.03.2007 13:55:53 net.sf.dozer.util.mapping.InterfacePerformanceTest testInterface
    INFO: Execution of 128 iterations times ApplicationUser = 16 Subscriber = 359
    20.03.2007 13:55:55 net.sf.dozer.util.mapping.InterfacePerformanceTest testInterface
    INFO: Execution of 256 iterations times ApplicationUser = 16 Subscriber = 1406
    20.03.2007 13:56:00 net.sf.dozer.util.mapping.InterfacePerformanceTest testInterface
    INFO: Execution of 512 iterations times ApplicationUser = 47 Subscriber = 5500
    20.03.2007 13:56:22 net.sf.dozer.util.mapping.InterfacePerformanceTest testInterface
    INFO: Execution of 1024 iterations times ApplicationUser = 16 Subscriber = 22046

    File Added: InterfacePerformanceTest.java

     
  • Mika Goeckel

    Mika Goeckel - 2007-03-20
    • priority: 5 --> 7
     
  • Mika Goeckel

    Mika Goeckel - 2007-03-20

    Logged In: YES
    user_id=306614
    Originator: YES

    (Quick)Fix:

    MappingProcessor line 961, exchange

    private List checkForSuperTypeMapping(Class sourceClass, Class destClass) {
    // Check cache first
    Object cacheKey = CacheKeyFactory.createKey(new Object[] { destClass, sourceClass });
    CacheEntry cacheEntry = superTypeCache.get(cacheKey);
    if (cacheEntry != null) {
    return (List) cacheEntry.getValue();
    }

    with defensive copy:

    private List checkForSuperTypeMapping(Class sourceClass, Class destClass) {
    // Check cache first
    Object cacheKey = CacheKeyFactory.createKey(new Object[] { destClass, sourceClass });
    CacheEntry cacheEntry = superTypeCache.get(cacheKey);
    if (cacheEntry != null) {
    List result = new ArrayList();
    Collections.copy((List)cacheEntry.getValue(), result);
    return result;
    }

     
  • Franz Garsombke

    Franz Garsombke - 2007-03-20
    • assigned_to: nobody --> fgarsombke
     
  • Matt Tierney

    Matt Tierney - 2007-03-21

    Logged In: YES
    user_id=1236069
    Originator: NO

    Mika,

    Thanks for submitting the detailed use case along with a unit test attached. That really helps us diagnosing issues.

     
  • Franz Garsombke

    Franz Garsombke - 2007-03-21
    • status: open --> pending
     
  • Franz Garsombke

    Franz Garsombke - 2007-03-21

    Logged In: YES
    user_id=550744
    Originator: NO

    I changed this to a HashSet and it seems to have fixed the problem. Will be in next release. Checked in.

     
  • Franz Garsombke

    Franz Garsombke - 2007-03-26
    • status: pending --> closed
     

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks