Commit 5e02ba4c authored by Nils Christian Ehmke's avatar Nils Christian Ehmke

#50 [Jump from calls to traces should not use a recursive algorithm] / #51...

#50 [Jump from calls to traces should not use a recursive algorithm] / #51 [Jump from calls to traces can lead to an error when unmonitored time or method call aggregation is active]
parent b4cfee9a
2.0.0:
30 Aug 2017
Bug (#51)
The jump from calls to traces leads no longer to an error in case that unmonitored time or method call aggregation is active.
30 Aug 2017
Internal Improvement (#50)
The jump from calls to traces no longer uses a recursive algorithm which might lead to a stack overflow in large traces.
10 Jul 2017
Feature (#49)
Dialogs can now be closed by using the escape button.
......
......@@ -16,9 +16,6 @@
package kieker.diagnosis.application.gui.components.treetable;
import kieker.diagnosis.application.service.data.domain.OperationCall;
import kieker.diagnosis.application.service.properties.MethodCallAggregation;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
......@@ -28,6 +25,8 @@ import java.util.ResourceBundle;
import java.util.stream.Collectors;
import javafx.scene.control.TreeItem;
import kieker.diagnosis.application.service.data.domain.OperationCall;
import kieker.diagnosis.application.service.properties.MethodCallAggregation;
/**
* @author Nils Christian Ehmke
......@@ -66,10 +65,19 @@ public final class LazyOperationCallTreeItem extends AbstractLazyOperationCallTr
protected void initializeChildren( ) {
final List<TreeItem<OperationCall>> result = new ArrayList<>( );
final List<OperationCall> childrenOperationCalls = getValue( ).getChildren( );
// Don't initialize, if our list is empty. Otherwise we will run into an infinite loop with
// some methods calling getChildren on the aggregation pseudo-node.
if ( childrenOperationCalls.isEmpty( ) ) {
return;
}
if ( ivShowUnmonitoredTime ) {
double percent = ivPercentCalculation ? getValue( ).getPercent( ) : 100.0;
long duration = getValue( ).getDuration( );
for ( final OperationCall child : getValue( ).getChildren( ) ) {
for ( final OperationCall child : childrenOperationCalls ) {
percent -= child.getPercent( );
duration -= child.getDuration( );
}
......@@ -83,22 +91,23 @@ public final class LazyOperationCallTreeItem extends AbstractLazyOperationCallTr
switch ( ivMethodCallAggregation ) {
case BY_DURATION:
aggregateByDuration( result );
break;
break;
case BY_THRESHOLD:
aggregateByThreshold( result );
break;
break;
case BY_TRACE_DEPTH:
aggregateByDepth( result );
break;
break;
case BY_TRACE_SIZE:
aggregateBySize( result );
break;
break;
case NONE:
default:
for ( final OperationCall child : getValue( ).getChildren( ) ) {
result.add( new LazyOperationCallTreeItem( child, ivShowUnmonitoredTime, ivPercentCalculation, ivMethodCallAggregation, ivThreshold, ivMaxCalls ) );
for ( final OperationCall child : childrenOperationCalls ) {
result.add( new LazyOperationCallTreeItem( child, ivShowUnmonitoredTime, ivPercentCalculation, ivMethodCallAggregation, ivThreshold,
ivMaxCalls ) );
}
break;
break;
}
......@@ -111,7 +120,8 @@ public final class LazyOperationCallTreeItem extends AbstractLazyOperationCallTr
if ( child.getPercent( ) < ivThreshold ) {
underThreshold.add( child );
} else {
aResult.add( new LazyOperationCallTreeItem( child, ivShowUnmonitoredTime, ivPercentCalculation, ivMethodCallAggregation, ivThreshold, ivMaxCalls ) );
aResult.add(
new LazyOperationCallTreeItem( child, ivShowUnmonitoredTime, ivPercentCalculation, ivMethodCallAggregation, ivThreshold, ivMaxCalls ) );
}
}
aggregate( aResult, underThreshold );
......@@ -132,8 +142,9 @@ public final class LazyOperationCallTreeItem extends AbstractLazyOperationCallTr
private void aggregateByProperty( final List<TreeItem<OperationCall>> aResult, final Comparator<OperationCall> aComparator ) {
final Iterator<OperationCall> iterator = getValue( ).getChildren( ).stream( ).sorted( aComparator ).iterator( );
int maxCalls = ivMaxCalls;
while ( ( maxCalls > 0 ) && iterator.hasNext( ) ) {
aResult.add( new LazyOperationCallTreeItem( iterator.next( ), ivShowUnmonitoredTime, ivPercentCalculation, ivMethodCallAggregation, ivThreshold, ivMaxCalls ) );
while ( maxCalls > 0 && iterator.hasNext( ) ) {
aResult.add( new LazyOperationCallTreeItem( iterator.next( ), ivShowUnmonitoredTime, ivPercentCalculation, ivMethodCallAggregation, ivThreshold,
ivMaxCalls ) );
maxCalls--;
}
......@@ -151,7 +162,8 @@ public final class LazyOperationCallTreeItem extends AbstractLazyOperationCallTr
final long duration = aToBeAggregated.stream( ).map( OperationCall::getDuration ).collect( Collectors.summingLong( Long::longValue ) );
final int traceDepth = aToBeAggregated.stream( ).map( OperationCall::getStackDepth ).max( Comparator.naturalOrder( ) ).get( );
final int traceSize = aToBeAggregated.stream( ).map( OperationCall::getStackSize ).collect( Collectors.summingInt( Integer::intValue ) );
final OperationCall call = new OperationCall( BLANK, BLANK, aToBeAggregated.size( ) + " " + METHOD_CALLS_AGGREGATED, getValue( ).getTraceID( ), -1 );
final OperationCall call = new OperationCall( BLANK, BLANK, aToBeAggregated.size( ) + " " + METHOD_CALLS_AGGREGATED, getValue( ).getTraceID( ),
-1 );
call.setPercent( (float) percent );
call.setDuration( duration );
call.setStackDepth( traceDepth );
......
......@@ -16,6 +16,20 @@
package kieker.diagnosis.application.gui.traces;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import javafx.scene.control.TreeItem;
import kieker.diagnosis.application.gui.components.treetable.LazyOperationCallTreeItem;
import kieker.diagnosis.application.gui.main.MainController;
import kieker.diagnosis.application.service.data.DataService;
......@@ -35,19 +49,6 @@ import kieker.diagnosis.architecture.exception.BusinessException;
import kieker.diagnosis.architecture.gui.AbstractController;
import kieker.diagnosis.architecture.service.properties.PropertiesService;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import javafx.scene.control.TreeItem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* The sub-controller responsible for the sub-view presenting the available traces.
*
......@@ -136,17 +137,28 @@ public class TracesController extends AbstractController<TracesView> {
}
private TreeItem<OperationCall> findCall( final TreeItem<OperationCall> aRoot, final OperationCall aCall ) {
if ( aRoot.getValue( ) == aCall ) {
aRoot.setExpanded( true );
return aRoot;
}
final Queue<TreeItem<OperationCall>> searchSpace = new LinkedList<>( );
searchSpace.add( aRoot );
while ( !searchSpace.isEmpty( ) ) {
final TreeItem<OperationCall> currentNode = searchSpace.remove( );
// Is the current node the node we search for?
if ( currentNode.getValue( ) == aCall ) {
// Yes. We have to expand the path to the current node to make it visible.
TreeItem<OperationCall> parent = currentNode;
for ( final TreeItem<OperationCall> child : aRoot.getChildren( ) ) {
final TreeItem<OperationCall> item = findCall( child, aCall );
if ( item != null ) {
aRoot.setExpanded( true );
return item;
while ( parent != null ) {
parent.setExpanded( true );
parent = parent.getParent( );
}
currentNode.setExpanded( true );
return currentNode;
}
// No. We search the node's children nodes.
searchSpace.addAll( currentNode.getChildren( ) );
}
return null;
......@@ -163,7 +175,8 @@ public class TracesController extends AbstractController<TracesView> {
getView( ).getContainer( ).setText( call.getContainer( ) );
getView( ).getComponent( ).setText( call.getComponent( ) );
getView( ).getOperation( ).setText( call.getOperation( ) );
getView( ).getTimestamp( ).setText( ivNameConverterService.toTimestampString( call.getTimestamp( ), sourceTimeUnit ) + " (" + call.getTimestamp( ) + ")" );
getView( ).getTimestamp( )
.setText( ivNameConverterService.toTimestampString( call.getTimestamp( ), sourceTimeUnit ) + " (" + call.getTimestamp( ) + ")" );
getView( ).getDuration( ).setText( ivNameConverterService.toDurationString( call.getDuration( ), sourceTimeUnit, targetTimeUnit ) );
getView( ).getTraceID( ).setText( Long.toString( call.getTraceID( ) ) );
getView( ).getTraceDepth( ).setText( Integer.toString( call.getStackDepth( ) ) );
......@@ -193,20 +206,29 @@ public class TracesController extends AbstractController<TracesView> {
final boolean searchInEntireTrace = ivPropertiesService.loadBooleanApplicationProperty( SearchInEntireTraceProperty.class );
final Predicate<OperationCall> predicate1 = ivFilterService.useFilter( getView( ).getShowAllButton( ), getView( ).getShowJustSuccessful( ),
getView( ).getShowJustFailedButton( ), getView( ).getShowJustFailureContainingButton( ), OperationCall::isFailed, OperationCall::containsFailure );
final Predicate<OperationCall> predicate2 = ivFilterService.useFilter( getView( ).getFilterContainer( ), OperationCall::getContainer, searchInEntireTrace );
final Predicate<OperationCall> predicate3 = ivFilterService.useFilter( getView( ).getFilterComponent( ), OperationCall::getComponent, searchInEntireTrace );
final Predicate<OperationCall> predicate4 = ivFilterService.useFilter( getView( ).getFilterOperation( ), OperationCall::getOperation, searchInEntireTrace );
final Predicate<OperationCall> predicate5 = ivFilterService.useFilter( getView( ).getFilterTraceID( ), call -> Long.toString( call.getTraceID( ) ), searchInEntireTrace );
final Predicate<OperationCall> predicate6 = ivFilterService.useFilter( getView( ).getFilterLowerDate( ), OperationCall::getTimestamp, true, searchInEntireTrace );
final Predicate<OperationCall> predicate7 = ivFilterService.useFilter( getView( ).getFilterUpperDate( ), OperationCall::getTimestamp, false, searchInEntireTrace );
final Predicate<OperationCall> predicate8 = ivFilterService.useFilter( getView( ).getFilterLowerTime( ), OperationCall::getTimestamp, true, searchInEntireTrace );
final Predicate<OperationCall> predicate9 = ivFilterService.useFilter( getView( ).getFilterUpperTime( ), OperationCall::getTimestamp, false, searchInEntireTrace );
final Predicate<OperationCall> predicate10 = ivFilterService.useFilter( getView( ).getFilterException( ), call -> call.isFailed( ) ? call.getFailedCause( ) : "",
getView( ).getShowJustFailedButton( ), getView( ).getShowJustFailureContainingButton( ), OperationCall::isFailed,
OperationCall::containsFailure );
final Predicate<OperationCall> predicate2 = ivFilterService.useFilter( getView( ).getFilterContainer( ), OperationCall::getContainer,
searchInEntireTrace );
final Predicate<OperationCall> predicate3 = ivFilterService.useFilter( getView( ).getFilterComponent( ), OperationCall::getComponent,
searchInEntireTrace );
final Predicate<OperationCall> predicate4 = ivFilterService.useFilter( getView( ).getFilterOperation( ), OperationCall::getOperation,
searchInEntireTrace );
final Predicate<OperationCall> predicate5 = ivFilterService.useFilter( getView( ).getFilterTraceID( ), call -> Long.toString( call.getTraceID( ) ),
searchInEntireTrace );
final Predicate<OperationCall> predicate6 = ivFilterService.useFilter( getView( ).getFilterLowerDate( ), OperationCall::getTimestamp, true,
searchInEntireTrace );
final Predicate<OperationCall> predicate7 = ivFilterService.useFilter( getView( ).getFilterUpperDate( ), OperationCall::getTimestamp, false,
searchInEntireTrace );
final Predicate<OperationCall> predicate8 = ivFilterService.useFilter( getView( ).getFilterLowerTime( ), OperationCall::getTimestamp, true,
searchInEntireTrace );
final Predicate<OperationCall> predicate9 = ivFilterService.useFilter( getView( ).getFilterUpperTime( ), OperationCall::getTimestamp, false,
searchInEntireTrace );
final Predicate<OperationCall> predicate10 = ivFilterService.useFilter( getView( ).getFilterException( ),
call -> call.isFailed( ) ? call.getFailedCause( ) : "", searchInEntireTrace );
ivPredicate = predicate1.and( predicate2 ).and( predicate3 ).and( predicate4 ).and( predicate5 ).and( predicate6 ).and( predicate7 ).and( predicate8 ).and( predicate9 )
.and( predicate10 );
ivPredicate = predicate1.and( predicate2 ).and( predicate3 ).and( predicate4 ).and( predicate5 ).and( predicate6 ).and( predicate7 ).and( predicate8 )
.and( predicate9 ).and( predicate10 );
reloadTreetable( );
}
......@@ -265,8 +287,8 @@ public class TracesController extends AbstractController<TracesView> {
final float threshold = ivPropertiesService.loadApplicationProperty( MethodCallThresholdProperty.class );
final int maxCalls = ivPropertiesService.loadApplicationProperty( MaxNumberOfMethodCallsProperty.class );
traces.stream( ).map( trace -> trace.getRootOperationCall( ) ).filter( ivPredicate )
.forEach( call -> rootChildren.add( new LazyOperationCallTreeItem( call, showUnmonitoredTime, percentCalculation, methodCallAggregation, threshold, maxCalls ) ) );
traces.stream( ).map( trace -> trace.getRootOperationCall( ) ).filter( ivPredicate ).forEach( call -> rootChildren
.add( new LazyOperationCallTreeItem( call, showUnmonitoredTime, percentCalculation, methodCallAggregation, threshold, maxCalls ) ) );
getView( ).getCounter( ).textProperty( ).set( rootChildren.size( ) + " " + getResourceBundle( ).getString( "TracesView.lblCounter.text" ) );
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment