Source/TNLTiming.m (64 lines of code) (raw):
//
// TNLTiming.m
// TwitterNetworkLayer
//
// Created on 5/12/16.
// Copyright © 2020 Twitter. All rights reserved.
//
#import <mach/mach_time.h>
#import "TNLTiming.h"
NS_ASSUME_NONNULL_BEGIN
static mach_timebase_info_data_t _TNLMachTimebaseInfo(void);
static mach_timebase_info_data_t _TNLMachTimebaseInfo(void)
{
static mach_timebase_info_data_t sMachInfo;
static dispatch_once_t sMachInfoOnceToken = 0;
dispatch_once(&sMachInfoOnceToken, ^{
if (mach_timebase_info(&sMachInfo) != KERN_SUCCESS) {
sMachInfo.numer = 0;
sMachInfo.denom = 1;
}
});
return sMachInfo;
}
uint64_t TNLAbsoluteFromNanoseconds(uint64_t nano)
{
mach_timebase_info_data_t machInfo = _TNLMachTimebaseInfo();
if (0 == machInfo.numer) {
// If we can't get a valid timebase, just convert to zero
return 0;
}
// Don't sweat imprecision going from Nano to Absolute
uint64_t absolute = nano * machInfo.denom;
absolute /= machInfo.numer;
return absolute;
}
uint64_t TNLAbsoluteToNanoseconds(uint64_t absolute)
{
mach_timebase_info_data_t machInfo = _TNLMachTimebaseInfo();
uint64_t nanoSeconds = absolute * machInfo.numer;
if (nanoSeconds < absolute) {
/*
Either overflow or zero numer
Overflow:
proceed with loss of precision
Zero numer:
this will happen when there's an error returned by
mach_timebase_info (I've never encountered this).
In this case, it will be best to just have all values
return as 0 instead of an inaccurate value. For
simplicity, we'll just use the overflow logic.
*/
nanoSeconds = absolute / machInfo.denom;
nanoSeconds *= machInfo.numer;
} else {
nanoSeconds /= machInfo.denom;
}
return nanoSeconds;
}
NSTimeInterval TNLAbsoluteToTimeInterval(uint64_t absolute)
{
uint64_t nanoSeconds = TNLAbsoluteToNanoseconds(absolute);
double preciseValueInSeconds = (((double)nanoSeconds) / NSEC_PER_SEC);
return preciseValueInSeconds;
}
uint64_t TNLAbsoluteFromTimeInterval(NSTimeInterval ti)
{
uint64_t nanoSeconds = (uint64_t)(ti * NSEC_PER_MSEC);
uint64_t absolute = TNLAbsoluteFromNanoseconds(nanoSeconds);
return absolute;
}
NSTimeInterval TNLComputeDuration(uint64_t startTime, uint64_t endTime)
{
if (!startTime) {
return 0;
}
if (!endTime) {
endTime = mach_absolute_time();
}
if (endTime < startTime) {
return -TNLAbsoluteToTimeInterval(startTime - endTime);
}
return TNLAbsoluteToTimeInterval(endTime - startTime);
}
NS_ASSUME_NONNULL_END