#!/usr/bin/perl

my $tag = "";

my $start_tsc = 0;
my $test_total_tsc = 0;
my $tsc = 0;

my $vmexit_count = 0;
my $vmexit_total_tsc = 0;

my $linecount = 0;
my $vmexit_flag = 0;
my $schedule_flag = 0;
my $schedule_time = 0;
my $total_schedule_time = 0;
my $param1 = 0;
my $param2 = 0;
my $param3 = 0;
my $param4 = 0;
my $param5 = 0;

my $vmexit_reason = 0;
my $vector = 0;
my $mmio = 0;
my $pf_type = 0;


# Reason of VMEXIT
my $EXCEPTION_NMI = 0x0;
my $EXTERNAL_INTERRUPT = 0x1;
my $PENDING_INTERRUPT = 0x7;
my $CPUID = 0xa;
my $HLT = 0xc;
my $INVLPG = 0xe;
my $RDTSC = 0x10;
my $VMCALL = 0x12;
my $CR_ACCESS = 0x1c;
my $DR_ACCESS = 0x1d;
my $IO_INSTRUCTION = 0x1e;
my $MSR_READ = 0x1f;
my $MSR_WRITE = 0x20;


# EXCEPTION_NMI
my $TRAP_no_device = 0x7;
my $TRAP_page_fault = 0xe;

my $TRAP_no_device_count = 0;
my $TRAP_pf_count = 0;

my $TRAP_no_device_total_tsc = 0;
my $TRAP_pf_total_tsc = 0;


# Type of PAGE_FAULT
my $mmio_count = 0;
my $shadow_pf_count = 0;
my $guest_pf_count = 0;

my $mmio_total_tsc = 0;
my $shadow_pf_total_tsc = 0;
my $guest_pf_total_tsc = 0;

my $pf_error_code = 0;

my $mmio_xen_count = 0;
my $mmio_xen_total_tsc = 0;

my $mmio_dm_count = 0;
my $mmio_dm_total_tsc = 0;

# Error Code of SHADOW_FAULT
%shadow_pf_error_code_counts;
%shadow_pf_error_code_total_tscs;

# Error Code of PAGE_FAULT
%guest_pf_error_code_counts;
%guest_pf_error_code_total_tscs;


# CR Access
my $mov_to_cr_count = 0;
my $mov_from_cr_count = 0;
my $clts_count = 0;
my $lmsw_count = 0;

my $mov_to_cr_total_tsc = 0;
my $mov_from_cr_total_tsc = 0;
my $clts_total_tsc = 0;
my $lmsw_total_tsc = 0;


# IO Ports
%io_counts;
%io_total_tscs;

# IO Ports Details
%io_counts1;
%io_total_tscs1;

my $pio_xen_count = 0;
my $pio_xen_total_tsc = 0;

my $pio_dm_count = 0;
my $pio_dm_total_tsc = 0;


# External Interrupts
%ext_intr_counts;
%ext_intr_total_tscs;


# Shadow
my $shadow = 0;
my $shadow_total_tsc = 0;
my $shadow_count = 0;

my $shadow_conflict = 0;
my $shadow_conflict_total_tsc = 0;
my $shadow_conflict_count = 0;

# INVPG Shadow
my $invlpg_shadow_total_tsc = 0;
my $invlpg_shadow_count = 0;

my $invlpg_shadow_conflict_total_tsc = 0;
my $invlpg_shadow_conflict_count = 0;

# CR3 Shadow
my $cr3_shadow_total_tsc = 0;
my $cr3_shadow_count = 0;

my $cr3_shadow_conflict_total_tsc = 0;
my $cr3_shadow_conflict_count = 0;

# Page Fault Shadow
my $pf_shadow_total_tsc = 0;
my $pf_shadow_count = 0;

my $pf_shadow_conflict_total_tsc = 0;
my $pf_shadow_conflict_count = 0;

# Shadow Page Fault Shadow
my $shadow_pf_shadow_total_tsc = 0;
my $shadow_pf_shadow_count = 0;

my $shadow_pf_shadow_conflict_total_tsc = 0;
my $shadow_pf_shadow_conflict_count = 0;

# Guest Page Fault Shadow
my $guest_pf_shadow_total_tsc = 0;
my $guest_pf_shadow_count = 0;

my $guest_pf_shadow_conflict_total_tsc = 0;
my $guest_pf_shadow_conflict_count = 0;

# MMIO shadow
my $mmio_shadow_total_tsc = 0;
my $mmio_shadow_count = 0;

my $mmio_shadow_conflict_total_tsc = 0;
my $mmio_shadow_conflict_count = 0;


my $exception_nmi_total_tsc = 0;
my $exception_nmi_count = 0;

my $external_interrupt_total_tsc = 0;
my $external_interrupt_count = 0;

my $pending_interrupt_total_tsc = 0;
my $pending_interrupt_count = 0;

my $cpuid_total_tsc = 0;
my $cpuid_count = 0;

my $hlt_total_tsc = 0;
my $hlt_count = 0;

my $invlpg_total_tsc = 0;
my $invlpg_count = 0;

my $rdtsc_total_tsc = 0;
my $rdtsc_count = 0;

my $vmcall_total_tsc = 0;
my $vmcall_count = 0;

my $cr_access_total_tsc = 0;
my $cr_access_count = 0;

my $dr_access_total_tsc = 0;
my $dr_access_count = 0;

