tmf: Update AbstractTimeGraphView and TimeGraphEntry API
[deliverable/tracecompass.git] / analysis / org.eclipse.tracecompass.analysis.os.linux.ui / src / org / eclipse / tracecompass / analysis / os / linux / ui / views / resources / ResourcesView.java
CommitLineData
6151d86c 1/*******************************************************************************
263c3747 2 * Copyright (c) 2012, 2016 Ericsson, École Polytechnique de Montréal
6151d86c
PT
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made 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 * Contributors:
10 * Patrick Tasse - Initial API and implementation
4999a196 11 * Geneviève Bastien - Move code to provide base classes for time graph views
6151d86c
PT
12 *******************************************************************************/
13
e363eae1 14package org.eclipse.tracecompass.analysis.os.linux.ui.views.resources;
6151d86c
PT
15
16import java.util.ArrayList;
1cf25311 17import java.util.Collections;
9ba941e9 18import java.util.Comparator;
1cf25311 19import java.util.HashMap;
6151d86c 20import java.util.List;
1cf25311 21import java.util.Map;
6151d86c
PT
22
23import org.eclipse.core.runtime.IProgressMonitor;
19ed6598
MK
24import org.eclipse.core.runtime.IStatus;
25import org.eclipse.core.runtime.Status;
8213a0c0 26import org.eclipse.jdt.annotation.NonNull;
d2120fb6 27import org.eclipse.jdt.annotation.Nullable;
9bdf1671
BH
28import org.eclipse.jface.action.IMenuManager;
29import org.eclipse.jface.viewers.ISelection;
30import org.eclipse.jface.viewers.IStructuredSelection;
024658d1 31import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelAnalysisModule;
8c684b48 32import org.eclipse.tracecompass.analysis.os.linux.core.signals.TmfCpuSelectedSignal;
e363eae1 33import org.eclipse.tracecompass.analysis.os.linux.ui.views.resources.ResourcesEntry.Type;
f69045e2 34import org.eclipse.tracecompass.internal.analysis.os.linux.core.kernel.Attributes;
e363eae1 35import org.eclipse.tracecompass.internal.analysis.os.linux.ui.Messages;
8c684b48
MK
36import org.eclipse.tracecompass.internal.analysis.os.linux.ui.actions.FollowCpuAction;
37import org.eclipse.tracecompass.internal.analysis.os.linux.ui.actions.UnfollowCpuAction;
e894a508
AM
38import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
39import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
e894a508 40import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
8c684b48 41import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
2bdf0193
AM
42import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
43import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
8213a0c0 44import org.eclipse.tracecompass.tmf.ui.views.timegraph.AbstractStateSystemTimeGraphView;
2bdf0193
AM
45import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
46import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
47import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.NullTimeEvent;
48import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeEvent;
49import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
6151d86c
PT
50
51/**
52 * Main implementation for the LTTng 2.0 kernel Resource view
53 *
54 * @author Patrick Tasse
55 */
8213a0c0 56public class ResourcesView extends AbstractStateSystemTimeGraphView {
6151d86c
PT
57
58 /** View ID. */
e363eae1 59 public static final String ID = "org.eclipse.tracecompass.analysis.os.linux.views.resources"; //$NON-NLS-1$
6151d86c 60
4999a196 61 private static final String[] FILTER_COLUMN_NAMES = new String[] {
747adf5c 62 Messages.ResourcesView_stateTypeName
4999a196 63 };
6151d86c 64
8c684b48
MK
65 private int fCurrentCpu = -1;
66
1cf25311
PT
67 // Timeout between updates in the build thread in ms
68 private static final long BUILD_UPDATE_TIMEOUT = 500;
69
6151d86c
PT
70 // ------------------------------------------------------------------------
71 // Constructors
72 // ------------------------------------------------------------------------
73
74 /**
75 * Default constructor
76 */
77 public ResourcesView() {
747adf5c
PT
78 super(ID, new ResourcesPresentationProvider());
79 setFilterColumns(FILTER_COLUMN_NAMES);
bb447fcb 80 setFilterLabelProvider(new ResourcesFilterLabelProvider());
263c3747 81 setEntryComparator(new ResourcesEntryComparator());
19ed6598 82 setAutoExpandLevel(1);
263c3747
PT
83 }
84
85 private static class ResourcesEntryComparator implements Comparator<ITimeGraphEntry> {
86 @Override
87 public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
88 ResourcesEntry entry1 = (ResourcesEntry) o1;
89 ResourcesEntry entry2 = (ResourcesEntry) o2;
90 if (entry1.getType() == Type.NULL && entry2.getType() == Type.NULL) {
91 /* sort trace entries alphabetically */
92 return entry1.getName().compareTo(entry2.getName());
93 }
94 /* sort resource entries by their defined order */
95 return entry1.compareTo(entry2);
96 }
bb447fcb
PT
97 }
98
8c684b48 99
9bdf1671
BH
100 /**
101 * @since 2.0
102 */
103 @Override
104 protected void fillTimeGraphEntryContextMenu(@NonNull IMenuManager menuManager) {
105 ISelection selection = getSite().getSelectionProvider().getSelection();
106 if (selection instanceof IStructuredSelection) {
107 IStructuredSelection sSel = (IStructuredSelection) selection;
108 if (sSel.getFirstElement() instanceof ResourcesEntry) {
109 ResourcesEntry resourcesEntry = (ResourcesEntry) sSel.getFirstElement();
110 if (resourcesEntry.getType().equals(ResourcesEntry.Type.CPU)) {
111 if (fCurrentCpu >= 0) {
112 menuManager.add(new UnfollowCpuAction(ResourcesView.this, resourcesEntry.getId(), resourcesEntry.getTrace()));
113 } else {
114 menuManager.add(new FollowCpuAction(ResourcesView.this, resourcesEntry.getId(), resourcesEntry.getTrace()));
8c684b48
MK
115 }
116 }
117 }
9bdf1671 118 }
8c684b48
MK
119 }
120
bb447fcb
PT
121 private static class ResourcesFilterLabelProvider extends TreeLabelProvider {
122 @Override
123 public String getColumnText(Object element, int columnIndex) {
124 ResourcesEntry entry = (ResourcesEntry) element;
125 if (columnIndex == 0) {
126 return entry.getName();
127 }
128 return ""; //$NON-NLS-1$
129 }
130
6151d86c
PT
131 }
132
1cf25311
PT
133 // ------------------------------------------------------------------------
134 // Internal
135 // ------------------------------------------------------------------------
136
6151d86c 137 @Override
4999a196
GB
138 protected String getNextText() {
139 return Messages.ResourcesView_nextResourceActionNameText;
6151d86c
PT
140 }
141
6151d86c 142 @Override
4999a196
GB
143 protected String getNextTooltip() {
144 return Messages.ResourcesView_nextResourceActionToolTipText;
fec1ac0b
BH
145 }
146
4999a196
GB
147 @Override
148 protected String getPrevText() {
149 return Messages.ResourcesView_previousResourceActionNameText;
6151d86c
PT
150 }
151
4999a196
GB
152 @Override
153 protected String getPrevTooltip() {
154 return Messages.ResourcesView_previousResourceActionToolTipText;
6151d86c
PT
155 }
156
4999a196 157 @Override
f8f46a52 158 protected void buildEntryList(ITmfTrace trace, ITmfTrace parentTrace, final IProgressMonitor monitor) {
8213a0c0 159 final ITmfStateSystem ssq = TmfStateSystemAnalysisModule.getStateSystem(trace, KernelAnalysisModule.ID);
1cf25311
PT
160 if (ssq == null) {
161 return;
162 }
fec1ac0b 163
1cf25311
PT
164 Map<Integer, ResourcesEntry> entryMap = new HashMap<>();
165 TimeGraphEntry traceEntry = null;
166
167 long startTime = ssq.getStartTime();
168 long start = startTime;
169 setStartTime(Math.min(getStartTime(), startTime));
170 boolean complete = false;
171 while (!complete) {
faa38350
PT
172 if (monitor.isCanceled()) {
173 return;
174 }
1cf25311
PT
175 complete = ssq.waitUntilBuilt(BUILD_UPDATE_TIMEOUT);
176 if (ssq.isCancelled()) {
177 return;
178 }
179 long end = ssq.getCurrentEndTime();
19ed6598
MK
180 if (start == end && !complete) {
181 // when complete execute one last time regardless of end time
1cf25311
PT
182 continue;
183 }
184 long endTime = end + 1;
185 setEndTime(Math.max(getEndTime(), endTime));
186
187 if (traceEntry == null) {
188 traceEntry = new ResourcesEntry(trace, trace.getName(), startTime, endTime, 0);
189 List<TimeGraphEntry> entryList = Collections.singletonList(traceEntry);
8213a0c0 190 addToEntryList(parentTrace, ssq, entryList);
1cf25311
PT
191 } else {
192 traceEntry.updateEndTime(endTime);
193 }
1cf25311 194 List<Integer> cpuQuarks = ssq.getQuarks(Attributes.CPUS, "*"); //$NON-NLS-1$
19ed6598 195 createCpuEntriesWithQuark(trace, ssq, entryMap, traceEntry, startTime, endTime, cpuQuarks);
1cf25311
PT
196 if (parentTrace.equals(getTrace())) {
197 refresh();
faa38350 198 }
f8f46a52 199 final List<@NonNull TimeGraphEntry> traceEntryChildren = traceEntry.getChildren();
8213a0c0
PT
200 final long resolution = Math.max(1, (endTime - ssq.getStartTime()) / getDisplayWidth());
201 final long qStart = start;
202 final long qEnd = end;
203 queryFullStates(ssq, qStart, qEnd, resolution, monitor, new IQueryHandler() {
204 @Override
205 public void handle(List<List<ITmfStateInterval>> fullStates, List<ITmfStateInterval> prevFullState) {
f8f46a52 206 for (TimeGraphEntry child : traceEntryChildren) {
19ed6598 207 if (!populateEventsRecursively(fullStates, prevFullState, child).isOK()) {
8213a0c0
PT
208 return;
209 }
19ed6598
MK
210 }
211 }
212
f8f46a52 213 private IStatus populateEventsRecursively(@NonNull List<List<ITmfStateInterval>> fullStates, @Nullable List<ITmfStateInterval> prevFullState, @NonNull TimeGraphEntry entry) {
19ed6598
MK
214 if (monitor.isCanceled()) {
215 return Status.CANCEL_STATUS;
216 }
f8f46a52
PT
217 List<ITimeEvent> eventList = getEventList(entry, ssq, fullStates, prevFullState, monitor);
218 if (eventList != null) {
219 for (ITimeEvent event : eventList) {
220 entry.addEvent(event);
a3188982 221 }
1cf25311 222 }
f8f46a52 223 for (TimeGraphEntry child : entry.getChildren()) {
19ed6598
MK
224 IStatus status = populateEventsRecursively(fullStates, prevFullState, child);
225 if (!status.isOK()) {
226 return status;
227 }
228 }
229 return Status.OK_STATUS;
1cf25311 230 }
8213a0c0 231 });
1cf25311
PT
232
233 start = end;
6151d86c 234 }
19ed6598
MK
235
236 }
237
238 private static void createCpuEntriesWithQuark(@NonNull ITmfTrace trace, final ITmfStateSystem ssq, Map<Integer, ResourcesEntry> entryMap, TimeGraphEntry traceEntry, long startTime, long endTime, List<Integer> cpuQuarks) {
239 for (Integer cpuQuark : cpuQuarks) {
240 final @NonNull String cpuName = ssq.getAttributeName(cpuQuark);
241 int cpu = Integer.parseInt(cpuName);
242 ResourcesEntry cpuEntry = entryMap.get(cpuQuark);
243 if (cpuEntry == null) {
244 cpuEntry = new ResourcesEntry(cpuQuark, trace, startTime, endTime, Type.CPU, cpu);
245 entryMap.put(cpuQuark, cpuEntry);
246 traceEntry.addChild(cpuEntry);
247 } else {
248 cpuEntry.updateEndTime(endTime);
249 }
250 List<Integer> irqQuarks = ssq.getQuarks(Attributes.CPUS, cpuName, Attributes.IRQS, "*"); //$NON-NLS-1$
251 createCpuInterruptEntryWithQuark(trace, ssq, entryMap, startTime, endTime, traceEntry, cpuEntry, irqQuarks, Type.IRQ);
252 List<Integer> softIrqQuarks = ssq.getQuarks(Attributes.CPUS, cpuName, Attributes.SOFT_IRQS, "*"); //$NON-NLS-1$
253 createCpuInterruptEntryWithQuark(trace, ssq, entryMap, startTime, endTime, traceEntry, cpuEntry, softIrqQuarks, Type.SOFT_IRQ);
254 }
255 }
256
257 /**
258 * Create and add execution contexts to a cpu entry. Also creates an
259 * aggregate entry in the root trace entry. The execution context is
260 * basically what the cpu is doing in its execution stack. It can be in an
261 * IRQ, Soft IRQ. MCEs, NMIs, Userland and Kernel execution is not yet
262 * supported.
263 *
264 * @param trace
265 * the trace
266 * @param ssq
267 * the state system
268 * @param entryMap
269 * the entry map
270 * @param startTime
271 * the start time in nanoseconds
272 * @param endTime
273 * the end time in nanoseconds
274 * @param traceEntry
275 * the trace timegraph entry
276 * @param cpuEntry
277 * the cpu timegraph entry (the entry under the trace entry
278 * @param childrenQuarks
279 * the quarks to add to cpu entry
280 * @param type
281 * the type of entry being added
282 */
283 private static void createCpuInterruptEntryWithQuark(@NonNull ITmfTrace trace,
284 final ITmfStateSystem ssq, Map<Integer, ResourcesEntry> entryMap,
285 long startTime, long endTime,
286 TimeGraphEntry traceEntry, ResourcesEntry cpuEntry,
287 List<Integer> childrenQuarks, Type type) {
288 for (Integer quark : childrenQuarks) {
289 final @NonNull String resourceName = ssq.getAttributeName(quark);
290 int resourceId = Integer.parseInt(resourceName);
291 ResourcesEntry interruptEntry = entryMap.get(quark);
292 if (interruptEntry == null) {
293 interruptEntry = new ResourcesEntry(quark, trace, startTime, endTime, type, resourceId);
294 entryMap.put(quark, interruptEntry);
295 cpuEntry.addChild(interruptEntry);
296 boolean found = false;
297 for (ITimeGraphEntry rootElem : traceEntry.getChildren()) {
298 if (rootElem instanceof AggregateResourcesEntry) {
299 AggregateResourcesEntry aggregateInterruptEntry = (AggregateResourcesEntry) rootElem;
300 if (aggregateInterruptEntry.getId() == resourceId && aggregateInterruptEntry.getType().equals(type)) {
301 found = true;
302 aggregateInterruptEntry.addContributor(interruptEntry);
ff0b7e58
MK
303 final AggregateResourcesEntry irqCpuEntry = new AggregateResourcesEntry(trace, cpuEntry.getName(), startTime, endTime, type, cpuEntry.getId());
304 irqCpuEntry.addContributor(interruptEntry);
305 aggregateInterruptEntry.addChild(irqCpuEntry);
19ed6598
MK
306 break;
307 }
308 }
309 }
310 if (!found) {
311 AggregateResourcesEntry aggregateInterruptEntry = new AggregateResourcesEntry(trace, startTime, endTime, type, resourceId);
312 aggregateInterruptEntry.addContributor(interruptEntry);
ff0b7e58
MK
313 final AggregateResourcesEntry irqCpuEntry = new AggregateResourcesEntry(trace, cpuEntry.getName(), startTime, endTime, type, cpuEntry.getId());
314 irqCpuEntry.addContributor(interruptEntry);
315 aggregateInterruptEntry.addChild(irqCpuEntry);
19ed6598
MK
316 traceEntry.addChild(aggregateInterruptEntry);
317 }
318 } else {
319 interruptEntry.updateEndTime(endTime);
320 }
321 }
6151d86c
PT
322 }
323
4999a196 324 @Override
8213a0c0
PT
325 protected @Nullable List<ITimeEvent> getEventList(@NonNull TimeGraphEntry entry, ITmfStateSystem ssq,
326 @NonNull List<List<ITmfStateInterval>> fullStates, @Nullable List<ITmfStateInterval> prevFullState, @NonNull IProgressMonitor monitor) {
1d46dc38 327 ResourcesEntry resourcesEntry = (ResourcesEntry) entry;
4999a196
GB
328 int quark = resourcesEntry.getQuark();
329
8213a0c0 330 if (resourcesEntry.getType().equals(Type.CPU)) {
19ed6598
MK
331 return createCpuEventsList(entry, ssq, fullStates, prevFullState, monitor, quark);
332 } else if ((resourcesEntry.getType().equals(Type.IRQ) || resourcesEntry.getType().equals(Type.SOFT_IRQ)) && (quark >= 0)) {
333 return createIrqEventsList(entry, fullStates, prevFullState, monitor, quark);
334 }
335
336 return null;
337 }
338
f8f46a52 339 private static List<ITimeEvent> createCpuEventsList(ITimeGraphEntry entry, ITmfStateSystem ssq, List<List<ITmfStateInterval>> fullStates, List<ITmfStateInterval> prevFullState, IProgressMonitor monitor, int quark) {
19ed6598
MK
340 List<ITimeEvent> eventList;
341 int statusQuark;
342 try {
343 statusQuark = ssq.getQuarkRelative(quark, Attributes.STATUS);
344 } catch (AttributeNotFoundException e) {
345 /*
346 * The sub-attribute "status" is not available. May happen if the
347 * trace does not have sched_switch events enabled.
348 */
349 return null;
350 }
351 eventList = new ArrayList<>(fullStates.size());
352 ITmfStateInterval lastInterval = prevFullState == null || statusQuark >= prevFullState.size() ? null : prevFullState.get(statusQuark);
353 long lastStartTime = lastInterval == null ? -1 : lastInterval.getStartTime();
354 long lastEndTime = lastInterval == null ? -1 : lastInterval.getEndTime() + 1;
355 for (List<ITmfStateInterval> fullState : fullStates) {
356 if (monitor.isCanceled()) {
8213a0c0
PT
357 return null;
358 }
19ed6598
MK
359 if (statusQuark >= fullState.size()) {
360 /* No information on this CPU (yet?), skip it for now */
361 continue;
8213a0c0 362 }
19ed6598
MK
363 ITmfStateInterval statusInterval = fullState.get(statusQuark);
364 int status = statusInterval.getStateValue().unboxInt();
365 long time = statusInterval.getStartTime();
366 long duration = statusInterval.getEndTime() - time + 1;
367 if (time == lastStartTime) {
368 continue;
369 }
370 if (!statusInterval.getStateValue().isNull()) {
371 if (lastEndTime != time && lastEndTime != -1) {
372 eventList.add(new TimeEvent(entry, lastEndTime, time - lastEndTime));
6151d86c 373 }
19ed6598
MK
374 eventList.add(new TimeEvent(entry, time, duration, status));
375 } else {
376 eventList.add(new NullTimeEvent(entry, time, duration));
6151d86c 377 }
19ed6598
MK
378 lastStartTime = time;
379 lastEndTime = time + duration;
6151d86c 380 }
19ed6598
MK
381 return eventList;
382 }
8213a0c0 383
f8f46a52 384 private static List<ITimeEvent> createIrqEventsList(ITimeGraphEntry entry, List<List<ITmfStateInterval>> fullStates, List<ITmfStateInterval> prevFullState, IProgressMonitor monitor, int quark) {
19ed6598
MK
385 List<ITimeEvent> eventList;
386 eventList = new ArrayList<>(fullStates.size());
387 ITmfStateInterval lastInterval = prevFullState == null || quark >= prevFullState.size() ? null : prevFullState.get(quark);
388 long lastStartTime = lastInterval == null ? -1 : lastInterval.getStartTime();
389 long lastEndTime = lastInterval == null ? -1 : lastInterval.getEndTime() + 1;
390 boolean lastIsNull = lastInterval == null ? false : lastInterval.getStateValue().isNull();
391 for (List<ITmfStateInterval> fullState : fullStates) {
392 if (monitor.isCanceled()) {
393 return null;
394 }
395 if (quark >= fullState.size()) {
396 /* No information on this IRQ (yet?), skip it for now */
397 continue;
398 }
399 ITmfStateInterval irqInterval = fullState.get(quark);
400 long time = irqInterval.getStartTime();
401 long duration = irqInterval.getEndTime() - time + 1;
402 if (time == lastStartTime) {
403 continue;
404 }
405 if (!irqInterval.getStateValue().isNull()) {
406 int cpu = irqInterval.getStateValue().unboxInt();
407 eventList.add(new TimeEvent(entry, time, duration, cpu));
408 lastIsNull = false;
409 } else {
410 if (lastEndTime != time && lastIsNull) {
411 /*
412 * This is a special case where we want to show IRQ_ACTIVE
413 * state but we don't know the CPU (it is between two null
414 * samples)
415 */
416 eventList.add(new TimeEvent(entry, lastEndTime, time - lastEndTime, -1));
417 }
418 eventList.add(new NullTimeEvent(entry, time, duration));
419 lastIsNull = true;
420 }
421 lastStartTime = time;
422 lastEndTime = time + duration;
423 }
6151d86c
PT
424 return eventList;
425 }
426
8c684b48
MK
427 /**
428 * Signal handler for a cpu selected signal.
429 *
430 * @param signal
431 * the cpu selected signal
432 * @since 2.0
433 */
434 @TmfSignalHandler
435 public void listenToCpu(TmfCpuSelectedSignal signal) {
436 if (signal.getCore() >= 0) {
437 fCurrentCpu = signal.getCore();
438 } else {
439 fCurrentCpu = -1;
440 }
441 }
442
6151d86c 443}
This page took 0.120432 seconds and 5 git commands to generate.