Implemented the new MulDiv128 stuff on macOS. To make things easier in regards to signedness, this implementation also uses a base, like the Unix one, and the mach_timebase_info() conversion is done in timerMonotonicTime() instead. (Also added the admittedly-redundant-since-the-current(ish)-implementation-cannot-fail error check to mach_timebase_info().) As a result, timerTimeSub() can now be end - start on all platforms. Also found and fixed bugs in the actual muldiv128 algorithm implementation. Next up: Windows.
This commit is contained in:
parent
952b36b1c2
commit
288c74b026
|
@ -259,14 +259,14 @@ static void int128MulDiv64(timerprivInt128 *x, timerprivInt128 *y, timerprivInt1
|
|||
numer.low = x64low * y64low; // b * d +
|
||||
add.neg = 0;
|
||||
add.high = x64high * y64low; // a * d * 2^32 +
|
||||
add.low = add.high & 0xFFFFFFFF00000000;
|
||||
add.low = (add.high & 0xFFFFFFFF) << 32;
|
||||
add.high >>= 32;
|
||||
int128UAdd(&numer, &add);
|
||||
add.high = x64low * y64high; // b * c * 2^32
|
||||
add.low = add.high & 0xFFFFFFFF00000000;
|
||||
add.low = (add.high & 0xFFFFFFFF) << 32;
|
||||
add.high >>= 32;
|
||||
int128UAdd(&numer, &add);
|
||||
// I did type this all by hand, btw; the idea does come from Apple's implementation, though they explain it a bit more obtusely, and the odd behavior with anding high and shifting it right is to avoid looking like I directly copied their code which does the opposite
|
||||
// I did type this all by hand, btw; the idea does come from Apple's implementation, though they explain it a bit more obtusely, and the odd behavior with anding high into low is to avoid looking like I directly copied their code which does the opposite
|
||||
|
||||
// and now long-divide
|
||||
// Apple's implementation uses Newton–Raphson division using doubles to store 1/z but I'd rather go with "slow but guaranteed to be accurate"
|
||||
|
@ -286,7 +286,7 @@ static void int128MulDiv64(timerprivInt128 *x, timerprivInt128 *y, timerprivInt1
|
|||
}
|
||||
}
|
||||
|
||||
void timerprivMulDiv64(int64_t x, int64_t y, int64_t z, timerprivInt128 *quot)
|
||||
void timerprivMulDivInt64(int64_t x, int64_t y, int64_t z, timerprivInt128 *quot)
|
||||
{
|
||||
timerprivInt128 a, b, c;
|
||||
|
||||
|
@ -296,7 +296,7 @@ void timerprivMulDiv64(int64_t x, int64_t y, int64_t z, timerprivInt128 *quot)
|
|||
int128MulDiv64(&a, &b, &c, quot);
|
||||
}
|
||||
|
||||
void timerprivMulDivU64(uint64_t x, uint64_t y, uint64_t z, timerprivInt128 *quot)
|
||||
void timerprivMulDivUint64(uint64_t x, uint64_t y, uint64_t z, timerprivInt128 *quot)
|
||||
{
|
||||
timerprivInt128 a, b, c;
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
typedef int64_t timerDuration;
|
||||
typedef int64_t timerTime;
|
||||
|
||||
#define timerTimeMax ((timerTime) INT64_MAX)
|
||||
|
||||
#define timerNanosecond ((timerDuration) 1)
|
||||
#define timerMicrosecond ((timerDuration) 1000)
|
||||
#define timerMillisecond ((timerDuration) 1000000)
|
||||
|
|
|
@ -15,24 +15,50 @@
|
|||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
#include "timer.h"
|
||||
#include "timerpriv.h"
|
||||
|
||||
static void mustpthread_once(pthread_once_t *once, void (*init)(void))
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_once(once, init);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "*** internal error in timerMonotonicNow(): pthread_once() failed: %s (%d)\n", strerror(err), err);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
timerTime timerMonotonicNow(void)
|
||||
static uint64_t base;
|
||||
static mach_timebase_info_data_t mt;
|
||||
static pthread_once_t baseOnce = PTHREAD_ONCE_INIT;
|
||||
|
||||
static void baseInit(void)
|
||||
{
|
||||
return (timerTime) mach_absolute_time();
|
||||
kern_return_t err;
|
||||
|
||||
base = mach_absolute_time();
|
||||
err = mach_timebase_info(&mt);
|
||||
if (err != KERN_SUCCESS) {
|
||||
fprintf(stderr, "*** internal error in timerMonotonicNow(): mach_timebase_info() failed: kern_return_t %d\n", err);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
timerDuration timerTimeSub(timerTime end, timerTime start)
|
||||
timerTime timerMonotonicNow(void)
|
||||
{
|
||||
mach_timebase_info_data_t mt;
|
||||
timerTime c;
|
||||
timerDuration ret;
|
||||
uint64_t t;
|
||||
timerprivInt128 quot;
|
||||
|
||||
mach_timebase_info(&mt);
|
||||
c = end - start;
|
||||
ret = ((timerDuration) c) * mt.numer / mt.denom;
|
||||
return ret;
|
||||
mustpthread_once(&baseOnce, baseInit);
|
||||
t = mach_absolute_time() - base;
|
||||
timerprivMulDivUint64(t, mt.numer, mt.denom, ");
|
||||
// on overflow, return the maximum possible timerTime; this is inspired by what Go does
|
||||
if (quot.high == 0)
|
||||
if (quot.low <= ((uint64_t) timerTimeMax))
|
||||
return (timerTime) (quot.low);
|
||||
return timerTimeMax;
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -61,13 +87,8 @@ timerTime timerMonotonicNow(void)
|
|||
{
|
||||
struct timespec ts;
|
||||
timerTime ret;
|
||||
int err;
|
||||
|
||||
err = pthread_once(&baseOnce, baseInit);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "*** internal error in timerMonotonicNow(): pthread_once() failed: %s (%d)\n", strerror(err), err);
|
||||
abort();
|
||||
}
|
||||
mustpthread_once(&baseOnce, baseInit);
|
||||
mustclock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
ts.tv_sec -= base.tv_sec;
|
||||
ts.tv_nsec -= base.tv_nsec;
|
||||
|
@ -80,13 +101,13 @@ timerTime timerMonotonicNow(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
timerDuration timerTimeSub(timerTime end, timerTime start)
|
||||
{
|
||||
return end - start;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct timeoutParams {
|
||||
jmp_buf retpos;
|
||||
struct itimerval prevDuration;
|
||||
|
|
|
@ -8,5 +8,5 @@ struct timerprivInt128 {
|
|||
uint64_t low;
|
||||
};
|
||||
|
||||
extern void timerprivMulDiv64(int64_t x, int64_t y, int64_t z, timerprivInt128 *quot);
|
||||
extern void timerprivMulDivU64(uint64_t x, uint64_t y, uint64_t z, timerprivInt128 *quot);
|
||||
extern void timerprivMulDivInt64(int64_t x, int64_t y, int64_t z, timerprivInt128 *quot);
|
||||
extern void timerprivMulDivUint64(uint64_t x, uint64_t y, uint64_t z, timerprivInt128 *quot);
|
||||
|
|
Loading…
Reference in New Issue