-
Notifications
You must be signed in to change notification settings - Fork 319
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve support for Apple Silicon and macOS #275
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -380,7 +380,7 @@ SpookyHashAlgorithm::SpookyHashAlgorithm() | |
inline | ||
SpookyHashAlgorithm::SpookyHashAlgorithm(const char *seed) | ||
: d_state( | ||
#if !defined(BSLS_PLATFORM_CPU_X86_64) && !defined(BSLS_PLATFORM_CPU_X86) | ||
#if !defined(BSLS_PLATFORM_IS_LITTLE_ENDIAN) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should also not be checking for little_endian - this is about whether the cpu handles unaligned reads properly. For now i would leave this as-is and we can engage the optimization at a later date if we make the m1 a more fully supported platform. |
||
static_cast<Uint64>(seed[0]) << 56 | | ||
static_cast<Uint64>(seed[1]) << 48 | | ||
static_cast<Uint64>(seed[2]) << 40 | | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -483,8 +483,11 @@ struct bsls_Platform_Assert; | |
#else | ||
#define BSLS_PLATFORM_CPU_SPARC_32 1 | ||
#endif | ||
#elif defined(__arm__) | ||
#elif defined(__arm__) || defined(__arm64__) | ||
#define BSLS_PLATFORM_CPU_ARM 1 | ||
#if defined(__arm64__) | ||
#define BSLS_PLATFORM_CPU_64_BIT 1 | ||
#endif | ||
#if defined(__ARM_ARCH) | ||
#if __ARM_ARCH == 6 | ||
#define BSLS_PLATFORM_CPU_ARM_V6 | ||
|
@@ -506,6 +509,11 @@ struct bsls_Platform_Assert; | |
|| defined(__ARM_ARCH_7M__) \ | ||
|| defined(__ARM_ARCH_7R__) | ||
#define BSLS_PLATFORM_CPU_ARM_V7 | ||
#elif defined(__ARM64_ARCH_8__) \ | ||
|| defined(__ARM_ARCH_8_3__) \ | ||
|| defined(__ARM_ARCH_8_4__) \ | ||
|| defined(__ARM_ARCH_8_5__) | ||
#define BSLS_PLATFORM_CPU_ARM_V8 | ||
#else | ||
#error "Unsupported ARM platform." | ||
#endif | ||
|
@@ -911,6 +919,8 @@ struct Platform { | |
struct CpuArmv5 : CpuArm {}; | ||
struct CpuArmv6 : CpuArm {}; | ||
struct CpuArmv7 : CpuArm {}; | ||
struct CpuArmv8 : CpuArm {}; | ||
struct CpuArmv9 : CpuArm {}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. v9 seems unused, we can remove that. |
||
|
||
// PLATFORM TRAITS | ||
|
||
|
@@ -987,6 +997,12 @@ struct Platform { | |
#if defined(BSLS_PLATFORM_CPU_ARM_V7) | ||
typedef CpuArmv7 Cpu; | ||
#endif | ||
#if defined(BSLS_PLATFORM_CPU_ARM_V8) | ||
typedef CpuArmv8 Cpu; | ||
#endif | ||
#if defined(BSLS_PLATFORM_CPU_ARM_V9) | ||
typedef CpuArmv9 Cpu; | ||
#endif | ||
|
||
}; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -448,114 +448,57 @@ struct MachTimerUtil { | |
|
||
private: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is fairly extensive. Looking at it I think it's fine, but needs a few changes (which i can't comment on directly because of github):
It seems based on documentation that this should also work on non-m1 darwin machines, but we'll have to try to verify that. |
||
// CLASS DATA | ||
static bsls::AtomicOperations::AtomicTypes::Int | ||
s_initRequired; | ||
|
||
static bsls::Types::Int64 s_initialTime; | ||
static bsls::Types::Uint64 s_initialTime; | ||
// initial time for the Mach | ||
// hardware timer | ||
|
||
static mach_timebase_info_data_t s_timeBase; | ||
// time base used to scale the | ||
// absolute raw timer values | ||
|
||
public: | ||
// CLASS METHODS | ||
static bsls::Types::Uint64 getNanosecondsUptime(); | ||
// Return converted to nanoseconds the current uptime as reported by | ||
// clock_gettime_nsec_np. | ||
|
||
static void initialize(); | ||
// Initialize the static data used by 'MachTimerUtil' (currently the | ||
// 's_initialTime' and the 's_timeBase' values). | ||
// 's_initialTime' value). | ||
|
||
static bsls::Types::Int64 getTimerRaw(); | ||
static bsls::Types::Uint64 getTimerRaw(); | ||
// Return a machine-dependent value representing the current time. | ||
// 'timeValue' must be converted by the 'convertRawTime' method to | ||
// conventional units (nanoseconds). This method is intended to | ||
// facilitate accurate timing of small segments of code, and care must | ||
// be used in interpreting the results. The behavior is undefined | ||
// unless 'initialize' has been called. Note that this method is | ||
// thread-safe only if 'initialize' has been called before. | ||
|
||
static bsls::Types::Int64 convertRawTime(bsls::Types::Int64 rawTime); | ||
// Convert the specified 'rawTime' to a value in nanoseconds, | ||
// referenced to an arbitrary but fixed origin, and return the result | ||
// of the conversion. The behavior is undefined unless 'initialize' | ||
// has been called. Note that this method is thread-safe only if | ||
// 'initialize' has been called before. | ||
}; | ||
|
||
bsls::Types::Int64 MachTimerUtil::s_initialTime = {-1}; | ||
mach_timebase_info_data_t MachTimerUtil::s_timeBase; | ||
bsls::Types::Uint64 MachTimerUtil::s_initialTime = {0}; | ||
|
||
inline | ||
void MachTimerUtil::initialize() | ||
bsls::Types::Uint64 MachTimerUtil::getNanosecondsUptime() | ||
{ | ||
static bsls::BslOnce once = BSLS_BSLONCE_INITIALIZER; | ||
|
||
bsls::BslOnceGuard onceGuard; | ||
if (onceGuard.enter(&once)) { | ||
|
||
// There is little official documentation on 'mach_absolute_time' | ||
// and 'mach_timebase_info'. The 'mach_absolute_time' return value | ||
// is declared 'uint64_t' in 'mach/mach_time.h' and it has been | ||
// observed to have the high bit set on hardware with an uptime of | ||
// only 18 days. Therefore, a base value is saved in 'initialize' | ||
// and all returned 'getTimerRaw' values are relative to that value. | ||
// | ||
// According to a technical question found on Apple's website, the | ||
// value returned by 'mach_absolute_time' can be scaled correctly | ||
// without a dependency on the 'CoreServices' framework by calling | ||
// 'mach_timebase_info' and using the returned values. The values | ||
// do not change, so they are cached in 'initialize'. | ||
// | ||
//: o https://developer.apple.com/library/mac/documentation/darwin | ||
//: /conceptual/kernelprogramming/services/services.html | ||
//: o https://developer.apple.com/library/mac/qa/qa1398/_index.html | ||
|
||
s_initialTime = (bsls::Types::Int64) mach_absolute_time(); | ||
|
||
(void) mach_timebase_info(&s_timeBase); | ||
// The original implementation used 'mach_absolute_time()', which is | ||
// considered deprecated (since it requires scaling on Apple Silicon). | ||
// | ||
//: o https://developer.apple.com/documentation/kernel/1462446-mach_absolute_time | ||
|
||
BSLS_ASSERT(0 < s_timeBase.numer); | ||
BSLS_ASSERT(0 < s_timeBase.denom); | ||
} | ||
return static_cast<bsls::Types::Uint64>( | ||
clock_gettime_nsec_np(CLOCK_UPTIME_RAW)); | ||
} | ||
|
||
inline | ||
bsls::Types::Int64 MachTimerUtil::convertRawTime(bsls::Types::Int64 rawTime) | ||
void MachTimerUtil::initialize() | ||
{ | ||
initialize(); | ||
|
||
#ifdef __SIZEOF_INT128__ | ||
|
||
// Use the built-in '__int128' type to avoid any potential overflow. | ||
|
||
__int128 result = (__int128) rawTime * | ||
(__int128) s_timeBase.numer / | ||
(__int128) s_timeBase.denom; | ||
return static_cast<bsls::Types::Int64>(result); | ||
|
||
#else // !__SIZEOF_INT128__ | ||
|
||
// In practice, it is not expected that multiplying 'rawTime' by | ||
// 's_timeBase.numer' will overflow an Int64. The 'numer' and | ||
// 'denom' values have been observed to both be 1 on a late model | ||
// laptop and Mac mini. Just to be safe, the overflow is checked in safe | ||
// builds. | ||
|
||
BSLS_ASSERT_SAFE(LLONG_MAX / s_timeBase.numer >= rawTime && | ||
LLONG_MIN / s_timeBase.numer <= rawTime); | ||
static bsls::BslOnce once = BSLS_BSLONCE_INITIALIZER; | ||
|
||
return rawTime * s_timeBase.numer / s_timeBase.denom; | ||
bsls::BslOnceGuard onceGuard; | ||
if (onceGuard.enter(&once)) { | ||
|
||
#endif // !__SIZEOF_INT128__ | ||
s_initialTime = getNanosecondsUptime(); | ||
} | ||
} | ||
|
||
inline | ||
bsls::Types::Int64 MachTimerUtil::getTimerRaw() | ||
bsls::Types::Uint64 MachTimerUtil::getTimerRaw() | ||
{ | ||
initialize(); | ||
|
||
return static_cast<bsls::Types::Int64>( | ||
mach_absolute_time() - s_initialTime); | ||
return static_cast<bsls::Types::Uint64>( | ||
getNanosecondsUptime() - s_initialTime); | ||
} | ||
|
||
#endif | ||
|
@@ -606,7 +549,7 @@ TimeUtil::convertRawTime(TimeUtil::OpaqueNativeTime rawTime) | |
|
||
#elif defined BSLS_PLATFORM_OS_DARWIN | ||
|
||
return MachTimerUtil::convertRawTime(rawTime.d_opaque); | ||
return rawTime.d_opaque; | ||
|
||
#elif defined BSLS_PLATFORM_OS_UNIX | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about alignment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huh, seems AArch64 typically allows unaligned accesses in user space.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, that is a good point - i wouldn't widen the existing assumption to all little endian machines.