Skip to content
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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions groups/bdl/bdlpcre/bdlpcre_regex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ namespace {
static const bool k_IS_JIT_SUPPORTED =
#if defined(BSLS_PLATFORM_CPU_SPARC) && defined (BSLS_PLATFORM_CPU_64_BIT)
false;
#elif defined(BSLS_PLATFORM_CPU_ARM) && defined (BSLS_PLATFORM_CPU_64_BIT)
false;
#else
true;
#endif
Expand Down
1 change: 0 additions & 1 deletion groups/bdl/bdlpcre/bdlpcre_regex.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,6 @@ BSLS_IDENT("$Id$ $CSID$")
// JIT is supported on the following platforms:
//..
// ARM 32-bit (v5, v7, and Thumb2)
// ARM 64-bit
// Intel x86 32-bit and 64-bit
// MIPS 32-bit and 64-bit
// Power PC 32-bit and 64-bit
Expand Down
2 changes: 2 additions & 0 deletions groups/bdl/bdlpcre/bdlpcre_regex.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1656,6 +1656,8 @@ int main(int argc, char *argv[])

#if defined(BSLS_PLATFORM_CPU_SPARC_V9)
ASSERT(false == Obj::isJitAvailable());
#elif defined(BSLS_PLATFORM_CPU_ARM) && defined(BSLS_PLATFORM_CPU_64_BIT)
ASSERT(false == Obj::isJitAvailable());
#else
ASSERT(true == Obj::isJitAvailable());
#endif
Expand Down
4 changes: 2 additions & 2 deletions groups/bdl/bdls/bdls_testutil.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ static int verbose, veryVerbose, veryVeryVerbose;

namespace {

#if defined(BSLS_PLATFORM_OS_WINDOWS)
#if defined(BSLS_PLATFORM_OS_WINDOWS) || defined(BSLS_PLATFORM_OS_DARWIN)
typedef struct stat StatType;
#else
typedef struct stat64 StatType;
Expand All @@ -329,7 +329,7 @@ typedef struct stat64 StatType;
inline
int fstatFunc(int fd, StatType *buf)
{
#if defined(BSLS_PLATFORM_OS_WINDOWS)
#if defined(BSLS_PLATFORM_OS_WINDOWS) || defined(BSLS_PLATFORM_OS_DARWIN)
return fstat(fd, buf);
#else
return fstat64(fd, buf);
Expand Down
2 changes: 1 addition & 1 deletion groups/bsl/bslh/bslh_siphashalgorithm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ static u64 u8to64_le(const u8* p)
{
BSLS_ASSERT(p);

#if defined(BSLS_PLATFORM_CPU_X86) || defined(BSLS_PLATFORM_CPU_X86_64)
#if defined(BSLS_PLATFORM_IS_LITTLE_ENDIAN)
return *reinterpret_cast<const u64 *>(p); // Ignore alignment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about alignment?

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.

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.

#else
u64 ret;
Expand Down
2 changes: 1 addition & 1 deletion groups/bsl/bslh/bslh_spookyhashalgorithm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Choose a reason for hiding this comment

The 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 |
Expand Down
4 changes: 2 additions & 2 deletions groups/bsl/bslim/bslim_testutil.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ static bool verbose, veryVerbose, veryVeryVerbose;
// GLOBAL HELPER TYPES AND FUNCTIONS
//-----------------------------------------------------------------------------

#if defined(BSLS_PLATFORM_OS_WINDOWS)
#if defined(BSLS_PLATFORM_OS_WINDOWS) || defined(BSLS_PLATFORM_OS_DARWIN)
typedef struct stat StatType;
#else
typedef struct stat64 StatType;
Expand All @@ -323,7 +323,7 @@ typedef struct stat64 StatType;
inline
int fstatFunc(int fd, StatType *buf)
{
#if defined(BSLS_PLATFORM_OS_WINDOWS)
#if defined(BSLS_PLATFORM_OS_WINDOWS) || defined(BSLS_PLATFORM_OS_DARWIN)
return fstat(fd, buf);
#else
return fstat64(fd, buf);
Expand Down
2 changes: 2 additions & 0 deletions groups/bsl/bsls/bsls_alignmentfromtype.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,8 @@ int main(int argc, char *argv[])
EXP_U1_ALIGNMENT = 8;
#if defined(BSLS_PLATFORM_CPU_POWERPC) && defined(BSLS_PLATFORM_OS_LINUX)
EXP_LONG_DOUBLE_ALIGNMENT = 8;
#elif defined(BSLS_PLATFORM_CPU_ARM)
EXP_LONG_DOUBLE_ALIGNMENT = 8;
#else
EXP_LONG_DOUBLE_ALIGNMENT = 16;
#endif
Expand Down
2 changes: 2 additions & 0 deletions groups/bsl/bsls/bsls_alignmentimp.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,8 @@ int main(int argc, char *argv[])
EXP_U1_ALIGNMENT = 8;
#if defined(BSLS_PLATFORM_CPU_POWERPC) && defined(BSLS_PLATFORM_OS_LINUX)
EXP_LONG_DOUBLE_ALIGNMENT = 8;
#elif defined(BSLS_PLATFORM_CPU_ARM)
EXP_LONG_DOUBLE_ALIGNMENT = 8;
#else
EXP_LONG_DOUBLE_ALIGNMENT = 16;
#endif
Expand Down
4 changes: 2 additions & 2 deletions groups/bsl/bsls/bsls_bsltestutil.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -842,15 +842,15 @@ double dummyDoubleFunction()
// GLOBAL HELPER CLASSES FOR TESTING
// ----------------------------------------------------------------------------

#if defined(BSLS_PLATFORM_OS_WINDOWS)
#if defined(BSLS_PLATFORM_OS_WINDOWS) || defined(BSLS_PLATFORM_OS_DARWIN)
typedef struct stat StatType;
#else
typedef struct stat64 StatType;
#endif

inline int fstatFunc(int fd, StatType *buf)
{
#if defined(BSLS_PLATFORM_OS_WINDOWS)
#if defined(BSLS_PLATFORM_OS_WINDOWS) || defined(BSLS_PLATFORM_OS_DARWIN)
return fstat(fd, buf);
#else
return fstat64(fd, buf);
Expand Down
4 changes: 2 additions & 2 deletions groups/bsl/bsls/bsls_log.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,15 +445,15 @@ const char *LargeTestData::expectedOutput() const
// GLOBAL HELPER CLASSES FOR TESTING
// ----------------------------------------------------------------------------

#if defined(BSLS_PLATFORM_OS_WINDOWS)
#if defined(BSLS_PLATFORM_OS_WINDOWS) || defined(BSLS_PLATFORM_OS_DARWIN)
typedef struct stat StatType;
#else
typedef struct stat64 StatType;
#endif

inline int fstatFunc(int fd, StatType *buf)
{
#if defined(BSLS_PLATFORM_OS_WINDOWS)
#if defined(BSLS_PLATFORM_OS_WINDOWS) || defined(BSLS_PLATFORM_OS_DARWIN)
return fstat(fd, buf);
#else
return fstat64(fd, buf);
Expand Down
18 changes: 17 additions & 1 deletion groups/bsl/bsls/bsls_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -911,6 +919,8 @@ struct Platform {
struct CpuArmv5 : CpuArm {};
struct CpuArmv6 : CpuArm {};
struct CpuArmv7 : CpuArm {};
struct CpuArmv8 : CpuArm {};
struct CpuArmv9 : CpuArm {};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

v9 seems unused, we can remove that.


// PLATFORM TRAITS

Expand Down Expand Up @@ -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

};

Expand Down
7 changes: 7 additions & 0 deletions groups/bsl/bsls/bsls_platformutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,13 @@ struct PlatformUtil {
// defined in 'bsls_platform' instead.
#endif

#if defined(BSLS_PLATFORM_CPU_ARM)
#define BSLS_PLATFORMUTIL_IS_LITTLE_ENDIAN \
BSLS_PLATFORM_IS_LITTLE_ENDIAN
// DEPRECATED: Use preprocessor macro 'BSLS_PLATFORM_IS_LITTLE_ENDIAN'
// defined in 'bsls_platform' instead.
#endif

#if !defined(BSLS_PLATFORMUTIL_IS_LITTLE_ENDIAN)
#define BSLS_PLATFORMUTIL_IS_BIG_ENDIAN BSLS_PLATFORM_IS_BIG_ENDIAN
// DEPRECATED: Use preprocessor macro 'BSLS_PLATFORM_IS_BIG_ENDIAN'
Expand Down
4 changes: 2 additions & 2 deletions groups/bsl/bsls/bsls_spinlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ extern "C" {
#include <time.h>
#endif

#if !(defined(BSLS_PLATFORM_OS_SOLARIS)) && !(defined(BSLS_PLATFORM_OS_AIX))
#if defined(BSLS_PLATFORM_CPU_X86) || defined(BSLS_PLATFORM_CPU_X86_64)
#include <immintrin.h>
#include <emmintrin.h>
#endif
Expand Down Expand Up @@ -451,7 +451,7 @@ void SpinLock::doBackoff(int *count) {

inline
void SpinLock::pause() {
#if !(defined(BSLS_PLATFORM_OS_SOLARIS)) && !(defined(BSLS_PLATFORM_OS_AIX))
#if defined(BSLS_PLATFORM_CPU_X86) || defined(BSLS_PLATFORM_CPU_X86_64)
_mm_pause();
#endif
}
Expand Down
107 changes: 25 additions & 82 deletions groups/bsl/bsls/bsls_timeutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,114 +448,57 @@ struct MachTimerUtil {

private:

Choose a reason for hiding this comment

The 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):

  1. I suspect the include of <mach/mach_time.h> is no longer the right include... it looks like it should just be <time.h>?

  2. Please change "MachTimerUtil" to "DarwinTimerUtil".

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
Expand Down Expand Up @@ -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

Expand Down
12 changes: 6 additions & 6 deletions groups/bsl/bsls/bsls_timeutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,17 +222,17 @@ struct TimeUtil {

// TYPES
#if defined BSLS_PLATFORM_OS_SOLARIS
typedef struct { Types::Int64 d_opaque; } OpaqueNativeTime;
typedef struct { Types::Int64 d_opaque; } OpaqueNativeTime;
#elif defined BSLS_PLATFORM_OS_AIX
typedef timebasestruct_t OpaqueNativeTime;
typedef timebasestruct_t OpaqueNativeTime;
#elif defined(BSLS_PLATFORM_OS_LINUX) || defined(BSLS_PLATFORM_OS_CYGWIN)
typedef timespec OpaqueNativeTime;
typedef timespec OpaqueNativeTime;
#elif defined BSLS_PLATFORM_OS_DARWIN
typedef struct { Types::Int64 d_opaque; } OpaqueNativeTime;
typedef struct { Types::Uint64 d_opaque; } OpaqueNativeTime;
#elif defined BSLS_PLATFORM_OS_UNIX
typedef timeval OpaqueNativeTime;
typedef timeval OpaqueNativeTime;
#elif defined BSLS_PLATFORM_OS_WINDOWS
typedef struct { Types::Int64 d_opaque; } OpaqueNativeTime;
typedef struct { Types::Int64 d_opaque; } OpaqueNativeTime;
#endif

// CLASS METHODS
Expand Down
Loading