VirtualBox

source: vbox/trunk/src/VBox/Runtime/timesup.cpp@ 628

Last change on this file since 628 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 6.1 KB
Line 
1/* $Id: timesup.cpp 1 1970-01-01 00:00:00Z vboxsync $ */
2/** @file
3 * InnoTek Portable Runtime - Time using SUPLib.
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP RTLOGGROUP_TIME
27#include <iprt/time.h>
28#include <iprt/asm.h>
29#include <iprt/assert.h>
30#include <iprt/err.h>
31#include <VBox/sup.h>
32#include "internal/time.h"
33
34
35/*******************************************************************************
36* Global Variables *
37*******************************************************************************/
38#ifndef IN_GUEST
39/** The previously returned nano TS.
40 * This handles TSC drift on SMP systems and expired interval.
41 * This is a valid range u64NanoTS to u64NanoTS + 1000000000 (ie. 1sec).
42 */
43static uint64_t volatile s_u64PrevNanoTS = 0;
44/**
45 * Number of times we've had to resort to 1ns walking. */
46static uint32_t volatile g_c1nsSteps = 0;
47#endif
48
49
50/**
51 * Calculate NanoTS using the information in the global information page (GIP)
52 * which the support library (SUPLib) exports.
53 *
54 * This function guarantees that the returned timestamp is later (in time) than
55 * any previous calls in the same thread.
56 *
57 * @returns Nanosecond timestamp.
58 *
59 * @remark The way the ever increasing time guarantee is currently implemented means
60 * that if you call this function at a freqency higher than 1GHz you're in for
61 * trouble. We currently assume that no idiot will do that for real life purposes.
62 */
63DECLINLINE(uint64_t) rtTimeNanoTSInternal(void)
64{
65#ifndef IN_GUEST
66 uint64_t u64Delta;
67 uint32_t u32NanoTSFactor0;
68 uint64_t u64TSC;
69 uint64_t u64NanoTS;
70 uint32_t u32UpdateIntervalTSC;
71 uint32_t u32TransactionId;
72 PCSUPGLOBALINFOPAGE pGip;
73
74 /*
75 * Read the data.
76 */
77 do
78 {
79 pGip = g_pSUPGlobalInfoPage;
80#ifdef IN_RING3
81 if (!pGip || pGip->u32Magic != SUPGLOBALINFOPAGE_MAGIC)
82 return RTTimeSystemNanoTS();
83#endif
84 u32TransactionId = pGip->u32TransactionId;
85#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));
95
96 /*
97 * Calc NanoTS delta.
98 */
99 u64Delta -= u64TSC;
100 if (u64Delta > u32UpdateIntervalTSC)
101 {
102 /*
103 * We've expired the interval. Do 1ns per call until we've
104 * got valid TSC deltas again (s_u64PrevNanoTS takes care of this).
105 */
106 u64Delta = u32UpdateIntervalTSC;
107 }
108#if !defined(_MSC_VER) || defined(__amd64__) /* GCC makes very pretty code from these two inline calls, while MSC cannot. */
109 u64Delta = ASMMult2xU32RetU64((uint32_t)u64Delta, u32NanoTSFactor0);
110 u64Delta = ASMDivU64ByU32RetU32(u64Delta, u32UpdateIntervalTSC);
111#else
112 __asm
113 {
114 mov eax, dword ptr [u64Delta]
115 mul dword ptr [u32NanoTSFactor0]
116 div dword ptr [u32UpdateIntervalTSC]
117 mov dword ptr [u64Delta], eax
118 xor edx, edx
119 mov dword ptr [u64Delta + 4], edx
120 }
121#endif
122
123 /*
124 * The most frequent case is that the delta is either too old
125 * or that our timestamp is higher (relative to u64NanoTS) than it.
126 */
127 uint64_t u64;
128 uint64_t u64PrevNanoTS = ASMAtomicReadU64(&s_u64PrevNanoTS);
129 uint64_t u64DeltaPrev = u64PrevNanoTS - u64NanoTS;
130 if ( u64DeltaPrev > 1000000000 /* (invalid prev) */
131 || (uint32_t)u64DeltaPrev < (uint32_t)u64Delta) /* (we're later) */
132 {
133 u64 = u64Delta + u64NanoTS;
134 if (ASMAtomicCmpXchgU64(&s_u64PrevNanoTS, u64, u64PrevNanoTS))
135 return u64;
136 }
137 else
138 {
139 /*
140 * Our timestamp is lower than the last returned timestamp;
141 * advance 1ns beyond that.
142 */
143 u64Delta = u64DeltaPrev + 1;
144 u64 = u64Delta + u64NanoTS;
145 ASMAtomicIncU32(&g_c1nsSteps);
146 }
147
148 /*
149 * Attempt updating the previous value.
150 * u64 == timestamp, u64Delta == delta relative to u64NanoTS.
151 */
152 for (int cTries = 100;;)
153 {
154 u64PrevNanoTS = ASMAtomicReadU64(&s_u64PrevNanoTS);
155 u64DeltaPrev = u64PrevNanoTS - u64NanoTS;
156 if (u64DeltaPrev > u64Delta)
157 break;
158 if (ASMAtomicCmpXchgU64(&s_u64PrevNanoTS, u64, u64PrevNanoTS))
159 break;
160 if (--cTries <= 0)
161 {
162 AssertBreakpoint(); /* (recursion) */
163 break;
164 }
165 }
166
167 return u64;
168#else /* IN_GUEST */
169 return RTTimeSystemNanoTS();
170#endif /* IN_GUEST */
171}
172
173
174/**
175 * Gets the current nanosecond timestamp.
176 *
177 * @returns nanosecond timestamp.
178 */
179RTDECL(uint64_t) RTTimeNanoTS(void)
180{
181 return rtTimeNanoTSInternal();
182}
183
184
185/**
186 * Gets the current millisecond timestamp.
187 *
188 * @returns millisecond timestamp.
189 */
190RTDECL(uint64_t) RTTimeMilliTS(void)
191{
192 return rtTimeNanoTSInternal() / 1000000;
193}
194
195
196#ifndef IN_GUEST
197/**
198 * Debugging the time api.
199 *
200 * @returns the number of 1ns steps which has been applied by rtTimeNanoTSInternal().
201 */
202RTDECL(uint32_t) RTTime1nsSteps(void)
203{
204 return g_c1nsSteps;
205}
206#endif
Note: See TracBrowser for help on using the repository browser.

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