Changeset 1692 in vbox for trunk/src/VBox
- Timestamp:
- Mar 26, 2007 7:22:22 AM (18 years ago)
- svn:sync-xref-src-repo-rev:
- 19840
- Location:
- trunk/src/VBox/Runtime/testcase
- Files:
-
- 1 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/testcase/Makefile
r1190 r1692 32 32 tstLdrLoad \ 33 33 tstAvl \ 34 tstTSC \ 34 35 tstTimer \ 35 36 tstTime \ … … 82 83 tstTimer_SOURCES = tstTimer.cpp 83 84 85 tstTSC_SOURCES = tstTSC.cpp 86 84 87 tstTime_SOURCES = tstTime.cpp 85 88 -
trunk/src/VBox/Runtime/testcase/tstTSC.cpp
r1688 r1692 1 1 /* $Id$ */ 2 2 /** @file 3 * InnoTek Portable Runtime Testcase - S imple RTTime test.3 * InnoTek Portable Runtime Testcase - SMP TSC testcase. 4 4 */ 5 5 … … 23 23 * Header Files * 24 24 *******************************************************************************/ 25 #ifdef __WIN__26 # include <Windows.h>27 28 #elif defined __L4__29 30 #else /* posix */31 # include <sys/time.h>32 #endif33 34 #include <iprt/time.h>35 #include <iprt/stream.h>36 25 #include <iprt/runtime.h> 37 #include <iprt/thread.h> 38 #include <VBox/sup.h> 39 40 DECLINLINE(uint64_t) OSNanoTS(void) 26 27 /******************************************************************************* 28 * Structures and Typedefs * 29 *******************************************************************************/ 30 typedef struct TSCDATA 41 31 { 42 #ifdef __WIN__ 43 uint64_t u64; /* manual say larger integer, should be safe to assume it's the same. */ 44 GetSystemTimeAsFileTime((LPFILETIME)&u64); 45 return u64 * 100; 46 47 #elif defined __L4__ 48 /** @todo fix a different timesource on l4. */ 49 return RTTimeNanoTS(); 50 51 #else /* posix */ 52 53 struct timeval tv; 54 gettimeofday(&tv, NULL); 55 return (uint64_t)tv.tv_sec * (uint64_t)(1000 * 1000 * 1000) 56 + (uint64_t)(tv.tv_usec * 1000); 57 #endif 32 /** The TSC. */ 33 uint64_t volatile TSC; 34 /** The APIC ID. */ 35 uint8_t volatile u8ApicId; 36 /** Did it succeed? */ 37 bool volatile fRead; 38 /** Did it fail? */ 39 bool volatile fFailed; 40 /** The thread handle. */ 41 RTTHREAD Thread; 42 } TSCDATA, *PTSCDATA; 43 44 /******************************************************************************* 45 * Global Variables * 46 *******************************************************************************/ 47 /** The number of CPUs waiting on their user event semaphore. */ 48 static volatile uint32_t g_cWaiting; 49 /** The number of CPUs ready (in spin) to do the TSC read. */ 50 static volatile uint32_t g_cReady; 51 /** The variable the CPUs are spinning on. 52 * 0: Spin. 53 * 1: Go ahead. 54 * 2: You're too late, back to square one. */ 55 static volatile uint32_t g_u32Go; 56 /** The number of CPUs that managed to read the TSC. */ 57 static volatile uint32_t g_cRead; 58 /** The number of CPUs that failed to read the TSC. */ 59 static volatile uint32_t g_cFailed; 60 61 /** Indicator forcing the threads to quit. */ 62 static volatile bool g_fDone; 63 64 65 /******************************************************************************* 66 * Internal Functions * 67 *******************************************************************************/ 68 static DECLCALLBACK(int) ThreadFunction(RTTHREAD Thread, void *pvUser); 69 70 71 /** 72 * Thread function for catching the other cpus. 73 * 74 * @returns VINF_SUCCESS (we don't care). 75 * @param Thread The thread handle. 76 * @param pvUser PTSCDATA. 77 */ 78 static DECLCALLBACK(int) ThreadFunction(RTTHREAD Thread, void *pvUser) 79 { 80 PTSCDATA pTscData = (PTSCDATA)pvUser; 81 82 while (!g_fDone) 83 { 84 /* 85 * Wait. 86 */ 87 ASMAtomicIncU32(&g_cWaiting); 88 RTThreadUserWait(Thread, RT_INDEFINITE_WAIT); 89 RTThreadUserReset(Thread); 90 ASMAtomicDecU32(&g_cWaiting); 91 if (g_fDone) 92 break; 93 94 /* 95 * Spin. 96 */ 97 ASMAtomicIncU32(&g_cReady); 98 while (!g_fDone) 99 { 100 const uint8_t ApicId1 = ASMGetApicId(); 101 const uint64_t TSC1 = ASMReadTSC(); 102 const uint32_t u32Go = g_u32Go; 103 if (u32Go == 0) 104 continue; 105 106 if (u32Go == 1) 107 { 108 /* do the reading. */ 109 const uint8_t ApicId2 = ASMGetApicId(); 110 const uint64_t TSC2 = ASMReadTSC(); 111 const uint8_t ApicId3 = ASMGetApicId(); 112 const uint64_t TSC3 = ASMReadTSC(); 113 const uint8_t ApicId4 = ASMGetApicId(); 114 115 if ( ApicId1 == ApicId2 116 && ApicId1 == ApicId3 117 && ApicId1 == ApicId4 118 && TSC3 - TSC1 < 1750 /* WARNING: This is just a guess, increase if it doesn't work for you. */ 119 && TSC2 - TSC1 < TSC3 - TSC1 120 ) 121 { 122 /* succeeded. */ 123 pTscData->TSC = TSC2; 124 pTscData->u8ApicId = ApicId1; 125 pTscData->fFailed = false; 126 pTscData->fRead = true; 127 ASMAtomicIncU32(&g_cRead); 128 break; 129 } 130 } 131 132 /* failed */ 133 pTscData->fFailed = true; 134 pTscData->fRead = false; 135 ASMAtomicIncU32(&g_cFailed); 136 break; 137 } 138 } 139 140 return VINF_SUCCESS; 58 141 } 59 60 142 61 143 62 144 int main() 63 145 { 64 unsigned cErrors = 0;65 int i;66 146 RTR3Init(); 67 SUPInit();68 RTPrintf("tstTime-2: TESTING...\n");69 147 70 148 /* 71 * RTNanoTimeTS() shall never return something which 72 * is less or equal to the return of the previous call. 149 * This is only relevant to on SMP systems. 73 150 */ 74 75 OSNanoTS(); RTTimeNanoTS(); RTThreadYield(); 76 uint64_t u64RTStartTS = RTTimeNanoTS(); 77 uint64_t u64OSStartTS = OSNanoTS(); 78 #define NUMBER_OF_CALLS (100*_1M) 79 80 for (i = 0; i < NUMBER_OF_CALLS; i++) 81 RTTimeNanoTS(); 82 83 uint64_t u64RTElapsedTS = RTTimeNanoTS(); 84 uint64_t u64OSElapsedTS = OSNanoTS(); 85 u64RTElapsedTS -= u64RTStartTS; 86 u64OSElapsedTS -= u64OSStartTS; 87 int64_t i64Diff = u64OSElapsedTS >= u64RTElapsedTS ? u64OSElapsedTS - u64RTElapsedTS : u64RTElapsedTS - u64OSElapsedTS; 88 if (i64Diff > (int64_t)(u64OSElapsedTS / 1000)) 89 { 90 RTPrintf("tstTime-2: error: total time differs too much! u64OSElapsedTS=%#llx u64RTElapsedTS=%#llx delta=%lld\n", 91 u64OSElapsedTS, u64RTElapsedTS, u64OSElapsedTS - u64RTElapsedTS); 92 cErrors++; 93 } 94 else 95 RTPrintf("tstTime-2: total time difference: u64OSElapsedTS=%#llx u64RTElapsedTS=%#llx delta=%lld\n", 96 u64OSElapsedTS, u64RTElapsedTS, u64OSElapsedTS - u64RTElapsedTS); 97 98 #if defined __WIN__ || defined __LINUX__ 99 RTPrintf("tstTime-2: RTTime1nsSteps -> %u out of %u calls\n", RTTime1nsSteps(), NUMBER_OF_CALLS); 100 #endif 101 if (!cErrors) 102 RTPrintf("tstTime-2: SUCCESS\n"); 103 else 104 RTPrintf("tstTime-2: FAILURE - %d errors\n", cErrors); 105 return !!cErrors; 151 const unsigned cCpus = RTSystemProcessorGetCount(); 152 if (cCpus <= 1) 153 { 154 RTPrintf("tstTSC: SKIPPED - Only relevant on SMP systems\n"); 155 return 0; 156 } 157 158 /* 159 * Create the threads. 160 */ 161 static TSCDATA s_aData[254]; 162 uint32_t i; 163 if (cCpus > RT_ELEMENTS(s_aData)) 164 { 165 RTPrintf("tstTSC: FAILED - too many CPUs (%u)\n", cCpus); 166 return 1; 167 } 168 169 /* ourselves. */ 170 s_aData[0].Thread = RTThreadSelf(); 171 172 /* the others */ 173 for (i = 1; i < cCpus; i++) 174 { 175 int rc = RTThreadCreate(&s_aData[i].Thread, ThreadFunction, &s_aData[i], 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "OTHERCPU"); 176 if (RT_FAILURE(rc)) 177 { 178 RTPrintf("tstTSC: FAILURE - RTThreatCreate failed when creating thread #%u, rc=%Rrc!\n", i, rc); 179 ASMAtomicXchgSize(&g_fDone, true); 180 while (i-- > 1) 181 { 182 RTThreadUserSignal(s_aData[i].Thread); 183 RTThreadWait(s_aData[i].Thread, 5000, NULL); 184 } 185 return 1; 186 } 187 } 188 189 /* 190 * Retry untill we get lucky (or give up). 191 */ 192 for (unsigned cTries = 0; ; cTries++) 193 { 194 if (cTries > 1024) 195 { 196 RTPrintf("tstTSC: FAILURE - %d attempts, giving.\n", cTries); 197 break; 198 } 199 200 /* 201 * Wait for the other threads to get ready (brute force active wait, I'm lazy). 202 */ 203 i = 0; 204 while (g_cWaiting < cCpus - 1) 205 { 206 if (i++ > _2G32) 207 break; 208 RTThreadSleep(i & 0xf); 209 } 210 if (g_cWaiting != cCpus - 1) 211 { 212 RTPrintf("tstTSC: FAILURE - threads failed to get waiting (%d != %d (i=%d))\n", g_cWaiting + 1, cCpus, i); 213 break; 214 } 215 216 /* 217 * Send them spinning. 218 */ 219 ASMAtomicXchgU32(&g_cReady, 0); 220 ASMAtomicXchgU32(&g_u32Go, 0); 221 ASMAtomicXchgU32(&g_cRead, 0); 222 ASMAtomicXchgU32(&g_cFailed, 0); 223 for (i = 1; i < cCpus; i++) 224 { 225 ASMAtomicXchgSize(&s_aData[i].fFailed, false); 226 ASMAtomicXchgSize(&s_aData[i].fRead, false); 227 ASMAtomicXchgU8(&s_aData[i].u8ApicId, 0xff); 228 229 int rc = RTThreadUserSignal(s_aData[i].Thread); 230 if (RT_FAILURE(rc)) 231 RTPrintf("tstTSC: WARNING - RTThreadUserSignal(%#u) -> rc=%Rrc!\n", i, rc); 232 } 233 234 /* wait for them to get ready. */ 235 i = 0; 236 while (g_cReady < cCpus - 1) 237 { 238 if (i++ > _2G32) 239 break; 240 } 241 if (g_cReady != cCpus - 1) 242 { 243 RTPrintf("tstTSC: FAILURE - threads failed to get ready (%d != %d, i=%d)\n", g_cWaiting + 1, cCpus, i); 244 break; 245 } 246 247 /* 248 * Flip the "go" switch and do our readings. 249 * We give the other threads the slack it takes to two extra TSC and APIC ID reads. 250 */ 251 const uint8_t ApicId1 = ASMGetApicId(); 252 const uint64_t TSC1 = ASMReadTSC(); 253 ASMAtomicXchgU32(&g_u32Go, 1); 254 const uint8_t ApicId2 = ASMGetApicId(); 255 const uint64_t TSC2 = ASMReadTSC(); 256 const uint8_t ApicId3 = ASMGetApicId(); 257 const uint64_t TSC3 = ASMReadTSC(); 258 const uint8_t ApicId4 = ASMGetApicId(); 259 const uint64_t TSC4 = ASMReadTSC(); 260 ASMAtomicXchgU32(&g_u32Go, 2); 261 const uint8_t ApicId5 = ASMGetApicId(); 262 const uint64_t TSC5 = ASMReadTSC(); 263 const uint8_t ApicId6 = ASMGetApicId(); 264 265 /* Compose our own result. */ 266 if ( ApicId1 == ApicId2 267 && ApicId1 == ApicId3 268 && ApicId1 == ApicId4 269 && ApicId1 == ApicId5 270 && ApicId1 == ApicId6 271 && TSC5 - TSC1 < 2000 /* WARNING: This is just a guess, increase if it doesn't work for you. */ 272 && TSC4 - TSC1 < TSC5 - TSC1 273 && TSC3 - TSC1 < TSC4 - TSC1 274 && TSC2 - TSC1 < TSC3 - TSC1 275 ) 276 { 277 /* succeeded. */ 278 s_aData[0].TSC = TSC2; 279 s_aData[0].u8ApicId = ApicId1; 280 s_aData[0].fFailed = false; 281 s_aData[0].fRead = true; 282 ASMAtomicIncU32(&g_cRead); 283 } 284 else 285 { 286 /* failed */ 287 s_aData[0].fFailed = true; 288 s_aData[0].fRead = false; 289 ASMAtomicIncU32(&g_cFailed); 290 } 291 292 /* 293 * Wait a little while to let the other ones to finish. 294 */ 295 i = 0; 296 while (g_cRead + g_cFailed < cCpus) 297 { 298 if (i++ > _2G32) 299 break; 300 if (i > _1M) 301 RTThreadSleep(i & 0xf); 302 } 303 if (g_cRead + g_cFailed != cCpus) 304 { 305 RTPrintf("tstTSC: FAILURE - threads failed to complete reading (%d + %d != %d)\n", g_cRead, g_cFailed, cCpus); 306 break; 307 } 308 309 /* 310 * If everone succeeded, print the results. 311 */ 312 if (!g_cFailed) 313 { 314 RTPrintf(" # ID TSC\n" 315 "-----------------------\n"); 316 for (i = 0; i < cCpus; i++) 317 RTPrintf("%2d %02x %RX64\n", i, s_aData[i].u8ApicId, s_aData[i].TSC); 318 RTPrintf("(Needed %u attempt%s.)\n", cTries + 1, cTries ? "s" : ""); 319 break; 320 } 321 } 322 323 /* 324 * Destroy the threads. 325 */ 326 ASMAtomicXchgSize(&g_fDone, true); 327 for (i = 1; i < cCpus; i++) 328 { 329 int rc = RTThreadUserSignal(s_aData[i].Thread); 330 if (RT_FAILURE(rc)) 331 RTPrintf("tstTSC: WARNING - RTThreadUserSignal(%#u) -> rc=%Rrc! (2)\n", i, rc); 332 } 333 for (i = 1; i < cCpus; i++) 334 { 335 int rc = RTThreadWait(s_aData[i].Thread, 5000, NULL); 336 if (RT_FAILURE(rc)) 337 RTPrintf("tstTSC: WARNING - RTThreadWait(%#u) -> rc=%Rrc!\n", i, rc); 338 } 339 340 return g_cFailed != 0 || g_cRead != cCpus; 106 341 }
Note:
See TracChangeset
for help on using the changeset viewer.