documentation: Add documentation for Latency views
[deliverable/tracecompass.git] / lttng / org.eclipse.tracecompass.lttng2.kernel.ui / src / org / eclipse / tracecompass / internal / lttng2 / kernel / ui / views / vm / vcpuview / VirtualMachineView.java
CommitLineData
b1a7aebb
MG
1/*******************************************************************************
2 * Copyright (c) 2016 École Polytechnique de Montréal
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
10package org.eclipse.tracecompass.internal.lttng2.kernel.ui.views.vm.vcpuview;
11
12import java.util.ArrayList;
13import java.util.Collection;
14import java.util.Collections;
15import java.util.Comparator;
16import java.util.HashMap;
17import java.util.List;
18import java.util.Map;
19
20import org.eclipse.core.runtime.IProgressMonitor;
21import org.eclipse.jdt.annotation.NonNull;
22import org.eclipse.jdt.annotation.Nullable;
23import org.eclipse.tracecompass.analysis.os.linux.core.kernelanalysis.KernelAnalysisModule;
24import org.eclipse.tracecompass.analysis.os.linux.core.kernelanalysis.KernelThreadInformationProvider;
25import org.eclipse.tracecompass.common.core.NonNullUtils;
26import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.VmAttributes;
27import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.module.VirtualMachineCpuAnalysis;
28import org.eclipse.tracecompass.internal.lttng2.kernel.core.analysis.vm.trace.VirtualMachineExperiment;
29import org.eclipse.tracecompass.internal.lttng2.kernel.ui.Activator;
30import org.eclipse.tracecompass.internal.lttng2.kernel.ui.views.vm.vcpuview.VirtualMachineCommon.Type;
31import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
32import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
33import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
34import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
35import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
36import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
37import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
38import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
39import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
40import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
41import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperimentUtils;
42import org.eclipse.tracecompass.tmf.ui.views.timegraph.AbstractTimeGraphView;
43import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
44import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
45import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.NullTimeEvent;
46import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeEvent;
47import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
48
49import com.google.common.collect.Multimap;
50
51/**
52 * Main implementation for the Virtual Machine view
53 *
54 * @author Mohamad Gebai
55 */
56public class VirtualMachineView extends AbstractTimeGraphView {
57
58 /** View ID. */
59 public static final String ID = "org.eclipse.tracecompass.lttng2.analysis.vm.ui.vmview"; //$NON-NLS-1$
60
61 private static final String[] COLUMN_NAMES = new String[] {
62 Messages.VmView_stateTypeName
63 };
64
65 private static final String[] FILTER_COLUMN_NAMES = new String[] {
66 Messages.VmView_stateTypeName
67 };
68
69 // Timeout between updates in the build thread in ms
70 private static final long BUILD_UPDATE_TIMEOUT = 500;
71 private static final int[] DEFAULT_WEIGHT = { 1, 3 };
72
6a492637 73 private Comparator<ITimeGraphEntry> fComparator = VirtualMachineViewEntry.getComparator();
b1a7aebb
MG
74
75 // ------------------------------------------------------------------------
76 // Constructors
77 // ------------------------------------------------------------------------
78
79 /**
80 * Default constructor
81 */
82 public VirtualMachineView() {
83 super(ID, new VirtualMachinePresentationProvider());
84 setFilterColumns(FILTER_COLUMN_NAMES);
85 setTreeColumns(COLUMN_NAMES);
86 setTreeLabelProvider(new VmViewTreeLabelProvider());
87 setWeight(DEFAULT_WEIGHT);
88 setAutoExpandLevel(2);
89 }
90
91 @Override
92 protected @Nullable String getNextText() {
93 return Messages.VmView_nextResourceActionNameText;
94 }
95
96 @Override
97 protected @Nullable String getNextTooltip() {
98 return Messages.VmView_nextResourceActionToolTipText;
99 }
100
101 @Override
102 protected @Nullable String getPrevText() {
103 return Messages.VmView_previousResourceActionNameText;
104 }
105
106 @Override
107 protected @Nullable String getPrevTooltip() {
108 return Messages.VmView_previousResourceActionToolTipText;
109 }
110
111 private static class VmViewTreeLabelProvider extends TreeLabelProvider {
112
113 @Override
114 public String getColumnText(@Nullable Object element, int columnIndex) {
115 if (!(element instanceof VirtualMachineViewEntry)) {
116 return ""; //$NON-NLS-1$
117 }
118 VirtualMachineViewEntry entry = (VirtualMachineViewEntry) element;
119
120 if (COLUMN_NAMES[columnIndex].equals(Messages.VmView_stateTypeName)) {
121 String name = entry.getName();
122 return (name == null) ? "" : name; //$NON-NLS-1$
123 }
124 return ""; //$NON-NLS-1$
125 }
126
127 }
128
129 // ------------------------------------------------------------------------
130 // Internal
131 // ------------------------------------------------------------------------
132
133 @Override
134 protected void buildEventList(ITmfTrace trace, ITmfTrace parentTrace, IProgressMonitor monitor) {
135 setStartTime(Long.MAX_VALUE);
136 setEndTime(Long.MIN_VALUE);
137
b1a7aebb
MG
138 if (!(parentTrace instanceof VirtualMachineExperiment)) {
139 return;
140 }
141 ITmfStateSystem ssq = TmfStateSystemAnalysisModule.getStateSystem(parentTrace, VirtualMachineCpuAnalysis.ID);
142 if (ssq == null) {
143 return;
144 }
145 VirtualMachineExperiment vmExperiment = (VirtualMachineExperiment) parentTrace;
146 long startTime = ssq.getStartTime();
147
148 ArrayList<VirtualMachineViewEntry> entryList = new ArrayList<>();
149 Map<String, VirtualMachineViewEntry> entryMap = new HashMap<>();
150
151 boolean complete = false;
507e1c50
GB
152 VirtualMachineViewEntry groupEntry = new VirtualMachineViewEntry.VmEntryBuilder(vmExperiment.getName(), startTime, startTime, vmExperiment).build();
153 entryList.add(groupEntry);
154 putEntryList(parentTrace, new ArrayList<TimeGraphEntry>(entryList));
b1a7aebb
MG
155
156 while (!complete) {
157 if (monitor.isCanceled()) {
158 return;
159 }
160 complete = ssq.waitUntilBuilt(BUILD_UPDATE_TIMEOUT);
161 if (ssq.isCancelled()) {
162 return;
163 }
164
165 long endTime = ssq.getCurrentEndTime() + 1;
507e1c50 166 groupEntry.updateEndTime(endTime);
b1a7aebb
MG
167
168 setStartTime(Math.min(getStartTime(), startTime));
169 setEndTime(Math.max(getEndTime(), endTime));
170
171 /*
172 * Create the entries for the VMs in this experiment and their
173 * respective threads
174 */
175 buildEntries(ssq, startTime, endTime, groupEntry, entryMap, vmExperiment);
176
177 if (parentTrace.equals(getTrace())) {
178 refresh();
179 }
180
507e1c50
GB
181 /* Build event lists for each entry */
182 buildEntryEventLists(entryList, ssq, startTime, endTime, monitor);
b1a7aebb
MG
183 }
184 }
185
186 private void buildEntries(ITmfStateSystem ssq, long startTime, long endTime, VirtualMachineViewEntry groupEntry,
187 Map<@NonNull String, @NonNull VirtualMachineViewEntry> entryMap, VirtualMachineExperiment vmExperiment) {
188 try {
189 List<Integer> vmQuarks = ssq.getQuarks(VmAttributes.VIRTUAL_MACHINES, "*"); //$NON-NLS-1$
190 /* For each virtual machine in the analysis */
191 for (Integer vmQuark : vmQuarks) {
192
193 /* Display an entry for the virtual machine */
194 String vmHostId = NonNullUtils.checkNotNull(ssq.getAttributeName(vmQuark));
195 ITmfStateInterval vmNameInterval = StateSystemUtils.queryUntilNonNullValue(ssq, vmQuark, startTime, endTime);
196 String vmName = vmHostId;
197 if (vmNameInterval != null) {
198 vmName = vmNameInterval.getStateValue().unboxStr();
199 }
200
201 VirtualMachineViewEntry vmEntry = entryMap.get(vmHostId);
202 if (vmEntry == null) {
203 vmEntry = new VirtualMachineViewEntry.VmEntryBuilder(vmName, startTime, endTime, vmExperiment).setId(vmHostId).setVmName(vmName).setNumericId(vmQuark).setType(Type.VM).build();
204 vmEntry.sortChildren(fComparator);
205
206 groupEntry.addChild(vmEntry);
207 entryMap.put(vmHostId, vmEntry);
208 } else {
209 vmEntry.updateEndTime(endTime);
210 }
211
212 /* Display an entry for each of its CPUs */
213 for (Integer vCpuQuark : ssq.getSubAttributes(vmQuark, false)) {
214 String vcpuId = ssq.getAttributeName(vCpuQuark);
215 VirtualMachineViewEntry vcpuEntry = entryMap.get(vmHostId + vcpuId);
216 if (vcpuEntry == null) {
217 vcpuEntry = new VirtualMachineViewEntry.VmEntryBuilder(vcpuId, startTime, endTime, vmExperiment).setId(vcpuId).setVmName(vmName).setNumericId(vCpuQuark).setType(Type.VCPU).build();
218
219 vmEntry.addChild(vcpuEntry);
220 entryMap.put(vmHostId + vcpuId, vcpuEntry);
221 } else {
222 vcpuEntry.updateEndTime(endTime);
223 }
224
225 }
226
507e1c50
GB
227 /* Add the entries for the threads */
228 buildThreadEntries(vmEntry, entryMap, startTime, endTime);
b1a7aebb
MG
229 }
230 } catch (AttributeNotFoundException e) {
231 /*
232 * The attribute may not exist yet if the state system is being
233 * built
234 */
235 } catch (TimeRangeException | StateValueTypeException e) {
236 Activator.getDefault().logError("VirtualMachineView: error building event list", e); //$NON-NLS-1$
237 }
238 }
239
507e1c50
GB
240 private static void buildThreadEntries(VirtualMachineViewEntry vmEntry, Map<String, VirtualMachineViewEntry> entryMap, long startTime, long endTime) {
241 String vmHostId = vmEntry.getId();
242 VirtualMachineExperiment vmExperiment = vmEntry.getExperiment();
243
244 /*
245 * Get the LTTng Kernel analysis module from the corresponding trace
246 */
247 KernelAnalysisModule kernelModule = TmfExperimentUtils.getAnalysisModuleOfClassForHost(vmExperiment, vmHostId, KernelAnalysisModule.class);
248 if (kernelModule == null) {
249 return;
250 }
251
252 VirtualMachineViewEntry threadEntry = entryMap.get(vmHostId + NonNullUtils.nullToEmptyString(Messages.VmView_threads));
253 if (threadEntry == null) {
254 threadEntry = new VirtualMachineViewEntry.VmEntryBuilder(NonNullUtils.nullToEmptyString(Messages.VmView_threads), startTime, endTime, vmExperiment).build();
255 entryMap.put(vmHostId + NonNullUtils.nullToEmptyString(Messages.VmView_threads), threadEntry);
256 vmEntry.addChild(threadEntry);
257 } else {
258 threadEntry.updateEndTime(endTime);
259 }
260
261 String vmName = vmEntry.getVmName();
262 if (vmName == null) {
263 return;
264 }
265
266 /*
267 * Display an entry for each thread.
268 *
269 * For each interval that is in a running status, intersect with the
270 * status of the virtual CPU it is currently running on
271 */
272 Collection<Integer> threadIds = KernelThreadInformationProvider.getThreadIds(kernelModule);
273 for (Integer threadId : threadIds) {
274 if (threadId == -1) {
275 continue;
276 }
277 VirtualMachineViewEntry oneThreadEntry = entryMap.get(vmHostId + ':' + threadId);
278 if (oneThreadEntry != null) {
279 oneThreadEntry.updateEndTime(endTime);
280 continue;
281 }
282 /*
283 * FIXME: Only add threads that are active during the trace
284 */
285 String threadName = KernelThreadInformationProvider.getExecutableName(kernelModule, threadId);
286 String tidString = NonNullUtils.checkNotNull(threadId.toString());
287 threadName = (threadName != null) ? tidString + ':' + ' ' + threadName : tidString;
288 oneThreadEntry = new VirtualMachineViewEntry.VmEntryBuilder(threadName, startTime, endTime, vmExperiment).setId(threadName).setVmName(vmName).setNumericId(threadId).setType(Type.THREAD).build();
289
290 threadEntry.addChild(oneThreadEntry);
291 entryMap.put(vmHostId + ':' + threadId, oneThreadEntry);
292 }
293
294 }
295
296 private void buildEntryEventLists(ArrayList<@NonNull VirtualMachineViewEntry> entryList, ITmfStateSystem ssq, long startTime, long endTime, IProgressMonitor monitor) {
297 for (VirtualMachineViewEntry entry : entryList) {
298 if (monitor.isCanceled()) {
299 return;
300 }
301 buildEntryEventList(entry, ssq, startTime, endTime, monitor);
302 }
303 }
304
b1a7aebb
MG
305 private void buildEntryEventList(TimeGraphEntry entry, ITmfStateSystem ssq, long start, long end, IProgressMonitor monitor) {
306 if (start < entry.getEndTime() && end > entry.getStartTime()) {
307
308 long startTime = Math.max(start, entry.getStartTime());
309 long endTime = Math.min(end + 1, entry.getEndTime());
310 long resolution = Math.max(1, (end - ssq.getStartTime()) / getDisplayWidth());
311 List<ITimeEvent> eventList = getEventList(entry, startTime, endTime, resolution, monitor);
312 entry.setEventList(eventList);
313 redraw();
314 for (ITimeGraphEntry child : entry.getChildren()) {
315 if (!(child instanceof TimeGraphEntry)) {
316 continue;
317 }
318 if (monitor.isCanceled()) {
319 return;
320 }
321 buildEntryEventList((TimeGraphEntry) child, ssq, start, end, monitor);
322 }
323 }
324 }
325
326 @Override
327 protected @Nullable List<ITimeEvent> getEventList(TimeGraphEntry entry,
328 long startTime, long endTime, long resolution,
329 IProgressMonitor monitor) {
330 if (!(entry instanceof VirtualMachineViewEntry)) {
331 return null;
332 }
333 if (monitor.isCanceled()) {
334 return null;
335 }
336
337 VirtualMachineViewEntry vmEntry = (VirtualMachineViewEntry) entry;
338
339 switch (vmEntry.getType()) {
340 case THREAD: {
507e1c50 341 return getThreadEventList(vmEntry, endTime, monitor);
b1a7aebb
MG
342 }
343 case VCPU: {
507e1c50 344 return getVcpuEventList(vmEntry, startTime, endTime, resolution, monitor);
b1a7aebb
MG
345 }
346 case VM: {
347 VirtualMachineExperiment experiment = vmEntry.getExperiment();
507e1c50 348 VirtualMachineCpuAnalysis vmAnalysis = TmfTraceUtils.getAnalysisModuleOfClass(experiment, VirtualMachineCpuAnalysis.class, VirtualMachineCpuAnalysis.ID);
b1a7aebb
MG
349 if (vmAnalysis == null) {
350 break;
351 }
352 Multimap<Integer, ITmfStateInterval> updatedThreadIntervals = vmAnalysis.getUpdatedThreadIntervals(vmEntry.getNumericId(), startTime, endTime, resolution, monitor);
353 vmEntry.setThreadIntervals(updatedThreadIntervals);
354 }
355 break;
356 case NULL:
357 /* These entry types are not used in this view */
358 break;
359 default:
360 break;
361 }
362
363 return null;
364 }
365
507e1c50 366 private static @Nullable List<@NonNull ITimeEvent> getVcpuEventList(VirtualMachineViewEntry vmEntry, long startTime, long endTime, long resolution, IProgressMonitor monitor) {
b1a7aebb
MG
367 List<ITimeEvent> eventList = null;
368 try {
369 int quark = vmEntry.getNumericId();
370
371 ITmfStateSystem ssq = TmfStateSystemAnalysisModule.getStateSystem(vmEntry.getExperiment(), VirtualMachineCpuAnalysis.ID);
372 if (ssq == null) {
373 return Collections.EMPTY_LIST;
374 }
375 final long realStart = Math.max(startTime, ssq.getStartTime());
376 final long realEnd = Math.min(endTime, ssq.getCurrentEndTime() + 1);
377 if (realEnd <= realStart) {
378 return Collections.EMPTY_LIST;
379 }
380 quark = ssq.getQuarkRelative(quark, VmAttributes.STATUS);
381 List<ITmfStateInterval> statusIntervals = StateSystemUtils.queryHistoryRange(ssq, quark, realStart, realEnd - 1, resolution, monitor);
b1a7aebb 382
507e1c50 383 eventList = parseIntervalsForEvents(vmEntry, statusIntervals, endTime, monitor);
b1a7aebb
MG
384 } catch (AttributeNotFoundException | TimeRangeException | StateValueTypeException e) {
385 Activator.getDefault().logError("Error getting event list", e); //$NON-NLS-1$
386 } catch (StateSystemDisposedException e) {
387 /* Ignored */
388 }
389 return eventList;
390 }
391
507e1c50 392 private static @Nullable List<@NonNull ITimeEvent> getThreadEventList(VirtualMachineViewEntry vmEntry, long endTime, IProgressMonitor monitor) {
b1a7aebb 393 List<ITimeEvent> eventList = null;
507e1c50
GB
394 Collection<ITmfStateInterval> threadIntervals = getThreadIntervalsForEntry(vmEntry);
395
396 if (threadIntervals != null) {
397 /*
398 * FIXME: I think the key for the alpha bug when alpha overlaps
399 * multiple events is around here
400 *
401 * Hint by Patrick: "The problem is that the thread intervals
402 * are sorted by start time, and drawn in that order.
403 *
404 * Given the intervals: Blue [0,10] Alpha [5,15] Red [10,20]
405 *
406 * Blue is drawn, then Alpha makes DarkBlue from [5,10] and
407 * DarkBackground from [10,15], then Red is drawn over [10,20],
408 * overwriting the DarkBackground. There is no DarkRed.
409 *
410 * For this to work you would have to draw all real states
411 * first, then all alpha states second.
412 *
413 * I think this would also have the side-effect that the find
414 * item used for tool tips would always find the real event and
415 * never the alpha event. This might be what we want. Right now
416 * the tool tip has State: (multiple).
417 *
418 * But using the Next Event button, we would skip to the next
419 * real event and not at the preemption event. Maybe not what we
420 * want.
421 *
422 * Maybe what we need is separate thread interval events:
423 *
424 * Blue [0,5] Preempted Blue [5,10] Preempted Red [10,15] Red
425 * [15,20]...
426 *
427 * The preempted events would have the real state value, but
428 * with a flag for alpha to be used in the postDrawEvent."
429 */
430 eventList = parseIntervalsForEvents(vmEntry, threadIntervals, endTime, monitor);
431 }
432 return eventList;
433 }
434
435 private static @Nullable List<@NonNull ITimeEvent> parseIntervalsForEvents(VirtualMachineViewEntry vmEntry, Collection<@NonNull ITmfStateInterval> intervals, long endTime, IProgressMonitor monitor) {
436 List<ITimeEvent> eventList = new ArrayList<>(intervals.size());
437 long lastEndTime = -1;
438 for (ITmfStateInterval interval : intervals) {
439 if (monitor.isCanceled()) {
440 return null;
441 }
442
443 long time = interval.getStartTime();
444 long duration = interval.getEndTime() - time + 1;
445 if (!interval.getStateValue().isNull()) {
446 int status = interval.getStateValue().unboxInt();
447 if (lastEndTime != time && lastEndTime != -1) {
448 eventList.add(new TimeEvent(vmEntry, lastEndTime, time - lastEndTime));
449 }
450 eventList.add(new TimeEvent(vmEntry, time, duration, status));
451 } else if (lastEndTime == -1 || time + duration >= endTime) {
452 /* add null event if it intersects the start or end time */
453 eventList.add(new NullTimeEvent(vmEntry, time, duration));
454 }
455 lastEndTime = time + duration;
456 }
457
458 return eventList;
459 }
460
461 private static @Nullable Collection<@NonNull ITmfStateInterval> getThreadIntervalsForEntry(VirtualMachineViewEntry vmEntry) {
462 Collection<ITmfStateInterval> threadIntervals = null;
463
b1a7aebb 464 /*
507e1c50
GB
465 * The parent VM entry will contain the thread intervals for all
466 * threads. Just take the list from there
b1a7aebb 467 */
b1a7aebb
MG
468 ITimeGraphEntry parent = vmEntry.getParent();
469 while (threadIntervals == null && parent != null) {
470 if (parent instanceof VirtualMachineViewEntry) {
471 threadIntervals = ((VirtualMachineViewEntry) parent).getThreadIntervals(vmEntry.getNumericId());
472 }
473 if (parent instanceof TimeGraphEntry) {
474 parent = ((TimeGraphEntry) parent).getParent();
475 }
476 }
507e1c50 477 return threadIntervals;
b1a7aebb
MG
478 }
479
480 @Override
481 protected Iterable<ITmfTrace> getTracesToBuild(@Nullable ITmfTrace trace) {
482 if (trace == null) {
483 return NonNullUtils.checkNotNull(Collections.EMPTY_SET);
484 }
485 return NonNullUtils.checkNotNull(Collections.singleton(trace));
486 }
487
488}
This page took 0.047329 seconds and 5 git commands to generate.