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