my $io_instruction_total_tsc = 0;
my $io_instruction_count = 0;

my $msr_read_total_tsc = 0;
my $msr_read_count = 0;

my $msr_write_total_tsc = 0;
my $msr_write_count = 0;

my $schedule_count = 0;
my $schedule_count1 = 0;
my $schedule_count2 = 0;
my $missed = 0;


if (length(@ARGV[0]) == 0) {
    print "Missing argument\n";
    print "Usage: ./generate.pl 'file'\n";
    exit(0);
}

if (!open(REPORT, @ARGV[0])) {
    print "Cant open input file!";
    exit(0);
} else {
    while (<REPORT>) {
        ($cpuid, $tsc, $tag, $param1, $param2, $param3, $param4, $param5) = split(' ');

        # start TSC of records
        if ($start_tsc == 0) {
            $start_tsc = $tsc;
        }

        $linecount++;

        if (index($tag, "VMEXIT") >= 0) {
            if ($vmexit_flag == 0) {
                $vmexit_tsc = $tsc;
            } else {
                print "Can not find its entry: $tsc\n";
                print "$linecount + 1:\t";
                print "$_";
            }
            $vmexit_flag = 1;
            next;
        } elsif (index($tag, "__enter_scheduler") >= 0) {
            $schedule_count = $schedule_count + 1;

            if ($schedule_flag == 0 && $vmexit_flag == 1) {
                $schedule_count1 = $schedule_count1 + 1;
                $schedule_time = $tsc;
                $schedule_flag = 1;
                next;
            } elsif ($schedule_flag == 1 && $vmexit_flag == 1) {
                $schedule_count2 = $schedule_count2 + 1;
                $schedule_time = $tsc - $schedule_time;
                $total_schedule_time = $total_schedule_time + $schedule_time;
            } else {
                $missed = $missed + 1;
                $schedule_time = 0;
            }

            $schedule_flag = 0;
            next;
        } elsif (index($tag, "VMENTRY") >= 0) {
            $vmexit_reason = $param1;

            if ($vmexit_flag == 1) {
                $vmexit_total_tsc += $tsc - $vmexit_tsc;
                parse_reason();
            } else {
                print "Can not find its exit: $tsc\n";
                print "$linecount + 1:\t";
                print "$_";
            }

            $vmexit_flag = 0;
            $vmexit_count++;
            $schedule_time = 0;
            $schedule_flag = 0;
            next;
        }
    }

    print_result();

    print_shadow();

    print "\n\n\n\tTotal schedule count: $schedule_count\n";
    print "\tSwitch Out: $schedule_count1\n";
    print "\tSwitch In: $schedule_count2\n";
    print "\tTotal Schedule Time: $total_schedule_time";
    print "\tMissed: $missed";
    close(REPORT);
}

sub parse_reason()
{
    $vmexit_reason = hex($vmexit_reason);

    $shadow = int($vmexit_reason / 0x80000000);
    if ($shadow == 1) {
        $shadow_total_tsc += $tsc - $vmexit_tsc;
        $shadow_count++;

        $shadow_conflict = int($vmexit_reason / 0xc0000000);
        if ($shadow_conflict == 1) {
            $shadow_conflict_total_tsc += $tsc - $vmexit_tsc;
            $shadow_conflict_count++;
        }
    }

    $mmio = int(($vmexit_reason % 0x10000000) / 0x8000000);

    $pf_type = int(($vmexit_reason % 0x2000000) / 0x1000000);

    $pf_error_code = int(($vmexit_reason % 0x1000000) / 0x10000);

    $vector = int($vmexit_reason / 256) % 256;

    $dm_mmio = int(($vmexit_reason % 0x4000000) / 0x2000000);

    $vmexit_reason = $vmexit_reason % 256;

    if ($vmexit_reason == $MSR_READ) {
        $msr_read_total_tsc += $tsc - $vmexit_tsc;
        $msr_read_count++;
    }

    if ($vmexit_reason == $MSR_WRITE) {
        $msr_write_total_tsc += $tsc - $vmexit_tsc;
        $msr_write_count++;
    }

    if ($vmexit_reason == $PENDING_INTERRUPT) {
        $pending_interrupt_total_tsc += $tsc - $vmexit_tsc;
        $pending_interrupt_count++;
    }

    if ($vmexit_reason == $CPUID) {
        $cpuid_total_tsc += $tsc - $vmexit_tsc;
        $cpuid_count++;
    }

    if ($vmexit_reason == $HLT) {
        $hlt_total_tsc += $tsc - $vmexit_tsc;
        $hlt_count++;
    }

    if ($vmexit_reason == $RDTSC) {
        $rdtsc_total_tsc += $tsc - $vmexit_tsc;
        $rdtsc_count++;
    }

    if ($vmexit_reason == $VMCALL) {
        $vmcall_total_tsc += $tsc - $vmexit_tsc;
        $vmcall_count++;
    }

    if ($vmexit_reason == $DR_ACCESS) {
        $dr_access_total_tsc += $tsc - $vmexit_tsc;
        $dr_access_count++;
    }

    if ($vmexit_reason == $INVLPG) {
        if ($shadow == 1) {
            $invlpg_shadow_total_tsc += $tsc - $vmexit_tsc;
            $invlpg_shadow_count++;

            if ($shadow_conflict == 1) {
                $invlpg_shadow_conflict_total_tsc += $tsc - $vmexit_tsc;
                $invlpg_shadow_conflict_count++;
            }
        }

        $invlpg_total_tsc += $tsc - $vmexit_tsc;
        $invlpg_count++;
    }

    if ($vmexit_reason == $EXCEPTION_NMI) {
        $exception_nmi_total_tsc += $tsc - $vmexit_tsc;
        $exception_nmi_count++;
        parse_exception_nmi();
    }

    if ($vmexit_reason == $EXTERNAL_INTERRUPT) {
        $external_interrupt_total_tsc += $tsc - $vmexit_tsc;
        $external_interrupt_count++;
        ext_int();
    }

    if ($vmexit_reason == $CR_ACCESS) {
        $cr_access_total_tsc += $tsc - $vmexit_tsc;
        $cr_access_count++;
        parse_cr_access();
    }

    if ($vmexit_reason == $IO_INSTRUCTION) {
        $io_instruction_total_tsc += $tsc - $vmexit_tsc;
        $io_instruction_count++;

        $dm_pio = int((hex($param2) % 0x80000000) / 0x40000000);
        if ($dm_pio == 1) {
            $pio_dm_total_tsc += $tsc - $vmexit_tsc;
            $pio_dm_count++;
        } else {
            $pio_xen_total_tsc += $tsc - $vmexit_tsc;
            $pio_xen_count++;
        }

        port_io();
    }
}

