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