CallbackItem.changeCallback() very expensive due to context tracking
kabirkhan Feb 22, 2010 8:51 AMI'm running a benchmark with 10 callbacks installed and 990 beans matching those callbacks, so I end up with 9,900 calls to SingleCallbackItem.changeCallback().
Relevant part of stacktrace along with number of calls and %cpu time taken
Thread [main] (Suspended)
(19,800 calls, 46.9% cpu) AbstractKernelControllerContext(AbstractControllerContext).getContextTracker() line: 389
(9,900 calls, 47.3% cpu) AbstractKernelControllerContext(AbstractControllerContext).getTarget(ControllerContext) line: 474
(9,900 calls, 47.6% cpu) ClassSingleCallbackItem(OwnerCallbackItem<T,C>).getTarget(ControllerContext, boolean) line: 68
ClassSingleCallbackItem(SingleCallbackItem<T>).changeCallback(ControllerContext, boolean) line: 62
ClassSingleCallbackItem(AbstractCallbackItem<T>).changeCallback(Controller, ControllerContext, boolean) line: 80
ClassSingleCallbackItem(OwnerCallbackItem<T,C>).changeCallback(Controller, ControllerContext, boolean) line: 116
What is really heavy inside ACC.getContextTracker() are:
A - 138,600 callls, 34% cpu
B - 19,800 calls 10.3% cpu
public ContextTracker getContextTracker() { if (tracker == null || tracker == NOOP) { synchronized (this) { // since we got through, we must be the same caller if (tracker == NOOP) return null; // we waited, got through, but it's now changed if (tracker != null && tracker != NOOP) return tracker; tracker = NOOP; // mark that we're initializing ContextTracker ct = null; MetaData metaData = scopeInfo.getMetaData(); //B if (metaData != null) { ct = metaData.getMetaData(ContextTracker.class); //C if (ct == null) { List<ScopeLevel> levels = CommonLevelsUtil.getSubLevels(DEFAULT_MINIMAL); int instanceIndex = levels.indexOf(CommonLevels.INSTANCE); for (int i = instanceIndex; i >= 0 && ct == null; i--) { MetaData md = metaData.getScopeMetaData(levels.get(i)); //A if (md != null) ct = md.getMetaData(ContextTracker.class); } } } tracker = ct; // should we care if it's still null? } } return tracker; }
For A, maybe scopeInfo could keep a reference to the MetaData to avoid having to access the repository every time we call scopeInfo.getMetaData()?
For B I don't really understand exactly why this is being done? It looks like we check for ContextTracker in each metadata level at INSTANCE level and above, up to JVM. Wouldn't that be handled by the call to metaData.getMetaData() in C anyway?