Skip to content

Commit 396b8f9

Browse files
committed
vm: Add flow analysis
Signed-off-by: philippe <beliasossim@gmail.com>
1 parent 2fdf319 commit 396b8f9

39 files changed

Lines changed: 4646 additions & 1 deletion

analyses/org.eclipse.tracecompass.incubator.executioncomparison.core/src/org/eclipse/tracecompass/incubator/internal/executioncomparison/core/DifferentialSeqCallGraphAnalysis.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,17 @@ public class DifferentialSeqCallGraphAnalysis extends TmfAbstractAnalysisModule
8989
*/
9090
public DifferentialSeqCallGraphAnalysis() {
9191
super();
92+
9293
// TODO: Make a way to register tracetype->callstack IDs.
9394
fCallStackAnalysisMap.put("org.eclipse.tracecompass.incubator.traceevent.core.trace", "org.eclipse.tracecompass.incubator.traceevent.analysis.callstack"); //$NON-NLS-1$ //$NON-NLS-2$
9495
fCallStackAnalysisMap.put("org.eclipse.linuxtools.lttng2.ust.tracetype", "org.eclipse.tracecompass.lttng2.ust.core.analysis.callstack"); //$NON-NLS-1$ //$NON-NLS-2$
96+
97+
// Adding VM/Native analysis
98+
fCallStackAnalysisMap.put("org.eclipse.linuxtools.lttng2.kernel.tracetype", //$NON-NLS-1$
99+
"org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.flow.analysis.vm.native.callstack"); //$NON-NLS-1$
100+
101+
/*fCallStackAnalysisMap.put("org.eclipse.tracecompass.tmf.core.experiment", //$NON-NLS-1$
102+
"org.eclipse.tracecompass.incubator.overhead.core.analysis.vm.native.callstack"); //$NON-NLS-1$*/
95103
}
96104

