VirtualBox

Changeset 1027 in vbox


Ignore:
Timestamp:
Feb 22, 2007 8:29:35 PM (18 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
18886
Message:

Initial GIP change. Missing detection of SMP systems with TSC drift.

Location:
trunk
Files:
1 deleted
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/sup.h

    r914 r1027  
    2424#include <VBox/cdefs.h>
    2525#include <VBox/types.h>
     26#include <iprt/assert.h>
     27#include <iprt/asm.h>
    2628
    2729__BEGIN_DECLS
     
    7476
    7577
    76 #pragma pack(1)
    77 /**
    78  * Global Information Page.
    79  *
    80  * This page contains useful information and can be mapped into any
    81  * process or VM. It can be accessed thru the g_pSUPGlobalInfoPage
    82  * pointer when a session is open.
    83  *
    84  * How to read data from this structure:
    85  *
    86  * @code
    87  *      PSUPGLOBALINFOPAGE pGIP;
    88  *      uint32_t u32TransactionId;
    89  *      do
    90  *      {
    91  *          pGIP = g_pSUPGlobalInfoPage;
    92  *          if (!pGIP)
    93  *              return VERR_GIP_NOT_PRESENT;
    94  *          u32TransactionId = pGIP->u32TransactionId;
    95  *          ... read stuff to local variables ...
    96  *      } while (   pGIP->u32TransactionId != u32TransactionId
    97  *               || (u32TransactionId & 1));
    98  * @endcode
    99  *
    100  * @remark This is currently an optional feature.
    101  */
    102 typedef struct SUPGLOBALINFOPAGE
    103 {
    104     /** Magic (SUPGLOBALINFOPAGE_MAGIC). */
    105     uint32_t            u32Magic;
    106 
    107     /** The update frequency of the of the NanoTS. */
    108     volatile uint32_t   u32UpdateHz;
    109     /** The update interval in nanoseconds. (10^9 / u32UpdateHz) */
    110     volatile uint32_t   u32UpdateIntervalNS;
    111 
    112     /** Padding / reserved space for future const variables. */
    113     uint32_t            au32Padding0[5];
    114 
     78#pragma pack(1) /* paranoia */
     79
     80/**
     81 * Per CPU data.
     82 * This is only used when
     83 */
     84typedef struct SUPGIPCPU
     85{
    11586    /** Update transaction number.
    11687     * This number is incremented at the start and end of each update. It follows
    11788     * thusly that odd numbers indicates update in progress, while even numbers
    11889     * indicate stable data. Use this to make sure that the data items you fetch
    119      * are consistent.
    120      */
     90     * are consistent. */
    12191    volatile uint32_t   u32TransactionId;
    12292    /** The interval in TSC ticks between two NanoTS updates.
    12393     * This is the average interval over the last 2, 4 or 8 updates + a little slack.
    12494     * The slack makes the time go a tiny tiny bit slower and extends the interval enough
    125      * to avoid getting ending up with too many 1ns increments. */
     95     * to avoid ending up with too many 1ns increments. */
    12696    volatile uint32_t   u32UpdateIntervalTSC;
    12797    /** Current nanosecond timestamp. */
     
    141111     */
    142112    volatile uint32_t   au32TSCHistory[8];
     113    /** Reserved for future per processor data. */
     114    volatile uint32_t   au32Reserved[6];
     115} SUPGIPCPU;
     116AssertCompileSize(SUPGIPCPU, 96);
     117/*AssertCompileMemberAlignment(SUPGIPCPU, u64TSC, 8); -fixme */
     118
     119/** Pointer to per cpu data. */
     120typedef SUPGIPCPU *PSUPGIPCPU;
     121/** Pointer to const per cpu data. */
     122typedef const SUPGIPCPU *PCSUPGIPCPU;
     123
     124/**
     125 * Global Information Page.
     126 *
     127 * This page contains useful information and can be mapped into any
     128 * process or VM. It can be accessed thru the g_pSUPGlobalInfoPage
     129 * pointer when a session is open.
     130 */
     131typedef struct SUPGLOBALINFOPAGE
     132{
     133    /** Magic (SUPGLOBALINFOPAGE_MAGIC). */
     134    uint32_t            u32Magic;
     135
     136    /** The GIP update mode, see SUPGIPMODE. */
     137    uint32_t            u32Mode;
     138
     139    /** The update frequency of the of the NanoTS. */
     140    volatile uint32_t   u32UpdateHz;
     141    /** The update interval in nanoseconds. (10^9 / u32UpdateHz) */
     142    volatile uint32_t   u32UpdateIntervalNS;
    143143    /** The timestamp of the last time we update the update frequency. */
    144144    volatile uint64_t   u64NanoTSLastUpdateHz;
     145
     146    /** Padding / reserved space for future data. */
     147    uint32_t            au32Padding0[10];
     148
     149    /** Array of per-cpu data.
     150     * If u32Mode == SUPGIPMODE_SYNC_TSC then only the first entry is used.
     151     * If u32Mode == SUPGIPMODE_ASYNC_TSC then the CPU ACPI ID is used as an
     152     * index into the array. */
     153    SUPGIPCPU           aCPUs[32];
    145154} SUPGLOBALINFOPAGE;
    146 #pragma pack()
     155AssertCompile(sizeof(SUPGLOBALINFOPAGE) <= 0x1000);
     156/* AssertCompileMemberAlignment(SUPGLOBALINFOPAGE, aCPU, 32); - fixme */
     157
    147158/** Pointer to the global info page. */
    148159typedef SUPGLOBALINFOPAGE *PSUPGLOBALINFOPAGE;
     
    150161typedef const SUPGLOBALINFOPAGE *PCSUPGLOBALINFOPAGE;
    151162
    152 /** Current value of the SUPGLOBALINFOPAGE::u32Magic field. */
    153 #define SUPGLOBALINFOPAGE_MAGIC     (0xbeef0001)
     163#pragma pack() /* end of paranoia */
     164
     165/** The value of the SUPGLOBALINFOPAGE::u32Magic field. (Soryo Fuyumi) */
     166#define SUPGLOBALINFOPAGE_MAGIC     0x19590106
     167
     168/**
     169 * SUPGLOBALINFOPAGE::u32Mode values.
     170 */
     171typedef enum SUPGIPMODE
     172{
     173    /** The usual invalid null entry. */
     174    SUPGIPMODE_INVALID = 0,
     175    /** The TSC of the cores and cpus in the system is in sync. */
     176    SUPGIPMODE_SYNC_TSC,
     177    /** Each core has it's own TSC. */
     178    SUPGIPMODE_ASYNC_TSC,
     179    /** The usual 32-bit hack. */
     180    SUPGIPMODE_32BIT_HACK = 0x7fffffff
     181} SUPGIPMODE;
    154182
    155183/** Pointer to the Global Information Page.
     
    182210
    183211
     212/**
     213 * Gets the TSC frequency of the calling CPU.
     214 *
     215 * @returns TSC frequency.
     216 * @param   pGip        The GIP pointer.
     217 */
     218DECLINLINE(uint64_t) SUPGetCpuHzFromGIP(PCSUPGLOBALINFOPAGE pGip)
     219{
     220    unsigned iCpu;
     221
     222    if (RT_UNLIKELY(!pGip || pGip->u32Magic != SUPGLOBALINFOPAGE_MAGIC))
     223        return ~(uint64_t)0;
     224
     225    if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
     226        iCpu = 0;
     227    else
     228    {
     229        iCpu = ASMGetApicId();
     230        if (RT_UNLIKELY(iCpu >= RT_ELEMENTS(pGip->aCPUs)))
     231            return ~(uint64_t)0;
     232    }
     233
     234    return pGip->aCPUs[iCpu].u64CpuHz;
     235}
     236
    184237
    185238#ifdef IN_RING3
  • trunk/include/iprt/asm.h

    r654 r1027  
    763763
    764764/**
     765 * Gets the APIC ID of the current CPU.
     766 *
     767 * @returns the APIC ID.
     768 */
     769#if RT_INLINE_ASM_EXTERNAL && !RT_INLINE_ASM_USES_INTRIN
     770DECLASM(uint8_t) ASMGetApicId(void);
     771#else
     772DECLINLINE(uint8_t) ASMGetApicId(void)
     773{
     774    RTCCUINTREG xBX;
     775# if RT_INLINE_ASM_GNU_STYLE
     776#  ifdef __AMD64__
     777    RTCCUINTREG uSpill;
     778    __asm__ ("cpuid"
     779             : "=a" (uSpill),
     780               "=b" (xBX)
     781             : "0" (1)
     782             : "rcx", "rdx");
     783#  elif (defined(PIC) || defined(__DARWIN__)) && defined(__i386__)
     784    RTCCUINTREG uSpill;
     785    __asm__ ("push  %%ebx\n\t"
     786             "cpuid\n\t"
     787             "xchgl %%ebx, %%ecx\n\t"
     788             "pop   %%ebx\n\t"
     789             : "=a" (uSpill),
     790               "=c" (xBX)
     791             : "0" (1)
     792             : "edx");
     793#  else
     794    RTCCUINTREG uSpill;
     795    __asm__ ("cpuid"
     796             : "=a" (uSpill),
     797               "=b" (xBX)
     798             : "0" (1)
     799             : "ecx", "edx");
     800#  endif
     801
     802# elif RT_INLINE_ASM_USES_INTRIN
     803    int aInfo[4];
     804    __cpuid(aInfo, 1);
     805    xBX = aInfo[1];
     806
     807# else
     808    __asm
     809    {
     810        push    ebx
     811        mov     eax, 1
     812        cpuid
     813        mov     [xBX], ebx
     814        pop     ebx
     815    }
     816# endif
     817    return (uint8_t)(xBX >> 24);
     818}
     819#endif
     820
     821/**
    765822 * Get cr0.
    766823 * @returns cr0.
  • trunk/src/VBox/HostDrivers/Support/SUPDRV.h

    r679 r1027  
    617617    /** The GIP DPC object associated with GipTimer. */
    618618    KDPC                    GipDpc;
     619    /** The GIP DPC objects for updating per-cpu data. */
     620    KDPC                    aGipCpuDpcs[32];
    619621    /** Pointer to the MDL for the pGip page. */
    620622    PMDL                    pGipMdl;
     
    626628    unsigned long           ulLastJiffies;
    627629    /** The last mono time stamp. */
    628     uint64_t                u64LastMonotime;
     630    uint64_t volatile       u64LastMonotime;
    629631#endif
    630632} SUPDRVDEVEXT;
     
    652654void  VBOXCALL  supdrvOSGipResume(PSUPDRVDEVEXT pDevExt);
    653655void  VBOXCALL  supdrvOSGipSuspend(PSUPDRVDEVEXT pDevExt);
     656unsigned VBOXCALL supdrvOSGetCPUCount(void);
    654657#endif
    655658
     
    671674void VBOXCALL   supdrvGipTerm(PSUPGLOBALINFOPAGE pGip);
    672675void VBOXCALL   supdrvGipUpdate(PSUPGLOBALINFOPAGE pGip, uint64_t u64NanoTS);
     676void VBOXCALL   supdrvGipUpdatePerCpu(PSUPGLOBALINFOPAGE pGip, uint64_t u64NanoTS, unsigned iCpu);
    673677
    674678__END_DECLS
  • trunk/src/VBox/HostDrivers/Support/SUPDRVIOC.h

    r914 r1027  
    176176#define SUPCOOKIE_MAGIC             "The Magic Word!"
    177177/** Current interface version. */
    178 #define SUPDRVIOC_VERSION           0x00030002
     178#define SUPDRVIOC_VERSION           0x00040000
    179179
    180180/** SUP_IOCTL_COOKIE Output. */
  • trunk/src/VBox/HostDrivers/Support/SUPDRVShared.c

    r982 r1027  
    22882288            if (pDevExt->cGipUsers == 1)
    22892289            {
     2290                PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
     2291                unsigned i;
     2292
    22902293                dprintf(("SUPR0GipMap: Resumes GIP updating\n"));
    2291                 ASMAtomicXchgU32(&pDevExt->pGip->u32TransactionId,
    2292                                  pDevExt->pGip->u32TransactionId & ~(GIP_UPDATEHZ_RECALC_FREQ * 2 - 1));
    2293                 ASMAtomicXchgU64(&pDevExt->pGip->u64NanoTSLastUpdateHz, 0);
     2294
     2295                for (i = 0; i < RT_ELEMENTS(pGip->aCPUs); i++)
     2296                    ASMAtomicXchgU32(&pGip->aCPUs[i].u32TransactionId, pGip->aCPUs[i].u32TransactionId & ~(GIP_UPDATEHZ_RECALC_FREQ * 2 - 1));
     2297                ASMAtomicXchgU64(&pGip->u64NanoTSLastUpdateHz, 0);
     2298
    22942299#ifdef USE_NEW_OS_INTERFACE
    2295                 rc = RTTimerStart(pDevExt->pGipTimer, 0); AssertRC(rc); rc = 0;
     2300                rc = RTTimerStart(pDevExt->pGipTimer, 0);
     2301                AssertRC(rc); rc = 0;
    22962302#else
    22972303                supdrvOSGipResume(pDevExt);
     
    40054011int VBOXCALL supdrvGipInit(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, RTHCPHYS HCPhys, uint64_t u64NanoTS, unsigned uUpdateHz)
    40064012{
     4013    unsigned i;
    40074014    dprintf(("supdrvGipInit: pGip=%p HCPhys=%lx u64NanoTS=%llu uUpdateHz=%d\n", pGip, (long)HCPhys, u64NanoTS, uUpdateHz));
    40084015
     4016    /*
     4017     * Initialize the structure.
     4018     */
    40094019    memset(pGip, 0, PAGE_SIZE);
    40104020    pGip->u32Magic          = SUPGLOBALINFOPAGE_MAGIC;
     4021    pGip->u32Mode           = SUPGIPMODE_SYNC_TSC;
    40114022    pGip->u32UpdateHz       = uUpdateHz;
    40124023    pGip->u32UpdateIntervalNS = 1000000000 / uUpdateHz;
    4013     pGip->u32TransactionId  = 2;
    4014     pGip->u64NanoTS         = u64NanoTS;
    40154024    pGip->u64NanoTSLastUpdateHz = u64NanoTS;
    4016     pGip->u64TSC            = ASMReadTSC();
    4017 
    4018     /*
    4019      * We don't know the following values until we've executed updates.
    4020      * So, we'll just insert very high values.
    4021      */
    4022     pGip->u64CpuHz          = _4G + 1;
    4023     pGip->u32UpdateIntervalTSC = _2G / 4;
    4024     pGip->au32TSCHistory[0] = _2G / 4;
    4025     pGip->au32TSCHistory[1] = _2G / 4;
    4026     pGip->au32TSCHistory[2] = _2G / 4;
    4027     pGip->au32TSCHistory[3] = _2G / 4;
    4028     pGip->au32TSCHistory[4] = _2G / 4;
    4029     pGip->au32TSCHistory[5] = _2G / 4;
    4030     pGip->au32TSCHistory[6] = _2G / 4;
    4031     pGip->au32TSCHistory[7] = _2G / 4;
     4025
     4026    for (i = 0; i < RT_ELEMENTS(pGip->aCPUs); i++)
     4027    {
     4028        pGip->aCPUs[i].u32TransactionId  = 2;
     4029        pGip->aCPUs[i].u64NanoTS         = u64NanoTS;
     4030        pGip->aCPUs[i].u64TSC            = ASMReadTSC();
     4031   
     4032        /*
     4033         * We don't know the following values until we've executed updates.
     4034         * So, we'll just insert very high values.
     4035         */
     4036        pGip->aCPUs[i].u64CpuHz          = _4G + 1;
     4037        pGip->aCPUs[i].u32UpdateIntervalTSC = _2G / 4;
     4038        pGip->aCPUs[i].au32TSCHistory[0] = _2G / 4;
     4039        pGip->aCPUs[i].au32TSCHistory[1] = _2G / 4;
     4040        pGip->aCPUs[i].au32TSCHistory[2] = _2G / 4;
     4041        pGip->aCPUs[i].au32TSCHistory[3] = _2G / 4;
     4042        pGip->aCPUs[i].au32TSCHistory[4] = _2G / 4;
     4043        pGip->aCPUs[i].au32TSCHistory[5] = _2G / 4;
     4044        pGip->aCPUs[i].au32TSCHistory[6] = _2G / 4;
     4045        pGip->aCPUs[i].au32TSCHistory[7] = _2G / 4;
     4046    }
    40324047
    40334048    /*
     
    40384053    pDevExt->cGipUsers = 0;
    40394054
     4055    /*
     4056     * Check if we should switch to async TSC mode.
     4057     */
     4058#if 0
     4059    if (supdrvOSGetCPUCount() > 1)
     4060    {
     4061        ASMCpuId(0,
     4062    }
     4063#endif
     4064
    40404065    return 0;
    40414066}
     
    40494074void VBOXCALL supdrvGipTerm(PSUPGLOBALINFOPAGE pGip)
    40504075{
    4051     pGip->iTSCHistoryHead = ~0;
    4052     pGip->u64NanoTS = 0;
    4053     pGip->u64TSC = 0;
     4076    unsigned i;
    40544077    pGip->u32Magic = 0;
    4055     pGip->iTSCHistoryHead = 0;
    4056 }
    4057 
    4058 
    4059 /**
    4060  * Updates the GIP.
    4061  *
    4062  * @param   pGip        Pointer to the GIP.
    4063  * @param   u64NanoTS   The current nanosecond timesamp.
    4064  */
    4065 void VBOXCALL   supdrvGipUpdate(PSUPGLOBALINFOPAGE pGip, uint64_t u64NanoTS)
     4078    for (i = 0; i < RT_ELEMENTS(pGip->aCPUs); i++)
     4079    {
     4080        pGip->aCPUs[i].u64NanoTS = 0;
     4081        pGip->aCPUs[i].u64TSC = 0;
     4082        pGip->aCPUs[i].iTSCHistoryHead = 0;
     4083    }
     4084}
     4085
     4086
     4087/**
     4088 * Worker routine for supdrvGipUpdate and supdrvGipUpdatePerCpu that
     4089 * updates all the per cpu data except the transaction id.
     4090 *
     4091 * @param   pGip            The GIP.
     4092 * @param   pGipCpu         Pointer to the per cpu data.
     4093 * @param   u64NanoTS       The current time stamp.
     4094 */
     4095static void supdrvGipDoUpdateCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pGipCpu, uint64_t u64NanoTS)
    40664096{
    40674097    uint64_t    u64TSC;
     
    40734103
    40744104    /*
     4105     * Update the NanoTS.
     4106     */
     4107    ASMAtomicXchgU64(&pGipCpu->u64NanoTS, u64NanoTS);
     4108
     4109    /*
     4110     * Calc TSC delta.
     4111     */
     4112    /** @todo validate the NanoTS delta, don't trust the OS to call us when it should... */
     4113    u64TSC = ASMReadTSC();
     4114    u64TSCDelta = u64TSC - pGipCpu->u64TSC;
     4115    ASMAtomicXchgU64(&pGipCpu->u64TSC, u64TSC);
     4116
     4117    if (u64TSCDelta >> 32)
     4118    {
     4119        u64TSCDelta = pGipCpu->u32UpdateIntervalTSC;
     4120        pGipCpu->cErrors++;
     4121    }
     4122
     4123    /*
     4124     * TSC History.
     4125     */
     4126    Assert(ELEMENTS(pGipCpu->au32TSCHistory) == 8);
     4127
     4128    iTSCHistoryHead = (pGipCpu->iTSCHistoryHead + 1) & 7;
     4129    ASMAtomicXchgU32(&pGipCpu->iTSCHistoryHead, iTSCHistoryHead);
     4130    ASMAtomicXchgU32(&pGipCpu->au32TSCHistory[iTSCHistoryHead], (uint32_t)u64TSCDelta);
     4131
     4132    /*
     4133     * UpdateIntervalTSC = average of last 8,2,1 intervals depending on update HZ.
     4134     */
     4135    if (pGip->u32UpdateHz >= 1000)
     4136    {
     4137        uint32_t u32;
     4138        u32  = pGipCpu->au32TSCHistory[0];
     4139        u32 += pGipCpu->au32TSCHistory[1];
     4140        u32 += pGipCpu->au32TSCHistory[2];
     4141        u32 += pGipCpu->au32TSCHistory[3];
     4142        u32 >>= 2;
     4143        u32UpdateIntervalTSC  = pGipCpu->au32TSCHistory[4];
     4144        u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[5];
     4145        u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[6];
     4146        u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[7];
     4147        u32UpdateIntervalTSC >>= 2;
     4148        u32UpdateIntervalTSC += u32;
     4149        u32UpdateIntervalTSC >>= 1;
     4150
     4151        /* Value choosen for a 2GHz Athlon64 running linux 2.6.10/11, . */
     4152        u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 14;
     4153    }
     4154    else if (pGip->u32UpdateHz >= 90)
     4155    {
     4156        u32UpdateIntervalTSC  = (uint32_t)u64TSCDelta;
     4157        u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[(iTSCHistoryHead - 1) & 7];
     4158        u32UpdateIntervalTSC >>= 1;
     4159
     4160        /* value choosen on a 2GHz thinkpad running windows */
     4161        u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 7;
     4162    }
     4163    else
     4164    {
     4165        u32UpdateIntervalTSC  = (uint32_t)u64TSCDelta;
     4166
     4167        /* This value hasn't be checked yet.. waiting for OS/2 and 33Hz timers.. :-) */
     4168        u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 6;
     4169    }
     4170    ASMAtomicXchgU32(&pGipCpu->u32UpdateIntervalTSC, u32UpdateIntervalTSC + u32UpdateIntervalTSCSlack);
     4171
     4172    /*
     4173     * CpuHz.
     4174     */
     4175    u64CpuHz = ASMMult2xU32RetU64(u32UpdateIntervalTSC, pGip->u32UpdateHz);
     4176    ASMAtomicXchgU64(&pGipCpu->u64CpuHz, u64CpuHz);
     4177}
     4178
     4179
     4180/**
     4181 * Updates the GIP.
     4182 *
     4183 * @param   pGip        Pointer to the GIP.
     4184 * @param   u64NanoTS   The current nanosecond timesamp.
     4185 */
     4186void VBOXCALL   supdrvGipUpdate(PSUPGLOBALINFOPAGE pGip, uint64_t u64NanoTS)
     4187{
     4188    /*
     4189     * Determin the relevant CPU data.
     4190     */
     4191    PSUPGIPCPU pGipCpu;
     4192    if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
     4193        pGipCpu = &pGip->aCPUs[0];
     4194    else
     4195    {
     4196        unsigned iCpu = ASMGetApicId();
     4197        if (RT_LIKELY(iCpu >= RT_ELEMENTS(pGip->aCPUs)))
     4198            return;
     4199        pGipCpu = &pGip->aCPUs[iCpu];
     4200    }
     4201
     4202    /*
    40754203     * Start update transaction.
    40764204     */
    4077     if (!(ASMAtomicIncU32(&pGip->u32TransactionId) & 1))
     4205    if (!(ASMAtomicIncU32(&pGipCpu->u32TransactionId) & 1))
    40784206    {
    40794207        /* this can happen on win32 if we're taking to long and there are more CPUs around. shouldn't happen though. */
    4080         AssertMsgFailed(("Invalid transaction id, %#x, not odd!\n", pGip->u32TransactionId));
    4081         ASMAtomicIncU32(&pGip->u32TransactionId);
    4082         pGip->cErrors++;
     4208        AssertMsgFailed(("Invalid transaction id, %#x, not odd!\n", pGipCpu->u32TransactionId));
     4209        ASMAtomicIncU32(&pGipCpu->u32TransactionId);
     4210        pGipCpu->cErrors++;
    40834211        return;
    40844212    }
    40854213
    4086     ASMAtomicXchgU64(&pGip->u64NanoTS, u64NanoTS);
    4087 
    40884214    /*
    40894215     * Recalc the update frequency every 0x800th time.
    40904216     */
    4091     if (!(pGip->u32TransactionId & (GIP_UPDATEHZ_RECALC_FREQ * 2 - 2)))
     4217    if (!(pGipCpu->u32TransactionId & (GIP_UPDATEHZ_RECALC_FREQ * 2 - 2)))
    40924218    {
    40934219        if (pGip->u64NanoTSLastUpdateHz)
     
    41074233
    41084234    /*
    4109      * Calc TSC delta.
    4110      */
    4111     /** @todo validate the NanoTS delta, don't trust the OS to call us when it should... */
    4112     u64TSC = ASMReadTSC();
    4113     u64TSCDelta = u64TSC - pGip->u64TSC;
    4114     ASMAtomicXchgU64(&pGip->u64TSC, u64TSC);
    4115 
    4116     if (u64TSCDelta >> 32)
    4117     {
    4118         u64TSCDelta = pGip->u32UpdateIntervalTSC;
    4119         pGip->cErrors++;
    4120     }
    4121 
    4122     /*
    4123      * TSC History.
    4124      */
    4125     Assert(ELEMENTS(pGip->au32TSCHistory) == 8);
    4126 
    4127     iTSCHistoryHead = (pGip->iTSCHistoryHead + 1) & 7;
    4128     ASMAtomicXchgU32(&pGip->iTSCHistoryHead, iTSCHistoryHead);
    4129     ASMAtomicXchgU32(&pGip->au32TSCHistory[iTSCHistoryHead], (uint32_t)u64TSCDelta);
    4130 
    4131     /*
    4132      * UpdateIntervalTSC = average of last 8,2,1 intervals depending on update HZ.
    4133      */
    4134     if (pGip->u32UpdateHz >= 1000)
    4135     {
    4136         uint32_t u32;
    4137         u32  = pGip->au32TSCHistory[0];
    4138         u32 += pGip->au32TSCHistory[1];
    4139         u32 += pGip->au32TSCHistory[2];
    4140         u32 += pGip->au32TSCHistory[3];
    4141         u32 >>= 2;
    4142         u32UpdateIntervalTSC  = pGip->au32TSCHistory[4];
    4143         u32UpdateIntervalTSC += pGip->au32TSCHistory[5];
    4144         u32UpdateIntervalTSC += pGip->au32TSCHistory[6];
    4145         u32UpdateIntervalTSC += pGip->au32TSCHistory[7];
    4146         u32UpdateIntervalTSC >>= 2;
    4147         u32UpdateIntervalTSC += u32;
    4148         u32UpdateIntervalTSC >>= 1;
    4149 
    4150         /* Value choosen for a 2GHz Athlon64 running linux 2.6.10/11, . */
    4151         u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 14;
    4152     }
    4153     else if (pGip->u32UpdateHz >= 90)
    4154     {
    4155         u32UpdateIntervalTSC  = (uint32_t)u64TSCDelta;
    4156         u32UpdateIntervalTSC += pGip->au32TSCHistory[(iTSCHistoryHead - 1) & 7];
    4157         u32UpdateIntervalTSC >>= 1;
    4158 
    4159         /* value choosen on a 2GHz thinkpad running windows */
    4160         u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 7;
    4161     }
    4162     else
    4163     {
    4164         u32UpdateIntervalTSC  = (uint32_t)u64TSCDelta;
    4165 
    4166         /* This value hasn't be checked yet.. waiting for OS/2 and 33Hz timers.. :-) */
    4167         u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 6;
    4168     }
    4169     ASMAtomicXchgU32(&pGip->u32UpdateIntervalTSC, u32UpdateIntervalTSC + u32UpdateIntervalTSCSlack);
    4170 
    4171     /*
    4172      * CpuHz.
    4173      */
    4174     u64CpuHz = ASMMult2xU32RetU64(u32UpdateIntervalTSC, pGip->u32UpdateHz);
    4175     ASMAtomicXchgU64(&pGip->u64CpuHz, u64CpuHz);
     4235     * Update the data.
     4236     */
     4237    supdrvGipDoUpdateCpu(pGip, pGipCpu, u64NanoTS);
    41764238
    41774239    /*
    41784240     * Complete transaction.
    41794241     */
    4180     ASMAtomicIncU32(&pGip->u32TransactionId);
     4242    ASMAtomicIncU32(&pGipCpu->u32TransactionId);
     4243}
     4244
     4245
     4246/**
     4247 * Updates the per cpu GIP data for the calling cpu.
     4248 *
     4249 * @param   pGip        Pointer to the GIP.
     4250 * @param   u64NanoTS   The current nanosecond timesamp.
     4251 * @param   iCpu        The CPU index.
     4252 */
     4253void VBOXCALL   supdrvGipUpdatePerCpu(PSUPGLOBALINFOPAGE pGip, uint64_t u64NanoTS, unsigned iCpu)
     4254{
     4255    PSUPGIPCPU  pGipCpu;
     4256
     4257    if (RT_LIKELY(iCpu <= RT_ELEMENTS(pGip->aCPUs)))
     4258    {
     4259        pGipCpu = &pGip->aCPUs[iCpu];
     4260
     4261        /*
     4262         * Start update transaction.
     4263         */
     4264        if (!(ASMAtomicIncU32(&pGipCpu->u32TransactionId) & 1))
     4265        {
     4266            AssertMsgFailed(("Invalid transaction id, %#x, not odd!\n", pGipCpu->u32TransactionId));
     4267            ASMAtomicIncU32(&pGipCpu->u32TransactionId);
     4268            pGipCpu->cErrors++;
     4269            return;
     4270        }
     4271
     4272        /*
     4273         * Update the data.
     4274         */
     4275        supdrvGipDoUpdateCpu(pGip, pGipCpu, u64NanoTS);
     4276
     4277        /*
     4278         * Complete transaction.
     4279         */
     4280        ASMAtomicIncU32(&pGipCpu->u32TransactionId);
     4281    }
    41814282}
    41824283
  • trunk/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c

    r876 r1027  
    13611361{
    13621362    PSUPDRVDEVEXT pDevExt  = (PSUPDRVDEVEXT)ulUser;
     1363    PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
    13631364    unsigned long ulNow    = jiffies;
    13641365    unsigned long ulDiff   = ulNow - pDevExt->ulLastJiffies;
     1366    uint64_t u64Monotime;
    13651367    pDevExt->ulLastJiffies = ulNow;
    13661368#ifdef TICK_NSEC
    1367     pDevExt->u64LastMonotime += ulDiff * TICK_NSEC;
     1369    u64Monotime = pDevExt->u64LastMonotime + ulDiff * TICK_NSEC;
    13681370#else
    1369     pDevExt->u64LastMonotime += ulDiff * (1000000 / HZ);
    1370 #endif
    1371     supdrvGipUpdate(pDevExt->pGip, pDevExt->u64LastMonotime);
     1371    u64Monotime = pDevExt->u64LastMonotime + ulDiff * (1000000 / HZ);
     1372#endif
     1373    ASMAtomicXchgU64(&pDevExt->u64LastMonotime, u64Monotime);
     1374    if (RT_LIKELY(pGip))
     1375    {
     1376#ifdef CONFIG_SMP
     1377        if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
     1378#endif
     1379            supdrvGipUpdate(pDevExt->pGip, u64Monotime);
     1380#ifdef CONFIG_SMP
     1381        else
     1382        {
     1383            smp_call_function(VBoxSupDrvGipPerCpu, pDevExt, 0 /* don't retry? */, 0 /* don't wait */);
     1384            supdrvGipUpdate(pDevExt->pGip, u64Monotime);
     1385        }
     1386#endif
     1387    }
    13721388    mod_timer(&g_GipTimer, jiffies + (HZ <= 1000 ? 0 : ONE_MSEC_IN_JIFFIES));
    13731389}
     1390
     1391
     1392#ifdef CONFIG_SMP
     1393/**
     1394 * smp_call_function callback.
     1395 * This is invoked on all the other CPUs.
     1396 *
     1397 * @param   pvUser  Pointer to the device extension.
     1398 */
     1399static void VBoxSupDrvGipPerCpu(void *pvUser)
     1400{
     1401    PSUPDRVDEVEXT pDevExt  = (PSUPDRVDEVEXT)ulUser;
     1402    PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
     1403    supdrvGipUpdatePerCpu(pGip, pDevExt->u64LastMonotime, ASMGetApicId());
     1404}
     1405#endif  /* CONFIG_SMP */
    13741406
    13751407
     
    14931525    if (timer_pending(&g_GipTimer))
    14941526        del_timer(&g_GipTimer);
     1527}
     1528
     1529
     1530/**
     1531 * Get the current CPU count.
     1532 * @returns Number of cpus.
     1533 */
     1534unsigned VBOXCALL supdrvOSGetCPUCount(void)
     1535{
     1536#ifdef CONFIG_SMP
     1537# ifdef num_present_cpus
     1538    return num_present_cpus();
     1539# else
     1540    return smp_num_cpus;
     1541# endif
     1542#else
     1543    return 1;
     1544#endif
    14951545}
    14961546
  • trunk/src/VBox/HostDrivers/Support/testcase/Makefile

    r1 r1027  
    6565tstPage_SOURCES       = $(VBOX_PATH_SUPPORT)/testcase/tstPage.cpp
    6666
    67 tstGIP-1_TEMPLATE     = VBOXR3TSTEXE
    68 tstGIP-1_SOURCES      = $(VBOX_PATH_SUPPORT)/testcase/tstGIP-1.c
    69 
    7067tstGIP-2_TEMPLATE     = VBOXR3TSTEXE
    7168tstGIP-2_SOURCES      = $(VBOX_PATH_SUPPORT)/testcase/tstGIP-2.cpp
  • trunk/src/VBox/HostDrivers/Support/testcase/tstGIP-2.cpp

    r1 r1027  
    5757                RTPrintf("tstGIP-2: %2d: %016llx %016llx %08x %d %08x %15llu %08x %08x %08x %08x %08x %08x %08x %08x\n",
    5858                         i,
    59                          g_pSUPGlobalInfoPage->u64NanoTS,
    60                          g_pSUPGlobalInfoPage->u64TSC,
    61                          g_pSUPGlobalInfoPage->u32UpdateIntervalTSC,
    62                          g_pSUPGlobalInfoPage->iTSCHistoryHead,
    63                          g_pSUPGlobalInfoPage->u32TransactionId,
    64                          g_pSUPGlobalInfoPage->u64CpuHz,
    65                          g_pSUPGlobalInfoPage->au32TSCHistory[0],
    66                          g_pSUPGlobalInfoPage->au32TSCHistory[1],
    67                          g_pSUPGlobalInfoPage->au32TSCHistory[2],
    68                          g_pSUPGlobalInfoPage->au32TSCHistory[3],
    69                          g_pSUPGlobalInfoPage->au32TSCHistory[4],
    70                          g_pSUPGlobalInfoPage->au32TSCHistory[5],
    71                          g_pSUPGlobalInfoPage->au32TSCHistory[6],
    72                          g_pSUPGlobalInfoPage->au32TSCHistory[7]);
     59                         g_pSUPGlobalInfoPage->aCPUs[0].u64NanoTS,
     60                         g_pSUPGlobalInfoPage->aCPUs[0].u64TSC,
     61                         g_pSUPGlobalInfoPage->aCPUs[0].u32UpdateIntervalTSC,
     62                         g_pSUPGlobalInfoPage->aCPUs[0].iTSCHistoryHead,
     63                         g_pSUPGlobalInfoPage->aCPUs[0].u32TransactionId,
     64                         g_pSUPGlobalInfoPage->aCPUs[0].u64CpuHz,
     65                         g_pSUPGlobalInfoPage->aCPUs[0].au32TSCHistory[0],
     66                         g_pSUPGlobalInfoPage->aCPUs[0].au32TSCHistory[1],
     67                         g_pSUPGlobalInfoPage->aCPUs[0].au32TSCHistory[2],
     68                         g_pSUPGlobalInfoPage->aCPUs[0].au32TSCHistory[3],
     69                         g_pSUPGlobalInfoPage->aCPUs[0].au32TSCHistory[4],
     70                         g_pSUPGlobalInfoPage->aCPUs[0].au32TSCHistory[5],
     71                         g_pSUPGlobalInfoPage->aCPUs[0].au32TSCHistory[6],
     72                         g_pSUPGlobalInfoPage->aCPUs[0].au32TSCHistory[7]);
    7373                RTThreadSleep(9);
    7474            }
  • trunk/src/VBox/HostDrivers/Support/win32/SUPDrv-win32.cpp

    r390 r1027  
    7070static void                VBoxSupDrvGipTerm(PSUPDRVDEVEXT pDevExt);
    7171static void     _stdcall   VBoxSupDrvGipTimer(IN PKDPC pDpc, IN PVOID pvUser, IN PVOID SystemArgument1, IN PVOID SystemArgument2);
     72static void     _stdcall   VBoxSupDrvGipPerCpuDpc(IN PKDPC pDpc, IN PVOID pvUser, IN PVOID SystemArgument1, IN PVOID SystemArgument2);
    7273
    7374
     
    789790                 */
    790791                KeInitializeTimerEx(&pDevExt->GipTimer, SynchronizationTimer);
    791                 KeInitializeDpc(&pDevExt->GipDpc, VBoxSupDrvGipTimer, pGip);
     792                KeInitializeDpc(&pDevExt->GipDpc, VBoxSupDrvGipTimer, pDevExt);
     793
     794                /*
     795                 * Initialize the DPCs we're using to update the per-cpu GIP data.
     796                 * (Not sure if we need to be this careful with KeSetTargetProcessorDpc...)
     797                 */
     798                UNICODE_STRING  RoutineName;
     799                RtlInitUnicodeString(&RoutineName, L"KeSetTargetProcessorDpc");
     800                VOID (*pfnKeSetTargetProcessorDpc)(IN PRKDPC, IN CCHAR) = (VOID (*)(IN PRKDPC, IN CCHAR))MmGetSystemRoutineAddress(&RoutineName);
     801
     802                for (unsigned i = 0; i < RT_ELEMENTS(pDevExt->aGipCpuDpcs); i++)
     803                {
     804                    KeInitializeDpc(&pDevExt->aGipCpuDpcs[i], VBoxSupDrvGipPerCpuDpc, pGip);
     805                    KeSetImportanceDpc(&pDevExt->aGipCpuDpcs[i], HighImportance);
     806                    if (pfnKeSetTargetProcessorDpc)
     807                        pfnKeSetTargetProcessorDpc(&pDevExt->aGipCpuDpcs[i], i);
     808                }
     809
    792810                dprintf(("VBoxSupDrvGipInit: ulClockFreq=%ld ulClockInterval=%ld ulClockIntervalActual=%ld Phys=%x%08x\n",
    793811                         ulClockFreq, ulClockInterval, ulClockIntervalActual, Phys.HighPart, Phys.LowPart));
    794812                return STATUS_SUCCESS;
    795813            }
    796             else
    797             {
    798                 dprintf(("VBoxSupDrvInitGip: IoAllocateMdl failed for %p/PAGE_SIZE\n", pGip));
    799                 rc = STATUS_NO_MEMORY;
    800             }
     814
     815            dprintf(("VBoxSupDrvInitGip: IoAllocateMdl failed for %p/PAGE_SIZE\n", pGip));
     816            rc = STATUS_NO_MEMORY;
    801817        }
    802818        else
     
    863879/**
    864880 * Timer callback function.
    865  * The ulUser parameter is the GIP pointer.
    866  */
    867 static void __stdcall VBoxSupDrvGipTimer(IN PKDPC pDpc, IN PVOID pvUser, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
     881 * The pvUser parameter is the pDevExt pointer.
     882 */
     883static void _stdcall VBoxSupDrvGipTimer(IN PKDPC pDpc, IN PVOID pvUser, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
     884{
     885    PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
     886    PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
     887    if (pGip)
     888    {
     889        if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
     890            supdrvGipUpdate(pGip, supdrvOSMonotime());
     891        else
     892        {
     893            RTCCUINTREG xFL = ASMGetFlags();
     894            ASMIntDisable();
     895
     896            /*
     897             * We cannot do other than assume a 1:1 relation ship between the
     898             * affinity mask and the process despite the warnings in the docs.
     899             * If someone knows a better way to get this done, please let bird know.
     900             */
     901            unsigned iSelf = KeGetCurrentProcessorNumber();
     902            KAFFINITY Mask = KeQueryActiveProcessors();
     903
     904            for (unsigned i = 0; i < RT_ELEMENTS(pDevExt->aGipCpuDpcs); i++)
     905            {
     906                if (    i != iSelf
     907                    &&  (Mask & (1 << i)))
     908                    KeInsertQueueDpc(&pDevExt->aGipCpuDpcs[i], 0, 0);
     909            }
     910
     911            /* Run the normal update. */
     912            supdrvGipUpdate(pGip, supdrvOSMonotime());
     913
     914            ASMSetFlags(xFL);
     915        }
     916    }
     917}
     918
     919
     920/**
     921 * Per cpu callback callback function.
     922 * The pvUser parameter is the pGip pointer.
     923 */
     924static void _stdcall VBoxSupDrvGipPerCpuDpc(IN PKDPC pDpc, IN PVOID pvUser, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
    868925{
    869926    PSUPGLOBALINFOPAGE pGip = (PSUPGLOBALINFOPAGE)pvUser;
    870     supdrvGipUpdate(pGip, supdrvOSMonotime());
     927    supdrvGipUpdatePerCpu(pGip, supdrvOSMonotime(), ASMGetApicId());
    871928}
    872929
  • trunk/src/VBox/Runtime/timesup.cpp

    r656 r1027  
    7575     * Read the data.
    7676     */
    77     do
     77    for (;;)
    7878    {
    7979        pGip = g_pSUPGlobalInfoPage;
     
    8282            return RTTimeSystemNanoTS();
    8383#endif
    84         u32TransactionId = pGip->u32TransactionId;
     84
     85        if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
     86        {
     87            u32TransactionId = pGip->aCPUs[0].u32TransactionId;
    8588#ifdef __L4__
    86         Assert((u32TransactionId & 1) == 0);
    87 #endif
    88         u32UpdateIntervalTSC = pGip->u32UpdateIntervalTSC;
    89         u64NanoTS = pGip->u64NanoTS;
    90         u64TSC = pGip->u64TSC;
    91         u32NanoTSFactor0 = pGip->u32UpdateIntervalNS;
    92         u64Delta = ASMReadTSC();
    93     } while (   pGip->u32TransactionId != u32TransactionId
    94              || (u32TransactionId & 1));
     89            Assert((u32TransactionId & 1) == 0);
     90#endif
     91            u32UpdateIntervalTSC = pGip->aCPUs[0].u32UpdateIntervalTSC;
     92            u64NanoTS = pGip->aCPUs[0].u64NanoTS;
     93            u64TSC = pGip->aCPUs[0].u64TSC;
     94            u32NanoTSFactor0 = pGip->u32UpdateIntervalNS;
     95            u64Delta = ASMReadTSC();
     96            if (RT_UNLIKELY(    pGip->aCPUs[0].u32TransactionId != u32TransactionId
     97                            ||  (u32TransactionId & 1)))
     98                continue;
     99        }
     100        else
     101        {
     102            /* SUPGIPMODE_ASYNC_TSC */
     103            PCSUPGIPCPU pGipCpu;
     104
     105            uint8_t u8ApicId = ASMGetApicId();
     106            if (RT_LIKELY(u8ApicId < RT_ELEMENTS(pGip->aCPUs)))
     107                pGipCpu = &pGip->aCPUs[u8ApicId];
     108            else
     109            {
     110                AssertMsgFailed(("%x\n", u8ApicId));
     111                pGipCpu = &pGip->aCPUs[0];
     112            }
     113
     114            u32TransactionId = pGipCpu->u32TransactionId;
     115#ifdef __L4__
     116            Assert((u32TransactionId & 1) == 0);
     117#endif
     118            u32UpdateIntervalTSC = pGipCpu->u32UpdateIntervalTSC;
     119            u64NanoTS = pGipCpu->u64NanoTS;
     120            u64TSC = pGipCpu->u64TSC;
     121            u32NanoTSFactor0 = pGip->u32UpdateIntervalNS;
     122            u64Delta = ASMReadTSC();
     123            if (RT_UNLIKELY(u8ApicId != ASMGetApicId()))
     124                continue;
     125            if (RT_UNLIKELY(    pGipCpu->u32TransactionId != u32TransactionId
     126                            ||  (u32TransactionId & 1)))
     127                continue;
     128        }
     129        break;
     130    }
    95131
    96132    /*
  • trunk/src/VBox/VMM/TM.cpp

    r443 r1027  
    289289    uint64_t    u64Hz;
    290290    PCSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage;
    291     if (pGip && (u64Hz = pGip->u64CpuHz) && u64Hz != ~(uint64_t)0)
    292     {
    293         RTThreadSleep(32);              /* To preserve old behaviour and to get a good CpuHz at startup. */
    294         pGip = g_pSUPGlobalInfoPage;
    295         if (pGip && (u64Hz = pGip->u64CpuHz) && u64Hz != ~(uint64_t)0)
    296             return u64Hz;
     291    if (    pGip
     292        &&  pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC)
     293    {
     294        unsigned iCpu = pGip->u32Mode != SUPGIPMODE_ASYNC_TSC ? 0 : ASMGetApicId();
     295        if (iCpu >= RT_ELEMENTS(pGip->aCPUs))
     296            AssertReleaseMsgFailed(("iCpu=%d - the ApicId is too high. send VBox.log and hardware specs!\n", iCpu));
     297        else
     298        {
     299            RTThreadSleep(32);              /* To preserve old behaviour and to get a good CpuHz at startup. */
     300            pGip = g_pSUPGlobalInfoPage;
     301            if (    pGip
     302                &&  pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC
     303                &&  (u64Hz = pGip->aCPUs[iCpu].u64CpuHz)
     304                &&  u64Hz != ~(uint64_t)0)
     305                return u64Hz;
     306        }
    297307    }
    298308
  • trunk/src/VBox/VMM/VMM.cpp

    r988 r1027  
    28042804            }
    28052805            uint64_t Ticks = ASMReadTSC() - StartTick;
    2806             if (Ticks < (g_pSUPGlobalInfoPage->u64CpuHz / 10000))
    2807                 RTPrintf("Warning: Ticks=%RU64 (< %RU64)\n", Ticks, g_pSUPGlobalInfoPage->u64CpuHz / 10000);
     2806            if (Ticks < (SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage) / 10000))
     2807                RTPrintf("Warning: Ticks=%RU64 (< %RU64)\n", Ticks, SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage) / 10000);
    28082808        }
    28092809
  • trunk/src/VBox/VMM/VMMAll/TMAll.cpp

    r23 r1027  
    612612            PCSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage;
    613613            if (pGip)
    614                 return pGip->u64CpuHz;
     614                return SUPGetCpuHzFromGIP(pGip) ;
    615615            return pTimer->CTXALLSUFF(pVM)->tm.s.cTSCTicksPerSecond;
    616616        }
  • trunk/src/VBox/VMM/VMMGC/VMMGC.cpp

    r988 r1027  
    102102        case VMMGC_DO_TESTCASE_INTERRUPT_MASKING:
    103103        {
    104             uint64_t u64MaxTicks = (g_pSUPGlobalInfoPage ? g_pSUPGlobalInfoPage->u64CpuHz : _2G) / 10000;
     104            uint64_t u64MaxTicks = (SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage) != ~(uint64_t)0
     105                                    ? SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage)
     106                                    : _2G)
     107                                   / 10000;
    105108            uint64_t u64StartTSC = ASMReadTSC();
    106109            uint64_t u64TicksNow;
Note: See TracChangeset for help on using the changeset viewer.

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