sub parse_exception_nmi()
{
    if ($vector == $TRAP_no_device) {
        $TRAP_no_device_total_tsc += $tsc - $vmexit_tsc;
        $TRAP_no_device_count++;
    }

    if ($vector == $TRAP_page_fault) {
        if ($shadow == 1) {
            $pf_shadow_total_tsc += $tsc - $vmexit_tsc;
            $pf_shadow_count++;

            if ($shadow_conflict == 1) {
                $pf_shadow_conflict_total_tsc += $tsc - $vmexit_tsc;
                $pf_shadow_conflict_count++;
            }
        }

        $TRAP_pf_total_tsc += $tsc - $vmexit_tsc;
        $TRAP_pf_count++;
        parse_page_fault();
    }
}

sub parse_page_fault()
{
    if ($pf_type == 1) {
        if ($shadow == 1) {
            $shadow_pf_shadow_total_tsc += $tsc - $vmexit_tsc;
            $shadow_pf_shadow_count++;

            if ($shadow_conflict == 1) {
                $shadow_pf_shadow_conflict_total_tsc += $tsc - $vmexit_tsc;
                $shadow_pf_shadow_conflict_count++;
            }
        }

        $shadow_pf_total_tsc += $tsc - $vmexit_tsc;
        $shadow_pf_count++;
        parse_shadow_pf_error_code();
    } elsif ($pf_type == 0) {
        if ($shadow == 1) {
            $guest_pf_shadow_total_tsc += $tsc - $vmexit_tsc;
            $guest_pf_shadow_count++;

            if ($shadow_conflict == 1) {
                $guest_pf_shadow_conflict_total_tsc += $tsc - $vmexit_tsc;
                $guest_pf_shadow_conflict_count++;
            }
        }

        $guest_pf_total_tsc += $tsc - $vmexit_tsc;
        $guest_pf_count++;
        parse_guest_pf_error_code();
    }

    if ($mmio == 1)
    {
        if ($shadow == 1) {
            $mmio_shadow_total_tsc += $tsc - $vmexit_tsc;
            $mmio_shadow_count++;

            if ($shadow_conflict == 1) {
                $mmio_shadow_conflict_total_tsc += $tsc - $vmexit_tsc;
                $mmio_shadow_conflict_count++;
            }
        }

        if ($dm_mmio == 1) {
            $mmio_dm_total_tsc += $tsc - $vmexit_tsc;
            $mmio_dm_count++;
        } else {
            $mmio_xen_total_tsc += $tsc - $vmexit_tsc;
            $mmio_xen_count++;
        }

        $mmio_total_tsc += $tsc - $vmexit_tsc;
        $mmio_count++;
    }
}

sub parse_shadow_pf_error_code()
{
    $shadow_pf_error_code_total_tscs{$pf_error_code} += $tsc - $vmexit_tsc;
    $shadow_pf_error_code_counts{$pf_error_code}++;
}

sub parse_guest_pf_error_code()
{
    $guest_pf_error_code_total_tscs{$pf_error_code} += $tsc - $vmexit_tsc;
    $guest_pf_error_code_counts{$pf_error_code}++;
}


# IO Ports
%mov_to_crs_counts;
%mov_to_crs_total_tscs;

%mov_from_crs_counts;
%mov_from_crs_total_tscs;

sub parse_cr_access()
{
    $cr_access_type = hex($param2);

    if ($cr_access_type == 0x00) {
        $mov_to_cr_total_tsc += $tsc - $vmexit_tsc;
        $mov_to_cr_count++;
        mov_to_crs();
    } elsif ($cr_access_type == 0x10) {
        $mov_from_cr_total_tsc += $tsc - $vmexit_tsc;
        $mov_from_cr_count++;
        mov_from_crs();
    } elsif ($cr_access_type == 0x20) {
        $clts_total_tsc += $tsc - $vmexit_tsc;
        $clts_count++;
    } elsif ($cr_access_type == 0x30) {
        $lmsw_total_tsc += $tsc - $vmexit_tsc;
        $lmsw_count++;
    }
}

