timing: Fix duration of flamegraph view
[deliverable/tracecompass.git] / analysis / org.eclipse.tracecompass.analysis.timing.ui / src / org / eclipse / tracecompass / internal / analysis / timing / ui / flamegraph / FlameGraphContentProvider.java
1 /*******************************************************************************
2 * Copyright (c) 2016 Ericsson
3 *
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 *******************************************************************************/
9
10 package org.eclipse.tracecompass.internal.analysis.timing.ui.flamegraph;
11
12 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
13
14 import java.util.ArrayDeque;
15 import java.util.ArrayList;
16 import java.util.Comparator;
17 import java.util.Deque;
18 import java.util.List;
19
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.eclipse.jface.viewers.Viewer;
22
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.core.trace.ITmfTrace;
26 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
27 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphContentProvider;
28 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
29 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
30
31 /**
32 * Content provider for the flame graph view
33 *
34 * @author Sonia Farrah
35 *
36 */
37 public class FlameGraphContentProvider implements ITimeGraphContentProvider {
38
39 private final List<FlamegraphDepthEntry> fFlameGraphEntries = new ArrayList<>();
40 private ITmfTrace fActiveTrace;
41 private SortOption fSortOption = SortOption.BY_NAME;
42 private @NonNull Comparator<FlamegraphDepthEntry> fThreadComparator = new ThreadNameComparator();
43
44
45 /**
46 * Parse the aggregated tree created by the callGraphAnalysis and creates
47 * the event list (functions) for each entry (depth)
48 *
49 * @param firstNode
50 * The first node of the aggregation tree
51 * @param childrenEntries
52 * The list of entries for one thread
53 * @param timestampStack
54 * A stack used to save the functions timeStamps
55 */
56 private void setData(AggregatedCalledFunction firstNode, List<FlamegraphDepthEntry> childrenEntries, Deque<Long> timestampStack) {
57 long lastEnd = timestampStack.peek();
58 for (int i = 0; i < firstNode.getMaxDepth(); i++) {
59 if (i >= childrenEntries.size()) {
60 FlamegraphDepthEntry entry = new FlamegraphDepthEntry(String.valueOf(i), 0, firstNode.getDuration(), i, i);
61 childrenEntries.add(entry);
62 }
63 childrenEntries.get(i).updateEndTime(lastEnd + firstNode.getDuration());
64 }
65 FlamegraphDepthEntry firstEntry = checkNotNull(childrenEntries.get(0));
66 firstEntry.addEvent(new FlamegraphEvent(firstEntry, lastEnd, firstNode));
67 // Build the event list for next entries (next depth)
68 addEvent(firstNode, childrenEntries, timestampStack);
69 timestampStack.pop();
70 }
71
72 /**
73 * Build the events list for an entry (depth), then creates recursively the
74 * events for the next entries. This parses the aggregation tree starting
75 * from the bottom. This uses a stack to save the timestamp for each
76 * function. Once we save a function's timestamp we'll use it to create the
77 * callees events.
78 *
79 * @param node
80 * The node of the aggregation tree
81 * @param childrenEntries
82 * The list of entries for one thread
83 * @param timestampStack
84 * A stack used to save the functions timeStamps
85 */
86 private void addEvent(AggregatedCalledFunction node, List<FlamegraphDepthEntry> childrenEntries, Deque<Long> timestampStack) {
87 if (node.hasChildren()) {
88 node.getChildren().stream()
89 .sorted(Comparator.comparingLong(AggregatedCalledFunction::getDuration))
90 .forEach(child -> {
91 addEvent(child, childrenEntries, timestampStack);
92 });
93 node.getChildren().stream().forEach(child -> {
94 timestampStack.pop();
95 });
96 }
97 FlamegraphDepthEntry entry = checkNotNull(childrenEntries.get(node.getDepth()));
98 // Create the event corresponding to the function using the caller's
99 // timestamp
100 entry.addEvent(new FlamegraphEvent(entry, timestampStack.peek(), node));
101 timestampStack.push(timestampStack.peek() + node.getDuration());
102 }
103
104 @Override
105 public boolean hasChildren(Object element) {
106 return !fFlameGraphEntries.isEmpty();
107 }
108
109 @Override
110 public ITimeGraphEntry[] getElements(Object inputElement) {
111 fFlameGraphEntries.clear();
112 // Get the root of each thread
113 fActiveTrace = TmfTraceManager.getInstance().getActiveTrace();
114 if (fActiveTrace == null) {
115 return new ITimeGraphEntry[0];
116 }
117
118 if (inputElement instanceof List<?>) {
119 List<?> threadNodes = (List<?>) inputElement;
120 for (Object object : threadNodes) {
121 if (object instanceof ThreadNode) {
122 buildChildrenEntries((ThreadNode) object);
123 }
124 }
125 }
126 // Sort the threads
127 fFlameGraphEntries.sort(fThreadComparator);
128 return fFlameGraphEntries.toArray(new ITimeGraphEntry[fFlameGraphEntries.size()]);
129 }
130
131 /**
132 * Build the entry list for one thread
133 *
134 * @param threadNode
135 * The node of the aggregation tree
136 */
137 private void buildChildrenEntries(ThreadNode threadNode) {
138 FlamegraphDepthEntry threadEntry = new FlamegraphDepthEntry("", 0, 0, fFlameGraphEntries.size(), threadNode.getId()); //$NON-NLS-1$
139 List<FlamegraphDepthEntry> childrenEntries = new ArrayList<>();
140 Deque<Long> timestampStack = new ArrayDeque<>();
141 timestampStack.push(0L);
142 // Sort children by duration
143 threadNode.getChildren().stream()
144 .sorted(Comparator.comparingLong(AggregatedCalledFunction::getDuration))
145 .forEach(rootFunction -> {
146 setData(rootFunction, childrenEntries, timestampStack);
147 long currentThreadDuration = timestampStack.pop() + rootFunction.getDuration();
148 timestampStack.push(currentThreadDuration);
149 });
150 childrenEntries.forEach(child -> {
151 if (child != null) {
152 threadEntry.addChild(child);
153 }
154 });
155 threadEntry.updateEndTime(timestampStack.pop());
156 threadEntry.setName(threadNode.getSymbol().toString());
157 fFlameGraphEntries.add(threadEntry);
158 }
159
160 @Override
161 public ITimeGraphEntry[] getChildren(Object parentElement) {
162 return fFlameGraphEntries.toArray(new TimeGraphEntry[fFlameGraphEntries.size()]);
163 }
164
165 @Override
166 public ITimeGraphEntry getParent(Object element) {
167 // Do nothing
168 return null;
169 }
170
171 @Override
172 public void dispose() {
173 // Do nothing
174 }
175
176 @Override
177 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
178 // Do nothing
179 }
180
181
182 /**
183 * Get the sort option
184 *
185 * @return the sort option.
186 */
187 public SortOption getSortOption() {
188 return fSortOption;
189 }
190
191 /**
192 * Set the sort option for sorting the thread entries
193 *
194 * @param sortOption
195 * the sort option to set
196 *
197 */
198 public void setSortOption(SortOption sortOption) {
199 fSortOption = sortOption;
200 switch (sortOption) {
201 case BY_NAME:
202 fThreadComparator = new ThreadNameComparator();
203 break;
204 case BY_NAME_REV:
205 fThreadComparator = checkNotNull(new ThreadNameComparator().reversed());
206 break;
207 case BY_ID:
208 fThreadComparator = new ThreadIdComparator();
209 break;
210 case BY_ID_REV:
211 fThreadComparator = checkNotNull(new ThreadIdComparator().reversed());
212 break;
213 default:
214 break;
215 }
216 }
217 }
This page took 0.057134 seconds and 5 git commands to generate.