mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-05-23 15:44:09 +00:00
Originally, we don't format the output of analyser well. It is hard to read the result. This patch make every entry of the result align with the corresponding title to make it easier for users to read. Without patch: Event NR_Exit NR_Exit/Sec Time Consumed(cycles) Time Percentage VMEXIT_INTERRUPT_WINDOW 78090 130.15 40 0.01 VMEXIT_CR_ACCESS 0 0.00 0 0.00 VMEXIT_APICV_ACCESS 0 0.00 0 0.00 VMEXIT_EXCEPTION_OR_NMI 0 0.00 0 0.00 VMEXIT_RDTSC 0 0.00 0 0.00 ... Vector Count NR_Exit/Sec 0x000000f0 82337 137.23 0x000000ef 247713 412.85 With patch: Event NR_Exit NR_Exit/Sec Time Consumed(cycles) Time percentage VMEXIT_APICV_WRITE 13352 22.25 14331304 0.00 VMEXIT_WRMSR 309085 515.14 241166212 0.02 VMEXIT_INTERRUPT_WINDOW 78090 130.15 76841734 0.01 ... Vector Count NR_Exit/Sec 0x000000f0 82337 137.23 0x000000ef 247713 412.85 Signed-off-by: Kaige Fu <kaige.fu@intel.com> Reviewed-by: Eddie Dong <eddie.dong@intel.com> Acked-by: Yan, Like <like.yan@intel.com>
218 lines
6.6 KiB
Python
Executable File
218 lines
6.6 KiB
Python
Executable File
#!/usr/bin/python3
|
|
# -*- coding: UTF-8 -*-
|
|
|
|
"""
|
|
This script defines the function to do the vm_exit analysis
|
|
"""
|
|
|
|
import csv
|
|
import struct
|
|
from config import TSC_FREQ
|
|
|
|
TSC_BEGIN = 0
|
|
TSC_END = 0
|
|
TOTAL_NR_EXITS = 0
|
|
|
|
VM_EXIT = 0x10
|
|
VM_ENTER = 0x11
|
|
VMEXIT_ENTRY = 0x10000
|
|
|
|
LIST_EVENTS = {
|
|
'VMEXIT_EXCEPTION_OR_NMI': VMEXIT_ENTRY + 0x00000000,
|
|
'VMEXIT_EXTERNAL_INTERRUPT': VMEXIT_ENTRY + 0x00000001,
|
|
'VMEXIT_INTERRUPT_WINDOW': VMEXIT_ENTRY + 0x00000002,
|
|
'VMEXIT_CPUID': VMEXIT_ENTRY + 0x00000004,
|
|
'VMEXIT_RDTSC': VMEXIT_ENTRY + 0x00000010,
|
|
'VMEXIT_VMCALL': VMEXIT_ENTRY + 0x00000012,
|
|
'VMEXIT_CR_ACCESS': VMEXIT_ENTRY + 0x0000001C,
|
|
'VMEXIT_IO_INSTRUCTION': VMEXIT_ENTRY + 0x0000001E,
|
|
'VMEXIT_RDMSR': VMEXIT_ENTRY + 0x0000001F,
|
|
'VMEXIT_WRMSR': VMEXIT_ENTRY + 0x00000020,
|
|
'VMEXIT_EPT_VIOLATION': VMEXIT_ENTRY + 0x00000030,
|
|
'VMEXIT_EPT_MISCONFIGURATION': VMEXIT_ENTRY + 0x00000031,
|
|
'VMEXIT_RDTSCP': VMEXIT_ENTRY + 0x00000033,
|
|
'VMEXIT_APICV_WRITE': VMEXIT_ENTRY + 0x00000038,
|
|
'VMEXIT_APICV_ACCESS': VMEXIT_ENTRY + 0x00000039,
|
|
'VMEXIT_APICV_VIRT_EOI': VMEXIT_ENTRY + 0x0000003A,
|
|
'VMEXIT_UNHANDLED': 0x20000
|
|
}
|
|
|
|
NR_EXITS = {
|
|
'VMEXIT_EXCEPTION_OR_NMI': 0,
|
|
'VMEXIT_EXTERNAL_INTERRUPT': 0,
|
|
'VMEXIT_INTERRUPT_WINDOW': 0,
|
|
'VMEXIT_CPUID': 0,
|
|
'VMEXIT_RDTSC': 0,
|
|
'VMEXIT_VMCALL': 0,
|
|
'VMEXIT_CR_ACCESS': 0,
|
|
'VMEXIT_IO_INSTRUCTION': 0,
|
|
'VMEXIT_RDMSR': 0,
|
|
'VMEXIT_WRMSR': 0,
|
|
'VMEXIT_APICV_ACCESS': 0,
|
|
'VMEXIT_APICV_VIRT_EOI': 0,
|
|
'VMEXIT_EPT_VIOLATION': 0,
|
|
'VMEXIT_EPT_MISCONFIGURATION': 0,
|
|
'VMEXIT_RDTSCP': 0,
|
|
'VMEXIT_APICV_WRITE': 0,
|
|
'VMEXIT_UNHANDLED': 0
|
|
}
|
|
|
|
TIME_IN_EXIT = {
|
|
'VMEXIT_EXCEPTION_OR_NMI': 0,
|
|
'VMEXIT_EXTERNAL_INTERRUPT': 0,
|
|
'VMEXIT_INTERRUPT_WINDOW': 0,
|
|
'VMEXIT_CPUID': 0,
|
|
'VMEXIT_RDTSC': 0,
|
|
'VMEXIT_VMCALL': 0,
|
|
'VMEXIT_CR_ACCESS': 0,
|
|
'VMEXIT_IO_INSTRUCTION': 0,
|
|
'VMEXIT_RDMSR': 0,
|
|
'VMEXIT_WRMSR': 0,
|
|
'VMEXIT_APICV_ACCESS': 0,
|
|
'VMEXIT_APICV_VIRT_EOI': 0,
|
|
'VMEXIT_EPT_VIOLATION': 0,
|
|
'VMEXIT_EPT_MISCONFIGURATION': 0,
|
|
'VMEXIT_RDTSCP': 0,
|
|
'VMEXIT_APICV_WRITE': 0,
|
|
'VMEXIT_UNHANDLED': 0
|
|
}
|
|
|
|
# 4 * 64bit per trace entry
|
|
TRCREC = "QQQQ"
|
|
|
|
def parse_trace_data(ifile):
|
|
"""parse the trace data file
|
|
Args:
|
|
ifile: input trace data file
|
|
Return:
|
|
None
|
|
"""
|
|
|
|
global TSC_BEGIN, TSC_END, TOTAL_NR_EXITS
|
|
last_ev_id = ''
|
|
tsc_enter = 0
|
|
tsc_exit = 0
|
|
tsc_last_exit_period = 0
|
|
|
|
fd = open(ifile, 'rb')
|
|
|
|
while True:
|
|
try:
|
|
line = fd.read(struct.calcsize(TRCREC))
|
|
if not line:
|
|
break
|
|
(tsc, event, d1, d2) = struct.unpack(TRCREC, line)
|
|
|
|
event = event & 0xffffffffffff
|
|
|
|
if event == VM_ENTER:
|
|
if TSC_BEGIN == 0:
|
|
TSC_BEGIN = tsc
|
|
tsc_exit = tsc
|
|
TOTAL_NR_EXITS = 0
|
|
|
|
tsc_enter = tsc
|
|
TSC_END = tsc_enter
|
|
tsc_last_exit_period = tsc_enter - tsc_exit
|
|
|
|
if tsc_last_exit_period != 0:
|
|
TIME_IN_EXIT[last_ev_id] += tsc_last_exit_period
|
|
|
|
elif event == VM_EXIT:
|
|
tsc_exit = tsc
|
|
TSC_END = tsc_exit
|
|
TOTAL_NR_EXITS += 1
|
|
|
|
else:
|
|
for key in LIST_EVENTS.keys():
|
|
if event == LIST_EVENTS.get(key):
|
|
NR_EXITS[key] += 1
|
|
last_ev_id = key
|
|
|
|
else:
|
|
# Skip the non-VMEXIT trace event
|
|
pass
|
|
|
|
except (IOError, struct.error) as e:
|
|
sys.exit()
|
|
|
|
def generate_report(ofile, freq):
|
|
""" generate analysis report
|
|
Args:
|
|
ofile: output report
|
|
freq: TSC frequency of the device trace data from
|
|
Return:
|
|
None
|
|
"""
|
|
global TSC_BEGIN, TSC_END, TOTAL_NR_EXITS
|
|
|
|
csv_name = ofile + '.csv'
|
|
try:
|
|
with open(csv_name, 'a') as filep:
|
|
f_csv = csv.writer(filep)
|
|
|
|
total_exit_time = 0
|
|
rt_cycle = TSC_END - TSC_BEGIN
|
|
assert rt_cycle != 0, "total_run_time in cycle is 0,\
|
|
tsc_end %d, tsc_begin %d"\
|
|
% (TSC_END, TSC_BEGIN)
|
|
|
|
rt_sec = float(rt_cycle) / (float(freq) * 1000 * 1000)
|
|
|
|
for event in LIST_EVENTS:
|
|
total_exit_time += TIME_IN_EXIT[event]
|
|
|
|
print ("Total run time: %d cycles" % (rt_cycle))
|
|
print ("TSC Freq: %f MHz" % (freq))
|
|
print ("Total run time: %d sec" % (rt_sec))
|
|
|
|
f_csv.writerow(['Run time(cycles)', 'Run time(Sec)', 'Freq(MHz)'])
|
|
f_csv.writerow(['%d' % (rt_cycle),
|
|
'%.3f' % (rt_sec),
|
|
'%d' % (freq)])
|
|
|
|
print ("%-28s\t%-12s\t%-12s\t%-24s\t%-16s" % ("Event", "NR_Exit",
|
|
"NR_Exit/Sec", "Time Consumed(cycles)", "Time percentage"))
|
|
f_csv.writerow(['Exit_Reason',
|
|
'NR_Exit',
|
|
'NR_Exit/Sec',
|
|
'Time Consumed(cycles)',
|
|
'Time Percentage'])
|
|
|
|
for event in LIST_EVENTS:
|
|
ev_freq = float(NR_EXITS[event]) / rt_sec
|
|
pct = float(TIME_IN_EXIT[event]) * 100 / float(rt_cycle)
|
|
|
|
print ("%-28s\t%-12d\t%-12.2f\t%-24d\t%-16.2f" %
|
|
(event, NR_EXITS[event], ev_freq, TIME_IN_EXIT[event], pct))
|
|
row = [event, NR_EXITS[event], '%.2f' % ev_freq, TIME_IN_EXIT[event],
|
|
'%2.2f' % (pct)]
|
|
f_csv.writerow(row)
|
|
|
|
ev_freq = float(TOTAL_NR_EXITS) / rt_sec
|
|
pct = float(total_exit_time) * 100 / float(rt_cycle)
|
|
print("%-28s\t%-12d\t%-12.2f\t%-24d\t%-16.2f"
|
|
% ("Total", TOTAL_NR_EXITS, ev_freq, total_exit_time, pct))
|
|
row = ["Total", TOTAL_NR_EXITS, '%.2f' % ev_freq, total_exit_time,
|
|
'%2.2f' % (pct)]
|
|
f_csv.writerow(row)
|
|
|
|
except IOError as err:
|
|
print ("Output File Error: " + str(err))
|
|
|
|
def analyze_vm_exit(ifile, ofile):
|
|
"""do the vm exits analysis
|
|
Args:
|
|
ifile: input trace data file
|
|
ofile: output report file
|
|
Return:
|
|
None
|
|
"""
|
|
|
|
print("VM exits analysis started... \n\tinput file: %s\n"
|
|
"\toutput file: %s.csv" % (ifile, ofile))
|
|
|
|
parse_trace_data(ifile)
|
|
# save report to the output file
|
|
generate_report(ofile, TSC_FREQ)
|