1*a0483764SConrad Meyer /* 2*a0483764SConrad Meyer * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc. 3*a0483764SConrad Meyer * All rights reserved. 4*a0483764SConrad Meyer * 5*a0483764SConrad Meyer * This source code is licensed under both the BSD-style license (found in the 6*a0483764SConrad Meyer * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7*a0483764SConrad Meyer * in the COPYING file in the root directory of this source tree). 8*a0483764SConrad Meyer * You may select, at your option, one of the above-listed licenses. 9*a0483764SConrad Meyer */ 10*a0483764SConrad Meyer 11*a0483764SConrad Meyer #if defined (__cplusplus) 12*a0483764SConrad Meyer extern "C" { 13*a0483764SConrad Meyer #endif 14*a0483764SConrad Meyer 15*a0483764SConrad Meyer 16*a0483764SConrad Meyer /*-**************************************** 17*a0483764SConrad Meyer * Dependencies 18*a0483764SConrad Meyer ******************************************/ 19*a0483764SConrad Meyer #include "util.h" /* note : ensure that platform.h is included first ! */ 20*a0483764SConrad Meyer #include <errno.h> 21*a0483764SConrad Meyer #include <assert.h> 22*a0483764SConrad Meyer 23*a0483764SConrad Meyer 24*a0483764SConrad Meyer int UTIL_fileExist(const char* filename) 25*a0483764SConrad Meyer { 26*a0483764SConrad Meyer stat_t statbuf; 27*a0483764SConrad Meyer #if defined(_MSC_VER) 28*a0483764SConrad Meyer int const stat_error = _stat64(filename, &statbuf); 29*a0483764SConrad Meyer #else 30*a0483764SConrad Meyer int const stat_error = stat(filename, &statbuf); 31*a0483764SConrad Meyer #endif 32*a0483764SConrad Meyer return !stat_error; 33*a0483764SConrad Meyer } 34*a0483764SConrad Meyer 35*a0483764SConrad Meyer int UTIL_isRegularFile(const char* infilename) 36*a0483764SConrad Meyer { 37*a0483764SConrad Meyer stat_t statbuf; 38*a0483764SConrad Meyer return UTIL_getFileStat(infilename, &statbuf); /* Only need to know whether it is a regular file */ 39*a0483764SConrad Meyer } 40*a0483764SConrad Meyer 41*a0483764SConrad Meyer int UTIL_getFileStat(const char* infilename, stat_t *statbuf) 42*a0483764SConrad Meyer { 43*a0483764SConrad Meyer int r; 44*a0483764SConrad Meyer #if defined(_MSC_VER) 45*a0483764SConrad Meyer r = _stat64(infilename, statbuf); 46*a0483764SConrad Meyer if (r || !(statbuf->st_mode & S_IFREG)) return 0; /* No good... */ 47*a0483764SConrad Meyer #else 48*a0483764SConrad Meyer r = stat(infilename, statbuf); 49*a0483764SConrad Meyer if (r || !S_ISREG(statbuf->st_mode)) return 0; /* No good... */ 50*a0483764SConrad Meyer #endif 51*a0483764SConrad Meyer return 1; 52*a0483764SConrad Meyer } 53*a0483764SConrad Meyer 54*a0483764SConrad Meyer int UTIL_setFileStat(const char *filename, stat_t *statbuf) 55*a0483764SConrad Meyer { 56*a0483764SConrad Meyer int res = 0; 57*a0483764SConrad Meyer struct utimbuf timebuf; 58*a0483764SConrad Meyer 59*a0483764SConrad Meyer if (!UTIL_isRegularFile(filename)) 60*a0483764SConrad Meyer return -1; 61*a0483764SConrad Meyer 62*a0483764SConrad Meyer timebuf.actime = time(NULL); 63*a0483764SConrad Meyer timebuf.modtime = statbuf->st_mtime; 64*a0483764SConrad Meyer res += utime(filename, &timebuf); /* set access and modification times */ 65*a0483764SConrad Meyer 66*a0483764SConrad Meyer #if !defined(_WIN32) 67*a0483764SConrad Meyer res += chown(filename, statbuf->st_uid, statbuf->st_gid); /* Copy ownership */ 68*a0483764SConrad Meyer #endif 69*a0483764SConrad Meyer 70*a0483764SConrad Meyer res += chmod(filename, statbuf->st_mode & 07777); /* Copy file permissions */ 71*a0483764SConrad Meyer 72*a0483764SConrad Meyer errno = 0; 73*a0483764SConrad Meyer return -res; /* number of errors is returned */ 74*a0483764SConrad Meyer } 75*a0483764SConrad Meyer 76*a0483764SConrad Meyer U32 UTIL_isDirectory(const char* infilename) 77*a0483764SConrad Meyer { 78*a0483764SConrad Meyer int r; 79*a0483764SConrad Meyer stat_t statbuf; 80*a0483764SConrad Meyer #if defined(_MSC_VER) 81*a0483764SConrad Meyer r = _stat64(infilename, &statbuf); 82*a0483764SConrad Meyer if (!r && (statbuf.st_mode & _S_IFDIR)) return 1; 83*a0483764SConrad Meyer #else 84*a0483764SConrad Meyer r = stat(infilename, &statbuf); 85*a0483764SConrad Meyer if (!r && S_ISDIR(statbuf.st_mode)) return 1; 86*a0483764SConrad Meyer #endif 87*a0483764SConrad Meyer return 0; 88*a0483764SConrad Meyer } 89*a0483764SConrad Meyer 90*a0483764SConrad Meyer U32 UTIL_isLink(const char* infilename) 91*a0483764SConrad Meyer { 92*a0483764SConrad Meyer /* macro guards, as defined in : https://linux.die.net/man/2/lstat */ 93*a0483764SConrad Meyer #ifndef __STRICT_ANSI__ 94*a0483764SConrad Meyer #if defined(_BSD_SOURCE) \ 95*a0483764SConrad Meyer || (defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) \ 96*a0483764SConrad Meyer || (defined(_XOPEN_SOURCE) && defined(_XOPEN_SOURCE_EXTENDED)) \ 97*a0483764SConrad Meyer || (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ 98*a0483764SConrad Meyer || (defined(__APPLE__) && defined(__MACH__)) 99*a0483764SConrad Meyer int r; 100*a0483764SConrad Meyer stat_t statbuf; 101*a0483764SConrad Meyer r = lstat(infilename, &statbuf); 102*a0483764SConrad Meyer if (!r && S_ISLNK(statbuf.st_mode)) return 1; 103*a0483764SConrad Meyer #endif 104*a0483764SConrad Meyer #endif 105*a0483764SConrad Meyer (void)infilename; 106*a0483764SConrad Meyer return 0; 107*a0483764SConrad Meyer } 108*a0483764SConrad Meyer 109*a0483764SConrad Meyer U64 UTIL_getFileSize(const char* infilename) 110*a0483764SConrad Meyer { 111*a0483764SConrad Meyer if (!UTIL_isRegularFile(infilename)) return UTIL_FILESIZE_UNKNOWN; 112*a0483764SConrad Meyer { int r; 113*a0483764SConrad Meyer #if defined(_MSC_VER) 114*a0483764SConrad Meyer struct __stat64 statbuf; 115*a0483764SConrad Meyer r = _stat64(infilename, &statbuf); 116*a0483764SConrad Meyer if (r || !(statbuf.st_mode & S_IFREG)) return UTIL_FILESIZE_UNKNOWN; 117*a0483764SConrad Meyer #elif defined(__MINGW32__) && defined (__MSVCRT__) 118*a0483764SConrad Meyer struct _stati64 statbuf; 119*a0483764SConrad Meyer r = _stati64(infilename, &statbuf); 120*a0483764SConrad Meyer if (r || !(statbuf.st_mode & S_IFREG)) return UTIL_FILESIZE_UNKNOWN; 121*a0483764SConrad Meyer #else 122*a0483764SConrad Meyer struct stat statbuf; 123*a0483764SConrad Meyer r = stat(infilename, &statbuf); 124*a0483764SConrad Meyer if (r || !S_ISREG(statbuf.st_mode)) return UTIL_FILESIZE_UNKNOWN; 125*a0483764SConrad Meyer #endif 126*a0483764SConrad Meyer return (U64)statbuf.st_size; 127*a0483764SConrad Meyer } 128*a0483764SConrad Meyer } 129*a0483764SConrad Meyer 130*a0483764SConrad Meyer 131*a0483764SConrad Meyer U64 UTIL_getTotalFileSize(const char* const * const fileNamesTable, unsigned nbFiles) 132*a0483764SConrad Meyer { 133*a0483764SConrad Meyer U64 total = 0; 134*a0483764SConrad Meyer int error = 0; 135*a0483764SConrad Meyer unsigned n; 136*a0483764SConrad Meyer for (n=0; n<nbFiles; n++) { 137*a0483764SConrad Meyer U64 const size = UTIL_getFileSize(fileNamesTable[n]); 138*a0483764SConrad Meyer error |= (size == UTIL_FILESIZE_UNKNOWN); 139*a0483764SConrad Meyer total += size; 140*a0483764SConrad Meyer } 141*a0483764SConrad Meyer return error ? UTIL_FILESIZE_UNKNOWN : total; 142*a0483764SConrad Meyer } 143*a0483764SConrad Meyer 144*a0483764SConrad Meyer #ifdef _WIN32 145*a0483764SConrad Meyer int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd, int followLinks) 146*a0483764SConrad Meyer { 147*a0483764SConrad Meyer char* path; 148*a0483764SConrad Meyer int dirLength, fnameLength, pathLength, nbFiles = 0; 149*a0483764SConrad Meyer WIN32_FIND_DATAA cFile; 150*a0483764SConrad Meyer HANDLE hFile; 151*a0483764SConrad Meyer 152*a0483764SConrad Meyer dirLength = (int)strlen(dirName); 153*a0483764SConrad Meyer path = (char*) malloc(dirLength + 3); 154*a0483764SConrad Meyer if (!path) return 0; 155*a0483764SConrad Meyer 156*a0483764SConrad Meyer memcpy(path, dirName, dirLength); 157*a0483764SConrad Meyer path[dirLength] = '\\'; 158*a0483764SConrad Meyer path[dirLength+1] = '*'; 159*a0483764SConrad Meyer path[dirLength+2] = 0; 160*a0483764SConrad Meyer 161*a0483764SConrad Meyer hFile=FindFirstFileA(path, &cFile); 162*a0483764SConrad Meyer if (hFile == INVALID_HANDLE_VALUE) { 163*a0483764SConrad Meyer UTIL_DISPLAYLEVEL(1, "Cannot open directory '%s'\n", dirName); 164*a0483764SConrad Meyer return 0; 165*a0483764SConrad Meyer } 166*a0483764SConrad Meyer free(path); 167*a0483764SConrad Meyer 168*a0483764SConrad Meyer do { 169*a0483764SConrad Meyer fnameLength = (int)strlen(cFile.cFileName); 170*a0483764SConrad Meyer path = (char*) malloc(dirLength + fnameLength + 2); 171*a0483764SConrad Meyer if (!path) { FindClose(hFile); return 0; } 172*a0483764SConrad Meyer memcpy(path, dirName, dirLength); 173*a0483764SConrad Meyer path[dirLength] = '\\'; 174*a0483764SConrad Meyer memcpy(path+dirLength+1, cFile.cFileName, fnameLength); 175*a0483764SConrad Meyer pathLength = dirLength+1+fnameLength; 176*a0483764SConrad Meyer path[pathLength] = 0; 177*a0483764SConrad Meyer if (cFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 178*a0483764SConrad Meyer if ( strcmp (cFile.cFileName, "..") == 0 179*a0483764SConrad Meyer || strcmp (cFile.cFileName, ".") == 0 ) 180*a0483764SConrad Meyer continue; 181*a0483764SConrad Meyer /* Recursively call "UTIL_prepareFileList" with the new path. */ 182*a0483764SConrad Meyer nbFiles += UTIL_prepareFileList(path, bufStart, pos, bufEnd, followLinks); 183*a0483764SConrad Meyer if (*bufStart == NULL) { free(path); FindClose(hFile); return 0; } 184*a0483764SConrad Meyer } else if ( (cFile.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) 185*a0483764SConrad Meyer || (cFile.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) 186*a0483764SConrad Meyer || (cFile.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) ) { 187*a0483764SConrad Meyer if (*bufStart + *pos + pathLength >= *bufEnd) { 188*a0483764SConrad Meyer ptrdiff_t const newListSize = (*bufEnd - *bufStart) + LIST_SIZE_INCREASE; 189*a0483764SConrad Meyer *bufStart = (char*)UTIL_realloc(*bufStart, newListSize); 190*a0483764SConrad Meyer if (*bufStart == NULL) { free(path); FindClose(hFile); return 0; } 191*a0483764SConrad Meyer *bufEnd = *bufStart + newListSize; 192*a0483764SConrad Meyer } 193*a0483764SConrad Meyer if (*bufStart + *pos + pathLength < *bufEnd) { 194*a0483764SConrad Meyer memcpy(*bufStart + *pos, path, pathLength+1 /* include final \0 */); 195*a0483764SConrad Meyer *pos += pathLength + 1; 196*a0483764SConrad Meyer nbFiles++; 197*a0483764SConrad Meyer } 198*a0483764SConrad Meyer } 199*a0483764SConrad Meyer free(path); 200*a0483764SConrad Meyer } while (FindNextFileA(hFile, &cFile)); 201*a0483764SConrad Meyer 202*a0483764SConrad Meyer FindClose(hFile); 203*a0483764SConrad Meyer return nbFiles; 204*a0483764SConrad Meyer } 205*a0483764SConrad Meyer 206*a0483764SConrad Meyer #elif defined(__linux__) || (PLATFORM_POSIX_VERSION >= 200112L) /* opendir, readdir require POSIX.1-2001 */ 207*a0483764SConrad Meyer 208*a0483764SConrad Meyer int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd, int followLinks) 209*a0483764SConrad Meyer { 210*a0483764SConrad Meyer DIR *dir; 211*a0483764SConrad Meyer struct dirent *entry; 212*a0483764SConrad Meyer char* path; 213*a0483764SConrad Meyer int dirLength, fnameLength, pathLength, nbFiles = 0; 214*a0483764SConrad Meyer 215*a0483764SConrad Meyer if (!(dir = opendir(dirName))) { 216*a0483764SConrad Meyer UTIL_DISPLAYLEVEL(1, "Cannot open directory '%s': %s\n", dirName, strerror(errno)); 217*a0483764SConrad Meyer return 0; 218*a0483764SConrad Meyer } 219*a0483764SConrad Meyer 220*a0483764SConrad Meyer dirLength = (int)strlen(dirName); 221*a0483764SConrad Meyer errno = 0; 222*a0483764SConrad Meyer while ((entry = readdir(dir)) != NULL) { 223*a0483764SConrad Meyer if (strcmp (entry->d_name, "..") == 0 || 224*a0483764SConrad Meyer strcmp (entry->d_name, ".") == 0) continue; 225*a0483764SConrad Meyer fnameLength = (int)strlen(entry->d_name); 226*a0483764SConrad Meyer path = (char*) malloc(dirLength + fnameLength + 2); 227*a0483764SConrad Meyer if (!path) { closedir(dir); return 0; } 228*a0483764SConrad Meyer memcpy(path, dirName, dirLength); 229*a0483764SConrad Meyer 230*a0483764SConrad Meyer path[dirLength] = '/'; 231*a0483764SConrad Meyer memcpy(path+dirLength+1, entry->d_name, fnameLength); 232*a0483764SConrad Meyer pathLength = dirLength+1+fnameLength; 233*a0483764SConrad Meyer path[pathLength] = 0; 234*a0483764SConrad Meyer 235*a0483764SConrad Meyer if (!followLinks && UTIL_isLink(path)) { 236*a0483764SConrad Meyer UTIL_DISPLAYLEVEL(2, "Warning : %s is a symbolic link, ignoring\n", path); 237*a0483764SConrad Meyer continue; 238*a0483764SConrad Meyer } 239*a0483764SConrad Meyer 240*a0483764SConrad Meyer if (UTIL_isDirectory(path)) { 241*a0483764SConrad Meyer nbFiles += UTIL_prepareFileList(path, bufStart, pos, bufEnd, followLinks); /* Recursively call "UTIL_prepareFileList" with the new path. */ 242*a0483764SConrad Meyer if (*bufStart == NULL) { free(path); closedir(dir); return 0; } 243*a0483764SConrad Meyer } else { 244*a0483764SConrad Meyer if (*bufStart + *pos + pathLength >= *bufEnd) { 245*a0483764SConrad Meyer ptrdiff_t newListSize = (*bufEnd - *bufStart) + LIST_SIZE_INCREASE; 246*a0483764SConrad Meyer *bufStart = (char*)UTIL_realloc(*bufStart, newListSize); 247*a0483764SConrad Meyer *bufEnd = *bufStart + newListSize; 248*a0483764SConrad Meyer if (*bufStart == NULL) { free(path); closedir(dir); return 0; } 249*a0483764SConrad Meyer } 250*a0483764SConrad Meyer if (*bufStart + *pos + pathLength < *bufEnd) { 251*a0483764SConrad Meyer memcpy(*bufStart + *pos, path, pathLength + 1); /* with final \0 */ 252*a0483764SConrad Meyer *pos += pathLength + 1; 253*a0483764SConrad Meyer nbFiles++; 254*a0483764SConrad Meyer } 255*a0483764SConrad Meyer } 256*a0483764SConrad Meyer free(path); 257*a0483764SConrad Meyer errno = 0; /* clear errno after UTIL_isDirectory, UTIL_prepareFileList */ 258*a0483764SConrad Meyer } 259*a0483764SConrad Meyer 260*a0483764SConrad Meyer if (errno != 0) { 261*a0483764SConrad Meyer UTIL_DISPLAYLEVEL(1, "readdir(%s) error: %s\n", dirName, strerror(errno)); 262*a0483764SConrad Meyer free(*bufStart); 263*a0483764SConrad Meyer *bufStart = NULL; 264*a0483764SConrad Meyer } 265*a0483764SConrad Meyer closedir(dir); 266*a0483764SConrad Meyer return nbFiles; 267*a0483764SConrad Meyer } 268*a0483764SConrad Meyer 269*a0483764SConrad Meyer #else 270*a0483764SConrad Meyer 271*a0483764SConrad Meyer int UTIL_prepareFileList(const char *dirName, char** bufStart, size_t* pos, char** bufEnd, int followLinks) 272*a0483764SConrad Meyer { 273*a0483764SConrad Meyer (void)bufStart; (void)bufEnd; (void)pos; (void)followLinks; 274*a0483764SConrad Meyer UTIL_DISPLAYLEVEL(1, "Directory %s ignored (compiled without _WIN32 or _POSIX_C_SOURCE)\n", dirName); 275*a0483764SConrad Meyer return 0; 276*a0483764SConrad Meyer } 277*a0483764SConrad Meyer 278*a0483764SConrad Meyer #endif /* #ifdef _WIN32 */ 279*a0483764SConrad Meyer 280*a0483764SConrad Meyer /* 281*a0483764SConrad Meyer * UTIL_createFileList - takes a list of files and directories (params: inputNames, inputNamesNb), scans directories, 282*a0483764SConrad Meyer * and returns a new list of files (params: return value, allocatedBuffer, allocatedNamesNb). 283*a0483764SConrad Meyer * After finishing usage of the list the structures should be freed with UTIL_freeFileList(params: return value, allocatedBuffer) 284*a0483764SConrad Meyer * In case of error UTIL_createFileList returns NULL and UTIL_freeFileList should not be called. 285*a0483764SConrad Meyer */ 286*a0483764SConrad Meyer const char** 287*a0483764SConrad Meyer UTIL_createFileList(const char **inputNames, unsigned inputNamesNb, 288*a0483764SConrad Meyer char** allocatedBuffer, unsigned* allocatedNamesNb, 289*a0483764SConrad Meyer int followLinks) 290*a0483764SConrad Meyer { 291*a0483764SConrad Meyer size_t pos; 292*a0483764SConrad Meyer unsigned i, nbFiles; 293*a0483764SConrad Meyer char* buf = (char*)malloc(LIST_SIZE_INCREASE); 294*a0483764SConrad Meyer char* bufend = buf + LIST_SIZE_INCREASE; 295*a0483764SConrad Meyer const char** fileTable; 296*a0483764SConrad Meyer 297*a0483764SConrad Meyer if (!buf) return NULL; 298*a0483764SConrad Meyer 299*a0483764SConrad Meyer for (i=0, pos=0, nbFiles=0; i<inputNamesNb; i++) { 300*a0483764SConrad Meyer if (!UTIL_isDirectory(inputNames[i])) { 301*a0483764SConrad Meyer size_t const len = strlen(inputNames[i]); 302*a0483764SConrad Meyer if (buf + pos + len >= bufend) { 303*a0483764SConrad Meyer ptrdiff_t newListSize = (bufend - buf) + LIST_SIZE_INCREASE; 304*a0483764SConrad Meyer buf = (char*)UTIL_realloc(buf, newListSize); 305*a0483764SConrad Meyer bufend = buf + newListSize; 306*a0483764SConrad Meyer if (!buf) return NULL; 307*a0483764SConrad Meyer } 308*a0483764SConrad Meyer if (buf + pos + len < bufend) { 309*a0483764SConrad Meyer memcpy(buf+pos, inputNames[i], len+1); /* with final \0 */ 310*a0483764SConrad Meyer pos += len + 1; 311*a0483764SConrad Meyer nbFiles++; 312*a0483764SConrad Meyer } 313*a0483764SConrad Meyer } else { 314*a0483764SConrad Meyer nbFiles += UTIL_prepareFileList(inputNames[i], &buf, &pos, &bufend, followLinks); 315*a0483764SConrad Meyer if (buf == NULL) return NULL; 316*a0483764SConrad Meyer } } 317*a0483764SConrad Meyer 318*a0483764SConrad Meyer if (nbFiles == 0) { free(buf); return NULL; } 319*a0483764SConrad Meyer 320*a0483764SConrad Meyer fileTable = (const char**)malloc((nbFiles+1) * sizeof(const char*)); 321*a0483764SConrad Meyer if (!fileTable) { free(buf); return NULL; } 322*a0483764SConrad Meyer 323*a0483764SConrad Meyer for (i=0, pos=0; i<nbFiles; i++) { 324*a0483764SConrad Meyer fileTable[i] = buf + pos; 325*a0483764SConrad Meyer pos += strlen(fileTable[i]) + 1; 326*a0483764SConrad Meyer } 327*a0483764SConrad Meyer 328*a0483764SConrad Meyer if (buf + pos > bufend) { free(buf); free((void*)fileTable); return NULL; } 329*a0483764SConrad Meyer 330*a0483764SConrad Meyer *allocatedBuffer = buf; 331*a0483764SConrad Meyer *allocatedNamesNb = nbFiles; 332*a0483764SConrad Meyer 333*a0483764SConrad Meyer return fileTable; 334*a0483764SConrad Meyer } 335*a0483764SConrad Meyer 336*a0483764SConrad Meyer /*-**************************************** 337*a0483764SConrad Meyer * Console log 338*a0483764SConrad Meyer ******************************************/ 339*a0483764SConrad Meyer int g_utilDisplayLevel; 340*a0483764SConrad Meyer 341*a0483764SConrad Meyer 342*a0483764SConrad Meyer /*-**************************************** 343*a0483764SConrad Meyer * Time functions 344*a0483764SConrad Meyer ******************************************/ 345*a0483764SConrad Meyer #if defined(_WIN32) /* Windows */ 346*a0483764SConrad Meyer 347*a0483764SConrad Meyer UTIL_time_t UTIL_getTime(void) { UTIL_time_t x; QueryPerformanceCounter(&x); return x; } 348*a0483764SConrad Meyer 349*a0483764SConrad Meyer U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd) 350*a0483764SConrad Meyer { 351*a0483764SConrad Meyer static LARGE_INTEGER ticksPerSecond; 352*a0483764SConrad Meyer static int init = 0; 353*a0483764SConrad Meyer if (!init) { 354*a0483764SConrad Meyer if (!QueryPerformanceFrequency(&ticksPerSecond)) 355*a0483764SConrad Meyer UTIL_DISPLAYLEVEL(1, "ERROR: QueryPerformanceFrequency() failure\n"); 356*a0483764SConrad Meyer init = 1; 357*a0483764SConrad Meyer } 358*a0483764SConrad Meyer return 1000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; 359*a0483764SConrad Meyer } 360*a0483764SConrad Meyer 361*a0483764SConrad Meyer U64 UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd) 362*a0483764SConrad Meyer { 363*a0483764SConrad Meyer static LARGE_INTEGER ticksPerSecond; 364*a0483764SConrad Meyer static int init = 0; 365*a0483764SConrad Meyer if (!init) { 366*a0483764SConrad Meyer if (!QueryPerformanceFrequency(&ticksPerSecond)) 367*a0483764SConrad Meyer UTIL_DISPLAYLEVEL(1, "ERROR: QueryPerformanceFrequency() failure\n"); 368*a0483764SConrad Meyer init = 1; 369*a0483764SConrad Meyer } 370*a0483764SConrad Meyer return 1000000000ULL*(clockEnd.QuadPart - clockStart.QuadPart)/ticksPerSecond.QuadPart; 371*a0483764SConrad Meyer } 372*a0483764SConrad Meyer 373*a0483764SConrad Meyer #elif defined(__APPLE__) && defined(__MACH__) 374*a0483764SConrad Meyer 375*a0483764SConrad Meyer UTIL_time_t UTIL_getTime(void) { return mach_absolute_time(); } 376*a0483764SConrad Meyer 377*a0483764SConrad Meyer U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd) 378*a0483764SConrad Meyer { 379*a0483764SConrad Meyer static mach_timebase_info_data_t rate; 380*a0483764SConrad Meyer static int init = 0; 381*a0483764SConrad Meyer if (!init) { 382*a0483764SConrad Meyer mach_timebase_info(&rate); 383*a0483764SConrad Meyer init = 1; 384*a0483764SConrad Meyer } 385*a0483764SConrad Meyer return (((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom))/1000ULL; 386*a0483764SConrad Meyer } 387*a0483764SConrad Meyer 388*a0483764SConrad Meyer U64 UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd) 389*a0483764SConrad Meyer { 390*a0483764SConrad Meyer static mach_timebase_info_data_t rate; 391*a0483764SConrad Meyer static int init = 0; 392*a0483764SConrad Meyer if (!init) { 393*a0483764SConrad Meyer mach_timebase_info(&rate); 394*a0483764SConrad Meyer init = 1; 395*a0483764SConrad Meyer } 396*a0483764SConrad Meyer return ((clockEnd - clockStart) * (U64)rate.numer) / ((U64)rate.denom); 397*a0483764SConrad Meyer } 398*a0483764SConrad Meyer 399*a0483764SConrad Meyer #elif (PLATFORM_POSIX_VERSION >= 200112L) \ 400*a0483764SConrad Meyer && (defined(__UCLIBC__) \ 401*a0483764SConrad Meyer || (defined(__GLIBC__) \ 402*a0483764SConrad Meyer && ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17) \ 403*a0483764SConrad Meyer || (__GLIBC__ > 2)))) 404*a0483764SConrad Meyer 405*a0483764SConrad Meyer UTIL_time_t UTIL_getTime(void) 406*a0483764SConrad Meyer { 407*a0483764SConrad Meyer UTIL_time_t time; 408*a0483764SConrad Meyer if (clock_gettime(CLOCK_MONOTONIC, &time)) 409*a0483764SConrad Meyer UTIL_DISPLAYLEVEL(1, "ERROR: Failed to get time\n"); /* we could also exit() */ 410*a0483764SConrad Meyer return time; 411*a0483764SConrad Meyer } 412*a0483764SConrad Meyer 413*a0483764SConrad Meyer UTIL_time_t UTIL_getSpanTime(UTIL_time_t begin, UTIL_time_t end) 414*a0483764SConrad Meyer { 415*a0483764SConrad Meyer UTIL_time_t diff; 416*a0483764SConrad Meyer if (end.tv_nsec < begin.tv_nsec) { 417*a0483764SConrad Meyer diff.tv_sec = (end.tv_sec - 1) - begin.tv_sec; 418*a0483764SConrad Meyer diff.tv_nsec = (end.tv_nsec + 1000000000ULL) - begin.tv_nsec; 419*a0483764SConrad Meyer } else { 420*a0483764SConrad Meyer diff.tv_sec = end.tv_sec - begin.tv_sec; 421*a0483764SConrad Meyer diff.tv_nsec = end.tv_nsec - begin.tv_nsec; 422*a0483764SConrad Meyer } 423*a0483764SConrad Meyer return diff; 424*a0483764SConrad Meyer } 425*a0483764SConrad Meyer 426*a0483764SConrad Meyer U64 UTIL_getSpanTimeMicro(UTIL_time_t begin, UTIL_time_t end) 427*a0483764SConrad Meyer { 428*a0483764SConrad Meyer UTIL_time_t const diff = UTIL_getSpanTime(begin, end); 429*a0483764SConrad Meyer U64 micro = 0; 430*a0483764SConrad Meyer micro += 1000000ULL * diff.tv_sec; 431*a0483764SConrad Meyer micro += diff.tv_nsec / 1000ULL; 432*a0483764SConrad Meyer return micro; 433*a0483764SConrad Meyer } 434*a0483764SConrad Meyer 435*a0483764SConrad Meyer U64 UTIL_getSpanTimeNano(UTIL_time_t begin, UTIL_time_t end) 436*a0483764SConrad Meyer { 437*a0483764SConrad Meyer UTIL_time_t const diff = UTIL_getSpanTime(begin, end); 438*a0483764SConrad Meyer U64 nano = 0; 439*a0483764SConrad Meyer nano += 1000000000ULL * diff.tv_sec; 440*a0483764SConrad Meyer nano += diff.tv_nsec; 441*a0483764SConrad Meyer return nano; 442*a0483764SConrad Meyer } 443*a0483764SConrad Meyer 444*a0483764SConrad Meyer #else /* relies on standard C (note : clock_t measurements can be wrong when using multi-threading) */ 445*a0483764SConrad Meyer 446*a0483764SConrad Meyer UTIL_time_t UTIL_getTime(void) { return clock(); } 447*a0483764SConrad Meyer U64 UTIL_getSpanTimeMicro(UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; } 448*a0483764SConrad Meyer U64 UTIL_getSpanTimeNano(UTIL_time_t clockStart, UTIL_time_t clockEnd) { return 1000000000ULL * (clockEnd - clockStart) / CLOCKS_PER_SEC; } 449*a0483764SConrad Meyer 450*a0483764SConrad Meyer #endif 451*a0483764SConrad Meyer 452*a0483764SConrad Meyer /* returns time span in microseconds */ 453*a0483764SConrad Meyer U64 UTIL_clockSpanMicro(UTIL_time_t clockStart ) 454*a0483764SConrad Meyer { 455*a0483764SConrad Meyer UTIL_time_t const clockEnd = UTIL_getTime(); 456*a0483764SConrad Meyer return UTIL_getSpanTimeMicro(clockStart, clockEnd); 457*a0483764SConrad Meyer } 458*a0483764SConrad Meyer 459*a0483764SConrad Meyer /* returns time span in microseconds */ 460*a0483764SConrad Meyer U64 UTIL_clockSpanNano(UTIL_time_t clockStart ) 461*a0483764SConrad Meyer { 462*a0483764SConrad Meyer UTIL_time_t const clockEnd = UTIL_getTime(); 463*a0483764SConrad Meyer return UTIL_getSpanTimeNano(clockStart, clockEnd); 464*a0483764SConrad Meyer } 465*a0483764SConrad Meyer 466*a0483764SConrad Meyer void UTIL_waitForNextTick(void) 467*a0483764SConrad Meyer { 468*a0483764SConrad Meyer UTIL_time_t const clockStart = UTIL_getTime(); 469*a0483764SConrad Meyer UTIL_time_t clockEnd; 470*a0483764SConrad Meyer do { 471*a0483764SConrad Meyer clockEnd = UTIL_getTime(); 472*a0483764SConrad Meyer } while (UTIL_getSpanTimeNano(clockStart, clockEnd) == 0); 473*a0483764SConrad Meyer } 474*a0483764SConrad Meyer 475*a0483764SConrad Meyer /* count the number of physical cores */ 476*a0483764SConrad Meyer #if defined(_WIN32) || defined(WIN32) 477*a0483764SConrad Meyer 478*a0483764SConrad Meyer #include <windows.h> 479*a0483764SConrad Meyer 480*a0483764SConrad Meyer typedef BOOL(WINAPI* LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD); 481*a0483764SConrad Meyer 482*a0483764SConrad Meyer int UTIL_countPhysicalCores(void) 483*a0483764SConrad Meyer { 484*a0483764SConrad Meyer static int numPhysicalCores = 0; 485*a0483764SConrad Meyer if (numPhysicalCores != 0) return numPhysicalCores; 486*a0483764SConrad Meyer 487*a0483764SConrad Meyer { LPFN_GLPI glpi; 488*a0483764SConrad Meyer BOOL done = FALSE; 489*a0483764SConrad Meyer PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL; 490*a0483764SConrad Meyer PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = NULL; 491*a0483764SConrad Meyer DWORD returnLength = 0; 492*a0483764SConrad Meyer size_t byteOffset = 0; 493*a0483764SConrad Meyer 494*a0483764SConrad Meyer glpi = (LPFN_GLPI)GetProcAddress(GetModuleHandle(TEXT("kernel32")), 495*a0483764SConrad Meyer "GetLogicalProcessorInformation"); 496*a0483764SConrad Meyer 497*a0483764SConrad Meyer if (glpi == NULL) { 498*a0483764SConrad Meyer goto failed; 499*a0483764SConrad Meyer } 500*a0483764SConrad Meyer 501*a0483764SConrad Meyer while(!done) { 502*a0483764SConrad Meyer DWORD rc = glpi(buffer, &returnLength); 503*a0483764SConrad Meyer if (FALSE == rc) { 504*a0483764SConrad Meyer if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { 505*a0483764SConrad Meyer if (buffer) 506*a0483764SConrad Meyer free(buffer); 507*a0483764SConrad Meyer buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(returnLength); 508*a0483764SConrad Meyer 509*a0483764SConrad Meyer if (buffer == NULL) { 510*a0483764SConrad Meyer perror("zstd"); 511*a0483764SConrad Meyer exit(1); 512*a0483764SConrad Meyer } 513*a0483764SConrad Meyer } else { 514*a0483764SConrad Meyer /* some other error */ 515*a0483764SConrad Meyer goto failed; 516*a0483764SConrad Meyer } 517*a0483764SConrad Meyer } else { 518*a0483764SConrad Meyer done = TRUE; 519*a0483764SConrad Meyer } 520*a0483764SConrad Meyer } 521*a0483764SConrad Meyer 522*a0483764SConrad Meyer ptr = buffer; 523*a0483764SConrad Meyer 524*a0483764SConrad Meyer while (byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength) { 525*a0483764SConrad Meyer 526*a0483764SConrad Meyer if (ptr->Relationship == RelationProcessorCore) { 527*a0483764SConrad Meyer numPhysicalCores++; 528*a0483764SConrad Meyer } 529*a0483764SConrad Meyer 530*a0483764SConrad Meyer ptr++; 531*a0483764SConrad Meyer byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); 532*a0483764SConrad Meyer } 533*a0483764SConrad Meyer 534*a0483764SConrad Meyer free(buffer); 535*a0483764SConrad Meyer 536*a0483764SConrad Meyer return numPhysicalCores; 537*a0483764SConrad Meyer } 538*a0483764SConrad Meyer 539*a0483764SConrad Meyer failed: 540*a0483764SConrad Meyer /* try to fall back on GetSystemInfo */ 541*a0483764SConrad Meyer { SYSTEM_INFO sysinfo; 542*a0483764SConrad Meyer GetSystemInfo(&sysinfo); 543*a0483764SConrad Meyer numPhysicalCores = sysinfo.dwNumberOfProcessors; 544*a0483764SConrad Meyer if (numPhysicalCores == 0) numPhysicalCores = 1; /* just in case */ 545*a0483764SConrad Meyer } 546*a0483764SConrad Meyer return numPhysicalCores; 547*a0483764SConrad Meyer } 548*a0483764SConrad Meyer 549*a0483764SConrad Meyer #elif defined(__APPLE__) 550*a0483764SConrad Meyer 551*a0483764SConrad Meyer #include <sys/sysctl.h> 552*a0483764SConrad Meyer 553*a0483764SConrad Meyer /* Use apple-provided syscall 554*a0483764SConrad Meyer * see: man 3 sysctl */ 555*a0483764SConrad Meyer int UTIL_countPhysicalCores(void) 556*a0483764SConrad Meyer { 557*a0483764SConrad Meyer static S32 numPhysicalCores = 0; /* apple specifies int32_t */ 558*a0483764SConrad Meyer if (numPhysicalCores != 0) return numPhysicalCores; 559*a0483764SConrad Meyer 560*a0483764SConrad Meyer { size_t size = sizeof(S32); 561*a0483764SConrad Meyer int const ret = sysctlbyname("hw.physicalcpu", &numPhysicalCores, &size, NULL, 0); 562*a0483764SConrad Meyer if (ret != 0) { 563*a0483764SConrad Meyer if (errno == ENOENT) { 564*a0483764SConrad Meyer /* entry not present, fall back on 1 */ 565*a0483764SConrad Meyer numPhysicalCores = 1; 566*a0483764SConrad Meyer } else { 567*a0483764SConrad Meyer perror("zstd: can't get number of physical cpus"); 568*a0483764SConrad Meyer exit(1); 569*a0483764SConrad Meyer } 570*a0483764SConrad Meyer } 571*a0483764SConrad Meyer 572*a0483764SConrad Meyer return numPhysicalCores; 573*a0483764SConrad Meyer } 574*a0483764SConrad Meyer } 575*a0483764SConrad Meyer 576*a0483764SConrad Meyer #elif defined(__linux__) 577*a0483764SConrad Meyer 578*a0483764SConrad Meyer /* parse /proc/cpuinfo 579*a0483764SConrad Meyer * siblings / cpu cores should give hyperthreading ratio 580*a0483764SConrad Meyer * otherwise fall back on sysconf */ 581*a0483764SConrad Meyer int UTIL_countPhysicalCores(void) 582*a0483764SConrad Meyer { 583*a0483764SConrad Meyer static int numPhysicalCores = 0; 584*a0483764SConrad Meyer 585*a0483764SConrad Meyer if (numPhysicalCores != 0) return numPhysicalCores; 586*a0483764SConrad Meyer 587*a0483764SConrad Meyer numPhysicalCores = (int)sysconf(_SC_NPROCESSORS_ONLN); 588*a0483764SConrad Meyer if (numPhysicalCores == -1) { 589*a0483764SConrad Meyer /* value not queryable, fall back on 1 */ 590*a0483764SConrad Meyer return numPhysicalCores = 1; 591*a0483764SConrad Meyer } 592*a0483764SConrad Meyer 593*a0483764SConrad Meyer /* try to determine if there's hyperthreading */ 594*a0483764SConrad Meyer { FILE* const cpuinfo = fopen("/proc/cpuinfo", "r"); 595*a0483764SConrad Meyer #define BUF_SIZE 80 596*a0483764SConrad Meyer char buff[BUF_SIZE]; 597*a0483764SConrad Meyer 598*a0483764SConrad Meyer int siblings = 0; 599*a0483764SConrad Meyer int cpu_cores = 0; 600*a0483764SConrad Meyer int ratio = 1; 601*a0483764SConrad Meyer 602*a0483764SConrad Meyer if (cpuinfo == NULL) { 603*a0483764SConrad Meyer /* fall back on the sysconf value */ 604*a0483764SConrad Meyer return numPhysicalCores; 605*a0483764SConrad Meyer } 606*a0483764SConrad Meyer 607*a0483764SConrad Meyer /* assume the cpu cores/siblings values will be constant across all 608*a0483764SConrad Meyer * present processors */ 609*a0483764SConrad Meyer while (!feof(cpuinfo)) { 610*a0483764SConrad Meyer if (fgets(buff, BUF_SIZE, cpuinfo) != NULL) { 611*a0483764SConrad Meyer if (strncmp(buff, "siblings", 8) == 0) { 612*a0483764SConrad Meyer const char* const sep = strchr(buff, ':'); 613*a0483764SConrad Meyer if (*sep == '\0') { 614*a0483764SConrad Meyer /* formatting was broken? */ 615*a0483764SConrad Meyer goto failed; 616*a0483764SConrad Meyer } 617*a0483764SConrad Meyer 618*a0483764SConrad Meyer siblings = atoi(sep + 1); 619*a0483764SConrad Meyer } 620*a0483764SConrad Meyer if (strncmp(buff, "cpu cores", 9) == 0) { 621*a0483764SConrad Meyer const char* const sep = strchr(buff, ':'); 622*a0483764SConrad Meyer if (*sep == '\0') { 623*a0483764SConrad Meyer /* formatting was broken? */ 624*a0483764SConrad Meyer goto failed; 625*a0483764SConrad Meyer } 626*a0483764SConrad Meyer 627*a0483764SConrad Meyer cpu_cores = atoi(sep + 1); 628*a0483764SConrad Meyer } 629*a0483764SConrad Meyer } else if (ferror(cpuinfo)) { 630*a0483764SConrad Meyer /* fall back on the sysconf value */ 631*a0483764SConrad Meyer goto failed; 632*a0483764SConrad Meyer } 633*a0483764SConrad Meyer } 634*a0483764SConrad Meyer if (siblings && cpu_cores) { 635*a0483764SConrad Meyer ratio = siblings / cpu_cores; 636*a0483764SConrad Meyer } 637*a0483764SConrad Meyer failed: 638*a0483764SConrad Meyer fclose(cpuinfo); 639*a0483764SConrad Meyer return numPhysicalCores = numPhysicalCores / ratio; 640*a0483764SConrad Meyer } 641*a0483764SConrad Meyer } 642*a0483764SConrad Meyer 643*a0483764SConrad Meyer #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) 644*a0483764SConrad Meyer 645*a0483764SConrad Meyer /* Use apple-provided syscall 646*a0483764SConrad Meyer * see: man 3 sysctl */ 647*a0483764SConrad Meyer int UTIL_countPhysicalCores(void) 648*a0483764SConrad Meyer { 649*a0483764SConrad Meyer static int numPhysicalCores = 0; 650*a0483764SConrad Meyer 651*a0483764SConrad Meyer if (numPhysicalCores != 0) return numPhysicalCores; 652*a0483764SConrad Meyer 653*a0483764SConrad Meyer numPhysicalCores = (int)sysconf(_SC_NPROCESSORS_ONLN); 654*a0483764SConrad Meyer if (numPhysicalCores == -1) { 655*a0483764SConrad Meyer /* value not queryable, fall back on 1 */ 656*a0483764SConrad Meyer return numPhysicalCores = 1; 657*a0483764SConrad Meyer } 658*a0483764SConrad Meyer return numPhysicalCores; 659*a0483764SConrad Meyer } 660*a0483764SConrad Meyer 661*a0483764SConrad Meyer #else 662*a0483764SConrad Meyer 663*a0483764SConrad Meyer int UTIL_countPhysicalCores(void) 664*a0483764SConrad Meyer { 665*a0483764SConrad Meyer /* assume 1 */ 666*a0483764SConrad Meyer return 1; 667*a0483764SConrad Meyer } 668*a0483764SConrad Meyer 669*a0483764SConrad Meyer #endif 670*a0483764SConrad Meyer 671*a0483764SConrad Meyer #if defined (__cplusplus) 672*a0483764SConrad Meyer } 673*a0483764SConrad Meyer #endif 674