// // File.c // BulletTest // // Copyright (c) 2011 Apple Inc. // #include #ifdef __APPLE__ #include #include #include #include #else #include "LinearMath/btAlignedAllocator.h" #endif //__APPLE__ #include #include "Utils.h" #pragma mark Timing int gReportNanoseconds = 0; #ifdef _WIN32 #include uint64_t ReadTicks(void) { return __rdtsc(); } double TicksToCycles(uint64_t delta) { return double(delta); } double TicksToSeconds(uint64_t delta) { return double(delta); } void *GuardCalloc(size_t count, size_t size, size_t *objectStride) { if (objectStride) *objectStride = size; return (void *)btAlignedAlloc(count * size, 16); } void GuardFree(void *buf) { btAlignedFree(buf); } #endif #ifdef __APPLE__ uint64_t ReadTicks(void) { return mach_absolute_time(); } double TicksToCycles(uint64_t delta) { static long double conversion = 0.0L; if (0.0L == conversion) { // attempt to get conversion to nanoseconds mach_timebase_info_data_t info; int err = mach_timebase_info(&info); if (err) return __builtin_nanf(""); conversion = (long double)info.numer / info.denom; // attempt to get conversion to cycles if (0 == gReportNanoseconds) { uint64_t frequency = 0; size_t freq_size = sizeof(frequency); err = sysctlbyname("hw.cpufrequency_max", &frequency, &freq_size, NULL, 0); if (err || 0 == frequency) vlog("Failed to get max cpu frequency. Reporting times as nanoseconds.\n"); else { conversion *= 1e-9L /* sec / ns */ * frequency /* cycles / sec */; vlog("Reporting times as cycles. (%2.2f MHz)\n", 1e-6 * frequency); } } else vlog("Reporting times as nanoseconds.\n"); } return (double)(delta * conversion); } double TicksToSeconds(uint64_t delta) { static long double conversion = 0.0L; if (0.0L == conversion) { // attempt to get conversion to nanoseconds mach_timebase_info_data_t info; int err = mach_timebase_info(&info); if (err) return __builtin_nanf(""); conversion = info.numer / (1e9L * info.denom); } return (double)(delta * conversion); } #pragma mark - #pragma mark GuardCalloc #define kPageSize 4096 typedef struct BufInfo { void *head; size_t count; size_t stride; size_t totalSize; } BufInfo; static int GuardMarkBuffer(void *buffer, int flag); void *GuardCalloc(size_t count, size_t size, size_t *objectStride) { if (objectStride) *objectStride = 0; // Round size up to a multiple of a page size size_t stride = (size + kPageSize - 1) & -kPageSize; //Calculate total size of the allocation size_t totalSize = count * (stride + kPageSize) + kPageSize; // Allocate char *buf = (char *)mmap(NULL, totalSize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, 0, 0); if (MAP_FAILED == buf) { vlog("mmap failed: %d\n", errno); return NULL; } // Find the first byte of user data char *result = buf + kPageSize; // Record what we did for posterity BufInfo *bptr = (BufInfo *)result - 1; bptr->head = buf; bptr->count = count; bptr->stride = stride; bptr->totalSize = totalSize; // Place the first guard page. Masks our record above. if (mprotect(buf, kPageSize, PROT_NONE)) { munmap(buf, totalSize); vlog("mprotect -1 failed: %d\n", errno); return NULL; } // Place the rest of the guard pages size_t i; char *p = result; for (i = 0; i < count; i++) { p += stride; if (mprotect(p, kPageSize, PROT_NONE)) { munmap(buf, totalSize); vlog("mprotect %lu failed: %d\n", i, errno); return NULL; } p += kPageSize; } // record the stride from object to object if (objectStride) *objectStride = stride + kPageSize; // return pointer to first object return result; } void GuardFree(void *buf) { if (mprotect((char *)buf - kPageSize, kPageSize, PROT_READ)) { vlog("Unable to read buf info. GuardFree failed! %p (%d)\n", buf, errno); return; } BufInfo *bptr = (BufInfo *)buf - 1; if (munmap(bptr->head, bptr->totalSize)) vlog("Unable to unmap data. GuardFree failed! %p (%d)\n", buf, errno); } int GuardMarkReadOnly(void *buf) { return GuardMarkBuffer(buf, PROT_READ); } int GuardMarkReadWrite(void *buf) { return GuardMarkBuffer(buf, PROT_READ | PROT_WRITE); } int GuardMarkWriteOnly(void *buf) { return GuardMarkBuffer(buf, PROT_WRITE); } static int GuardMarkBuffer(void *buf, int flag) { if (mprotect((char *)buf - kPageSize, kPageSize, PROT_READ)) { vlog("Unable to read buf info. GuardMarkBuffer %d failed! %p (%d)\n", flag, buf, errno); return errno; } BufInfo *bptr = (BufInfo *)buf - 1; size_t count = bptr->count; size_t stride = bptr->stride; size_t i; for (i = 0; i < count; i++) { if (mprotect(buf, stride, flag)) { vlog("Unable to protect segment %ld. GuardMarkBuffer %d failed! %p (%d)\n", i, flag, buf, errno); return errno; } bptr += stride + kPageSize; } if (mprotect((char *)buf - kPageSize, kPageSize, PROT_NONE)) { vlog("Unable to protect leading guard page. GuardMarkBuffer %d failed! %p (%d)\n", flag, buf, errno); return errno; } return 0; } #endif uint32_t random_number32(void) { return ((uint32_t)rand() << 16) ^ rand(); } uint64_t random_number64(void) { return ((uint64_t)rand() << 48) ^ ((uint64_t)rand() << 32) ^ ((uint64_t)rand() << 16) ^ rand(); }