Skip to content

Commit

Permalink
CPU Info Shenanigans (#4468)
Browse files Browse the repository at this point in the history
1. Add CPU detection
2. Turn on AVX flags at build time
3. If you are running on a non-AVX box pop a warning saying may not
   work in the future
4. move the FPUState stuff and reinstate it in XT while at it

Closes #4466
  • Loading branch information
baconpaul authored May 3, 2021
1 parent 9131e31 commit a5388b4
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 111 deletions.
20 changes: 18 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,21 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
add_compile_options(-msse2 -mfpmath=sse)
endif()
endif()

# Add AVX support
include(CheckCXXSourceCompiles)
check_cxx_source_compiles("
#if defined(__x86_64__) || defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
#ifndef __AVX__
#error
#endif
#endif
int main() {}" COMPILER_HAS_AVX_OR_IS_ARM)
if (NOT COMPILER_HAS_AVX_OR_IS_ARM)
message(STATUS "Adding -mavx to allow __AVX__ compiles" )
add_compile_options("-mavx")
endif()

if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# Any Clang
add_compile_options(
Expand Down Expand Up @@ -76,7 +91,6 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
endif()

if(MSVC)
# MSVC and pretenders
add_compile_options(
-WX # treat all warnings as errors

Expand All @@ -97,6 +111,8 @@ if(MSVC)
/Zc:alignedNew
/bigobj

/arch:AVX

# Build with Multiple Processes (Clang-cl builds use Ninja instead)
$<$<CXX_COMPILER_ID:MSVC>:/MP>
)
Expand Down Expand Up @@ -269,11 +285,11 @@ set(SURGE_SHARED_SOURCES
src/common/dsp/Wavetable.cpp
src/common/dsp/WavetableOscillator.cpp
src/common/dsp/WindowOscillator.cpp
src/common/util/FpuState.cpp
src/common/vt_dsp/basic_dsp.cpp
src/common/vt_dsp/halfratefilter.cpp
src/common/vt_dsp/lipol.cpp
src/common/vt_dsp/macspecific.cpp
src/common/CPUFeatures.cpp
src/common/DebugHelpers.cpp
src/common/ModulatorPresetManager.cpp
src/common/Parameter.cpp
Expand Down
206 changes: 206 additions & 0 deletions src/common/CPUFeatures.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
/*
** Surge Synthesizer is Free and Open Source Software
**
** Surge is made available under the Gnu General Public License, v3.0
** https://www.gnu.org/licenses/gpl-3.0.en.html
**
** Copyright 2004-2021 by various individuals as described by the Git transaction log
**
** All source at: https://github.com/surge-synthesizer/surge.git
**
** Surge was a commercial product from 2004-2018, with Copyright and ownership
** in that period held by Claes Johanson at Vember Audio. Claes made Surge
** open source in September 2018.
*/

#include "CPUFeatures.h"
#include "globals.h"

#if MAC
#include <sys/types.h>
#include <sys/sysctl.h>
#endif

#if LINUX
#include <fstream>
#endif

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace Surge
{
namespace CPUFeatures
{

#if LINUX && !ARM_NEON
#ifdef __GNUC__
// Thanks to https://gist.github.com/hi2p-perim/7855506
void __cpuid(int *cpuinfo, int info)
{
__asm__ __volatile__("xchg %%ebx, %%edi;"
"cpuid;"
"xchg %%ebx, %%edi;"
: "=a"(cpuinfo[0]), "=D"(cpuinfo[1]), "=c"(cpuinfo[2]), "=d"(cpuinfo[3])
: "0"(info));
}

unsigned long long _xgetbv(unsigned int index)
{
unsigned int eax, edx;
__asm__ __volatile__("xgetbv;" : "=a"(eax), "=d"(edx) : "c"(index));
return ((unsigned long long)edx << 32) | eax;
}

#endif
#endif

std::string cpuBrand()
{
std::string arch = "Unknown CPU";
#if MAC

char buffer[1024];
size_t bufsz = sizeof(buffer);
if (sysctlbyname("machdep.cpu.brand_string", (void *)(&buffer), &bufsz, nullptr, (size_t)0) < 0)
{
#if ARM_NEON
arch = "Apple Silicon";
#endif
}
else
{
arch = buffer;
#if ARM_NEON
arch += " (Apple Silicon)";
#endif
}

#elif WINDOWS
std::string platform = "Windows";

int CPUInfo[4] = {-1};
unsigned nExIds, i = 0;
char CPUBrandString[0x40];
// Get the information associated with each extended ID.
__cpuid(CPUInfo, 0x80000000);
nExIds = CPUInfo[0];
for (i = 0x80000000; i <= nExIds; ++i)
{
__cpuid(CPUInfo, i);
// Interpret CPU brand string
if (i == 0x80000002)
memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
else if (i == 0x80000003)
memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo));
else if (i == 0x80000004)
memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
}
arch = CPUBrandString;
#elif LINUX
std::string platform = "Linux";

// Lets see what /proc/cpuinfo has to say for us
// on intels this is "model name"
auto pinfo = std::ifstream("/proc/cpuinfo");
if (pinfo.is_open())
{
std::string line;
while (std::getline(pinfo, line))
{
if (line.find("model name") == 0)
{
auto colon = line.find(":");
arch = line.substr(colon + 1);
break;
}
if (line.find("Model") == 0) // rasperry pi branch
{
auto colon = line.find(":");
arch = line.substr(colon + 1);
break;
}
}
}
pinfo.close();
#endif
return arch;
}

bool isArm()
{
#if ARM_NEON
return true;
#else
return false;
#endif
}
bool isX86()
{
#if ARM_NEON
return false;
#else
return true;
#endif
}
bool hasSSE2() { return true; }
bool hasAVX()
{
#if ARM_NEON
return true; // thanks simde
#else
#if MAC
return true;
#endif
#if WINDOWS || LINUX
bool avxSup;
int cpuinfo[4];
__cpuid(cpuinfo, 1);

avxSup = cpuinfo[2] & (1 << 28) || false;
bool osxsaveSup = cpuinfo[2] & (1 << 27) || false;
if (osxsaveSup && avxSup)
{
// _XCR_XFEATURE_ENABLED_MASK = 0
unsigned long long xcrFeatureMask = _xgetbv(0);
avxSup = (xcrFeatureMask & 0x6) == 0x6;
}
return avxSup;
#endif

#endif
}

#if !(__AVX__ || ARM_NEON)
#error "You must compile SURGE with AVX support in compiler flags"
#endif

FPUStateGuard::FPUStateGuard()
{
#ifndef ARM_NEON
auto _SSE_Flags = 0x8040;
bool fpuExceptions = false;

priorS = _mm_getcsr();
if (fpuExceptions)
{
_mm_setcsr(((priorS & ~_MM_MASK_MASK) | _SSE_Flags) | _MM_EXCEPT_MASK); // all on
}
else
{
_mm_setcsr((priorS | _SSE_Flags) | _MM_MASK_MASK);
}

_MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST);
#endif
}

FPUStateGuard::~FPUStateGuard()
{
#ifndef ARM_NEON
_mm_setcsr(priorS);
#endif
}
} // namespace CPUFeatures
} // namespace Surge
41 changes: 41 additions & 0 deletions src/common/CPUFeatures.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
** Surge Synthesizer is Free and Open Source Software
**
** Surge is made available under the Gnu General Public License, v3.0
** https://www.gnu.org/licenses/gpl-3.0.en.html
**
** Copyright 2004-2021 by various individuals as described by the Git transaction log
**
** All source at: https://github.com/surge-synthesizer/surge.git
**
** Surge was a commercial product from 2004-2018, with Copyright and ownership
** in that period held by Claes Johanson at Vember Audio. Claes made Surge
** open source in September 2018.
*/

#ifndef SURGE_XT_CPUFEATURES_H
#define SURGE_XT_CPUFEATURES_H

#include <string>

namespace Surge
{
namespace CPUFeatures
{
std::string cpuBrand();
bool isArm();
bool isX86();
bool hasSSE2();
bool hasAVX();

struct FPUStateGuard
{
FPUStateGuard();
~FPUStateGuard();

int priorS;
};
}; // namespace CPUFeatures
} // namespace Surge

#endif // SURGE_XT_CPUFEATURES_H
11 changes: 11 additions & 0 deletions src/common/SurgeSynthesizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "SurgeSynthesizer.h"
#include "DspUtilities.h"
#include <ctime>
#include "CPUFeatures.h"
#if MAC || LINUX
#include <pthread.h>
#else
Expand All @@ -38,6 +39,16 @@ SurgeSynthesizer::SurgeSynthesizer(PluginLayer *parent, std::string suppliedData
: storage(suppliedDataPath), hpA(&storage), hpB(&storage), _parent(parent), halfbandA(6, true),
halfbandB(6, true), halfbandIN(6, true)
{
// Remember CPU features works on ARM also
if (!Surge::CPUFeatures::hasAVX())
{
storage.reportError(
"Surge XT in the future will require processor with AVX extensions. Surge Xt may"
" not work on this hardware in future versions. Enjoy Surge 1.9!",
"CPU Incompatability");
// Try anyway
}

switch_toggled_queued = false;
audio_processing_active = false;
halt_engine = false;
Expand Down
35 changes: 0 additions & 35 deletions src/common/util/FpuState.cpp

This file was deleted.

13 changes: 0 additions & 13 deletions src/common/util/FpuState.h

This file was deleted.

Loading

0 comments on commit a5388b4

Please sign in to comment.