Skip to content

Commit

Permalink
Flat and Tree aggregators reworked, support multiple groupings
Browse files Browse the repository at this point in the history
This is the groundwork for switching aggregations between within-thread
aggregation, over-thread aggregation, by method name or method + line Nr
or by BCI.

- Groupings introduced for determining the key for an item which is used
for grouping LeanNodes when aggregating
- Got rid of the K typing for the key, it wasn't going to be used, and
it makes things easier to fix it as a String, especially for the new
Groupings which had to group into a String anyway
-
  • Loading branch information
PhRX committed Feb 2, 2017
1 parent 8ae98ca commit 78f0617
Show file tree
Hide file tree
Showing 37 changed files with 577 additions and 455 deletions.
@@ -1,11 +1,16 @@
package com.insightfullogic.honest_profiler.core.aggregation; package com.insightfullogic.honest_profiler.core.aggregation;


import static com.insightfullogic.honest_profiler.core.aggregation.grouping.FrameGrouping.BY_FQMN;
import static com.insightfullogic.honest_profiler.core.aggregation.grouping.ThreadGrouping.ALL_THREADS_TOGETHER;
import static com.insightfullogic.honest_profiler.core.aggregation.grouping.ThreadGrouping.THREADS_BY_NAME;

import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;


import com.insightfullogic.honest_profiler.core.aggregation.aggregator.Aggregator; import com.insightfullogic.honest_profiler.core.aggregation.aggregator.FlatProfileAggregator;
import com.insightfullogic.honest_profiler.core.aggregation.aggregator.FlatByFqmnAggregator; import com.insightfullogic.honest_profiler.core.aggregation.aggregator.ProfileAggregator;
import com.insightfullogic.honest_profiler.core.aggregation.aggregator.TreeByFqmnAggregator; import com.insightfullogic.honest_profiler.core.aggregation.aggregator.TreeProfileAggregator;
import com.insightfullogic.honest_profiler.core.aggregation.grouping.CombinedGrouping;
import com.insightfullogic.honest_profiler.core.aggregation.result.Aggregation; import com.insightfullogic.honest_profiler.core.aggregation.result.Aggregation;
import com.insightfullogic.honest_profiler.core.aggregation.result.straight.Entry; import com.insightfullogic.honest_profiler.core.aggregation.result.straight.Entry;
import com.insightfullogic.honest_profiler.core.aggregation.result.straight.Flat; import com.insightfullogic.honest_profiler.core.aggregation.result.straight.Flat;
Expand All @@ -20,15 +25,15 @@
*/ */
public class AggregationProfile public class AggregationProfile
{ {
private static final Aggregator<AggregationProfile, String, Entry<String>> flatAggregator = new FlatByFqmnAggregator(); private static final ProfileAggregator<Entry> flatAggregator = new FlatProfileAggregator();
private static final Aggregator<AggregationProfile, String, Node<String>> treeAggregator = new TreeByFqmnAggregator(); private static final ProfileAggregator<Node> treeAggregator = new TreeProfileAggregator();


private final LeanProfile source; private final LeanProfile source;
private final Map<String, FqmnLink> fqmnLinks; private final Map<String, FqmnLink> fqmnLinks;


private final NumericInfo global; private final NumericInfo global;


private Map<Aggregator<?, ?, ?>, Aggregation<?, ?>> cachedAggregations; private Map<ProfileAggregator<?>, Aggregation<?>> cachedAggregations;


public AggregationProfile(LeanProfile source) public AggregationProfile(LeanProfile source)
{ {
Expand Down Expand Up @@ -67,18 +72,20 @@ public Map<String, FqmnLink> getFqmnLinks()
return fqmnLinks; return fqmnLinks;
} }


@SuppressWarnings("unchecked") public Flat getFlat()
public Flat<String> getFlat()
{ {
cachedAggregations.putIfAbsent(flatAggregator, flatAggregator.aggregate(this, this)); cachedAggregations.putIfAbsent(
return (Flat<String>)cachedAggregations.get(flatAggregator); flatAggregator,
flatAggregator.aggregate(this, new CombinedGrouping(ALL_THREADS_TOGETHER, BY_FQMN)));
return (Flat)cachedAggregations.get(flatAggregator);
} }


@SuppressWarnings("unchecked") public Tree getTree()
public Tree<String> getTree()
{ {
cachedAggregations.putIfAbsent(treeAggregator, treeAggregator.aggregate(this, this)); cachedAggregations.putIfAbsent(
return (Tree<String>)cachedAggregations.get(treeAggregator); treeAggregator,
treeAggregator.aggregate(this, new CombinedGrouping(THREADS_BY_NAME, BY_FQMN)));
return (Tree)cachedAggregations.get(treeAggregator);
} }


private void aggregateGlobal() private void aggregateGlobal()
Expand Down
Expand Up @@ -20,7 +20,7 @@ public final class ReferenceUtil
* @param tree the {@link Tree} whose references are to be changed * @param tree the {@link Tree} whose references are to be changed
* @param mode the strategy for setting the references * @param mode the strategy for setting the references
*/ */
public static <K> void switchReference(Tree<K> tree, ReferenceMode mode) public static <K> void switchReference(Tree tree, ReferenceMode mode)
{ {
switch (mode) switch (mode)
{ {
Expand Down Expand Up @@ -51,13 +51,13 @@ public static <K> void switchReference(Tree<K> tree, ReferenceMode mode)
* @param treeDiff the {@link TreeDiff} whose references are to be changed * @param treeDiff the {@link TreeDiff} whose references are to be changed
* @param mode the strategy for setting the references * @param mode the strategy for setting the references
*/ */
public static <K> void switchReference(TreeDiff<K> treeDiff, ReferenceMode mode) public static <K> void switchReference(TreeDiff treeDiff, ReferenceMode mode)
{ {
switchReference(treeDiff.getBaseAggregation(), mode); switchReference(treeDiff.getBaseAggregation(), mode);
switchReference(treeDiff.getNewAggregation(), mode); switchReference(treeDiff.getNewAggregation(), mode);
} }


private static <K> void setReferenceToParent(Node<K> parent, Node<K> child) private static <K> void setReferenceToParent(Node parent, Node child)
{ {


if (parent == null) if (parent == null)
Expand Down
Expand Up @@ -20,32 +20,32 @@
/** /**
* Aggregator which takes an {@link Entry} and aggregates the ancestors into a {@link Tree}. * Aggregator which takes an {@link Entry} and aggregates the ancestors into a {@link Tree}.
*/ */
public class AncestorTreeAggregator implements Aggregator<Entry<String>, String, Node<String>> public class AncestorTreeAggregator implements SubAggregator<Entry, Node>
{ {
// Aggregator Implementation // Aggregator Implementation


/** /**
* @see Aggregator#aggregate(Object, LeanNode) * @see SubAggregator#aggregate(Object, LeanNode)
*/ */
@Override @Override
public Tree<String> aggregate(AggregationProfile source, Entry<String> input) public Tree aggregate(AggregationProfile source, Entry input)
{ {
Node<String> root = new Node<>(input, new ArrayList<>()); Node root = new Node(input);
List<Node<String>> list = new ArrayList<>(); List<Node> list = new ArrayList<>();
list.add(root); list.add(root);


Tree<String> result = new Tree<>(source, list); Tree result = new Tree(source, list);
Set<String> processed = new HashSet<>(); Set<String> processed = new HashSet<>();


addAncestors(source, root, result, processed); addAncestors(source, root, result, processed);
return result; return result;
} }


private void addAncestors(AggregationProfile source, Node<String> parent, Tree<String> tree, private void addAncestors(AggregationProfile source, Node parent, Tree tree,
Set<String> processed) Set<String> processed)
{ {
FqmnLink fqmnLink = source.getFqmnLinks().get(parent.getKey()); FqmnLink fqmnLink = source.getFqmnLinks().get(parent.getKey());
Map<String, Node<String>> callers = fqmnLink.getParents().values().stream() Map<String, Node> callers = fqmnLink.getParents().values().stream()
.flatMap(set -> set.stream()).filter( .flatMap(set -> set.stream()).filter(
node -> node != null node -> node != null
&& !node.isThreadNode() && !node.isThreadNode()
Expand All @@ -57,14 +57,14 @@ private void addAncestors(AggregationProfile source, Node<String> parent, Tree<S
parent.addAll(callers); parent.addAll(callers);
} }


private Collector<LeanNode, Node<String>, Node<String>> getCollector(AggregationProfile source, private Collector<LeanNode, Node, Node> getCollector(AggregationProfile source, Tree tree,
Tree<String> tree, Set<String> processed) Set<String> processed)
{ {
return of( return of(
// Supplier // Supplier
() -> () ->
{ {
Node<String> node = new Node<>(tree); Node node = new Node(tree);
node.setReference(source.getGlobalData()); node.setReference(source.getGlobalData());
return node; return node;
}, },
Expand Down
Expand Up @@ -16,18 +16,18 @@
* Aggregator which takes a {@link Node}, and aggregates the values of the {@link Node} and its descendants into a * Aggregator which takes a {@link Node}, and aggregates the values of the {@link Node} and its descendants into a
* {@link Flat}. * {@link Flat}.
*/ */
public class DescendantFlatAggregator implements Aggregator<Node<String>, String, Entry<String>> public class DescendantFlatAggregator implements SubAggregator<Node, Entry>
{ {
/** /**
* This method aggregates a {@link Node} and all its all descendants. * This method aggregates a {@link Node} and all its all descendants.
* *
* @see Aggregator#aggregate(Object, LeanNode) * @see SubAggregator#aggregate(Object, LeanNode)
*/ */
@Override @Override
public Flat<String> aggregate(AggregationProfile source, Node<String> parent) public Flat aggregate(AggregationProfile source, Node parent)
{ {
List<Entry<String>> result = new ArrayList<>(); List<Entry> result = new ArrayList<>();
Flat<String> aggregation = new Flat<>(source, result); Flat aggregation = new Flat(source, result);


result.addAll( result.addAll(
parent.flatten().collect( parent.flatten().collect(
Expand All @@ -37,7 +37,7 @@ public Flat<String> aggregate(AggregationProfile source, Node<String> parent)
// Supplier // Supplier
() -> () ->
{ {
Entry<String> entry = new Entry<>(aggregation); Entry entry = new Entry(aggregation);
entry.setReference(source.getGlobalData()); entry.setReference(source.getGlobalData());
return entry; return entry;
}, },
Expand Down
Expand Up @@ -20,32 +20,32 @@
/** /**
* Aggregator which takes an {@link Entry} and aggregates the descendants into a {@link Tree}. * Aggregator which takes an {@link Entry} and aggregates the descendants into a {@link Tree}.
*/ */
public class DescendantTreeAggregator implements Aggregator<Entry<String>, String, Node<String>> public class DescendantTreeAggregator implements SubAggregator<Entry, Node>
{ {
// Aggregator Implementation // Aggregator Implementation


/** /**
* @see Aggregator#aggregate(Object, LeanNode) * @see SubAggregator#aggregate(Object, LeanNode)
*/ */
@Override @Override
public Tree<String> aggregate(AggregationProfile source, Entry<String> input) public Tree aggregate(AggregationProfile source, Entry input)
{ {
Node<String> root = new Node<>(input, new ArrayList<>()); Node root = new Node(input);
List<Node<String>> list = new ArrayList<>(); List<Node> list = new ArrayList<>();
list.add(root); list.add(root);


Tree<String> result = new Tree<>(source, list); Tree result = new Tree(source, list);
Set<String> processed = new HashSet<>(); Set<String> processed = new HashSet<>();


addDescendants(source, root, result, processed); addDescendants(source, root, result, processed);
return result; return result;
} }


private void addDescendants(AggregationProfile source, Node<String> parent, Tree<String> tree, private void addDescendants(AggregationProfile source, Node parent, Tree tree,
Set<String> processed) Set<String> processed)
{ {
FqmnLink fqmnLink = source.getFqmnLinks().get(parent.getKey()); FqmnLink fqmnLink = source.getFqmnLinks().get(parent.getKey());
Map<String, Node<String>> callers = fqmnLink.getChildren().values().stream() Map<String, Node> callers = fqmnLink.getChildren().values().stream()
.flatMap(set -> set.stream()).filter( .flatMap(set -> set.stream()).filter(
node -> node != null node -> node != null
&& !node.isThreadNode() && !node.isThreadNode()
Expand All @@ -57,14 +57,14 @@ private void addDescendants(AggregationProfile source, Node<String> parent, Tree
parent.addAll(callers); parent.addAll(callers);
} }


private Collector<LeanNode, Node<String>, Node<String>> getCollector(AggregationProfile source, private Collector<LeanNode, Node, Node> getCollector(AggregationProfile source, Tree tree,
Tree<String> tree, Set<String> processed) Set<String> processed)
{ {
return of( return of(
// Supplier // Supplier
() -> () ->
{ {
Node<String> node = new Node<>(tree); Node node = new Node(tree);
node.setReference(source.getGlobalData()); node.setReference(source.getGlobalData());
return node; return node;
}, },
Expand Down

This file was deleted.

@@ -0,0 +1,69 @@
package com.insightfullogic.honest_profiler.core.aggregation.aggregator;

import static java.util.stream.Collector.of;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;

import java.util.Map;

import com.insightfullogic.honest_profiler.core.aggregation.AggregationProfile;
import com.insightfullogic.honest_profiler.core.aggregation.grouping.CombinedGrouping;
import com.insightfullogic.honest_profiler.core.aggregation.result.straight.Entry;
import com.insightfullogic.honest_profiler.core.aggregation.result.straight.Flat;
import com.insightfullogic.honest_profiler.core.profiles.lean.LeanNode;
import com.insightfullogic.honest_profiler.core.profiles.lean.LeanProfile;
import com.insightfullogic.honest_profiler.core.profiles.lean.LeanThreadNode;

/**
* Aggregator which takes an {@link AggregationProfile}, and uses the data to aggregate the values into a {@link Flat}
* aggregation.
*
* NOTE : The {@link LeanThreadNode}s are also aggregated, so the resulting {@link Flat} will contain {@link Entry}s
* aggregating the thread-level data as well !
*/
public class FlatProfileAggregator implements ProfileAggregator<Entry>
{
/**
* Aggregates an {@link AggregationProfile} into a {@link Flat}. The {@link CombinedGrouping} specifies which
* {@link LeanNode}s are aggregated together.
*
* @see ProfileAggregator#aggregate(AggregationProfile, CombinedGrouping)
*/
@Override
public Flat aggregate(AggregationProfile input, CombinedGrouping grouping)
{
// Prepare result.
Flat result = new Flat(input);

LeanProfile source = input.getSource();

// Flatten all LeanNodes into a Stream, then collect it into a Map where the key is calculated by the groupings,
// and the value is the aggregation of the LeanNodes corresponding to the key.
Map<String, Entry> entryMap = source.getThreads().values().stream()
.flatMap(LeanNode::flatten).collect(
groupingBy(
// Group LeanNodes by calculated key
node -> grouping.apply(input, node),
// Downstream collector, collects LeanNodes in a single group
of(
// Supplier, creates an empty Entry
() -> new Entry(result),
// Accumulator, aggregates a LeanNode into the Entry accumulator
(x, y) -> x.add(y),
// Combiner, combines two Entries with the same key
(x, y) -> x.combine(y))));

// Add the aggregated Entries to the result list, after setting their key and reference. The key is the
// Map.Entry key, the Entry is the Map.Entry value.
result.getData().addAll(entryMap.entrySet().stream().map(mapEntry ->
{
Entry entry = mapEntry.getValue();
entry.setKey(mapEntry.getKey());
// By default, the reference for Entries is the global, over-thread aggregation.
entry.setReference(input.getGlobalData());
return entry;
}).collect(toList()));

return result;
}
}
@@ -0,0 +1,24 @@
package com.insightfullogic.honest_profiler.core.aggregation.aggregator;

import com.insightfullogic.honest_profiler.core.aggregation.AggregationProfile;
import com.insightfullogic.honest_profiler.core.aggregation.grouping.CombinedGrouping;
import com.insightfullogic.honest_profiler.core.aggregation.result.Aggregation;
import com.insightfullogic.honest_profiler.core.aggregation.result.Keyed;

/**
* Generic interface for aggregation functions which operate on the entire {@link AggregationProfile}. An Aggregator
* aggregates an input {@link AggregationProfile} into an {@link Aggregation} containing results of type <T>, which are
* keyed by a String.
*
* @param <T> the type of the content items in the resulting {@link Aggregation}
*/
public interface ProfileAggregator<T extends Keyed<String>>
{
/**
* Aggregate the provided {@link AggregationProfile}.
*
* @param input the {@link AggregationProfile} to be aggregated
* @return the resulting {@link Aggregation}
*/
Aggregation<T> aggregate(AggregationProfile input, CombinedGrouping grouping);
}

0 comments on commit 78f0617

Please sign in to comment.