97105
/**

vm/org.eclipse.tracecompass.incubator.virtual.machine.analysis.core/META-INF/MANIFEST.MF

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Require-Bundle: org.eclipse.core.runtime,
2121
Export-Package: org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core;x-internal:=true,
2222
org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.data;x-friends:="org.eclipse.tracecompass.incubator.virtual.machine.analysis.core.tests,org.eclipse.tracecompass.incubator.virtual.machine.analysis.ui",
2323
org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.event.matching;x-internal:=true,
24+
org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.flow.analysis.core.data.provider;x-friends:="org.eclipse.tracecompass.incubator.virtual.machine.analysis.ui",
2425
org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.fused;x-friends:="org.eclipse.tracecompass.incubator.virtual.machine.analysis.ui,org.eclipse.tracecompass.incubator.virtual.machine.analysis.core.tests",
2526
org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.fused.handlers;x-friends:="org.eclipse.tracecompass.incubator.virtual.machine.analysis.ui,org.eclipse.tracecompass.incubator.virtual.machine.analysis.core.tests",
2627
org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.model;x-friends:="org.eclipse.tracecompass.incubator.virtual.machine.analysis.core.tests,org.eclipse.tracecompass.incubator.virtual.machine.analysis.ui",

vm/org.eclipse.tracecompass.incubator.virtual.machine.analysis.core/plugin.xml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,28 @@
5252
class="org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.trace.VirtualMachineExperiment">
5353
</tracetype>
5454
</module>
55+
56+
<module
57+
analysis_module="org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.flow.analysis.KvmExitAnalysisModule"
58+
automatic="false"
59+
id="org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.flow.analysis.state.system.module"
60+
name="Exit analysis">
61+
<tracetype
62+
class="org.eclipse.tracecompass.tmf.core.trace.TmfTrace">
63+
</tracetype>
64+
</module>
65+
<module
66+
analysis_module="org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.flow.analysis.VMNativeComparisonAnalysis"
67+
id="org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.flow.analysis.vmcomparison"
68+
name="VM vs Native Comparison">
69+
<tracetype
70+
class="org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment">
71+
</tracetype>
72+
</module>
73+
<module
74+
analysis_module="org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.flow.analysis.VMNativeCallStackAnalysis"
75+
id="org.eclipse.tracecompass.incubator.virtual.machine.analysis.ui.module3"
76+
name="VM Native CallStack">
77+
</module>
5578
</extension>
5679
</plugin>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.flow.analysis;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import java.io.File;
6+
import java.io.FileOutputStream;
7+
import java.io.IOException;
8+
import java.io.PrintWriter;
9+
10+
/**
11+
* Represents a complete execution sequence: Guest → VM Exit → Host → VM Entry
12+
*
13+
* @author philippe
14+
*/
15+
public class ExecutionSequence {
16+
private final List<FlowEvent> guestEvents = new ArrayList<>();
17+
private final List<FlowEvent> hypervisorEvents = new ArrayList<>();
18+
private FlowEvent vmExit;
19+
private FlowEvent vmEntry;
20+
21+
void addGuestEvent(FlowEvent event) {
22+
guestEvents.add(event);
23+
}
24+
25+
void addHypervisorEvent(FlowEvent event) {
26+
hypervisorEvents.add(event);
27+
}
28+
29+
void setVmExit(FlowEvent event) {
30+
this.vmExit = event;
31+
}
32+
33+
void setVmEntry(FlowEvent event) {
34+
this.vmEntry = event;
35+
}
36+
37+
void printSequence() throws IOException {
38+
try (
39+
40+
FileOutputStream fos = new FileOutputStream(new File("/home/philippe/Desktop/virtualized_flow.txt"), true); //$NON-NLS-1$
41+
PrintWriter writer = new PrintWriter(fos)) {
42+
for (FlowEvent guestEvent : guestEvents) {
43+
KernelEventInfo evt = guestEvent.kernelEvent;
44+
System.out.printf(" [GUEST] %s (TID:%d, CPU:%d)\n", evt.name, evt.tid, evt.cpuid); //$NON-NLS-1$
45+
writer.printf(" [GUEST] %s (TID:%d, CPU:%d)\n", evt.name, evt.tid, evt.cpuid); //$NON-NLS-1$
46+
}
47+
48+
// Print VM exit
49+
if (vmExit != null) {
50+
System.out.printf(" ↓ [VM_EXIT] %s (CPU:%d, VCPU:%d, exit_reason:%s)\n", vmExit.kernelEvent.name, //$NON-NLS-1$
51+
vmExit.kernelEvent.cpuid, vmExit.kernelEvent.vcpuid, vmExit.kernelEvent.exitReason);
52+
53+
writer.printf(" ↓ [VM_EXIT] %s (CPU:%d, VCPU:%d, exit_reason:%s)\n", vmExit.kernelEvent.name, //$NON-NLS-1$
54+
vmExit.kernelEvent.cpuid, vmExit.kernelEvent.vcpuid, vmExit.kernelEvent.exitReason);
55+
}
56+
57+
// Print hypervisor events
58+
for (FlowEvent hypervisorEvent : hypervisorEvents) {
59+
KernelEventInfo evt = hypervisorEvent.kernelEvent;
60+
System.out.printf(" [HOST] %s (PID:%d, CPU:%d)\n", evt.name, evt.pid, evt.cpuid); //$NON-NLS-1$
61+
62+
writer.printf(" [HOST] %s (PID:%d, CPU:%d)\n", evt.name, evt.pid, evt.cpuid); //$NON-NLS-1$
63+
}
64+
65+
// Print VM entry
66+
if (vmEntry != null) {
67+
System.out.printf(" ↑ [VM_ENTRY] %s (CPU:%d, VCPU:%d)\n", vmEntry.kernelEvent.name, //$NON-NLS-1$
68+
vmEntry.kernelEvent.cpuid, vmEntry.kernelEvent.vcpuid);
69+
70+
writer.printf(" ↑ [VM_ENTRY] %s (CPU:%d, VCPU:%d)\n", vmEntry.kernelEvent.name, //$NON-NLS-1$
71+
vmEntry.kernelEvent.cpuid, vmEntry.kernelEvent.vcpuid);
72+
}
73+
74+
// Print timing summary
75+
if (!guestEvents.isEmpty() && vmEntry != null) {
76+
long totalDuration = vmEntry.kernelEvent.timestamp -
77+
guestEvents.get(0).kernelEvent.timestamp;
78+
System.out.printf(" Total sequence duration: %d µs\n", totalDuration / 1000); //$NON-NLS-1$
79+
80+
writer.printf(" Total sequence duration: %d µs\n", totalDuration / 1000); //$NON-NLS-1$
81+
}
82+
}
83+
}
84+
85+
boolean isComplete() {
86+
return !guestEvents.isEmpty() && vmExit != null && vmEntry != null;
87+
}
88+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.flow.analysis;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
7+
/**
8+
* Mapping of Exit reason number to their text description
9+
* @author Francois Belias
10+
*/
11+
public class ExitReasonMap {
12+
13+
private static final Map<Integer, String> exitReasonMap = new HashMap<>();
14+
15+
static {
16+
// VMX specific reasons
17+
exitReasonMap.put(0x80000000, "VMX_EXIT_REASONS_FAILED_VMENTRY"); //$NON-NLS-1$
18+
exitReasonMap.put(0x08000000, "VMX_EXIT_REASONS_SGX_ENCLAVE_MODE"); //$NON-NLS-1$
19+
20+
// General exit reasons
21+
exitReasonMap.put(0, "EXIT_REASON_EXCEPTION_NMI"); //$NON-NLS-1$
22+
exitReasonMap.put(1, "EXIT_REASON_EXTERNAL_INTERRUPT"); //$NON-NLS-1$
23+
exitReasonMap.put(2, "EXIT_REASON_TRIPLE_FAULT"); //$NON-NLS-1$
24+
exitReasonMap.put(3, "EXIT_REASON_INIT_SIGNAL"); //$NON-NLS-1$
25+
exitReasonMap.put(4, "EXIT_REASON_SIPI_SIGNAL"); //$NON-NLS-1$
26+
27+
exitReasonMap.put(7, "EXIT_REASON_INTERRUPT_WINDOW"); //$NON-NLS-1$
28+
exitReasonMap.put(8, "EXIT_REASON_NMI_WINDOW"); //$NON-NLS-1$
29+
exitReasonMap.put(9, "EXIT_REASON_TASK_SWITCH"); //$NON-NLS-1$
30+
exitReasonMap.put(10, "EXIT_REASON_CPUID"); //$NON-NLS-1$
31+
exitReasonMap.put(12, "EXIT_REASON_HLT"); //$NON-NLS-1$
32+
exitReasonMap.put(13, "EXIT_REASON_INVD"); //$NON-NLS-1$
33+
exitReasonMap.put(14, "EXIT_REASON_INVLPG"); //$NON-NLS-1$
34+
exitReasonMap.put(15, "EXIT_REASON_RDPMC"); //$NON-NLS-1$
35+
exitReasonMap.put(16, "EXIT_REASON_RDTSC"); //$NON-NLS-1$
36+
exitReasonMap.put(18, "EXIT_REASON_VMCALL"); //$NON-NLS-1$
37+
exitReasonMap.put(19, "EXIT_REASON_VMCLEAR"); //$NON-NLS-1$
38+
exitReasonMap.put(20, "EXIT_REASON_VMLAUNCH"); //$NON-NLS-1$
39+
exitReasonMap.put(21, "EXIT_REASON_VMPTRLD"); //$NON-NLS-1$
40+
exitReasonMap.put(22, "EXIT_REASON_VMPTRST"); //$NON-NLS-1$
41+
exitReasonMap.put(23, "EXIT_REASON_VMREAD"); //$NON-NLS-1$
42+
exitReasonMap.put(24, "EXIT_REASON_VMRESUME"); //$NON-NLS-1$
43+
exitReasonMap.put(25, "EXIT_REASON_VMWRITE"); //$NON-NLS-1$
44+
exitReasonMap.put(26, "EXIT_REASON_VMOFF"); //$NON-NLS-1$
45+
exitReasonMap.put(27, "EXIT_REASON_VMON"); //$NON-NLS-1$
46+
exitReasonMap.put(28, "EXIT_REASON_CR_ACCESS"); //$NON-NLS-1$
47+
exitReasonMap.put(29, "EXIT_REASON_DR_ACCESS"); //$NON-NLS-1$
48+
exitReasonMap.put(30, "EXIT_REASON_IO_INSTRUCTION"); //$NON-NLS-1$
49+
exitReasonMap.put(31, "EXIT_REASON_MSR_READ"); //$NON-NLS-1$
50+
exitReasonMap.put(32, "EXIT_REASON_MSR_WRITE"); //$NON-NLS-1$
51+
exitReasonMap.put(33, "EXIT_REASON_INVALID_STATE"); //$NON-NLS-1$
52+
exitReasonMap.put(34, "EXIT_REASON_MSR_LOAD_FAIL"); //$NON-NLS-1$
53+
exitReasonMap.put(36, "EXIT_REASON_MWAIT_INSTRUCTION"); //$NON-NLS-1$
54+
exitReasonMap.put(37, "EXIT_REASON_MONITOR_TRAP_FLAG"); //$NON-NLS-1$
55+
exitReasonMap.put(39, "EXIT_REASON_MONITOR_INSTRUCTION"); //$NON-NLS-1$
56+
exitReasonMap.put(40, "EXIT_REASON_PAUSE_INSTRUCTION"); //$NON-NLS-1$
57+
exitReasonMap.put(41, "EXIT_REASON_MCE_DURING_VMENTRY"); //$NON-NLS-1$
58+
exitReasonMap.put(43, "EXIT_REASON_TPR_BELOW_THRESHOLD"); //$NON-NLS-1$
59+
exitReasonMap.put(44, "EXIT_REASON_APIC_ACCESS"); //$NON-NLS-1$
60+
exitReasonMap.put(45, "EXIT_REASON_EOI_INDUCED"); //$NON-NLS-1$
61+
exitReasonMap.put(46, "EXIT_REASON_GDTR_IDTR"); //$NON-NLS-1$
62+
exitReasonMap.put(47, "EXIT_REASON_LDTR_TR"); //$NON-NLS-1$
63+
exitReasonMap.put(48, "EXIT_REASON_EPT_VIOLATION"); //$NON-NLS-1$
64+
exitReasonMap.put(49, "EXIT_REASON_EPT_MISCONFIG"); //$NON-NLS-1$
65+
exitReasonMap.put(50, "EXIT_REASON_INVEPT"); //$NON-NLS-1$
66+
exitReasonMap.put(51, "EXIT_REASON_RDTSCP"); //$NON-NLS-1$
67+
exitReasonMap.put(52, "EXIT_REASON_PREEMPTION_TIMER"); //$NON-NLS-1$
68+
exitReasonMap.put(53, "EXIT_REASON_INVVPID"); //$NON-NLS-1$
69+
exitReasonMap.put(54, "EXIT_REASON_WBINVD"); //$NON-NLS-1$
70+
exitReasonMap.put(55, "EXIT_REASON_XSETBV"); //$NON-NLS-1$
71+
exitReasonMap.put(56, "EXIT_REASON_APIC_WRITE"); //$NON-NLS-1$
72+
exitReasonMap.put(57, "EXIT_REASON_RDRAND"); //$NON-NLS-1$
73+
exitReasonMap.put(58, "EXIT_REASON_INVPCID"); //$NON-NLS-1$
74+
exitReasonMap.put(59, "EXIT_REASON_VMFUNC"); //$NON-NLS-1$
75+
exitReasonMap.put(60, "EXIT_REASON_ENCLS"); //$NON-NLS-1$
76+
exitReasonMap.put(61, "EXIT_REASON_RDSEED"); //$NON-NLS-1$
77+
exitReasonMap.put(62, "EXIT_REASON_PML_FULL"); //$NON-NLS-1$
78+
exitReasonMap.put(63, "EXIT_REASON_XSAVES"); //$NON-NLS-1$
79+
exitReasonMap.put(64, "EXIT_REASON_XRSTORS"); //$NON-NLS-1$
80+
exitReasonMap.put(67, "EXIT_REASON_UMWAIT"); //$NON-NLS-1$
81+
exitReasonMap.put(68, "EXIT_REASON_TPAUSE"); //$NON-NLS-1$
82+
exitReasonMap.put(74, "EXIT_REASON_BUS_LOCK"); //$NON-NLS-1$
83+
exitReasonMap.put(75, "EXIT_REASON_NOTIFY"); //$NON-NLS-1$
84+
}
85+
86+
/**
87+
* @param code The code of the exit type
88+
* @return The text describing the exit type
89+
*/
90+
public static String getExitReasonName(int code) {
91+
return exitReasonMap.getOrDefault(code, "UNKNOWN_EXIT_REASON"); //$NON-NLS-1$
92+
}
93+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.flow.analysis;
2+
3+
/**
4+
* Represents a single event in the unified flow
5+
*/
6+
public class FlowEvent {
7+
final KernelEventInfo kernelEvent;
8+
final FlowEventType type;
9+
long correlatedGuestTimestamp = -1; // For hypervisor events
10+
11+
FlowEvent(KernelEventInfo kernelEvent, FlowEventType type) {
12+
this.kernelEvent = kernelEvent;
13+
this.type = type;
14+
}
15+
}
16+
17+
18+
/**
19+
* Types of events in the unified flow
20+
*/
21+
enum FlowEventType {
22+
GUEST_EVENT, // Normal guest process event
23+
VM_EXIT, // VM exit to hypervisor
24+
HYPERVISOR_EVENT, // Host/hypervisor processing
25+
VM_ENTRY, // VM entry back to guest
26+
NATIVE // Native system
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.flow.analysis;
2+
3+
4+
/**
5+
*
6+
*/
7+
public class KernelEventInfo {
8+
/**
9+
*
10+
*/
11+
public final String name;
12+
public final long timestamp;
13+
public final int pid;
14+
public final int tid;
15+
public final String processName;
16+
public final TraceType source;
17+
public final int cpuid;
18+
public final int vcpuid;
19+
public final String exitReason;
20+
21+
/**
22+
* @param name
23+
* @param timestamp
24+
* @param pid
25+
* @param tid
26+
* @param processName
27+
* @param source
28+
* @param cpuid
29+
* @param vcpuid
30+
* @param exitReason
31+
*/
32+
@SuppressWarnings("javadoc")
33+
public KernelEventInfo(String name, long timestamp, int pid, int tid, String processName,
34+
TraceType source, int cpuid, int vcpuid, String exitReason) {
35+
this.name = name;
36+
this.timestamp = timestamp;
37+
this.pid = pid;
38+
this.tid = tid;
39+
this.processName = processName;
40+
this.source = source;
41+
this.cpuid = cpuid;
42+
this.vcpuid = vcpuid;
43+
this.exitReason = exitReason;
44+
45+
}
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/***********************************************************************
2+
* KVM Exit Analysis Module
3+
* This module analyzes and tracks KVM exit event per cpu
4+
***********************************************************************/
5+
6+
package org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.flow.analysis;
7+
8+
9+
import java.util.Objects;
10+
11+
import org.eclipse.jdt.annotation.NonNull;
12+
import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider;
13+
import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
14+
15+
16+
/**
17+
* Analysis module that builds a state system from KVM exit events in a trace.
18+
* It tracks the number and types of VM exits for each CPU.
19+
*/
20+
public class KvmExitAnalysisModule extends TmfStateSystemAnalysisModule {
21+
22+
/**
23+
* The ID of this analysis module
24+
*/
25+
public static final @NonNull String ID = "org.eclipse.tracecompass.incubator.internal.virtual.machine.analysis.core.flow.analysis.state.system.module"; //$NON-NLS-1$
26+
27+
@Override
28+
protected @NonNull ITmfStateProvider createStateProvider() {
29+
return new KvmExitStateProvider(Objects.requireNonNull(getTrace()));
30+
}
31+
32+
33+
@Override
34+
protected @NonNull String getFullHelpText() {
35+
return "This analysis tracks KVM exit events by CPU. It shows when a virtual machine " + //$NON-NLS-1$
36+
"exits to the hypervisor, which helps identify performance bottlenecks in " + //$NON-NLS-1$
37+
"virtualized environments."; //$NON-NLS-1$
38+
}
39+
}

0 commit comments

Comments
 (0)