1 /*******************************************************************************
2 * Copyright (c) 2014, 2015 École Polytechnique de Montréal
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
10 * Mohamad Gebai - Initial API and implementation
11 * Geneviève Bastien - Initial API and implementation
12 *******************************************************************************/
14 package org
.eclipse
.tracecompass
.internal
.lttng2
.kernel
.core
.analysis
.vm
.module
;
16 import java
.util
.Comparator
;
17 import java
.util
.HashSet
;
20 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
21 import org
.eclipse
.jdt
.annotation
.NonNull
;
22 import org
.eclipse
.jdt
.annotation
.Nullable
;
23 import org
.eclipse
.tracecompass
.analysis
.os
.linux
.core
.kernelanalysis
.KernelAnalysis
;
24 import org
.eclipse
.tracecompass
.analysis
.os
.linux
.core
.kernelanalysis
.KernelThreadInformationProvider
;
25 import org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
;
26 import org
.eclipse
.tracecompass
.internal
.lttng2
.kernel
.core
.analysis
.vm
.VcpuStateValues
;
27 import org
.eclipse
.tracecompass
.internal
.lttng2
.kernel
.core
.analysis
.vm
.VmAttributes
;
28 import org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystem
;
29 import org
.eclipse
.tracecompass
.statesystem
.core
.StateSystemUtils
;
30 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.AttributeNotFoundException
;
31 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.StateSystemDisposedException
;
32 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.ITmfStateInterval
;
33 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.TmfStateInterval
;
34 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
35 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.TmfStateValue
;
36 import org
.eclipse
.tracecompass
.tmf
.core
.analysis
.IAnalysisModule
;
37 import org
.eclipse
.tracecompass
.tmf
.core
.statesystem
.ITmfStateProvider
;
38 import org
.eclipse
.tracecompass
.tmf
.core
.statesystem
.TmfStateSystemAnalysisModule
;
39 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
40 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceManager
;
41 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceUtils
;
42 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.experiment
.TmfExperiment
;
43 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.experiment
.TmfExperimentUtils
;
45 import com
.google
.common
.collect
.ImmutableSet
;
46 import com
.google
.common
.collect
.Multimap
;
47 import com
.google
.common
.collect
.TreeMultimap
;
50 * Module for the virtual machine CPU analysis. It tracks the status of the
51 * virtual CPUs for each guest of the experiment.
53 * @author Mohamad Gebai
54 * @author Geneviève Bastien
56 public class VirtualMachineCpuAnalysis
extends TmfStateSystemAnalysisModule
{
58 // TODO: Update with event layout when requirements are back */
59 static final Set
<String
> REQUIRED_EVENTS
= NonNullUtils
.checkNotNull(ImmutableSet
.<String
> of(
60 // LttngStrings.SCHED_SWITCH
63 /* State value for a preempted virtual CPU */
64 private static final ITmfStateValue VCPU_PREEMPT_VALUE
= TmfStateValue
.newValueInt(VcpuStateValues
.VCPU_PREEMPT
);
69 public VirtualMachineCpuAnalysis() {
74 protected ITmfStateProvider
createStateProvider() {
75 ITmfTrace trace
= getTrace();
76 if (!(trace
instanceof TmfExperiment
)) {
77 throw new IllegalStateException();
79 return new VirtualMachineStateProvider((TmfExperiment
) trace
);
83 protected @NonNull StateSystemBackendType
getBackendType() {
84 return StateSystemBackendType
.FULL
;
88 public String
getHelpText() {
89 return Messages
.getMessage(Messages
.VirtualMachineCPUAnalysis_Help
);
93 protected Iterable
<IAnalysisModule
> getDependentAnalyses() {
94 Set
<IAnalysisModule
> modules
= new HashSet
<>();
95 /* Depends on the LTTng Kernel analysis modules */
96 for (ITmfTrace trace
: TmfTraceManager
.getTraceSet(getTrace())) {
97 for (KernelAnalysis module
: TmfTraceUtils
.getAnalysisModulesOfClass(trace
, KernelAnalysis
.class)) {
104 private static Multimap
<Integer
, ITmfStateInterval
> createThreadMultimap() {
107 * Create the multimap for threads with the appropriate comparator
108 * objects for keys and values
110 final Multimap
<Integer
, ITmfStateInterval
> map
= NonNullUtils
.checkNotNull(TreeMultimap
.<Integer
, ITmfStateInterval
> create(
111 new Comparator
<Integer
>() {
113 public int compare(@Nullable Integer arg0
, @Nullable Integer arg1
) {
115 * Keys do not have to be sorted, just use natural
118 if (arg0
== null || arg1
== null) {
121 return arg0
.compareTo(arg1
);
123 }, new Comparator
<ITmfStateInterval
>() {
125 public int compare(@Nullable ITmfStateInterval arg0
, @Nullable ITmfStateInterval arg1
) {
126 if (arg0
== null || arg1
== null) {
129 if (arg1
.getStateValue() == VCPU_PREEMPT_VALUE
&& arg0
.getStateValue() != VCPU_PREEMPT_VALUE
) {
131 * For VCPU_PREEMPT state values, the state has to
132 * be after any other state that it overlaps,
133 * because those intervals usually decorate the
136 if (((Long
) arg0
.getEndTime()).compareTo(arg1
.getStartTime()) < 0) {
139 return ((Long
) arg0
.getStartTime()).compareTo(arg1
.getEndTime());
141 /* Otherwise, we use ordering by start time */
142 return (((Long
) arg0
.getStartTime()).compareTo(arg1
.getStartTime()));
149 * Get the status intervals for the threads from a virtual machine. Those
150 * intervals are correlated with the data from the virtual CPU's preemption
153 * This method uses the Linux Kernel Analysis data for the thread's status
157 * The quark of the virtual machine
159 * The start time of the period to get the intervals from
161 * The end time of the period to get the intervals from
165 * A progress monitor for this task
166 * @return A map of status intervals for the machine's threads, including
167 * preempted intervals. Intervals from the thread status and the CPU
168 * preemption status overlap and are ordered such that CPU
169 * preemption intervals are after any interval they overlap with
171 public Multimap
<Integer
, ITmfStateInterval
> getUpdatedThreadIntervals(int vmQuark
, long start
, long end
, long resolution
, IProgressMonitor monitor
) {
173 final Multimap
<Integer
, ITmfStateInterval
> map
= createThreadMultimap();
175 ITmfStateSystem ss
= getStateSystem();
179 ITmfTrace trace
= getTrace();
180 if (!(trace
instanceof TmfExperiment
)) {
184 String vmHostId
= NonNullUtils
.checkNotNull(ss
.getAttributeName(vmQuark
));
185 KernelAnalysis kernelModule
= TmfExperimentUtils
.getAnalysisModuleOfClassForHost((TmfExperiment
) trace
, vmHostId
, KernelAnalysis
.class);
186 if (kernelModule
== null) {
191 * Initialize the map with the original status intervals from the kernel
194 for (Integer tid
: KernelThreadInformationProvider
.getThreadIds(kernelModule
)) {
196 throw new IllegalStateException();
198 map
.putAll(tid
, KernelThreadInformationProvider
.getStatusIntervalsForThread(kernelModule
, tid
, start
, end
, resolution
, monitor
));
199 if (monitor
.isCanceled()) {
205 /* Correlate thread information with virtual CPU information */
206 for (Integer vcpuQuark
: ss
.getSubAttributes(vmQuark
, false)) {
207 Long virtualCPU
= Long
.parseLong(ss
.getAttributeName(vcpuQuark
));
208 Integer statusQuark
= ss
.getQuarkRelative(vcpuQuark
, VmAttributes
.STATUS
);
210 for (ITmfStateInterval cpuInterval
: StateSystemUtils
.queryHistoryRange(ss
, statusQuark
, start
, end
- 1, resolution
, monitor
)) {
211 ITmfStateValue stateValue
= cpuInterval
.getStateValue();
212 switch (stateValue
.getType()) {
214 int value
= stateValue
.unboxInt();
216 * If the current CPU is either preempted or in
217 * hypervisor mode, add preempted intervals to running
220 if ((value
& (VcpuStateValues
.VCPU_PREEMPT
| VcpuStateValues
.VCPU_VMM
)) == 0) {
223 Integer threadOnCpu
= KernelThreadInformationProvider
.getThreadOnCpu(kernelModule
, virtualCPU
, cpuInterval
.getStartTime());
224 if (threadOnCpu
!= null) {
225 map
.put(threadOnCpu
, new TmfStateInterval(cpuInterval
.getStartTime(), cpuInterval
.getEndTime(), threadOnCpu
, VCPU_PREEMPT_VALUE
));
238 } catch (AttributeNotFoundException
| StateSystemDisposedException e
) {
240 return NonNullUtils
.checkNotNull(map
);