<!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>&nbsp;</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>&nbsp;</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>&nbsp;public List&lt;Member&gt; getCalculatedMembers() {</FONT> 
  <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  List&lt;Member&gt; list = new ArrayList&lt;Member&gt;();</FONT> <BR><FONT 
  face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp;for (Formula formula : calculatedMembers) {</FONT> 
  <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp; &nbsp;Member member = formula.getMdxMember();</FONT> <BR><FONT 
  face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if 
  (getRole().canAccess(member)) {</FONT> <BR><FONT face=sans-serif size=2>&nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp;list.add(member);</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</FONT> <BR><FONT face=sans-serif 
  size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</FONT> <BR><FONT 
  face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return 
  list;</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; 
  }</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; 
  </FONT><BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; 
  becomes</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; 
  </FONT><BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp;public List&lt;Member&gt; getCalculatedMembers() {</FONT> <BR><FONT 
  face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp;if(Access.ALL == getRole().getAccess()){</FONT> <BR><FONT 
  face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;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>&nbsp; &nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</FONT> <BR><FONT 
  face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp;</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;List&lt;Member&gt; list = new 
  ArrayList&lt;Member&gt;();</FONT> <BR><FONT face=sans-serif size=2>&nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for 
  (Formula formula : calculatedMembers) {</FONT> <BR><FONT face=sans-serif 
  size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp; &nbsp; &nbsp;Member member = formula.getMdxMember();</FONT> <BR><FONT 
  face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (getRole().canAccess(member)) {</FONT> 
  <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp;list.add(member);</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp;}</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</FONT> <BR><FONT 
  face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return 
  list;</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; 
  }</FONT>&nbsp;<SPAN class=285595516-18102007><FONT face=Verdana color=#000080 
  size=2>&nbsp;</FONT></SPAN></DIV>
  <DIV><SPAN class=285595516-18102007><FONT face=Verdana color=#000080 
  size=2></FONT></SPAN>&nbsp;</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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
  </FONT><BR><FONT face=sans-serif size=2>2) In the RolapMember equals method 
  :</FONT> <BR><BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; 
  private boolean equals(RolapMember that) {</FONT> <BR><FONT face=sans-serif 
  size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; assert that != 
  null; </FONT><BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; 
  </FONT><BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp; &nbsp; &nbsp; return 
  this.getUniqueName().equals(that.getUniqueName());</FONT> <BR><FONT 
  face=sans-serif size=2>&nbsp; &nbsp; }</FONT> <BR><FONT face=sans-serif 
  size=2>&nbsp; &nbsp; </FONT><BR><FONT face=sans-serif size=2>&nbsp; &nbsp; 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>&nbsp; &nbsp; when compared 
  to a null check.</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; 
  </FONT><BR><FONT face=sans-serif size=2>&nbsp; &nbsp; it can be changed 
  to:</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; </FONT><BR><FONT 
  face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; private boolean 
  equals(RolapMember that) {</FONT> <BR><FONT face=sans-serif size=2>&nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(that == null){</FONT> 
  <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return false;</FONT> <BR><FONT 
  face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  }</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; 
  </FONT><BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp; &nbsp; &nbsp; return 
  this.getUniqueName().equals(that.getUniqueName());</FONT> <BR><FONT 
  face=sans-serif size=2>&nbsp; &nbsp; }</FONT>&nbsp;<BR><FONT 
  face=sans-serif><FONT size=2><SPAN class=285595516-18102007><FONT face=Verdana 
  color=#000080>&nbsp;</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>&nbsp;</SPAN>&nbsp;&nbsp;&nbsp; 
  </FONT></FONT><BR><FONT face=sans-serif size=2>3) In RolapEvaluator :</FONT> 
  <BR><FONT face=sans-serif size=2>&nbsp;public final Member setContext(Member 
  member) {</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; 
  final RolapMember m = (RolapMember) member;</FONT> <BR><FONT face=sans-serif 
  size=2>&nbsp; &nbsp; &nbsp; &nbsp; final int ordinal = 
  m.getDimension().getOrdinal(root.cube);</FONT> <BR><FONT face=sans-serif 
  size=2>&nbsp; &nbsp; &nbsp; &nbsp; final Member previous = 
  currentMembers[ordinal];</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; 
  &nbsp; &nbsp; </FONT><BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; 
  &nbsp; if (previous.isCalculated()) {</FONT> <BR><FONT face=sans-serif 
  size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  removeCalcMember(previous);</FONT> <BR><FONT face=sans-serif size=2>&nbsp; 
  &nbsp; &nbsp; &nbsp; }</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; 
  &nbsp; &nbsp; currentMembers[ordinal] = m;</FONT> <BR><FONT face=sans-serif 
  size=2>&nbsp; &nbsp; &nbsp; &nbsp; if (m.isCalculated()) {</FONT> <BR><FONT 
  face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  addCalcMember(m);</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; 
  &nbsp; }</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; 
  return previous;</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; 
  }</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; </FONT><BR><FONT 
  face=sans-serif size=2>&nbsp; &nbsp; 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>&nbsp; &nbsp; </FONT><BR><FONT face=sans-serif 
  size=2>&nbsp; &nbsp; &nbsp;public final Member setContext(Member member) 
  {</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp; final RolapMember m = (RolapMember) member;</FONT> <BR><FONT 
  face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; final int 
  ordinal = m.getDimension().getOrdinal(root.cube);</FONT> <BR><FONT 
  face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; final Member 
  previous = currentMembers[ordinal];</FONT> <BR><FONT face=sans-serif 
  size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if 
  (m.equals(previous))</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return previous;</FONT> <BR><FONT 
  face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if 
  (previous.isCalculated()) {</FONT> <BR><FONT face=sans-serif size=2>&nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  removeCalcMember(previous);</FONT> <BR><FONT face=sans-serif size=2>&nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</FONT> <BR><FONT face=sans-serif 
  size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currentMembers[ordinal] = 
  m;</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp; if (m.isCalculated()) {</FONT> <BR><FONT face=sans-serif size=2>&nbsp; 
  &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; addCalcMember(m);</FONT> 
  <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  }</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
  &nbsp; return previous;</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; 
  }</FONT> <BR><FONT face=sans-serif size=2>&nbsp; &nbsp; </FONT><BR><FONT 
  face=sans-serif size=2>&nbsp; &nbsp; this reduces some operations in case of 
  massive number of invocations to this method.</FONT>&nbsp;<SPAN 
  class=285595516-18102007><FONT face=Verdana color=#000080 
  size=2>&nbsp;</FONT></SPAN></DIV>
  <DIV><SPAN class=285595516-18102007><FONT face=Verdana color=#000080 
  size=2></FONT></SPAN>&nbsp;</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>&nbsp;</DIV>
<DIV><SPAN class=285595516-18102007><FONT face=Verdana color=#000080 
size=2>Julian</FONT></SPAN></DIV></BODY></HTML>