sub port_io()
{
    $port = hex($param2) % 0x10000;

    $io_total_tscs{$port} += $tsc - $vmexit_tsc;
    $io_counts{$port}++;

    $dir = int(hex($param2) / 0x80000000);

    $io_total_tscs1{"$port$dir"} += $tsc - $vmexit_tsc;
    $io_counts1{"$port$dir"}++;
}

sub mov_to_crs()
{
    $cr_index = hex($param3);

    if ($cr_index == 3) {
        if ($shadow == 1) {
            $cr3_shadow_total_tsc += $tsc - $vmexit_tsc;
            $cr3_shadow_count++;

            if ($shadow_conflict == 1) {
                $cr3_shadow_conflict_total_tsc += $tsc - $vmexit_tsc;
                $cr3_shadow_conflict_count++;
            }
        }
    }

    $mov_to_crs_total_tscs{$cr_index} += $tsc - $vmexit_tsc;
    $mov_to_crs_counts{$cr_index}++;
}

sub mov_from_crs()
{
    $cr_index = hex($param3);

    $mov_from_crs_total_tscs{$cr_index} += $tsc - $vmexit_tsc;
    $mov_from_crs_counts{$cr_index}++;
}

sub ext_int()
{
    $ext_intr_total_tscs{hex($param2)} += ($tsc - $vmexit_tsc);
    $ext_intr_counts{hex($param2)}++;
}


