<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META http-equiv=Content-Type content="text/html; charset=us-ascii">
<META content="MSHTML 6.00.6000.16546" name=GENERATOR></HEAD>
<BODY>
<DIV dir=ltr align=left><FONT face=Verdana color=#000080 size=2><SPAN
class=285595516-18102007>See my comments inline.</SPAN></FONT></DIV>
<DIV dir=ltr align=left><FONT face=Verdana color=#000080 size=2><SPAN
class=285595516-18102007></SPAN></FONT> </DIV>
<DIV dir=ltr align=left><FONT face=Verdana color=#000080 size=2><SPAN
class=285595516-18102007>Lastly: there is a developer's guide, which contains
coding guidelines among other things. Enough said. <A
href="http://mondrian.pentaho.org/documentation/developers_guide.php">http://mondrian.pentaho.org/documentation/developers_guide.php</A></SPAN></FONT></DIV>
<DIV dir=ltr align=left><FONT face=Verdana color=#000080 size=2><SPAN
class=285595516-18102007></SPAN></FONT> </DIV>
<DIV dir=ltr align=left><FONT face=Verdana color=#000080 size=2><SPAN
class=285595516-18102007>Julian</SPAN></FONT></DIV><BR>
<BLOCKQUOTE
style="PADDING-LEFT: 5px; MARGIN-LEFT: 5px; BORDER-LEFT: #000080 2px solid; MARGIN-RIGHT: 0px">
<DIV class=OutlookMessageHeader lang=en-us dir=ltr align=left>
<HR tabIndex=-1>
<FONT face=Tahoma size=2><B>From:</B> mondrian-bounces@pentaho.org
[mailto:mondrian-bounces@pentaho.org] <B>On Behalf Of </B>Ajit Vasudeo
Joglekar<BR><B>Sent:</B> Thursday, October 18, 2007 5:36 AM<BR><B>To:</B>
mondrian@pentaho.org<BR><B>Subject:</B> [Mondrian] Some optimizations based on
profiler results<BR></FONT><BR></DIV>
<DIV></DIV>
<DIV><BR><FONT face=sans-serif size=2>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.</FONT> <BR><BR><FONT face=sans-serif size=2>We would like to introduce
these changes. Inviting comments, suggestions</FONT> <BR><BR><FONT
face=sans-serif size=2>Thanks,</FONT> <BR><FONT face=sans-serif size=2>-Ajit,
Ashwin</FONT> <BR><BR><FONT face=sans-serif size=2>===================</FONT>
<BR><BR><FONT face=sans-serif size=2>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.</FONT> <BR><BR><FONT
face=sans-serif size=2>In the scenario where we have a huge number of
calculated members and no Role configured this operation becomes quite
expensive on multiple invocations.</FONT> <BR><BR><FONT face=sans-serif
size=2>We can fix this by returning the original list of calculated members if
the access is the default access</FONT> <BR><BR><FONT face=sans-serif
size=2> public List<Member> getCalculatedMembers() {</FONT>
<BR><FONT face=sans-serif size=2>
List<Member> list = new ArrayList<Member>();</FONT> <BR><FONT
face=sans-serif size=2>
for (Formula formula : calculatedMembers) {</FONT>
<BR><FONT face=sans-serif size=2>
Member member = formula.getMdxMember();</FONT> <BR><FONT
face=sans-serif size=2>
if
(getRole().canAccess(member)) {</FONT> <BR><FONT face=sans-serif size=2>
list.add(member);</FONT> <BR><FONT face=sans-serif size=2>
}</FONT> <BR><FONT face=sans-serif
size=2>
}</FONT> <BR><FONT
face=sans-serif size=2> return
list;</FONT> <BR><FONT face=sans-serif size=2>
}</FONT> <BR><FONT face=sans-serif size=2>
</FONT><BR><FONT face=sans-serif size=2>
becomes</FONT> <BR><FONT face=sans-serif size=2>
</FONT><BR><FONT face=sans-serif size=2>
public List<Member> getCalculatedMembers() {</FONT> <BR><FONT
face=sans-serif size=2>
if(Access.ALL == getRole().getAccess()){</FONT> <BR><FONT
face=sans-serif size=2>
return calculatedMembers; // indicative -
need to convert [] to list. one option is We can maintain ArrayList and return
[] where ever necessary</FONT> <BR><FONT face=sans-serif size=2>
}</FONT> <BR><FONT
face=sans-serif size=2>
</FONT> <BR><FONT face=sans-serif size=2>
List<Member> list = new
ArrayList<Member>();</FONT> <BR><FONT face=sans-serif size=2>
for
(Formula formula : calculatedMembers) {</FONT> <BR><FONT face=sans-serif
size=2>
Member member = formula.getMdxMember();</FONT> <BR><FONT
face=sans-serif size=2>
if (getRole().canAccess(member)) {</FONT>
<BR><FONT face=sans-serif size=2>
list.add(member);</FONT> <BR><FONT face=sans-serif size=2>
}</FONT> <BR><FONT face=sans-serif size=2>
}</FONT> <BR><FONT
face=sans-serif size=2> return
list;</FONT> <BR><FONT face=sans-serif size=2>
}</FONT> <SPAN class=285595516-18102007><FONT face=Verdana color=#000080
size=2> </FONT></SPAN></DIV>
<DIV><SPAN class=285595516-18102007><FONT face=Verdana color=#000080
size=2></FONT></SPAN> </DIV></BLOCKQUOTE>
<DIV><SPAN class=285595516-18102007><FONT face=Verdana color=#000080 size=2>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.</FONT></SPAN></DIV>
<BLOCKQUOTE
style="PADDING-LEFT: 5px; MARGIN-LEFT: 5px; BORDER-LEFT: #000080 2px solid; MARGIN-RIGHT: 0px">
<DIV><FONT face=sans-serif size=2>
</FONT><BR><FONT face=sans-serif size=2>2) In the RolapMember equals method
:</FONT> <BR><BR><FONT face=sans-serif size=2>
private boolean equals(RolapMember that) {</FONT> <BR><FONT face=sans-serif
size=2> assert that !=
null; </FONT><BR><FONT face=sans-serif size=2>
</FONT><BR><FONT face=sans-serif size=2>
return
this.getUniqueName().equals(that.getUniqueName());</FONT> <BR><FONT
face=sans-serif size=2> }</FONT> <BR><FONT face=sans-serif
size=2> </FONT><BR><FONT face=sans-serif size=2> 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 </FONT><BR><FONT face=sans-serif size=2> when compared
to a null check.</FONT> <BR><FONT face=sans-serif size=2>
</FONT><BR><FONT face=sans-serif size=2> it can be changed
to:</FONT> <BR><FONT face=sans-serif size=2> </FONT><BR><FONT
face=sans-serif size=2> private boolean
equals(RolapMember that) {</FONT> <BR><FONT face=sans-serif size=2>
if(that == null){</FONT>
<BR><FONT face=sans-serif size=2>
return false;</FONT> <BR><FONT
face=sans-serif size=2>
}</FONT> <BR><FONT face=sans-serif size=2>
</FONT><BR><FONT face=sans-serif size=2>
return
this.getUniqueName().equals(that.getUniqueName());</FONT> <BR><FONT
face=sans-serif size=2> }</FONT> <BR><FONT
face=sans-serif><FONT size=2><SPAN class=285595516-18102007><FONT face=Verdana
color=#000080> </FONT></SPAN></FONT></FONT></DIV></BLOCKQUOTE>
<DIV><FONT face=sans-serif><FONT face=Verdana color=#000080 size=2><SPAN
class=285595516-18102007>This is a terrible idea. If you don't like the overhead
of asserts, turn them off: 'java -da -dsa'.</SPAN></FONT></FONT></DIV>
<BLOCKQUOTE
style="PADDING-LEFT: 5px; MARGIN-LEFT: 5px; BORDER-LEFT: #000080 2px solid; MARGIN-RIGHT: 0px">
<DIV><FONT face=sans-serif><FONT size=2><SPAN
class=285595516-18102007> </SPAN>
</FONT></FONT><BR><FONT face=sans-serif size=2>3) In RolapEvaluator :</FONT>
<BR><FONT face=sans-serif size=2> public final Member setContext(Member
member) {</FONT> <BR><FONT face=sans-serif size=2>
final RolapMember m = (RolapMember) member;</FONT> <BR><FONT face=sans-serif
size=2> final int ordinal =
m.getDimension().getOrdinal(root.cube);</FONT> <BR><FONT face=sans-serif
size=2> final Member previous =
currentMembers[ordinal];</FONT> <BR><FONT face=sans-serif size=2>
</FONT><BR><FONT face=sans-serif size=2>
if (previous.isCalculated()) {</FONT> <BR><FONT face=sans-serif
size=2>
removeCalcMember(previous);</FONT> <BR><FONT face=sans-serif size=2>
}</FONT> <BR><FONT face=sans-serif size=2>
currentMembers[ordinal] = m;</FONT> <BR><FONT face=sans-serif
size=2> if (m.isCalculated()) {</FONT> <BR><FONT
face=sans-serif size=2>
addCalcMember(m);</FONT> <BR><FONT face=sans-serif size=2>
}</FONT> <BR><FONT face=sans-serif size=2>
return previous;</FONT> <BR><FONT face=sans-serif size=2>
}</FONT> <BR><FONT face=sans-serif size=2> </FONT><BR><FONT
face=sans-serif size=2> now we can optimize this by adding an
equals to verify that m and previous are not the same.</FONT> <BR><FONT
face=sans-serif size=2> </FONT><BR><FONT face=sans-serif
size=2> public final Member setContext(Member member)
{</FONT> <BR><FONT face=sans-serif size=2>
final RolapMember m = (RolapMember) member;</FONT> <BR><FONT
face=sans-serif size=2> final int
ordinal = m.getDimension().getOrdinal(root.cube);</FONT> <BR><FONT
face=sans-serif size=2> final Member
previous = currentMembers[ordinal];</FONT> <BR><FONT face=sans-serif
size=2> if
(m.equals(previous))</FONT> <BR><FONT face=sans-serif size=2>
return previous;</FONT> <BR><FONT
face=sans-serif size=2> if
(previous.isCalculated()) {</FONT> <BR><FONT face=sans-serif size=2>
removeCalcMember(previous);</FONT> <BR><FONT face=sans-serif size=2>
}</FONT> <BR><FONT face=sans-serif
size=2> currentMembers[ordinal] =
m;</FONT> <BR><FONT face=sans-serif size=2>
if (m.isCalculated()) {</FONT> <BR><FONT face=sans-serif size=2>
addCalcMember(m);</FONT>
<BR><FONT face=sans-serif size=2>
}</FONT> <BR><FONT face=sans-serif size=2>
return previous;</FONT> <BR><FONT face=sans-serif size=2>
}</FONT> <BR><FONT face=sans-serif size=2> </FONT><BR><FONT
face=sans-serif size=2> this reduces some operations in case of
massive number of invocations to this method.</FONT> <SPAN
class=285595516-18102007><FONT face=Verdana color=#000080
size=2> </FONT></SPAN></DIV>
<DIV><SPAN class=285595516-18102007><FONT face=Verdana color=#000080
size=2></FONT></SPAN> </DIV></BLOCKQUOTE>
<DIV><SPAN class=285595516-18102007><FONT face=Verdana color=#000080 size=2>If
the profiler says this ia major save, go ahead and add it.</FONT></SPAN></DIV>
<DIV><SPAN class=285595516-18102007></SPAN> </DIV>
<DIV><SPAN class=285595516-18102007><FONT face=Verdana color=#000080
size=2>Julian</FONT></SPAN></DIV></BODY></HTML>