Skip to content

Commit

Permalink
feature: add runtime cpu check (#343) (#344)
Browse files Browse the repository at this point in the history
Check at startup for required cpu instructions (SSE2, SSSE3, POPCOUNT)
  • Loading branch information
variar authored Jun 16, 2021
1 parent 9bde202 commit 4657f4a
Show file tree
Hide file tree
Showing 6 changed files with 223 additions and 4 deletions.
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,9 @@ if(MSVC)
ENDIF (CMAKE_C_FLAGS MATCHES "/W[0-4]")
else()
ucm_add_flags(CXX "-fno-sized-deallocation")
ucm_add_flags(C CXX "-mmmx -msse -msse2 -msse3 -mssse3 -mpopcnt")
if (KLOGG_GENERIC_CPU)
ucm_add_flags(C CXX "-march=core2 -mtune=generic")
ucm_add_flags(C CXX "-march=x86-64 -mtune=generic")
else()
ucm_add_flags(C CXX "-march=native -mtune=generic")
endif()
Expand Down
9 changes: 7 additions & 2 deletions src/app/crashhandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
#include <QTimer>
#include <QUrlQuery>
#include <QVBoxLayout>
#include <cstdint>
#include <cstdlib>
#include <string_view>

#ifdef KLOGG_USE_MIMALLOC
Expand All @@ -44,6 +46,7 @@
#include "client/crash_report_database.h"
#include "sentry.h"

#include "cpu_info.h"
#include "issuereporter.h"
#include "klogg_version.h"
#include "log.h"
Expand Down Expand Up @@ -251,14 +254,16 @@ CrashHandler::CrashHandler()

addExtra( "memory", physicalMemory() );

addExtra( "cpuInstructions", static_cast<unsigned>( supportedCpuInstructions() ) );

memoryUsageTimer_ = std::make_unique<QTimer>();
QObject::connect( memoryUsageTimer_.get(), &QTimer::timeout, [ addExtra ]() {
const auto vmUsed = usedMemory();
addExtra( "vm_used", vmUsed );

#ifdef KLOGG_USE_MIMALLOC
size_t elapsedMsecs, userMsecs, systemMsecs, currentRss, peakRss, currentCommit,
peakCommit, pageFaults;
size_t elapsedMsecs, userMsecs, systemMsecs, currentRss, peakRss, currentCommit, peakCommit,
pageFaults;

mi_process_info( &elapsedMsecs, &userMsecs, &systemMsecs, &currentRss, &peakRss,
&currentCommit, &peakCommit, &pageFaults );
Expand Down
13 changes: 12 additions & 1 deletion src/app/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
*/

#include <QtGlobal>
#include <QMessageBox>

#ifdef Q_OS_WIN
#define WIN32_LEAN_AND_MEAN
Expand All @@ -53,6 +54,7 @@
#endif

#include "configuration.h"
#include "cpu_info.h"
#include "log.h"
#include "mainwindow.h"
#include "styles.h"
Expand Down Expand Up @@ -90,7 +92,7 @@ void setApplicationAttributes( bool enableQtHdpi, int scaleFactorRounding )
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(
static_cast<Qt::HighDpiScaleFactorRoundingPolicy>( scaleFactorRounding ) );
#else
Q_UNUSED(scaleFactorRounding);
Q_UNUSED( scaleFactorRounding );
#endif
}
else {
Expand All @@ -106,6 +108,15 @@ void setApplicationAttributes( bool enableQtHdpi, int scaleFactorRounding )

int main( int argc, char* argv[] )
{
auto requiredInstructuins = CpuInstructions::SSE2;
requiredInstructuins |= CpuInstructions::SSSE3;
requiredInstructuins |= CpuInstructions::POPCNT;
if ( !hasRequiredInstructions( supportedCpuInstructions(), requiredInstructuins ) ) {
QMessageBox::critical( nullptr, "Klogg", "Current CPU is not supported",
QMessageBox::Close );
exit( EXIT_FAILURE );
}

#ifdef KLOGG_USE_MIMALLOC
mi_stats_reset();
#endif
Expand Down
2 changes: 2 additions & 0 deletions src/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ add_library(utils STATIC
${CMAKE_CURRENT_SOURCE_DIR}/src/klogg_version.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/readablesize.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/memory_info.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/cpu_info.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/issuereporter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/atomicflag.h
${CMAKE_CURRENT_SOURCE_DIR}/include/configuration.h
Expand All @@ -23,6 +24,7 @@ add_library(utils STATIC
${CMAKE_CURRENT_SOURCE_DIR}/include/readablesize.h
${CMAKE_CURRENT_SOURCE_DIR}/include/synchronization.h
${CMAKE_CURRENT_SOURCE_DIR}/include/memory_info.h
${CMAKE_CURRENT_SOURCE_DIR}/include/cpu_info.h
${CMAKE_CURRENT_SOURCE_DIR}/include/overload_visitor.h
${CMAKE_CURRENT_SOURCE_DIR}/include/resourcewrapper.h
${CMAKE_CURRENT_SOURCE_DIR}/include/styles.h
Expand Down
61 changes: 61 additions & 0 deletions src/utils/include/cpu_info.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (C) 2021 Anton Filimonov and other contributors
*
* This file is part of klogg.
*
* klogg is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* klogg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with klogg. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef KLOGG_CPU_INFO_H
#define KLOGG_CPU_INFO_H

enum class CpuInstructions : unsigned {
/// Indicates that no SIMD instructions are supported
NONE = 0,
SSE2 = 1 << 1,
SSE3 = 1 << 2,
SSSE3 = 1 << 3,
SSE41 = 1 << 4,
POPCNT = 1 << 5,
AVX = 1 << 6,
AVX2 = 1 << 7,
};

inline CpuInstructions& operator|=( CpuInstructions& x, const CpuInstructions& y )
{
x = static_cast<CpuInstructions>( static_cast<unsigned>( x ) | static_cast<unsigned>( y ) );
return x;
}

inline CpuInstructions operator&( const CpuInstructions& x, const CpuInstructions& y )
{
return static_cast<CpuInstructions>( static_cast<unsigned>( x ) & static_cast<unsigned>( y ) );
}

inline CpuInstructions operator~( const CpuInstructions& x )
{
return static_cast<CpuInstructions>( ~static_cast<unsigned>( x ) );
}

inline bool hasRequiredInstructions( CpuInstructions current, CpuInstructions required )
{
if ( ( ~current & required ) == CpuInstructions::NONE ) {
return true;
}
return false;
}

CpuInstructions supportedCpuInstructions();

#endif
139 changes: 139 additions & 0 deletions src/utils/src/cpu_info.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright (C) 2021 Anton Filimonov and other contributors
*
* This file is part of klogg.
*
* klogg is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* klogg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with klogg. If not, see <http://www.gnu.org/licenses/>.
*/

#include "cpu_info.h"
#include <QtGlobal>

#if defined( Q_OS_WIN )

#include <array>
#include <bitset>
#include <vector>

#include <intrin.h>

CpuInstructions supportedCpuInstructions()
{
CpuInstructions cpuInstructions = CpuInstructions::NONE;

std::array<int, 4> cpui;

// Calling __cpuid with 0x0 as the function_id argument
// gets the number of the highest valid function ID.
__cpuid( cpui.data(), 0 );

const auto nIds = cpui[ 0 ];
std::vector<std::array<int, 4>> data;

for ( int i = 0; i <= nIds; ++i ) {
__cpuidex( cpui.data(), i, 0 );
data.push_back( cpui );
}

// load bitset with flags for function 0x00000001
if ( nIds >= 1 ) {
std::bitset<32> f_1_ECX = data[ 1 ][ 2 ];
std::bitset<32> f_1_EDX = data[ 1 ][ 3 ];

if ( f_1_EDX[ 26 ] ) {
cpuInstructions |= CpuInstructions::SSE2;
}
if ( f_1_ECX[ 0 ] ) {
cpuInstructions |= CpuInstructions::SSE3;
}
if ( f_1_ECX[ 9 ] ) {
cpuInstructions |= CpuInstructions::SSSE3;
}
if ( f_1_ECX[ 19 ] ) {
cpuInstructions |= CpuInstructions::SSE41;
}

if ( f_1_ECX[ 23 ] ) {
cpuInstructions |= CpuInstructions::POPCNT;
}

if ( f_1_ECX[ 28 ] ) {
cpuInstructions |= CpuInstructions::AVX;
}
}

// load bitset with flags for function 0x00000007
if ( nIds >= 7 ) {
std::bitset<32> f_7_EBX = data[ 7 ][ 1 ];

if ( f_7_EBX[ 5 ] ) {
cpuInstructions |= CpuInstructions::AVX2;
}
}

return cpuInstructions;
}
#else
CpuInstructions supportedCpuInstructions()
{
CpuInstructions cpuInstructions = CpuInstructions::NONE;

if ( __builtin_cpu_supports( "avx512f" ) ) {
cpuInstructions |= CpuInstructions::SSE2;
cpuInstructions |= CpuInstructions::SSE3;
cpuInstructions |= CpuInstructions::SSSE3;
cpuInstructions |= CpuInstructions::SSE41;
cpuInstructions |= CpuInstructions::AVX;
cpuInstructions |= CpuInstructions::AVX2;
}
else if ( __builtin_cpu_supports( "avx2" ) ) {
cpuInstructions |= CpuInstructions::SSE2;
cpuInstructions |= CpuInstructions::SSE3;
cpuInstructions |= CpuInstructions::SSSE3;
cpuInstructions |= CpuInstructions::SSE41;
cpuInstructions |= CpuInstructions::AVX;
cpuInstructions |= CpuInstructions::AVX2;
}
else if ( __builtin_cpu_supports( "avx" ) ) {
cpuInstructions |= CpuInstructions::SSE2;
cpuInstructions |= CpuInstructions::SSE3;
cpuInstructions |= CpuInstructions::SSSE3;
cpuInstructions |= CpuInstructions::SSE41;
cpuInstructions |= CpuInstructions::AVX;
}
else if ( __builtin_cpu_supports( "sse4.1" ) ) {
cpuInstructions |= CpuInstructions::SSE2;
cpuInstructions |= CpuInstructions::SSE3;
cpuInstructions |= CpuInstructions::SSSE3;
cpuInstructions |= CpuInstructions::SSE41;
}
else if ( __builtin_cpu_supports( "ssse3" ) ) {
cpuInstructions |= CpuInstructions::SSE2;
cpuInstructions |= CpuInstructions::SSE3;
cpuInstructions |= CpuInstructions::SSSE3;
}
else if ( __builtin_cpu_supports( "sse3" ) ) {
cpuInstructions |= CpuInstructions::SSE3;
cpuInstructions |= CpuInstructions::SSE2;
}
else if ( __builtin_cpu_supports( "sse2" ) ) {
cpuInstructions |= CpuInstructions::SSE2;
}
if ( __builtin_cpu_supports( "popcnt" ) ) {
cpuInstructions |= CpuInstructions::POPCNT;
}
return cpuInstructions;
}

#endif

0 comments on commit 4657f4a

Please sign in to comment.