1 /*******************************************************************************
2 * Copyright (c) 2016 Ericsson
4 * All rights reserved. This program and the accompanying materials are made
5 * available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *******************************************************************************/
10 package org
.eclipse
.tracecompass
.internal
.analysis
.timing
.ui
.flamegraph
;
12 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
14 import java
.util
.ArrayDeque
;
15 import java
.util
.ArrayList
;
16 import java
.util
.Collection
;
17 import java
.util
.Comparator
;
18 import java
.util
.Deque
;
19 import java
.util
.List
;
21 import org
.eclipse
.jdt
.annotation
.NonNull
;
22 import org
.eclipse
.jface
.viewers
.Viewer
;
23 import org
.eclipse
.tracecompass
.internal
.analysis
.timing
.core
.callgraph
.AggregatedCalledFunction
;
24 import org
.eclipse
.tracecompass
.internal
.analysis
.timing
.core
.callgraph
.ThreadNode
;
25 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphContentProvider
;
26 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
27 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.TimeGraphEntry
;
30 * Content provider for the flame graph view
32 * @author Sonia Farrah
35 public class FlameGraphContentProvider
implements ITimeGraphContentProvider
{
37 private final List
<FlamegraphDepthEntry
> fFlameGraphEntries
= new ArrayList
<>();
38 private SortOption fSortOption
= SortOption
.BY_NAME
;
39 private @NonNull Comparator
<FlamegraphDepthEntry
> fThreadComparator
= new ThreadNameComparator();
42 * Parse the aggregated tree created by the callGraphAnalysis and creates
43 * the event list (functions) for each entry (depth)
46 * The first node of the aggregation tree
47 * @param childrenEntries
48 * The list of entries for one thread
49 * @param timestampStack
50 * A stack used to save the functions timeStamps
52 private void setData(AggregatedCalledFunction firstNode
, List
<FlamegraphDepthEntry
> childrenEntries
, Deque
<Long
> timestampStack
) {
53 long lastEnd
= timestampStack
.peek();
54 for (int i
= 0; i
< firstNode
.getMaxDepth(); i
++) {
55 if (i
>= childrenEntries
.size()) {
56 FlamegraphDepthEntry entry
= new FlamegraphDepthEntry(String
.valueOf(i
), 0, firstNode
.getDuration(), i
, i
);
57 childrenEntries
.add(entry
);
59 childrenEntries
.get(i
).updateEndTime(lastEnd
+ firstNode
.getDuration());
61 FlamegraphDepthEntry firstEntry
= checkNotNull(childrenEntries
.get(0));
62 firstEntry
.addEvent(new FlamegraphEvent(firstEntry
, lastEnd
, firstNode
));
63 // Build the event list for next entries (next depth)
64 addEvent(firstNode
, childrenEntries
, timestampStack
);
69 * Build the events list for an entry (depth), then creates recursively the
70 * events for the next entries. This parses the aggregation tree starting
71 * from the bottom. This uses a stack to save the timestamp for each
72 * function. Once we save a function's timestamp we'll use it to create the
76 * The node of the aggregation tree
77 * @param childrenEntries
78 * The list of entries for one thread
79 * @param timestampStack
80 * A stack used to save the functions timeStamps
82 private void addEvent(AggregatedCalledFunction node
, List
<FlamegraphDepthEntry
> childrenEntries
, Deque
<Long
> timestampStack
) {
83 if (node
.hasChildren()) {
84 node
.getChildren().stream()
85 .sorted(Comparator
.comparingLong(AggregatedCalledFunction
::getDuration
))
87 addEvent(child
, childrenEntries
, timestampStack
);
89 node
.getChildren().stream().forEach(child
-> {
93 FlamegraphDepthEntry entry
= checkNotNull(childrenEntries
.get(node
.getDepth()));
94 // Create the event corresponding to the function using the caller's
96 entry
.addEvent(new FlamegraphEvent(entry
, timestampStack
.peek(), node
));
97 timestampStack
.push(timestampStack
.peek() + node
.getDuration());
101 public boolean hasChildren(Object element
) {
102 return !fFlameGraphEntries
.isEmpty();
106 public ITimeGraphEntry
[] getElements(Object inputElement
) {
107 fFlameGraphEntries
.clear();
108 // Get the root of each thread
109 if (inputElement
instanceof Collection
<?
>) {
110 Collection
<?
> threadNodes
= (Collection
<?
>) inputElement
;
111 for (Object object
: threadNodes
) {
112 if (object
instanceof ThreadNode
) {
113 buildChildrenEntries((ThreadNode
) object
);
117 return new ITimeGraphEntry
[0];
121 fFlameGraphEntries
.sort(fThreadComparator
);
122 return fFlameGraphEntries
.toArray(new ITimeGraphEntry
[fFlameGraphEntries
.size()]);
126 * Build the entry list for one thread
129 * The node of the aggregation tree
131 private void buildChildrenEntries(ThreadNode threadNode
) {
132 FlamegraphDepthEntry threadEntry
= new FlamegraphDepthEntry("", 0, 0, fFlameGraphEntries
.size(), threadNode
.getId()); //$NON-NLS-1$
133 List
<FlamegraphDepthEntry
> childrenEntries
= new ArrayList
<>();
134 Deque
<Long
> timestampStack
= new ArrayDeque
<>();
135 timestampStack
.push(0L);
136 // Sort children by duration
137 threadNode
.getChildren().stream()
138 .sorted(Comparator
.comparingLong(AggregatedCalledFunction
::getDuration
))
139 .forEach(rootFunction
-> {
140 setData(rootFunction
, childrenEntries
, timestampStack
);
141 long currentThreadDuration
= timestampStack
.pop() + rootFunction
.getDuration();
142 timestampStack
.push(currentThreadDuration
);
144 childrenEntries
.forEach(child
-> {
146 threadEntry
.addChild(child
);
149 threadEntry
.updateEndTime(timestampStack
.pop());
150 threadEntry
.setName(threadNode
.getSymbol().toString());
151 fFlameGraphEntries
.add(threadEntry
);
155 public ITimeGraphEntry
[] getChildren(Object parentElement
) {
156 return fFlameGraphEntries
.toArray(new TimeGraphEntry
[fFlameGraphEntries
.size()]);
160 public ITimeGraphEntry
getParent(Object element
) {
166 public void dispose() {
171 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
176 * Get the sort option
178 * @return the sort option.
180 public SortOption
getSortOption() {
185 * Set the sort option for sorting the thread entries
188 * the sort option to set
191 public void setSortOption(SortOption sortOption
) {
192 fSortOption
= sortOption
;
193 switch (sortOption
) {
195 fThreadComparator
= new ThreadNameComparator();
198 fThreadComparator
= checkNotNull(new ThreadNameComparator().reversed());
201 fThreadComparator
= new ThreadIdComparator();
204 fThreadComparator
= checkNotNull(new ThreadIdComparator().reversed());