[Mondrian] Some optimizations based on profiler results

Julian Hyde julianhyde at speakeasy.net
Thu Oct 18 13:07:58 EDT 2007


See my comments inline.
 
Lastly: there is a developer's guide, which contains coding guidelines among
other things. Enough said.
http://mondrian.pentaho.org/documentation/developers_guide.php
 
Julian


  _____  

From: mondrian-bounces at pentaho.org [mailto:mondrian-bounces at pentaho.org] On
Behalf Of Ajit Vasudeo Joglekar
Sent: Thursday, October 18, 2007 5:36 AM
To: mondrian at pentaho.org
Subject: [Mondrian] Some optimizations based on profiler results



We did some profiling on mondrian code base. We have a large catalog with
hundreds of dimensions and measures. Based on the hotspots identified by the
profiler here are some optimizations that make considerable difference in
performance in the evaluation of a single mdx. 

We would like to introduce these changes. Inviting comments, suggestions 

Thanks, 
-Ajit, Ashwin 

=================== 

1) In RolapCubeSchemaReader we have a getCalculatedMembers method that
creates a new list of calculated members based on the role configured in the
Mondrian schema. 

In the scenario where we have a huge number of calculated members and no
Role configured this operation becomes quite expensive on multiple
invocations. 

We can fix this by returning the original list of calculated members if the
access is the default access 

 public List<Member> getCalculatedMembers() { 
            List<Member> list = new ArrayList<Member>(); 
                       for (Formula formula : calculatedMembers) { 
                                     Member member = formula.getMdxMember();

                                     if (getRole().canAccess(member)) { 
                                         list.add(member); 
                                     } 
                                 } 
            return list; 
        } 
        
        becomes 
        
         public List<Member> getCalculatedMembers() { 
                 if(Access.ALL == getRole().getAccess()){ 
                         return calculatedMembers; // indicative - need to
convert [] to list. one option is We can maintain ArrayList and return []
where ever necessary 
                 } 
                  
                 List<Member> list = new ArrayList<Member>(); 
                     for (Formula formula : calculatedMembers) { 
                         Member member = formula.getMdxMember(); 
                         if (getRole().canAccess(member)) { 
                             list.add(member); 
                         } 
                     } 
            return list; 
        }  
 

I guess you have a lot of calculated members? Your code is low on specifics
- in particular there's not actually a Role.getAccess() method - but I can
see that computing the set of accessible calc members once per role would be
useful.

        
2) In the RolapMember equals method : 

        private boolean equals(RolapMember that) { 
                assert that != null; 
        
                return this.getUniqueName().equals(that.getUniqueName()); 
    } 
    
    Now if the assert fails it will throw an exception which means equals
will fail with a non boolean value which should not happen and assert is an
expensive operation 
    when compared to a null check. 
    
    it can be changed to: 
    
        private boolean equals(RolapMember that) { 
                if(that == null){ 
                        return false; 
                } 
        
                return this.getUniqueName().equals(that.getUniqueName()); 
    } 
 

This is a terrible idea. If you don't like the overhead of asserts, turn
them off: 'java -da -dsa'.

     
3) In RolapEvaluator : 
 public final Member setContext(Member member) { 
        final RolapMember m = (RolapMember) member; 
        final int ordinal = m.getDimension().getOrdinal(root.cube); 
        final Member previous = currentMembers[ordinal]; 
        
        if (previous.isCalculated()) { 
            removeCalcMember(previous); 
        } 
        currentMembers[ordinal] = m; 
        if (m.isCalculated()) { 
            addCalcMember(m); 
        } 
        return previous; 
    } 
    
    now we can optimize this by adding an equals to verify that m and
previous are not the same. 
    
     public final Member setContext(Member member) { 
            final RolapMember m = (RolapMember) member; 
            final int ordinal = m.getDimension().getOrdinal(root.cube); 
            final Member previous = currentMembers[ordinal]; 
            if (m.equals(previous)) 
                return previous; 
            if (previous.isCalculated()) { 
                removeCalcMember(previous); 
            } 
            currentMembers[ordinal] = m; 
            if (m.isCalculated()) { 
                addCalcMember(m); 
            } 
            return previous; 
    } 
    
    this reduces some operations in case of massive number of invocations to
this method.  
 

If the profiler says this ia major save, go ahead and add it.
 
Julian
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.pentaho.org/pipermail/mondrian/attachments/20071018/01953620/attachment.html 


More information about the Mondrian mailing list