sub print_result()
{
    if ($vmexit_count == 0) {
        print "\n\tNo VMExit\n";
        return;
    }
    print "\n\tVMExit/Entry Count:\t$vmexit_count\n";

    if ($vmexit_total_tsc == 0) {
        print "\n\tTotal TSC of Handling VMExits is Zero\n";
        return;
    }
    print "\tTotal TSC of Handling VMExits:\t$vmexit_total_tsc\n";

    $test_total_tsc = $tsc - $start_tsc;
    if ($test_total_tsc == 0) {
        print "\n\tTotal TSC of Test is Zero\n";
        return;
    }
    print "\tTotal TSC of Test:\t$test_total_tsc\n";

    $tmp = $vmexit_total_tsc / $test_total_tsc;
    print "\tTSC Ratio:\t$tmp\n";

    $tmp = $vmexit_total_tsc / $vmexit_count;
    print "\tAverage TSC of handling VMExits:\t$tmp\n";


    print "\n\tType of VMEXIT\tTotal TSC\tTSC Ratio\tTotal Count\tCount Ratio\tAverage TSC\n";
    if ($exception_nmi_count != 0) {
        $tmp = $exception_nmi_total_tsc / $exception_nmi_count;
        $tmp1 = $exception_nmi_total_tsc / $vmexit_total_tsc;
        $tmp2 = $exception_nmi_count / $vmexit_count;
        print "\tEXCEPTION_NMI\t$exception_nmi_total_tsc\t$tmp1\t$exception_nmi_count\t$tmp2\t$tmp\n";
    }
    if ($external_interrupt_count != 0) {
        $tmp = $external_interrupt_total_tsc / $external_interrupt_count;
        $tmp1 = $external_interrupt_total_tsc / $vmexit_total_tsc;
        $tmp2 = $external_interrupt_count / $vmexit_count;
        print "\tEXTERNAL_INTERRUPT\t$external_interrupt_total_tsc\t$tmp1\t$external_interrupt_count\t$tmp2\t$tmp\n";
    }
    if ($pending_interrupt_count != 0) {
        $tmp = $pending_interrupt_total_tsc / $pending_interrupt_count;
        $tmp1 = $pending_interrupt_total_tsc / $vmexit_total_tsc;
        $tmp2 = $pending_interrupt_count / $vmexit_count;
        print "\tPENDING_INTERRUPT\t$pending_interrupt_total_tsc\t$tmp1\t$pending_interrupt_count\t$tmp2\t$tmp\n";
    }
    if ($hlt_count != 0) {
        $tmp = $hlt_total_tsc / $hlt_count;
        $tmp1 = $hlt_total_tsc / $vmexit_total_tsc;
        $tmp2 = $hlt_count / $vmexit_count;
        print "\tHLT\t$hlt_total_tsc\t$tmp1\t$hlt_count\t$tmp2\t$tmp\n";
    }
    if ($io_instruction_count != 0) {
        $tmp = $io_instruction_total_tsc / $io_instruction_count;
        $tmp1 = $io_instruction_total_tsc / $vmexit_total_tsc;
        $tmp2 = $io_instruction_count / $vmexit_count;
        print "\tIO_INSTRUCTION\t$io_instruction_total_tsc\t$tmp1\t$io_instruction_count\t$tmp2\t$tmp\n";
    }
    if ($cr_access_count != 0) {
        $tmp = $cr_access_total_tsc / $cr_access_count;
        $tmp1 = $cr_access_total_tsc / $vmexit_total_tsc;
        $tmp2 = $cr_access_count / $vmexit_count;
        print "\tCR_ACCESS\t$cr_access_total_tsc\t$tmp1\t$cr_access_count\t$tmp2\t$tmp\n";
    }
    if ($invlpg_count != 0) {
        $tmp = $invlpg_total_tsc / $invlpg_count;
        $tmp1 = $invlpg_total_tsc / $vmexit_total_tsc;
        $tmp2 = $invlpg_count / $vmexit_count;
        print "\tINVLPG\t$invlpg_total_tsc\t$tmp1\t$invlpg_count\t$tmp2\t$tmp\n";
    }
    if ($dr_access_count != 0) {
        $tmp = $dr_access_total_tsc / $dr_access_count;
        $tmp1 = $dr_access_total_tsc / $vmexit_total_tsc;
        $tmp2 = $dr_access_count / $vmexit_count;
        print "\tDR_ACCESS\t$dr_access_total_tsc\t$tmp1\t$dr_access_count\t$tmp2\t$tmp\n";
    }
    if ($cpuid_count != 0) {
        $tmp = $cpuid_total_tsc / $cpuid_count;
        $tmp1 = $cpuid_total_tsc / $vmexit_total_tsc;
        $tmp2 = $cpuid_count / $vmexit_count;
        print "\tCPUID\t$cpuid_total_tsc\t$tmp1\t$cpuid_count\t$tmp2\t$tmp\n";
    }
    if ($msr_read_count != 0) {
        $tmp = $msr_read_total_tsc / $msr_read_count;
        $tmp1 = $msr_read_total_tsc / $vmexit_total_tsc;
        $tmp2 = $msr_read_count / $vmexit_count;
        print "\tMSR_READ\t$msr_read_total_tsc\t$tmp1\t$msr_read_count\t$tmp2\t$tmp\n";
    }
    if ($msr_write_count != 0) {
        $tmp = $msr_write_total_tsc / $msr_write_count;
        $tmp1 = $msr_write_total_tsc / $vmexit_total_tsc;
        $tmp2 = $msr_write_count / $vmexit_count;
        print "\tMSR_WRITE\t$msr_write_total_tsc\t$tmp1\t$msr_write_count\t$tmp2\t$tmp\n";
    }
    if ($rdtsc_count != 0) {
        $tmp = $rdtsc_total_tsc / $rdtsc_count;
        $tmp1 = $rdtsc_total_tsc / $vmexit_total_tsc;
        $tmp2 = $rdtsc_count / $vmexit_count;
        print "\tRDTSC\t$rdtsc_total_tsc\t$tmp1\t$rdtsc_count\t$tmp2\t$tmp\n";
    }
    if ($vmcall_count != 0) {
        $tmp = $vmcall_total_tsc / $vmcall_count;
        $tmp1 = $vmcall_total_tsc / $vmexit_total_tsc;
        $tmp2 = $vmcall_count / $vmexit_count;
        print "\tVMCALL\t$vmcall_total_tsc\t$tmp1\t$vmcall_count\t$tmp2\t$tmp\n";
    }


    print "\n\n\tType of NMI TRAP\tTotal TSC\tTSC Ratio\tTotal Count\tCount Ratio\tAverage TSC\n";
    if ($TRAP_no_device_count != 0) {
        $tmp = $TRAP_no_device_total_tsc / $TRAP_no_device_count;
        $tmp1 = $TRAP_no_device_total_tsc / $exception_nmi_total_tsc;
        $tmp2 = $TRAP_no_device_count / $exception_nmi_count;
        print "\tTRAP_no_device\t$TRAP_no_device_total_tsc\t$tmp1\t$TRAP_no_device_count\t$tmp2\t$tmp\n";
    }
    if ($TRAP_pf_count != 0) {
        $tmp = $TRAP_pf_total_tsc / $TRAP_pf_count;
        $tmp1 = $TRAP_pf_total_tsc / $exception_nmi_total_tsc;
        $tmp2 = $TRAP_pf_count / $exception_nmi_count;
        print "\tTRAP_page_fault\t$TRAP_pf_total_tsc\t$tmp1\t$TRAP_pf_count\t$tmp2\t$tmp\n";
    }

    print "\n\tType of PAGE_FAULT\tTotal TSC\tTSC Ratio\tTotal Count\tCount Ratio\tAverage TSC\n";
    if ($shadow_pf_count != 0) {
        $tmp = $shadow_pf_total_tsc / $shadow_pf_count;
        $tmp1 = $shadow_pf_total_tsc / $TRAP_pf_total_tsc;
        $tmp2 = $shadow_pf_count / $TRAP_pf_count;
        print "\tshadow_pf\t$shadow_pf_total_tsc\t$tmp1\t$shadow_pf_count\t$tmp2\t$tmp\n";
    }
    if ($guest_pf_count != 0) {
        $tmp = $guest_pf_total_tsc / $guest_pf_count;
        $tmp1 = $guest_pf_total_tsc / $TRAP_pf_total_tsc;
        $tmp2 = $guest_pf_count / $TRAP_pf_count;
        print "\tguest_pf\t$guest_pf_total_tsc\t$tmp1\t$guest_pf_count\t$tmp2\t$tmp\n";
    }
    if ($mmio_count != 0) {
        $tmp = $mmio_total_tsc / $mmio_count;
        $tmp1 = $mmio_total_tsc / $TRAP_pf_total_tsc;
        $tmp2 = $mmio_count / $TRAP_pf_count;
        print "\n\tmmio\t$mmio_total_tsc\t$tmp1\t$mmio_count\t$tmp2\t$tmp\n";
    }

    print "\n\tType of MMIO\tTotal TSC\tTSC Ratio\tTotal Count\tCount Ratio\tAverage TSC\n";
    if ($mmio_xen_count != 0) {
        $tmp = $mmio_xen_total_tsc / $mmio_xen_count;
        $tmp1 = $mmio_xen_total_tsc / $mmio_total_tsc;
        $tmp2 = $mmio_xen_count / $mmio_count;
        print "\tmmio in xen\t$mmio_xen_total_tsc\t$tmp1\t$mmio_xen_count\t$tmp2\t$tmp\n";
    }
    if ($mmio_dm_count != 0) {
        $tmp = $mmio_dm_total_tsc / $mmio_dm_count;
        $tmp1 = $mmio_dm_total_tsc / $mmio_total_tsc;
        $tmp2 = $mmio_dm_count / $mmio_count;
        print "\tmmio to dm\t$mmio_dm_total_tsc\t$tmp1\t$mmio_dm_count\t$tmp2\t$tmp\n";
    }

    print "\n\tError_Code of shadow_pf\tTotal TSC\tTSC Ratio\tTotal Count\tCount Ratio\tAverage TSC\n";
    foreach $key (sort keys %shadow_pf_error_code_counts) {
        if ($shadow_pf_error_code_counts{$key} != 0) {
            $tmp = $shadow_pf_error_code_total_tscs{$key} / $shadow_pf_error_code_counts{$key};
            $tmp1 = $shadow_pf_error_code_total_tscs{$key} / $shadow_pf_total_tsc;
            $tmp2 = $shadow_pf_error_code_counts{$key} / $shadow_pf_count;
            print "\t$key\t$shadow_pf_error_code_total_tscs{$key}\t$tmp1\t$shadow_pf_error_code_counts{$key}\t$tmp2\t$tmp\n";
        }
    }
    print "\n\tError_Code of guest_pf\tTotal TSC\tTSC Ratio\tTotal Count\tCount Ratio\tAverage TSC\n";
    foreach $key (sort keys %guest_pf_error_code_counts) {
        if ($guest_pf_error_code_counts{$key} != 0) {
            $tmp = $guest_pf_error_code_total_tscs{$key} / $guest_pf_error_code_counts{$key};
            $tmp1 = $guest_pf_error_code_total_tscs{$key} / $guest_pf_total_tsc;
            $tmp2 = $guest_pf_error_code_counts{$key} / $guest_pf_count;
            print "\t$key\t$guest_pf_error_code_total_tscs{$key}\t$tmp1\t$guest_pf_error_code_counts{$key}\t$tmp2\t$tmp\n";
        }
    }


    print "\n\n\tExternal Intr\tTotal TSC\tTSC Ratio\tTotal Count\tCount Ratio\tAverage TSC\n";
    foreach $key (sort keys %ext_intr_counts) {
        $tmp = 0; $tmp1 = 0; $tmp2 = 0;
        if ($ext_intr_counts{$key} != 0) {
            $tmp = $ext_intr_total_tscs{$key} / $ext_intr_counts{$key};
        }
        $tmp1 = $ext_intr_total_tscs{$key} / $external_interrupt_total_tsc;
        $tmp2 = $ext_intr_counts{$key} / $external_interrupt_count;
        print "\t$key\t$ext_intr_total_tscs{$key}\t$tmp1\t$ext_intr_counts{$key}\t$tmp2\t$tmp\n";
    }


    print "\n\n\tType of CR_ACCESS\tTotal TSC\tTSC Ratio\tTotal Count\tCount Ratio\tAverage TSC\n";
    if ($mov_to_cr_count != 0) {
        $tmp = $mov_to_cr_total_tsc / $mov_to_cr_count;
        $tmp1 = $mov_to_cr_total_tsc / $cr_access_total_tsc;
        $tmp2 = $mov_to_cr_count / $cr_access_count;
        print "\tmov_to_cr\t$mov_to_cr_total_tsc\t$tmp1\t$mov_to_cr_count\t$tmp2\t$tmp\n";
    }
    if ($mov_from_cr_count != 0) {
        $tmp = $mov_from_cr_total_tsc / $mov_from_cr_count;
        $tmp1 = $mov_from_cr_total_tsc / $cr_access_total_tsc;
        $tmp2 = $mov_from_cr_count / $cr_access_count;
        print "\tmov_from_cr\t$mov_from_cr_total_tsc\t$tmp1\t$mov_from_cr_count\t$tmp2\t$tmp\n";
    }
    if ($clts_count != 0) {
        $tmp = $clts_total_tsc / $clts_count;
        $tmp1 = $clts_total_tsc / $cr_access_total_tsc;
        $tmp2 = $clts_count / $cr_access_count;
        print "\tclts\t$clts_total_tsc\t$tmp1\t$clts_count\t$tmp2\t$tmp\n";
    }
    if ($lmsw_count != 0) {
        $tmp = $lmsw_total_tsc / $lmsw_count;
        $tmp1 = $lmsw_total_tsc / $cr_access_total_tsc;
        $tmp2 = $lmsw_count / $cr_access_count;
        print "\tlmsw\t$lmsw_total_tsc\t$tmp1\t$lmsw_count\t$tmp2\t$tmp\n";
    }

    print "\n\tmov_to_crs\tTotal TSC\tTSC Ratio\tTotal Count\tCount Ratio\tAverage TSC\n";
    foreach $key (sort keys %mov_to_crs_counts) {
        if ($mov_to_crs_counts{$key} != 0) {
            $tmp = $mov_to_crs_total_tscs{$key} / $mov_to_crs_counts{$key};
            $tmp1 = $mov_to_crs_total_tscs{$key} / $mov_to_cr_total_tsc;
            $tmp2 = $mov_to_crs_counts{$key} / $mov_to_cr_count;
        }
        print "\t$key\t$mov_to_crs_total_tscs{$key}\t$tmp1\t$mov_to_crs_counts{$key}\t$tmp2\t$tmp\n";
    }

    print "\n\tmov_from_crs\tTotal TSC\tTSC Ratio\tTotal Count\tCount Ratio\tAverage TSC\n";
    foreach $key (sort keys %mov_from_crs_counts) {
        if ($mov_from_crs_counts{$key} != 0) {
            $tmp = $mov_from_crs_total_tscs{$key} / $mov_from_crs_counts{$key};
            $tmp1 = $mov_from_crs_total_tscs{$key} / $mov_from_cr_total_tsc;
            $tmp2 = $mov_from_crs_counts{$key} / $mov_from_cr_count;
            print "\t$key\t$mov_from_crs_total_tscs{$key}\t$tmp1\t$mov_from_crs_counts{$key}\t$tmp2\t$tmp\n";
        }
    }


    print "\n\n\tType of PIO\tTotal TSC\tTSC Ratio\tTotal Count\tCount Ratio\tAverage TSC\n";
    if ($pio_xen_count != 0) {
        $tmp = $pio_xen_total_tsc / $pio_xen_count;
        $tmp1 = $pio_xen_total_tsc / $io_instruction_total_tsc;
        $tmp2 = $pio_xen_count / $io_instruction_count;
        print "\tpio in xen\t$pio_xen_total_tsc\t$tmp1\t$pio_xen_count\t$tmp2\t$tmp\n";
    }
    if ($pio_dm_count != 0) {
        $tmp = $pio_dm_total_tsc / $pio_dm_count;
        $tmp1 = $pio_dm_total_tsc / $io_instruction_total_tsc;
        $tmp2 = $pio_dm_count / $io_instruction_count;
        print "\tpio to dm\t$pio_dm_total_tsc\t$tmp1\t$pio_dm_count\t$tmp2\t$tmp\n";
    }

    print "\n\tioports\tTotal TSC\tTSC Ratio\tTotal Count\tCount Ratio\tAverage TSC\n";
    foreach $key (sort keys %io_counts) {
        if ($io_counts{$key} != 0) {
            $tmp = $io_total_tscs{$key} / $io_counts{$key};
            $tmp1 = $io_total_tscs{$key} / $io_instruction_total_tsc;
            $tmp2 = $io_counts{$key} / $io_instruction_count;
            print "\t$key\t$io_total_tscs{$key}\t$tmp1\t$io_counts{$key}\t$tmp2\t$tmp\n";
        }
    }

    print "\n\tioports details\tTotal TSC\tTSC Ratio\tTotal Count\tCount Ratio\tAverage TSC\n";
    foreach $key (sort keys %io_counts1) {
        if ($io_counts1{$key} != 0) {
            $tmp = $io_total_tscs1{$key} / $io_counts1{$key};
            $tmp1 = $io_total_tscs1{$key} / $io_instruction_total_tsc;
            $tmp2 = $io_counts1{$key} / $io_instruction_count;
            print "\t$key\t$io_total_tscs1{$key}\t$tmp1\t$io_counts1{$key}\t$tmp2\t$tmp\n";
        }
    }
}


