// get current time, without recalibration __forceinline ULONGLONG gethectonanotime_norecal(void) { ULONGLONG curtsc; // get the timestamp right up front curtsc = gettsc(); return hectonanotime_of_tsc(curtsc); }
/* We have 3 entropy sources: * - random values given in auxv at startup (32 bytes) * - /dev/urandom * - rdtsc + gettimeofday */ static void reseed_pool(Elf_auxv_t *auxv){ SHA256_CTX ctx; int i; int fd; uint8_t buffer[32]; uint32_t tsc[2]; SHA256_Init(&ctx); gettsc(tsc); SHA256_Update(&ctx, tsc, sizeof(tsc)); #ifdef AT_RANDOM for (i=0; auxv[i].a_type != AT_NULL; ++i){ switch(auxv[i].a_type){ case AT_RANDOM: /* 16 random bytes */ SHA256_Update(&ctx, (void *)auxv[i].a_un.a_val, 16); break; } } #endif gettsc(tsc); SHA256_Update(&ctx, tsc, sizeof(tsc)); fd = open("/dev/urandom", O_RDONLY); if(fd >= 0){ read(fd, buffer, sizeof(buffer)); SHA256_Update(&ctx, buffer, sizeof(buffer)); close(fd); } else { fd = open("/dev/random", O_RDONLY); if (fd >= 0){ /* /dev/random is more expensive to use */ read(fd, buffer, 8); SHA256_Update(&ctx, buffer, 8); close(fd); } } for (i=0;i<32;++i){ getpid(); gettsc(tsc); SHA256_Update(&ctx, tsc, sizeof(tsc)); } SHA256_Final(entropy_pool, &ctx); }
// get time of call, possibly recalibrating before returning __forceinline ULONGLONG gethectonanotime_first(void) { ULONGLONG curtsc = gettsc(); ULONGLONG now = hectonanotime_of_tsc(curtsc); if ((lastrecal == 0) || (now - lastrecal) > recalinterval) { recalibrate(); now = hectonanotime_of_tsc(curtsc); } return now; }
void recalibrate(void) { int i; ULONGLONG basetscs[nreps]; // basetsc for each round ULONGLONG basests[nreps]; // basest for each round char buf[100] = "0"; // read calibration HKEY key; DWORD cbData; RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\NetSem\\TTHEE",0,KEY_READ,&key); cbData = sizeof(tscfreq); RegQueryValueEx(key,"tscfreq",NULL,NULL,(BYTE *)&tscfreq,&cbData); cbData = sizeof(tscsd); RegQueryValueEx(key,"tscsd",NULL,NULL,(BYTE *)&tscsd,&cbData); // double error = double(tscsd) / double(tscfreq); cbData = sizeof(buf)-1; RegQueryValueEx(key,"ugly_hack_offset",NULL,NULL,(BYTE *)buf,&cbData); buf[cbData] = '\0'; ugly_hack_offset = _atoi64(buf); // get base times for (i=0; i<nreps; i++) { FILETIME baseft; Sleep(5); // to be sure we're on a tick boundary basetscs[i] = gettsc(); // get this first because it changes very fast GetSystemTimeAsFileTime(&baseft); // no rush; we have 1/64 sec to read this before it changes basests[i] = ((ULONGLONG)baseft.dwHighDateTime)<<32 | ((ULONGLONG)baseft.dwLowDateTime); } basetsc = basetscs[nreps-1]; /* Now: we want to know the correct basest for the latest basetsc. Each measurement can be extrapolated to give us a basest for the latest basetsc. But if there was a delay between the tick and our process being scheduled in a particular round, this will show up as the basetsc being high, a.k.a., the basest being low. Thus, we take the highest computed basest. */ basest = basests[nreps-1]; for (i=0; i<nreps; i++) { ULONGLONG basestx = basests[i] + (10000000 * (basetscs[nreps-1] - basetscs[i])) / tscfreq; // don't worry about overflow; at 500MHz (glia) it won't overflow until just over an hour if (basestx > basest) { basest = basestx; } } basest -= ugly_hack_offset; // apply the hack offset. lastrecal = basest; // we just recalibrated. }