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