sub print_shadow()
{
    if ($shadow_count == 0) {
        print "\n\n\tNever tried to hold shadow lock\n";
        return;
    }
    print "\n\n\tshadow count:\t$shadow_count\n";
    print "\ttotal shadow tsc:\t$shadow_total_tsc\n";

    $tmp = $shadow_total_tsc / $shadow_count;
    print "\n\tAverage TSC of Shadow handling:\t$tmp\n";

    print "\n\n\tshadow lock details\tTotal TSC\tTSC Ratio\tTotal Count\tCount Ratio\tAverage TSC\n";
    if ($shadow_conflict_count != 0) {
        $tmp = $shadow_conflict_total_tsc / $shadow_conflict_count;
        $tmp1 = $shadow_conflict_total_tsc / $shadow_total_tsc;
        $tmp2 = $shadow_conflict_count / $shadow_count;
        print "\tshadow conflict\t$shadow_conflict_total_tsc\t$tmp1\t$shadow_conflict_count\t$tmp1\t$tmp\n";
    }


    if ($invlpg_shadow_count != 0) {
        $tmp = $invlpg_shadow_total_tsc / $invlpg_shadow_count;
        $tmp1 = $invlpg_shadow_total_tsc / $shadow_total_tsc;
        $tmp2 = $invlpg_shadow_count / $shadow_count;
        print "\n\tinvlpg_shadow_total_tsc\t$invlpg_shadow_total_tsc\t$tmp1\t$invlpg_shadow_count\t$tmp2\t$tmp\n";
    }
    if ($invlpg_shadow_conflict_count != 0) {
        $tmp = $invlpg_shadow_conflict_total_tsc / $invlpg_shadow_conflict_count;
        $tmp1 = $invlpg_shadow_conflict_total_tsc / $shadow_conflict_total_tsc;
        $tmp2 = $invlpg_shadow_conflict_count / $shadow_conflict_count;
        print "\tinvlpg_shadow_conflict_total_tsc\t$invlpg_shadow_conflict_total_tsc\t$tmp1\t$invlpg_shadow_conflict_count\t$tmp2\t$tmp\n";
    }


    if ($cr3_shadow_count != 0) {
        $tmp = $cr3_shadow_total_tsc / $cr3_shadow_count;
        $tmp1 = $cr3_shadow_total_tsc / $shadow_total_tsc;
        $tmp2 = $cr3_shadow_count / $shadow_count;
        print "\n\tcr3_shadow_total_tsc\t$cr3_shadow_total_tsc\t$tmp1\t$cr3_shadow_count\t$tmp2\t$tmp\n";
    }
    if ($cr3_shadow_conflict_count != 0) {
        $tmp = $cr3_shadow_conflict_total_tsc / $cr3_shadow_conflict_count;
        $tmp1 = $cr3_shadow_conflict_total_tsc / $shadow_conflict_total_tsc;
        $tmp2 = $cr3_shadow_conflict_count / $shadow_conflict_count;
        print "\tcr3_shadow_conflict_total_tsc\t$cr3_shadow_conflict_total_tsc\t$tmp1\t$cr3_shadow_conflict_count\t$tmp2\t$tmp\n";
    }

    if ($pf_shadow_count != 0) {
        $tmp = $pf_shadow_total_tsc / $pf_shadow_count;
        $tmp1 = $pf_shadow_total_tsc / $shadow_total_tsc;
        $tmp2 = $pf_shadow_count / $shadow_count;
        print "\n\tpf_shadow_total_tsc\t$pf_shadow_total_tsc\t$tmp1\t$pf_shadow_count\t$tmp2\t$tmp\n";
    }
    if ($pf_shadow_conflict_count != 0) {
        $tmp = $pf_shadow_conflict_total_tsc / $pf_shadow_conflict_count;
        $tmp1 = $pf_shadow_conflict_total_tsc / $shadow_conflict_total_tsc;
        $tmp2 = $pf_shadow_conflict_count / $shadow_conflict_count;
        print "\tpf_shadow_conflict_total_tsc\t$pf_shadow_conflict_total_tsc\t$tmp1\t$pf_shadow_conflict_count\t$tmp2\t$tmp\n";
    }


    if ($shadow_pf_shadow_count != 0) {
        $tmp = $shadow_pf_shadow_total_tsc / $shadow_pf_shadow_count;
        $tmp1 = $shadow_pf_shadow_total_tsc / $pf_shadow_total_tsc;
        $tmp2 = $shadow_pf_shadow_count / $pf_shadow_count;
        print "\n\tshadow_pf_shadow_total_tsc\t$shadow_pf_shadow_total_tsc\t$tmp1\t$shadow_pf_shadow_count\t$tmp2\t$tmp\n";
    }
    if ($shadow_pf_shadow_conflict_count != 0) {
        $tmp = $shadow_pf_shadow_conflict_total_tsc / $shadow_pf_shadow_conflict_count;
        $tmp1 = $shadow_pf_shadow_conflict_total_tsc / $pf_shadow_conflict_total_tsc;
        $tmp2 = $shadow_pf_shadow_conflict_count / $pf_shadow_conflict_count;
        print "\tshadow_pf_shadow_conflict_total_tsc\t$shadow_pf_shadow_conflict_total_tsc\t$tmp1\t$shadow_pf_shadow_conflict_count\t$tmp2\t$tmp\n";
    }

    if ($guest_pf_shadow_count != 0) {
        $tmp = $guest_pf_shadow_total_tsc / $guest_pf_shadow_count;
        $tmp1 = $guest_pf_shadow_total_tsc / $pf_shadow_total_tsc;
        $tmp2 = $guest_pf_shadow_count / $pf_shadow_count;
        print "\n\tguest_pf_shadow_total_tsc\t$guest_pf_shadow_total_tsc\t$tmp1\t$guest_pf_shadow_count\t$tmp2\t$tmp\n";
    }
    if ($guest_pf_shadow_conflict_count != 0) {
        $tmp = $guest_pf_shadow_conflict_total_tsc / $guest_pf_shadow_conflict_count;
        $tmp1 = $guest_pf_shadow_conflict_total_tsc / $pf_shadow_conflict_total_tsc;
        $tmp2 = $guest_pf_shadow_conflict_count / $pf_shadow_conflict_count;
        print "\tguest_pf_shadow_conflict_total_tsc\t$guest_pf_shadow_conflict_total_tsc\t$tmp1\t$guest_pf_shadow_conflict_count\t$tmp2\t$tmp\n";
    }
    if ($mmio_shadow_count != 0) {
        $tmp = $mmio_shadow_total_tsc / $mmio_shadow_count;
        $tmp1 = $mmio_shadow_total_tsc / $pf_shadow_total_tsc;
        $tmp2 = $mmio_shadow_count / $pf_shadow_count;
        print "\n\tmmio_shadow_total_tsc\t$mmio_shadow_total_tsc\t$tmp1\t$mmio_shadow_count\t$tmp2\t$tmp\n";
    }

    if ($mmio_shadow_conflict_count != 0) {
        $tmp = $mmio_shadow_conflict_total_tsc / $mmio_shadow_conflict_count;
        $tmp1 = $mmio_shadow_conflict_total_tsc / $pf_shadow_conflict_total_tsc;
        $tmp2 = $mmio_shadow_conflict_count / $pf_shadow_conflict_count;
        print "\tmmio_shadow_conflict_total_tsc\t$mmio_shadow_conflict_total_tsc\t$tmp1\t$mmio_shadow_conflict_count\t$tmp2\t$tmp\n";
    }
}
