acrn-hypervisor/tools/acrntrace/scripts/vmexit_analyze.py
Kaige Fu 18d44cc928 tools: acrnalyze: Make the result easier to read
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>
2018-08-15 10:59:31 +08:00

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)