VirtualBox

Changeset 74529 in vbox


Ignore:
Timestamp:
Sep 28, 2018 5:44:49 PM (6 years ago)
Author:
vboxsync
Message:

VMM/testcase: Ported NemRawBench-1 to linux. bugref:9044

Location:
trunk/src/VBox/VMM/testcase
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/testcase/Makefile.kmk

    r74524 r74529  
    411411# Special NEM host testcase.
    412412#
    413 if1of ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),win.amd64)
     413if1of ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH), $(if-expr "$(USERNAME)" == "bird",linux.amd64,) win.amd64)
    414414 PROGRAMS += NemRawBench-1
    415415 NemRawBench-1_TEMPLATE = VBoxR3Static
    416416 NemRawBench-1_SOURCES = NemRawBench-1.cpp
    417  NemRawBench-1_BLD_TYPE = release
     417 #NemRawBench-1_BLD_TYPE = release
    418418 NemRawBench-1_INCS.win = \
    419419        $(KBUILD_DEVTOOLS)/win.x86/sdk/v10.0.17134.0/include/10.0.17134.0/um \
  • trunk/src/VBox/VMM/testcase/NemRawBench-1.cpp

    r74524 r74529  
    77# include <WinHvPlatform.h>
    88typedef unsigned long long uint64_t;
     9
     10#elif defined(RT_OS_LINUX)
     11# include <linux/kvm.h>
     12# include <errno.h>
     13# include <stdint.h>
     14# include <sys/fcntl.h>
     15# include <sys/ioctl.h>
     16# include <sys/mman.h>
     17# include <unistd.h>
     18# include <time.h>
     19
    920#else
    1021# error "port me"
    1122#endif
     23
     24#include <stdarg.h>
    1225#include <stdio.h>
    13 #include <stdarg.h>
     26#include <stdlib.h>
     27#include <string.h>
    1428
    1529
     
    5468/** @} */
    5569static uint64_t (WINAPI                            *g_pfnRtlGetSystemTimePrecise)(void);
     70
     71#elif defined(RT_OS_LINUX)
     72/** The VM handle.   */
     73static int                      g_fdVm;
     74/** The VCPU handle.   */
     75static int                      g_fdVCpu;
     76/** The kvm_run structure for the VCpu. */
     77static struct kvm_run          *g_pVCpuRun;
     78/** The size of the g_pVCpuRun mapping. */
     79static ssize_t                  g_cbVCpuRun;
    5680#endif
    5781
     
    7296#ifdef RT_OS_WINDOWS
    7397    return g_pfnRtlGetSystemTimePrecise() * 100;
     98#elif defined(RT_OS_LINUX)
     99    struct timespec ts;
     100    clock_gettime(CLOCK_MONOTONIC, &ts);
     101    return (uint64_t)ts.tv_sec * UINT64_C(1000000000) + ts.tv_nsec;
    74102#else
    75103# error "port me"
     
    79107
    80108#ifdef RT_OS_WINDOWS
     109
     110/*
     111 * Windows - Hyper-V Platform API.
     112 */
    81113
    82114static int createVM(void)
     
    227259    return 1;
    228260}
    229 
    230261
    231262
     
    374405}
    375406
     407
     408
    376409#elif defined(RT_OS_LINUX)
    377 # error "port me"
     410
     411/*
     412 * GNU/linux - KVM
     413 */
     414
     415static int createVM(void)
     416{
     417    int fd = open("/dev/kvm", O_RDWR);
     418    if (fd < 0)
     419        return error("Error opening /dev/kvm: %d\n", errno);
     420
     421    g_fdVm = ioctl(fd, KVM_CREATE_VM, (uintptr_t)0);
     422    if (g_fdVm < 0)
     423        return error("KVM_CREATE_VM failed: %d\n", errno);
     424
     425    /* Create the VCpu. */
     426    g_cbVCpuRun = ioctl(fd, KVM_GET_VCPU_MMAP_SIZE, (uintptr_t)0);
     427    if (g_cbVCpuRun <= 0x1000 || (g_cbVCpuRun & 0xfff))
     428        return error("Failed to get KVM_GET_VCPU_MMAP_SIZE: %#xz errno=%d\n", g_cbVCpuRun, errno);
     429
     430    g_fdVCpu = ioctl(g_fdVm, KVM_CREATE_VCPU, (uintptr_t)0);
     431    if (g_fdVCpu < 0)
     432        return error("KVM_CREATE_VCPU failed: %d\n", errno);
     433
     434    g_pVCpuRun = (struct kvm_run *)mmap(NULL, g_cbVCpuRun, PROT_READ | PROT_WRITE, MAP_PRIVATE, g_fdVCpu, 0);
     435    if ((void *)g_pVCpuRun == MAP_FAILED)
     436        return error("mmap kvm_run failed: %d\n", errno);
     437
     438    /* Memory. */
     439    g_pbMem = (unsigned char *)mmap(NULL, g_cbMem, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
     440    if ((void *)g_pbMem == MAP_FAILED)
     441        return error("mmap RAM failed: %d\n", errno);
     442
     443    struct kvm_userspace_memory_region MemReg;
     444    MemReg.slot            = 0;
     445    MemReg.flags           = 0;
     446    MemReg.guest_phys_addr = MY_MEM_BASE;
     447    MemReg.memory_size     = g_cbMem;
     448    MemReg.userspace_addr  = (uintptr_t)g_pbMem;
     449    int rc = ioctl(g_fdVm, KVM_SET_USER_MEMORY_REGION, &MemReg);
     450    if (rc != 0)
     451        return error("KVM_SET_USER_MEMORY_REGION failed: %d (%d)\n", errno, rc);
     452
     453    close(fd);
     454    return 0;
     455}
     456
     457
     458static void printSReg(const char *pszName, struct kvm_segment const *pSReg)
     459{
     460    fprintf(stderr, "     %5s=%04x  base=%016llx  limit=%08x type=%#x p=%d dpl=%d db=%d s=%d l=%d g=%d avl=%d un=%d\n",
     461            pszName, pSReg->selector, pSReg->base, pSReg->limit, pSReg->type, pSReg->present, pSReg->dpl,
     462            pSReg->db, pSReg->s, pSReg->l, pSReg->g, pSReg->avl, pSReg->unusable);
     463}
     464
     465
     466static int runtimeError(const char *pszFormat, ...)
     467{
     468    fprintf(stderr, "runtime error: ");
     469    va_list va;
     470    va_start(va, pszFormat);
     471    vfprintf(stderr, pszFormat, va);
     472    va_end(va);
     473
     474    fprintf(stderr, "                  exit_reason=%#010x\n", g_pVCpuRun->exit_reason);
     475    fprintf(stderr, "ready_for_interrupt_injection=%#x\n", g_pVCpuRun->ready_for_interrupt_injection);
     476    fprintf(stderr, "                      if_flag=%#x\n", g_pVCpuRun->if_flag);
     477    fprintf(stderr, "                        flags=%#x\n", g_pVCpuRun->flags);
     478    fprintf(stderr, "               kvm_valid_regs=%#018llx\n", g_pVCpuRun->kvm_valid_regs);
     479    fprintf(stderr, "               kvm_dirty_regs=%#018llx\n", g_pVCpuRun->kvm_dirty_regs);
     480
     481    struct kvm_regs Regs;
     482    memset(&Regs, 0, sizeof(Regs));
     483    struct kvm_sregs SRegs;
     484    memset(&SRegs, 0, sizeof(SRegs));
     485    if (   ioctl(g_fdVCpu, KVM_GET_REGS, &Regs) != -1
     486        && ioctl(g_fdVCpu, KVM_GET_SREGS, &SRegs) != -1)
     487    {
     488        fprintf(stderr, "       rip=%016llx\n", Regs.rip);
     489        printSReg("cs", &SRegs.cs);
     490        fprintf(stderr, "    rflags=%08llx\n", Regs.rflags);
     491        fprintf(stderr, "       rax=%016llx\n", Regs.rax);
     492        fprintf(stderr, "       rbx=%016llx\n", Regs.rcx);
     493        fprintf(stderr, "       rdx=%016llx\n", Regs.rdx);
     494        fprintf(stderr, "       rcx=%016llx\n", Regs.rbx);
     495        fprintf(stderr, "       rsp=%016llx\n", Regs.rsp);
     496        fprintf(stderr, "       rbp=%016llx\n", Regs.rbp);
     497        fprintf(stderr, "       rsi=%016llx\n", Regs.rsi);
     498        fprintf(stderr, "       rdi=%016llx\n", Regs.rdi);
     499        printSReg("ss", &SRegs.ss);
     500        printSReg("ds", &SRegs.ds);
     501        printSReg("es", &SRegs.es);
     502        printSReg("fs", &SRegs.fs);
     503        printSReg("gs", &SRegs.gs);
     504        printSReg("tr", &SRegs.tr);
     505        printSReg("ldtr", &SRegs.ldt);
     506
     507        uint64_t const offMem = Regs.rip + SRegs.cs.base - MY_MEM_BASE;
     508        if (offMem < g_cbMem - 10)
     509            fprintf(stderr, "  bytes at PC (%#zx): %02x %02x %02x %02x %02x %02x %02x %02x\n", (size_t)(offMem + MY_MEM_BASE),
     510                    g_pbMem[offMem    ], g_pbMem[offMem + 1], g_pbMem[offMem + 2], g_pbMem[offMem + 3],
     511                    g_pbMem[offMem + 4], g_pbMem[offMem + 5], g_pbMem[offMem + 6], g_pbMem[offMem + 7]);
     512    }
     513
     514    return 1;
     515}
     516
     517static int runRealModeTest(unsigned cInstructions, const char *pszInstruction,
     518                           unsigned uEax, unsigned uEcx, unsigned uEdx, unsigned uEbx,
     519                           unsigned uEsp, unsigned uEbp, unsigned uEsi, unsigned uEdi)
     520{
     521    /*
     522     * Setup real mode context.
     523     */
     524#define SET_SEG(a_SReg, a_Base, a_Limit, a_Sel, a_fCode) \
     525        do { \
     526            a_SReg.base     = (a_Base); \
     527            a_SReg.limit    = (a_Limit); \
     528            a_SReg.selector = (a_Sel); \
     529            a_SReg.type     = (a_fCode) ? 10 : 3; \
     530            a_SReg.present  = 1; \
     531            a_SReg.dpl      = 0; \
     532            a_SReg.db       = 0; \
     533            a_SReg.s        = 1; \
     534            a_SReg.l        = 0; \
     535            a_SReg.g        = 0; \
     536            a_SReg.avl      = 0; \
     537            a_SReg.unusable = 0; \
     538            a_SReg.padding  = 0; \
     539        } while (0)
     540    struct kvm_regs Regs;
     541    memset(&Regs, 0, sizeof(Regs));
     542    Regs.rax = uEax;
     543    Regs.rcx = uEcx;
     544    Regs.rdx = uEdx;
     545    Regs.rbx = uEbx;
     546    Regs.rsp = uEsp;
     547    Regs.rbp = uEbp;
     548    Regs.rsi = uEsi;
     549    Regs.rdi = uEdi;
     550    Regs.rip = MY_TEST_RIP;
     551    Regs.rflags = 1;
     552    int rc = ioctl(g_fdVCpu, KVM_SET_REGS, &Regs);
     553    if (rc != 0)
     554        return error("KVM_SET_REGS failed: %d (rc=%d)\n", errno, rc);
     555
     556    struct kvm_sregs SRegs;
     557    memset(&SRegs, 0, sizeof(SRegs));
     558    rc = ioctl(g_fdVCpu, KVM_GET_SREGS, &SRegs);
     559    if (rc != 0)
     560        return error("KVM_GET_SREGS failed: %d (rc=%d)\n", errno, rc);
     561    SET_SEG(SRegs.es, 0x00000, 0xffff, 0x0000, 0);
     562    SET_SEG(SRegs.cs, 0x00000, 0xffff, 0x0000, 1);
     563    SET_SEG(SRegs.ss, 0x00000, 0xffff, 0x0000, 0);
     564    SET_SEG(SRegs.ds, 0x00000, 0xffff, 0x0000, 0);
     565    SET_SEG(SRegs.fs, 0x00000, 0xffff, 0x0000, 0);
     566    SET_SEG(SRegs.gs, 0x00000, 0xffff, 0x0000, 0);
     567    //SRegs.cr0 = 0x10010 /*WP+ET*/;
     568    SRegs.cr2 = 0;
     569    //SRegs.cr3 = 0;
     570    //SRegs.cr4 = 0;
     571    rc = ioctl(g_fdVCpu, KVM_SET_SREGS, &SRegs);
     572    if (rc != 0)
     573        return error("KVM_SET_SREGS failed: %d (rc=%d)\n", errno, rc);
     574
     575    /*
     576     * Run the test.
     577     */
     578    uint64_t const nsStart = getNanoTS();
     579    for (;;)
     580    {
     581        rc = ioctl(g_fdVCpu, KVM_RUN, (uintptr_t)0);
     582        if (rc == 0)
     583        {
     584            if (g_pVCpuRun->exit_reason == KVM_EXIT_IO)
     585            {
     586                if (g_pVCpuRun->io.port == MY_NOP_PORT)
     587                { /* likely: nop instruction */ }
     588                else if (g_pVCpuRun->io.port == MY_TERM_PORT)
     589                    break;
     590                else
     591                    return runtimeError("Unexpected I/O port access (for %s): %#x\n", pszInstruction, g_pVCpuRun->io.port);
     592            }
     593            else if (g_pVCpuRun->exit_reason == KVM_EXIT_MMIO)
     594            {
     595                if (g_pVCpuRun->mmio.phys_addr == MY_NOP_MMIO)
     596                { /* likely: nop address */ }
     597                else
     598                    return runtimeError("Unexpected memory access (for %s): %#llx\n", pszInstruction, g_pVCpuRun->mmio.phys_addr);
     599            }
     600            else
     601                return runtimeError("Unexpected exit (for %s): %d\n", pszInstruction, g_pVCpuRun->exit_reason);
     602        }
     603        else
     604            return runtimeError("KVM_RUN failed (for %s): %#x (ret %d)\n", pszInstruction, errno, rc);
     605    }
     606    uint64_t const nsElapsed = getNanoTS() - nsStart;
     607
     608    /* Report the results. */
     609    uint64_t const cInstrPerSec = nsElapsed ? (uint64_t)cInstructions * 1000000000 / nsElapsed : 0;
     610    printf("%10u %s instructions per second\n", (unsigned)cInstrPerSec, pszInstruction);
     611    return 0;
     612}
     613
     614
    378615#elif defined(RT_OS_DARWIN)
    379616# error "port me"
     
    383620
    384621
    385 static int ioportTest(unsigned cFactor)
     622int ioportTest(unsigned cFactor)
    386623{
    387624    /*
     
    398635    /* JNZ MY_TEST_RIP */
    399636    *pb++ = 0x75;
    400     *pb++ = (signed char)(pbStart - pb + 1);
     637    *pb   = (signed char)(pbStart - pb + 1);
     638    pb++;
    401639    /* OUT 1, AL -  Temination port call. */
    402640    *pb++ = 0xe6;
     
    411649
    412650
    413 static int cpuidTest(unsigned cFactor)
     651int cpuidTest(unsigned cFactor)
    414652{
    415653    /*
     
    421659    {
    422660        /* XOR EAX,EAX */
     661#ifndef RT_OS_LINUX /* Broken on 4.18.0, probably wrong rip advance (2 instead of 3 bytes). */
    423662        *pb++ = 0x66;
     663#endif
    424664        *pb++ = 0x33;
    425665        *pb++ = 0xc0;
     
    434674    /* JNZ MY_TEST_RIP */
    435675    *pb++ = 0x75;
    436     *pb++ = (signed char)(pbStart - pb + 1);
     676    *pb   = (signed char)(pbStart - pb + 1);
     677    pb++;
    437678    /* OUT 1, AL -  Temination port call. */
    438679    *pb++ = 0xe6;
     
    447688
    448689
    449 static int mmioTest(unsigned cFactor)
     690int mmioTest(unsigned cFactor)
    450691{
    451692    /*
     
    465706    /* JNZ MY_TEST_RIP */
    466707    *pb++ = 0x75;
    467     *pb++ = (signed char)(pbStart - pb + 1);
     708    *pb   = (signed char)(pbStart - pb + 1);
     709    pb++;
    468710    /* OUT 1, AL -  Temination port call. */
    469711    *pb++ = 0xe6;
     
    541783         */
    542784        ioportTest(cFactor);
     785#ifndef RT_OS_LINUX
    543786        cpuidTest(cFactor);
     787#endif
    544788        mmioTest(cFactor);
    545789
     
    548792    return rcExit;
    549793}
     794
     795/*
     796 * Results:
     797 *
     798 * - Linux 4.18.0-1-amd64 (debian); AMD Threadripper:
     799 *     545108 OUT instructions per second
     800 *     373159 MMIO/r1 instructions per second
     801 *
     802 *
     803 */
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette