timing: Add a threadId field for the flame graph
[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 java.util.ArrayDeque;
13 import java.util.ArrayList;
14 import java.util.Comparator;
15 import java.util.Deque;
16 import java.util.List;
17
18 import org.eclipse.jface.viewers.Viewer;
19 import org.eclipse.tracecompass.common.core.NonNullUtils;
20 import org.eclipse.tracecompass.internal.analysis.timing.core.callgraph.AggregatedCalledFunction;
21 import org.eclipse.tracecompass.internal.analysis.timing.core.callgraph.ThreadNode;
22 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
23 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
24 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphContentProvider;
25 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
26 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
27
28 import com.google.common.collect.Lists;
29
30 /**
31 * Content provider for the flame graph view
32 *
33 * @author Sonia Farrah
34 *
35 */
36 public class FlameGraphContentProvider implements ITimeGraphContentProvider {
37
38 private List<FlamegraphDepthEntry> fFlameGraphEntries = new ArrayList<>();
39 private long fThreadDuration;
40 private ITmfTrace fActiveTrace;
41
42 /**
43 * Parse the aggregated tree created by the callGraphAnalysis and creates
44 * the event list (functions) for each entry (depth)
45 *
46 * @param firstNode
47 * The first node of the aggregation tree
48 * @param childrenEntries
49 * The list of entries for one thread
50 * @param timestampStack
51 * A stack used to save the functions timeStamps
52 */
53 private void setData(AggregatedCalledFunction firstNode, List<FlamegraphDepthEntry> childrenEntries, Deque<Long> timestampStack) {
54 for (int i = 0; i < firstNode.getMaxDepth(); i++) {
55 if (i >= childrenEntries.size()) {
56 FlamegraphDepthEntry entry = new FlamegraphDepthEntry(String.valueOf(i), 0, fActiveTrace.getEndTime().toNanos() - fActiveTrace.getStartTime().toNanos(), i, i);
57 childrenEntries.add(entry);
58 }
59 }
60 FlamegraphDepthEntry firstEntry = NonNullUtils.checkNotNull(childrenEntries.get(0));
61 firstEntry.addEvent(new FlamegraphEvent(firstEntry, timestampStack.peek(), firstNode));
62 // Build the event list for next entries (next depth)
63 addEvent(firstNode, childrenEntries, timestampStack);
64 }
65
66 /**
67 * Build the events list for an entry (depth), then creates recursively the
68 * events for the next entries. This parses the aggregation tree starting
69 * from the bottom. This uses a stack to save the timestamp for each
70 * function. Once we save a function's timestamp we'll use it to create the
71 * callees events.
72 *
73 * @param node
74 * The node of the aggregation tree
75 * @param childrenEntries
76 * The list of entries for one thread
77 * @param timestampStack
78 * A stack used to save the functions timeStamps
79 */
80 private void addEvent(AggregatedCalledFunction node, List<FlamegraphDepthEntry> childrenEntries, Deque<Long> timestampStack) {
81 if (node.hasChildren()) {
82 node.getChildren().stream()
83 .sorted(Comparator.comparingLong(AggregatedCalledFunction::getDuration))
84 .forEach(child -> {
85 addEvent(child, childrenEntries, timestampStack);
86 });
87 node.getChildren().stream().forEach(child -> {
88 timestampStack.pop();
89 });
90 }
91 FlamegraphDepthEntry entry = NonNullUtils.checkNotNull(childrenEntries.get(node.getDepth()));
92 // Create the event corresponding to the function using the caller's
93 // timestamp
94 entry.addEvent(new FlamegraphEvent(entry, timestampStack.peek(), node));
95 timestampStack.push(timestampStack.peek() + node.getDuration());
96 }
97
98 @Override
99 public boolean hasChildren(Object element) {
100 return !fFlameGraphEntries.isEmpty();
101 }
102
103 @Override
104 public ITimeGraphEntry[] getElements(Object inputElement) {
105 fFlameGraphEntries.clear();
106 // Get the root of each thread
107 fActiveTrace = TmfTraceManager.getInstance().getActiveTrace();
108 if (fActiveTrace == null) {
109 return new ITimeGraphEntry[0];
110 }
111
112 if (inputElement instanceof List<?>) {
113 List<?> threadNodes = (List<?>) inputElement;
114 for (Object object : threadNodes) {
115 if (object instanceof ThreadNode) {
116 buildChildrenEntries((ThreadNode) object);
117 }
118 }
119 }
120 // Reverse the order of threads
121 fFlameGraphEntries = Lists.reverse(fFlameGraphEntries);
122 return fFlameGraphEntries.toArray(new ITimeGraphEntry[fFlameGraphEntries.size()]);
123 }
124
125 /**
126 * Build the entry list for one thread
127 *
128 * @param threadNode
129 * The node of the aggregation tree
130 */
131 private void buildChildrenEntries(ThreadNode threadNode) {
132 FlamegraphDepthEntry threadEntry = new FlamegraphDepthEntry("", 0, fActiveTrace.getEndTime().toNanos() - fActiveTrace.getStartTime().toNanos(), fFlameGraphEntries.size(), threadNode.getId()); //$NON-NLS-1$
133 List<FlamegraphDepthEntry> childrenEntries = new ArrayList<>();
134 fThreadDuration = 0L;
135 // Sort children by duration
136 threadNode.getChildren().stream()
137 .sorted(Comparator.comparingLong(AggregatedCalledFunction::getDuration))
138 .forEach(rootFunction -> {
139 Deque<Long> timestampStack = new ArrayDeque<>();
140 timestampStack.push(fThreadDuration);
141 setData(rootFunction, childrenEntries, timestampStack);
142 fThreadDuration += rootFunction.getDuration();
143 timestampStack.pop();
144 });
145 childrenEntries.forEach(child -> {
146 if (child != null) {
147 threadEntry.addChild(child);
148 }
149 });
150 threadEntry.setName(threadNode.getSymbol().toString());
151 fFlameGraphEntries.add(threadEntry);
152 }
153
154 @Override
155 public ITimeGraphEntry[] getChildren(Object parentElement) {
156 return fFlameGraphEntries.toArray(new TimeGraphEntry[fFlameGraphEntries.size()]);
157 }
158
159 @Override
160 public ITimeGraphEntry getParent(Object element) {
161 // Do nothing
162 return null;
163 }
164
165 @Override
166 public void dispose() {
167 // Do nothing
168 }
169
170 @Override
171 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
172 // Do nothing
173 }
174
175 }
This page took 0.037004 seconds and 6 git commands to generate.