{"id":15,"date":"2011-11-15T14:22:00","date_gmt":"2011-11-15T03:22:00","guid":{"rendered":"http:\/\/www.lazydungeon.com\/blog\/proxying-object-for-fun-and-profit\/"},"modified":"2011-11-15T14:22:00","modified_gmt":"2011-11-15T03:22:00","slug":"proxying-object-for-fun-and-profit","status":"publish","type":"post","link":"https:\/\/www.lazydungeon.com\/blog\/proxying-object-for-fun-and-profit\/","title":{"rendered":"Proxying object for fun and profit"},"content":{"rendered":"<p>Got a little performance issue, fired up the\u00a0profiler\u00a0and tracked 75% of CPU cycle on this block of code.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npublic int indexOf(ReportColumn col, UseType use) { \n  ReportColumn copyColumn = col.copy(); \n  copyColumn.setUse(use); \n  return columnList.indexOf(copyColumn);\n}\n<\/pre>\n<p>The majority of the hold up is in the copy() function which produce a deep clone of the ReportColumn object via reflection. Not only is this very slow, but it also increase the memory needed because of the deep clone process.<\/p>\n<p>My immediate reaction was to use remember the &#8220;use&#8221; value of the column, make a change to the col object, find the index and change it back. But then I started to worry about the original intent of the function, since I didn&#8217;t write it, I just assume whom ever did write it this way must use deep cloning for a reason. Maybe they expect col object to be read by another thread while the search is happening. Hence I just abandoned plan A.<\/p>\n<p>Plan B involved proxying, and went a bit like this.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npublic int slowIndexOf(ReportColumn col, final UseType use) { \n  ProxyFactory pf = new ProxyFactory(); \n  pf.setTarget(col); \n  pf.addAdvice(new MethodInterceptor() {  \n    @Override  public Object invoke(MethodInvocation mi) throws Throwable {   \n      if (mi.getMethod().getName().startsWith(&quot;getUse&quot;)) {\n        return use;   \n      }  \n      else {\n        return mi.proceed();\n      }\n     }\n   }); \n   ReportColumn copyColumn = (ReportColumn) pf.getProxy(); \n   return columnList.indexOf(copyColumn);\n}\n<\/pre>\n<p>By using the spring&#8217;s inbuilt proxying libraries, I constructed a method interceptor to intercept call to getUse and replace the value with the use we want to search for.<\/p>\n<p>However, as the name indicates, it was very slow, slower than I thought it would be, in fact pf.getProxy() was 4 times slower than the deep clone method.<\/p>\n<p>Back to the drawing board, I ended up tracing the code to see if I can find any potential code that might be reading the col object while it is been used, hoping that I can try a locking to prevent that from happening. As it turns out, there is no concurrent access. So I ended up with this.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npublic int indexOf(ReportColumn col, final UseType use) {\n  UseType oldUse = col.getUse(); \n  col.setUse(use); \n  int index = columnList.indexOf(col); \n  col.setUse(oldUse); \n  return index;\n}\n<\/pre>\n<p>Lesson here, first instinct\/simplest solution is often the best, also question your initial assumptions.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Got a little performance issue, fired up the\u00a0profiler\u00a0and tracked 75% of CPU cycle on this block of code. public int indexOf(ReportColumn col, UseType use) { ReportColumn copyColumn = col.copy(); copyColumn.setUse(use); return columnList.indexOf(copyColumn); } The majority of the hold up is in the copy() function which produce a deep clone of the ReportColumn object via reflection. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[26,21,27],"class_list":["post-15","post","type-post","status-publish","format-standard","hentry","category-debug","tag-debug","tag-java-2","tag-performance"],"_links":{"self":[{"href":"https:\/\/www.lazydungeon.com\/blog\/wp-json\/wp\/v2\/posts\/15","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lazydungeon.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lazydungeon.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lazydungeon.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lazydungeon.com\/blog\/wp-json\/wp\/v2\/comments?post=15"}],"version-history":[{"count":0,"href":"https:\/\/www.lazydungeon.com\/blog\/wp-json\/wp\/v2\/posts\/15\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.lazydungeon.com\/blog\/wp-json\/wp\/v2\/media?parent=15"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lazydungeon.com\/blog\/wp-json\/wp\/v2\/categories?post=15"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lazydungeon.com\/blog\/wp-json\/wp\/v2\/tags?post=15"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}