for (CauseCluster cluster : causeClusters) { double exclusiveDurationSum = 0.0; for (InvocationSequenceData invocation : cluster.getCauseInvocations()) { exclusiveDurationSum += DiagnosisHelper.getExclusiveDuration(invocation);
/** * In case there is just one cause invocation then the parent of the problem context is the * cause invocation, otherwise a new instance of CauseCluster will be created with the only * invocation in the list. * * @param causeInvocation * Invocation to get the parent of it if is the only one itself it has no parent. * @return Returns the CauseCluster. */ private CauseCluster getCauseCluster(InvocationSequenceData causeInvocation) { if ((causeInvocation.getParentSequence() != null) && !(causeInvocation.equals(globalContext))) { CauseCluster causeCluster = new CauseCluster(causeInvocation.getParentSequence()); causeCluster.getCauseInvocations().clear(); causeCluster.getCauseInvocations().add(causeInvocation); return causeCluster; } else { return new CauseCluster(causeInvocation); } }
/** * Creates list with clusters. For each InvocationSequenceData in the Time Wasting Operation a * cluster is build initially. * * @return Returns a list of causeCluster. */ private List<CauseCluster> populateCauseCluster() { List<InvocationSequenceData> causeInvocations = timeWastingOperation.getRawInvocationsSequenceElements(); List<CauseCluster> causeClusters = new LinkedList<>(); for (InvocationSequenceData invocation : causeInvocations) { causeClusters.add(new CauseCluster(invocation)); } return causeClusters; }
@Test public void isReturningTheProperValue() { long methodIdent = 108L; InvocationSequenceData root = new InvocationSequenceData(DEF_DATE, 10, 10, methodIdent); InvocationSequenceData firstInvocationSequenceData = new InvocationSequenceData(DEF_DATE, 10, 10, methodIdent); firstInvocationSequenceData.setParentSequence(root); InvocationSequenceData secondInvocationSequenceData = new InvocationSequenceData(DEF_DATE, 10, 10, methodIdent); secondInvocationSequenceData.setParentSequence(root); root.getNestedSequences().add(firstInvocationSequenceData); root.getNestedSequences().add(secondInvocationSequenceData); CauseCluster one = new CauseCluster(firstInvocationSequenceData); CauseCluster two = new CauseCluster(secondInvocationSequenceData); one.setDistanceToNextCluster(1); one.setDepthOfCommonContext(1); two.setDistanceToNextCluster(1); two.setDepthOfCommonContext(1); List<CauseCluster> clustersToMerge = new ArrayList<CauseCluster>(); clustersToMerge.add(one); clustersToMerge.add(two); CauseCluster merged = new CauseCluster(clustersToMerge); assertThat("The returned problemContext must have size 2", merged.getCauseInvocations().size(), is(2)); assertThat("The returned problemContext must be the root one element", merged.getCommonContext(), is(root)); }
/** * Creates a new cluster from the passed list of {@link #CauseCluster}. Sets the * <code>commonContext</code> to the parent of the new cluster. The parent subsumes all * {@link InvocationSequenceData} the cluster currently holds. * * @param clustersToMerge * List with clusters this cluster is merged with. * */ public CauseCluster(List<CauseCluster> clustersToMerge) { if ((clustersToMerge == null) || (clustersToMerge.isEmpty())) { throw new IllegalArgumentException("Clusters are not allowed to be null or empty!"); } int distanceToParent = clustersToMerge.get(0).getDistanceToNextCluster(); InvocationSequenceData parent = clustersToMerge.get(0).getCommonContext(); for (int i = 0; (i < distanceToParent) && (parent.getParentSequence() != null); i++) { parent = parent.getParentSequence(); } commonContext = parent; for (CauseCluster cluster : clustersToMerge) { causeInvocations.addAll(cluster.getCauseInvocations()); } }
/** * Aggregate all the invocations that are considered as rootCause to the object * {@link RootCause}. * * @return Returns the number of candidates that are already checked. */ private int getRootCauses() { int causeCandidatesChecked = 0; double problemContextCommonContextDuration = InvocationSequenceDataHelper.calculateDuration(problemContext.getCommonContext()); // Root Cause candidates are put into one Root Cause as long as the condition is true. while ((sumExclusiveTime < (PROPORTION * problemContextCommonContextDuration)) && (causeCandidatesChecked < causeCandidates.size())) { InvocationSequenceData invocation = causeCandidates.get(causeCandidatesChecked); if (null == rootCause) { rootCause = diagnosisDataAggregator.getAggregatedDiagnosisData(invocation); } else { diagnosisDataAggregator.aggregate(rootCause, invocation); } sumExclusiveTime += DiagnosisHelper.getExclusiveDuration(invocation); causeCandidatesChecked++; } return causeCandidatesChecked; }
invocation = iterator.next(); int minDepth = Math.min(iterator.currentDepth(), MAX_CLUSTER_CONTEXT_DISTANCE); if (nextCluster.getCommonContext() == invocation) { if (null != currentCluster) { int depthDistance = Math.max((currentCauseDepth - minDepth) + 1, 0); currentCluster.setDistanceToNextCluster(depthDistance); currentCluster.setDistanceToNextCluster(MAX_CLUSTER_CONTEXT_DISTANCE);
@Test public void getExclusiveDurationMustReturnZeroIfTheInvocationHasNotTimerDataNeitherSqlData() { InvocationSequenceData invocationData = new InvocationSequenceData(); double exclusiveDuration = DiagnosisHelper.getExclusiveDuration(invocationData); assertThat("Exclusive duration must be 0.", exclusiveDuration, is(0d)); }
/** * Calculates the absolute maximum depth for the common context of the * <code>ProblemContext</code>. * * @return Returns the maximum depth of the recursion. */ private int calculateMaxRecursionDepth() { // The Root Causes can only be in the invocation tree with the Problem Context as root node. InvocationSequenceDataIterator iterator = new InvocationSequenceDataIterator(problemContext.getCommonContext()); // Checks if a Root Cause method is called by another Root Cause method. If so, there is // recursion. Stack<Integer> recursionStack = new Stack<>(); int maxRecursionDepth = 0; int maxIterationsToCheck = 0; while (iterator.hasNext() && (maxIterationsToCheck < MAX_CALLS_TO_CHECK) && (maxRecursionDepth < 2)) { InvocationSequenceData invocation = iterator.next(); if (!recursionStack.isEmpty() && (recursionStack.peek() >= iterator.currentDepth())) { recursionStack.pop(); } if (isCauseInvocation(invocation)) { recursionStack.push(iterator.currentDepth()); if (recursionStack.size() > maxRecursionDepth) { maxRecursionDepth = recursionStack.size(); } maxIterationsToCheck++; } } return maxRecursionDepth; }
for (CauseCluster cluster : causeClusters) { clustersToMerge.add(cluster); if (cluster.getDistanceToNextCluster() > distance) { if (clustersToMerge.size() > 1) { newClusters.add(new CauseCluster(clustersToMerge)); merged = true; } else {
/** * Rule execution. * * @return DIAGNOSIS_TAG_PROBLEM_CAUSE */ @Action(resultTag = RuleConstants.DIAGNOSIS_TAG_PROBLEM_CAUSE) public AggregatedDiagnosisData action() { causeCandidates = problemContext.getCauseInvocations(); int causeCandidatesChecked = getRootCauses(); threeSigmaApproach(causeCandidatesChecked); return rootCause; }
@Test public void wrongGlobalContextResultsInWrongCommonContext() { long methodIdent = 108L; InvocationSequenceData root = new InvocationSequenceData(DEF_DATE, 10, 10, methodIdent); InvocationSequenceData firstInvocationSequenceData = new InvocationSequenceData(DEF_DATE, 10, 10, methodIdent); firstInvocationSequenceData.setParentSequence(root); InvocationSequenceData secondInvocationSequenceData = new InvocationSequenceData(DEF_DATE, 10, 10, methodIdent); secondInvocationSequenceData.setParentSequence(root); root.getNestedSequences().add(firstInvocationSequenceData); root.getNestedSequences().add(secondInvocationSequenceData); CauseCluster one = new CauseCluster(root); CauseCluster two = new CauseCluster(secondInvocationSequenceData); one.setDistanceToNextCluster(1); one.setDepthOfCommonContext(1); two.setDistanceToNextCluster(1); two.setDepthOfCommonContext(1); List<CauseCluster> clustersToMerge = new ArrayList<CauseCluster>(); clustersToMerge.add(one); clustersToMerge.add(two); CauseCluster merged = new CauseCluster(clustersToMerge); assertThat("The returned problemContext must has size 2", merged.getCauseInvocations().size(), is(2)); assertThat("The returned root cause rule must not be null", merged.getCommonContext(), not(nullValue())); }
int i = 0; for (InvocationSequenceData invocation : rootCause.getRawInvocationsSequenceElements()) { durations[i] = DiagnosisHelper.getExclusiveDuration(invocation); i++; double duration = DiagnosisHelper.getExclusiveDuration(invocation); if (duration > lowerThreshold) { diagnosisDataAggregator.aggregate(rootCause, invocation);
@Test public void rootCauseMustBeNullWhenMethodIdentIsEqualAndInvocationHasNotTimerData() { double highDuration = RANDOM.nextDouble() + 1000; List<InvocationSequenceData> nestedSequences = new ArrayList<InvocationSequenceData>(); nestedSequences.add(new InvocationSequenceData(DEF_DATE, PLATFORM_IDENT, SENSOR_TYPE_IDENT, METHOD_IDENT_EQUAL)); nestedSequences.add(new InvocationSequenceData(DEF_DATE, PLATFORM_IDENT, SENSOR_TYPE_IDENT, METHOD_IDENT_EQUAL)); when(problemContext.getCommonContext()).thenReturn(commonContext); when(commonContext.getMethodIdent()).thenReturn(1L); when(commonContext.getDuration()).thenReturn(highDuration); when(commonContext.getNestedSequences()).thenReturn(nestedSequences); AggregatedDiagnosisData rootCause = problemCauseRule.action(); assertThat("The returned root cause rule must be null", rootCause, nullValue()); }
@Test public void getExclusiveDurationMustReturnZeroIfTheExclusiveTimeIsNotAvailable() { InvocationSequenceData invocationData = new InvocationSequenceData(); TimerData timerData = new TimerData(new Timestamp(System.currentTimeMillis()), 10L, 20L, 30L); invocationData.setTimerData(timerData); double exclusiveDuration = DiagnosisHelper.getExclusiveDuration(invocationData); assertThat("Exclusive duration must be 0.", exclusiveDuration, is(timerData.getExclusiveDuration())); }
@Test public void problemContextMustBeTheSameInvocationIfItIsTheOnlyOneAndIsTheInvoker() { long methodIdent = 108L; Timestamp defDate = new Timestamp(new Date().getTime()); long platformIdent = RANDOM.nextLong(); long sensorTypeIdent = RANDOM.nextLong(); InvocationSequenceData parentSequence = new InvocationSequenceData(defDate, platformIdent, sensorTypeIdent, methodIdent); InvocationSequenceData childSequence = new InvocationSequenceData(defDate, platformIdent, sensorTypeIdent, methodIdent); List<InvocationSequenceData> rawInvocations = new ArrayList<InvocationSequenceData>(); parentSequence.getNestedSequences().add(childSequence); rawInvocations.add(parentSequence); when(timeWastingOperation.getRawInvocationsSequenceElements()).thenReturn(rawInvocations); CauseCluster problemContext = problemContextRule.action(); assertThat("The returned problemContext must be the invoker", problemContext.getCommonContext(), is(parentSequence)); }
@Test public void getExclusiveDurationMustReturnTheExclusiveDurationOfTheTimerDataWhenItIsARegularTimerData() { InvocationSequenceData invocationData = new InvocationSequenceData(); TimerData timerData = new TimerData(new Timestamp(System.currentTimeMillis()), 10L, 20L, 30L); timerData.calculateExclusiveMin(300d); timerData.setExclusiveDuration(300d); invocationData.setTimerData(timerData); double exclusiveDuration = DiagnosisHelper.getExclusiveDuration(invocationData); assertThat("Exclusive duration must be 300.", exclusiveDuration, is(timerData.getExclusiveDuration())); }
@Test public void problemContextMustBeGlobalContext() { Timestamp currentTime = new Timestamp(System.currentTimeMillis()); List<InvocationSequenceData> rawInvocations = new ArrayList<InvocationSequenceData>(); TimerData timerData = new TimerData(currentTime, 10L, 20L, 30L); timerData.calculateExclusiveMin(RANDOM.nextDouble()); timerData.setExclusiveDuration(RANDOM.nextDouble()); when(globalContext.getTimerData()).thenReturn(timerData); rawInvocations.add(globalContext); when(timeWastingOperation.getRawInvocationsSequenceElements()).thenReturn(rawInvocations); CauseCluster problemContext = problemContextRule.action(); assertThat("The returned problemContext must be the most significant cluster context", problemContext.getCommonContext(), is(globalContext)); }
@Test public void getExclusiveDurationMustReturnTheExclusiveDurationOfTheTimerDataWhenItIsASqlData() { InvocationSequenceData invocationData = new InvocationSequenceData(); SqlStatementData timerData = new SqlStatementData(new Timestamp(System.currentTimeMillis()), 10L, 20L, 30L); timerData.calculateExclusiveMin(300d); timerData.setExclusiveDuration(300d); timerData.setCount(1); invocationData.setSqlStatementData(timerData); double exclusiveDuration = DiagnosisHelper.getExclusiveDuration(invocationData); assertThat("Exclusive duration must be 300.", exclusiveDuration, is(timerData.getExclusiveDuration())); } }
@Test public void problemContextMustBeTheProperInvocationIfThereOneAndIsTheInvokerWithAParentSequence() { long methodIdent = 108L; Timestamp defDate = new Timestamp(new Date().getTime()); long platformIdent = RANDOM.nextLong(); long sensorTypeIdent = RANDOM.nextLong(); InvocationSequenceData parentSequence = new InvocationSequenceData(defDate, platformIdent, sensorTypeIdent, methodIdent); InvocationSequenceData childSequence = new InvocationSequenceData(defDate, platformIdent, sensorTypeIdent, methodIdent); List<InvocationSequenceData> rawInvocations = new ArrayList<InvocationSequenceData>(); childSequence.setParentSequence(parentSequence); rawInvocations.add(childSequence); when(timeWastingOperation.getRawInvocationsSequenceElements()).thenReturn(rawInvocations); CauseCluster problemContext = problemContextRule.action(); assertThat("The returned problemContext must be the invoker", problemContext.getCommonContext(), is(childSequence.getParentSequence())); }