diff --git a/include/firestarter/CpuModel.hpp b/include/firestarter/CpuModel.hpp new file mode 100644 index 00000000..4cfeeacc --- /dev/null +++ b/include/firestarter/CpuModel.hpp @@ -0,0 +1,42 @@ +/****************************************************************************** + * FIRESTARTER - A Processor Stress Test Utility + * Copyright (C) 2024 TU Dresden, Center for Information Services and High + * Performance Computing + * + * This program 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. + * + * This program 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 this program. If not, see . + * + * Contact: daniel.hackenberg@tu-dresden.de + *****************************************************************************/ + +#pragma once + +namespace firestarter { + +/// Abstract class that defines the methods required to check if one cpu model is equal to another +class CpuModel { +public: + CpuModel() = default; + virtual ~CpuModel() = default; + + /// \arg Other The model to which operator < should be checked. + /// \return true if this is less than other + [[nodiscard]] virtual auto operator<(const CpuModel& Other) const -> bool = 0; + + /// Check if two models match. + /// \arg Other The model to which equality should be checked. + /// \return true if this and the other model match + [[nodiscard]] virtual auto operator==(const CpuModel& Other) const -> bool = 0; +}; + +} // namespace firestarter diff --git a/include/firestarter/Platform/PlatformConfig.hpp b/include/firestarter/Platform/PlatformConfig.hpp index 3eda4783..19c3d21d 100644 --- a/include/firestarter/Platform/PlatformConfig.hpp +++ b/include/firestarter/Platform/PlatformConfig.hpp @@ -22,6 +22,7 @@ #pragma once #include "firestarter/Config/InstructionGroups.hpp" +#include "firestarter/CpuModel.hpp" #include "firestarter/Logging/Log.hpp" #include "firestarter/Payload/Payload.hpp" #include "firestarter/ProcessorInformation.hpp" @@ -59,19 +60,15 @@ class PlatformConfig { [[nodiscard]] auto payload() const -> const auto& { return Payload; } /// Check if this platform is available and the default on the current system. - /// \arg Topology The reference to the CPUTopology that is used to check agains if this payload is supported. - /// \returns true if the platform is the default one for a given CPUTopology. - [[nodiscard]] auto isDefault(const ProcessorInformation& Topology) const -> bool { return isDefault(&Topology); } + /// \arg Model The reference to the cpu model that is used to check if this config is the default. + /// \arg CpuFeatures Features that this payload requires to check agains if this payload is supported. + /// \returns true if the platform is the default one. + [[nodiscard]] virtual auto isDefault(const CpuModel& Model, const CpuFeatures& Features) const -> bool = 0; protected: /// Non const Getter for the settings of the platform. [[nodiscard]] auto settings() -> payload::PayloadSettings& { return Settings; } - /// Check if this platform is available and the default on the current system. - /// \arg Topology The pointer to the CPUTopology that is used to check agains if this payload is supported. - /// \returns true if the platform is the default one for a given CPUTopology. - [[nodiscard]] virtual auto isDefault(const ProcessorInformation*) const -> bool = 0; - public: PlatformConfig() = delete; diff --git a/include/firestarter/ProcessorInformation.hpp b/include/firestarter/ProcessorInformation.hpp index 2eeaa097..c2c1c46f 100644 --- a/include/firestarter/ProcessorInformation.hpp +++ b/include/firestarter/ProcessorInformation.hpp @@ -22,6 +22,7 @@ #pragma once #include "firestarter/CpuFeatures.hpp" +#include "firestarter/CpuModel.hpp" #include #include @@ -38,7 +39,8 @@ namespace firestarter { /// This class models the properties of a processor. class ProcessorInformation { public: - explicit ProcessorInformation(std::string Architecture, std::unique_ptr&& Features); + explicit ProcessorInformation(std::string Architecture, std::unique_ptr&& Features, + std::unique_ptr&& Model); virtual ~ProcessorInformation() = default; /// Getter for the clockrate in Hz @@ -56,6 +58,9 @@ class ProcessorInformation { /// Getter for the cpu features abstraction [[nodiscard]] auto cpuFeatures() const -> const CpuFeatures& { return *Features; } + /// Getter for the cpu model abstraction + [[nodiscard]] auto cpuModel() const -> const CpuModel& { return *Model; } + /// Print the information about this process to a stream. void print() const; @@ -75,6 +80,8 @@ class ProcessorInformation { std::string Vendor; /// The cpu features of this processor. std::unique_ptr Features; + /// The cpu model of this processor. + std::unique_ptr Model; /// Helper function to open a filepath and return a stringstream with its contents. /// \arg FilePath The file to open diff --git a/include/firestarter/X86/Platform/BulldozerConfig.hpp b/include/firestarter/X86/Platform/BulldozerConfig.hpp index a1496e20..89209824 100644 --- a/include/firestarter/X86/Platform/BulldozerConfig.hpp +++ b/include/firestarter/X86/Platform/BulldozerConfig.hpp @@ -29,7 +29,10 @@ class BulldozerConfig final : public X86PlatformConfig { public: BulldozerConfig() noexcept : X86PlatformConfig( - /*Name=*/"BLD_OPTERON", /*Family=*/21, /*Models=*/{1, 2, 3}, + /*Name=*/"BLD_OPTERON", + /*RequestedModels=*/ + {X86CpuModel(/*FamilyId=*/21, /*ModelId=*/1), X86CpuModel(/*FamilyId=*/21, /*ModelId=*/2), + X86CpuModel(/*FamilyId=*/21, /*ModelId=*/3)}, /*Settings=*/ firestarter::payload::PayloadSettings( /*Threads=*/{1}, /*DataCacheBufferSize=*/{16384, 1048576, 786432}, /*RamBufferSize=*/104857600, diff --git a/include/firestarter/X86/Platform/HaswellConfig.hpp b/include/firestarter/X86/Platform/HaswellConfig.hpp index e117b20d..09c390e5 100644 --- a/include/firestarter/X86/Platform/HaswellConfig.hpp +++ b/include/firestarter/X86/Platform/HaswellConfig.hpp @@ -29,7 +29,10 @@ class HaswellConfig final : public X86PlatformConfig { public: HaswellConfig() noexcept : X86PlatformConfig( - /*Name=*/"HSW_COREI", /*Family=*/6, /*Models=*/{60, 61, 69, 70, 71}, + /*Name=*/"HSW_COREI", /*RequestedModels=*/ + {X86CpuModel(/*FamilyId=*/6, /*ModelId=*/60), X86CpuModel(/*FamilyId=*/6, /*ModelId=*/61), + X86CpuModel(/*FamilyId=*/6, /*ModelId=*/69), X86CpuModel(/*FamilyId=*/6, /*ModelId=*/70), + X86CpuModel(/*FamilyId=*/6, /*ModelId=*/71)}, /*Settings=*/ firestarter::payload::PayloadSettings( /*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{32768, 262144, 1572864}, /*RamBufferSize=*/104857600, diff --git a/include/firestarter/X86/Platform/HaswellEPConfig.hpp b/include/firestarter/X86/Platform/HaswellEPConfig.hpp index d0b7f014..977eab72 100644 --- a/include/firestarter/X86/Platform/HaswellEPConfig.hpp +++ b/include/firestarter/X86/Platform/HaswellEPConfig.hpp @@ -29,7 +29,8 @@ class HaswellEPConfig final : public X86PlatformConfig { public: HaswellEPConfig() noexcept : X86PlatformConfig( - /*Name=*/"HSW_XEONEP", /*Family=*/6, /*Models=*/{63, 79}, + /*Name=*/"HSW_XEONEP", /*RequestedModels=*/ + {X86CpuModel(/*FamilyId=*/6, /*ModelId=*/63), X86CpuModel(/*FamilyId=*/6, /*ModelId=*/79)}, /*Settings=*/ firestarter::payload::PayloadSettings( /*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{32768, 262144, 2621440}, diff --git a/include/firestarter/X86/Platform/KnightsLandingConfig.hpp b/include/firestarter/X86/Platform/KnightsLandingConfig.hpp index e46ebdc5..ac020436 100644 --- a/include/firestarter/X86/Platform/KnightsLandingConfig.hpp +++ b/include/firestarter/X86/Platform/KnightsLandingConfig.hpp @@ -28,7 +28,8 @@ namespace firestarter::x86::platform { class KnightsLandingConfig final : public X86PlatformConfig { public: KnightsLandingConfig() noexcept - : X86PlatformConfig(/*Name=*/"KNL_XEONPHI", /*Family=*/6, /*Models=*/{87}, + : X86PlatformConfig(/*Name=*/"KNL_XEONPHI", /*RequestedModels=*/ + {X86CpuModel(/*FamilyId=*/6, /*ModelId=*/87)}, /*Settings=*/ firestarter::payload::PayloadSettings( /*Threads=*/{4}, /*DataCacheBufferSize=*/{32768, 524288, 236279125}, diff --git a/include/firestarter/X86/Platform/NaplesConfig.hpp b/include/firestarter/X86/Platform/NaplesConfig.hpp index 5bbb25f5..7411899e 100644 --- a/include/firestarter/X86/Platform/NaplesConfig.hpp +++ b/include/firestarter/X86/Platform/NaplesConfig.hpp @@ -29,7 +29,9 @@ class NaplesConfig final : public X86PlatformConfig { public: NaplesConfig() noexcept : X86PlatformConfig( - /*Name=*/"ZEN_EPYC", /*Family=*/23, /*Models=*/{1, 8, 17, 24}, + /*Name=*/"ZEN_EPYC", /*RequestedModels=*/ + {X86CpuModel(/*FamilyId=*/23, /*ModelId=*/1), X86CpuModel(/*FamilyId=*/23, /*ModelId=*/8), + X86CpuModel(/*FamilyId=*/23, /*ModelId=*/17), X86CpuModel(/*FamilyId=*/23, /*ModelId=*/24)}, /*Settings=*/ firestarter::payload::PayloadSettings( /*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{65536, 524288, 2097152}, /*RamBufferSize=*/104857600, diff --git a/include/firestarter/X86/Platform/NehalemConfig.hpp b/include/firestarter/X86/Platform/NehalemConfig.hpp index c1f0e3b3..638ec27a 100644 --- a/include/firestarter/X86/Platform/NehalemConfig.hpp +++ b/include/firestarter/X86/Platform/NehalemConfig.hpp @@ -29,7 +29,9 @@ class NehalemConfig final : public X86PlatformConfig { public: NehalemConfig() noexcept : X86PlatformConfig( - /*Name=*/"NHM_COREI", /*Family=*/6, /*Models=*/{30, 37, 23}, + /*Name=*/"NHM_COREI", /*RequestedModels=*/ + {X86CpuModel(/*FamilyId=*/6, /*ModelId=*/30), X86CpuModel(/*FamilyId=*/6, /*ModelId=*/37), + X86CpuModel(/*FamilyId=*/6, /*ModelId=*/23)}, /*Settings=*/ firestarter::payload::PayloadSettings(/*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{32768, 262144, 1572864}, /*RamBufferSize=*/104857600, /*Lines=*/1536, diff --git a/include/firestarter/X86/Platform/NehalemEPConfig.hpp b/include/firestarter/X86/Platform/NehalemEPConfig.hpp index c02e7f47..648dd681 100644 --- a/include/firestarter/X86/Platform/NehalemEPConfig.hpp +++ b/include/firestarter/X86/Platform/NehalemEPConfig.hpp @@ -28,7 +28,8 @@ namespace firestarter::x86::platform { class NehalemEPConfig final : public X86PlatformConfig { public: NehalemEPConfig() noexcept - : X86PlatformConfig(/*Name=*/"NHM_XEONEP", /*Family=*/6, /*Models=*/{26, 44}, + : X86PlatformConfig(/*Name=*/"NHM_XEONEP", /*RequestedModels=*/ + {X86CpuModel(/*FamilyId=*/6, /*ModelId=*/26), X86CpuModel(/*FamilyId=*/6, /*ModelId=*/44)}, /*Settings=*/ firestarter::payload::PayloadSettings( /*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{32768, 262144, 2097152}, diff --git a/include/firestarter/X86/Platform/RomeConfig.hpp b/include/firestarter/X86/Platform/RomeConfig.hpp index 5a2d04e4..bd0e156f 100644 --- a/include/firestarter/X86/Platform/RomeConfig.hpp +++ b/include/firestarter/X86/Platform/RomeConfig.hpp @@ -29,7 +29,8 @@ class RomeConfig final : public X86PlatformConfig { public: RomeConfig() noexcept : X86PlatformConfig( - /*Name=*/"ZEN_2_EPYC", /*Family=*/23, /*Models=*/{49}, + /*Name=*/"ZEN_2_EPYC", /*RequestedModels=*/ + {X86CpuModel(/*FamilyId=*/23, /*ModelId=*/49)}, /*Settings=*/ firestarter::payload::PayloadSettings( /*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{32768, 524288, 2097152}, /*RamBufferSize=*/104857600, diff --git a/include/firestarter/X86/Platform/SandyBridgeConfig.hpp b/include/firestarter/X86/Platform/SandyBridgeConfig.hpp index 50fd8a00..ec08244f 100644 --- a/include/firestarter/X86/Platform/SandyBridgeConfig.hpp +++ b/include/firestarter/X86/Platform/SandyBridgeConfig.hpp @@ -29,7 +29,8 @@ class SandyBridgeConfig final : public X86PlatformConfig { public: SandyBridgeConfig() noexcept : X86PlatformConfig( - /*Name=*/"SNB_COREI", /*Family=*/6, /*Models=*/{42, 58}, + /*Name=*/"SNB_COREI", /*RequestedModels=*/ + {X86CpuModel(/*FamilyId=*/6, /*ModelId=*/42), X86CpuModel(/*FamilyId=*/6, /*ModelId=*/58)}, /*Settings=*/ firestarter::payload::PayloadSettings( /*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{32768, 262144, 1572864}, /*RamBufferSize=*/104857600, diff --git a/include/firestarter/X86/Platform/SandyBridgeEPConfig.hpp b/include/firestarter/X86/Platform/SandyBridgeEPConfig.hpp index 5f6ec9ce..3b9625b6 100644 --- a/include/firestarter/X86/Platform/SandyBridgeEPConfig.hpp +++ b/include/firestarter/X86/Platform/SandyBridgeEPConfig.hpp @@ -29,7 +29,8 @@ class SandyBridgeEPConfig final : public X86PlatformConfig { public: SandyBridgeEPConfig() noexcept : X86PlatformConfig( - /*Name=*/"SNB_XEONEP", /*Family=*/6, /*Models=*/{45, 62}, + /*Name=*/"SNB_XEONEP", /*RequestedModels=*/ + {X86CpuModel(/*FamilyId=*/6, /*ModelId=*/45), X86CpuModel(/*FamilyId=*/6, /*ModelId=*/62)}, /*Settings=*/ firestarter::payload::PayloadSettings( /*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{32768, 262144, 2621440}, /*RamBufferSize=*/104857600, diff --git a/include/firestarter/X86/Platform/SkylakeConfig.hpp b/include/firestarter/X86/Platform/SkylakeConfig.hpp index 843151db..3d0b38f1 100644 --- a/include/firestarter/X86/Platform/SkylakeConfig.hpp +++ b/include/firestarter/X86/Platform/SkylakeConfig.hpp @@ -29,7 +29,8 @@ class SkylakeConfig final : public X86PlatformConfig { public: SkylakeConfig() noexcept : X86PlatformConfig( - /*Name=*/"SKL_COREI", /*Family=*/6, /*Models=*/{78, 94}, + /*Name=*/"SKL_COREI", /*RequestedModels=*/ + {X86CpuModel(/*FamilyId=*/6, /*ModelId=*/78), X86CpuModel(/*FamilyId=*/6, /*ModelId=*/94)}, /*Settings=*/ firestarter::payload::PayloadSettings( /*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{32768, 262144, 1572864}, diff --git a/include/firestarter/X86/Platform/SkylakeSPConfig.hpp b/include/firestarter/X86/Platform/SkylakeSPConfig.hpp index c3b50c13..0703c223 100644 --- a/include/firestarter/X86/Platform/SkylakeSPConfig.hpp +++ b/include/firestarter/X86/Platform/SkylakeSPConfig.hpp @@ -28,7 +28,8 @@ namespace firestarter::x86::platform { class SkylakeSPConfig final : public X86PlatformConfig { public: SkylakeSPConfig() noexcept - : X86PlatformConfig(/*Name=*/"SKL_XEONEP", /*Family=*/6, /*Models=*/{85}, + : X86PlatformConfig(/*Name=*/"SKL_XEONEP", /*RequestedModels=*/ + {X86CpuModel(/*FamilyId=*/6, /*ModelId=*/85)}, /*Settings=*/ firestarter::payload::PayloadSettings(/*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{32768, 1048576, 1441792}, diff --git a/include/firestarter/X86/Platform/X86PlatformConfig.hpp b/include/firestarter/X86/Platform/X86PlatformConfig.hpp index f62c14d5..af909a4d 100644 --- a/include/firestarter/X86/Platform/X86PlatformConfig.hpp +++ b/include/firestarter/X86/Platform/X86PlatformConfig.hpp @@ -22,30 +22,27 @@ #pragma once #include "firestarter/Platform/PlatformConfig.hpp" -#include "firestarter/ProcessorInformation.hpp" -#include "firestarter/X86/X86ProcessorInformation.hpp" +#include "firestarter/X86/X86CpuModel.hpp" +#include namespace firestarter::x86::platform { /// Models a platform config that is the default based on x86 CPU family and model ids. class X86PlatformConfig : public firestarter::platform::PlatformConfig { private: - /// The famility id of the processor for which this is the default platform config. - unsigned Family; - /// The list of model ids in combination with the family for which this is the default platform config. - std::list Models; + /// The set of requested cpu models + std::set RequestedModels; public: - X86PlatformConfig(std::string Name, unsigned Family, std::list&& Models, + X86PlatformConfig(std::string Name, std::set&& RequestedModels, firestarter::payload::PayloadSettings&& Settings, std::shared_ptr&& Payload) noexcept : PlatformConfig(std::move(Name), std::move(Settings), std::move(Payload)) - , Family(Family) - , Models(std::move(Models)) {} + , RequestedModels(std::move(RequestedModels)) {} /// Clone a the platform config. [[nodiscard]] auto clone() const -> std::unique_ptr final { - auto Ptr = std::make_unique(name(), Family, std::list(Models), + auto Ptr = std::make_unique(name(), std::set(RequestedModels), firestarter::payload::PayloadSettings(settings()), std::shared_ptr(payload())); return Ptr; @@ -62,21 +59,14 @@ class X86PlatformConfig : public firestarter::platform::PlatformConfig { return Ptr; } -private: - /// Check if this platform is available and the default on the current system. This is done by checking if the family - /// id in the CPUTopology matches the one saved in Family and if the model id in the CPUTopology is contained in - /// Models. - /// \arg Topology The pointer to the CPUTopology that is used to check agains if this payload is supported. - /// \returns true if the platform is the default one for a given CPUTopology. - [[nodiscard]] auto isDefault(const ProcessorInformation* Topology) const -> bool final { - const auto* FinalTopology = dynamic_cast(Topology); - assert(FinalTopology && "isDefault not called with const X86CPUTopology*"); - - // Check if the family of the topology matches the family of the config, if the model of the topology is contained - // in the models list of the config and if the config is available on the current platform. - return Family == FinalTopology->familyId() && - (std::find(Models.begin(), Models.end(), FinalTopology->modelId()) != Models.end()) && - payload()->isAvailable(Topology->cpuFeatures()); + /// Check if this platform is available and the default on the current system. This is done by checking if the cpu + /// model matches one of the requested ones and that the payload is available with the supplied cpu features. + /// \arg Model The reference to the cpu model that is used to check if this config is the default. + /// \arg CpuFeatures Features that this payload requires to check agains if this payload is supported. + /// \returns true if the platform is the default one. + [[nodiscard]] auto isDefault(const CpuModel& Model, const CpuFeatures& Features) const -> bool override { + const auto ModelIt = std::find(RequestedModels.cbegin(), RequestedModels.cend(), Model); + return ModelIt != RequestedModels.cend() && payload()->isAvailable(Features); } }; diff --git a/include/firestarter/X86/X86CpuModel.hpp b/include/firestarter/X86/X86CpuModel.hpp new file mode 100644 index 00000000..6f99cae2 --- /dev/null +++ b/include/firestarter/X86/X86CpuModel.hpp @@ -0,0 +1,70 @@ +/****************************************************************************** + * FIRESTARTER - A Processor Stress Test Utility + * Copyright (C) 2024 TU Dresden, Center for Information Services and High + * Performance Computing + * + * This program 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. + * + * This program 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 this program. If not, see . + * + * Contact: daniel.hackenberg@tu-dresden.de + *****************************************************************************/ + +#pragma once + +#include "firestarter/CpuModel.hpp" + +#include +#include +#include + +namespace firestarter::x86 { + +/// This class models the cpu features on the x86_64 platform. +class X86CpuModel : public CpuModel { +private: + /// The x86 family id + unsigned FamilyId; + /// The x86 model id + unsigned ModelId; + +public: + X86CpuModel() = delete; + explicit X86CpuModel(unsigned FamilyId, unsigned ModelId) noexcept + : FamilyId(FamilyId) + , ModelId(ModelId) {} + + /// \arg Other The model to which operator < should be checked. + /// \return true if this is less than other + [[nodiscard]] auto operator<(const CpuModel& Other) const -> bool override { + const auto* DerivedModel = dynamic_cast(&Other); + if (!DerivedModel) { + throw std::runtime_error("Other is not of the correct type X86CpuModel"); + } + + return std::tie(FamilyId, ModelId) < std::tie(DerivedModel->FamilyId, DerivedModel->ModelId); + } + + /// Check if two models match. + /// \arg Other The model to which equality should be checked. + /// \return true if this and the other model match + [[nodiscard]] auto operator==(const CpuModel& Other) const -> bool override { + const auto* DerivedModel = dynamic_cast(&Other); + if (!DerivedModel) { + throw std::runtime_error("Other is not of the correct type X86CpuModel"); + } + + return std::tie(FamilyId, ModelId) == std::tie(DerivedModel->FamilyId, DerivedModel->ModelId); + } +}; + +} // namespace firestarter::x86 diff --git a/include/firestarter/X86/X86ProcessorInformation.hpp b/include/firestarter/X86/X86ProcessorInformation.hpp index b7922a66..d282a38a 100644 --- a/include/firestarter/X86/X86ProcessorInformation.hpp +++ b/include/firestarter/X86/X86ProcessorInformation.hpp @@ -34,8 +34,6 @@ class X86ProcessorInformation final : public ProcessorInformation { /// Getter for the list of CPU features [[nodiscard]] auto features() const -> std::list const& override { return this->FeatureList; } - /// Getter for the CPU features class from asmjit - [[nodiscard]] auto featuresAsmjit() const -> const asmjit::CpuFeatures& { return this->CpuInfo.features(); } /// Getter for the clockrate in Hz [[nodiscard]] auto clockrate() const -> uint64_t override; @@ -43,12 +41,6 @@ class X86ProcessorInformation final : public ProcessorInformation { /// Get the current hardware timestamp [[nodiscard]] auto timestamp() const -> uint64_t override; - /// The family id of the x86 processor - [[nodiscard]] auto familyId() const -> unsigned { return this->CpuInfo.familyId(); } - /// The model id of the x86 processor - [[nodiscard]] auto modelId() const -> unsigned { return this->CpuInfo.modelId(); } - /// The stepping id of the x86 processor - [[nodiscard]] auto stepping() const -> unsigned { return this->CpuInfo.stepping(); } /// The CPU vendor i.e., Intel or AMD. [[nodiscard]] auto vendor() const -> std::string const& final { return Vendor; } /// Get the string containing family, model and stepping ids. diff --git a/src/firestarter/Firestarter.cpp b/src/firestarter/Firestarter.cpp index 4eeaf6da..9e664158 100644 --- a/src/firestarter/Firestarter.cpp +++ b/src/firestarter/Firestarter.cpp @@ -25,7 +25,9 @@ #include "firestarter/Optimizer/Algorithm/NSGA2.hpp" #include "firestarter/Optimizer/History.hpp" #include "firestarter/Optimizer/Problem/CLIArgumentProblem.hpp" +#include "firestarter/X86/X86CpuFeatures.hpp" #include "firestarter/X86/X86FunctionSelection.hpp" +#include "firestarter/X86/X86ProcessorInformation.hpp" #include #include @@ -48,8 +50,7 @@ Firestarter::Firestarter(Config&& ProvidedConfig) if constexpr (firestarter::OptionalFeatures.IsX86) { // Error detection uses crc32 instruction added by the SSE4.2 extension to x86 if (Cfg.ErrorDetection) { - const auto& X86ProcessorInfos = *dynamic_cast(ProcessorInfos.get()); - if (!X86ProcessorInfos.featuresAsmjit().has(asmjit::CpuFeatures::X86::kSSE4_2)) { + if (!ProcessorInfos->cpuFeatures().hasAll(x86::X86CpuFeatures().add(asmjit::CpuFeatures::X86::kSSE4_2))) { throw std::invalid_argument("Option --error-detection requires the crc32 " "instruction added with SSE_4_2.\n"); } diff --git a/src/firestarter/FunctionSelection.cpp b/src/firestarter/FunctionSelection.cpp index 4b8a2ff8..953d475c 100644 --- a/src/firestarter/FunctionSelection.cpp +++ b/src/firestarter/FunctionSelection.cpp @@ -67,7 +67,7 @@ auto FunctionSelection::selectDefaultOrFallbackFunction(const ProcessorInformati for (const auto& Platform : platform::PlatformConfigAndThreads::fromPlatformConfigs(platformConfigs())) { // default function - if (Platform.Config->isDefault(ProcessorInfos)) { + if (Platform.Config->isDefault(ProcessorInfos.cpuModel(), ProcessorInfos.cpuFeatures())) { if (Platform.ThreadCount == ProcessorThreadsPerCore) { return Platform.Config->cloneConcreate(ProcessorICacheSize, Platform.ThreadCount); } diff --git a/src/firestarter/ProcessorInformation.cpp b/src/firestarter/ProcessorInformation.cpp index 8c66cc24..ad86b4d2 100644 --- a/src/firestarter/ProcessorInformation.cpp +++ b/src/firestarter/ProcessorInformation.cpp @@ -48,8 +48,10 @@ void ProcessorInformation::print() const { << " supported features: " << Ss.str(); } -ProcessorInformation::ProcessorInformation(std::string Architecture, std::unique_ptr&& Features) +ProcessorInformation::ProcessorInformation(std::string Architecture, std::unique_ptr&& Features, + std::unique_ptr&& Model) : Features(std::move(Features)) + , Model(std::move(Model)) , Architecture(std::move(Architecture)) { // get vendor, processor name and clockrate for linux diff --git a/src/firestarter/X86/X86ProcessorInformation.cpp b/src/firestarter/X86/X86ProcessorInformation.cpp index 42f336fe..451083de 100644 --- a/src/firestarter/X86/X86ProcessorInformation.cpp +++ b/src/firestarter/X86/X86ProcessorInformation.cpp @@ -22,8 +22,10 @@ #include "firestarter/X86/X86ProcessorInformation.hpp" #include "firestarter/Logging/Log.hpp" #include "firestarter/X86/X86CpuFeatures.hpp" +#include "firestarter/X86/X86CpuModel.hpp" #include +#include #ifdef _MSC_VER #include @@ -35,13 +37,15 @@ namespace firestarter::x86 { X86ProcessorInformation::X86ProcessorInformation() - : ProcessorInformation("x86_64", std::make_unique(asmjit::CpuInfo::host().features())) + : ProcessorInformation( + "x86_64", std::make_unique(asmjit::CpuInfo::host().features()), + std::make_unique(asmjit::CpuInfo::host().familyId(), asmjit::CpuInfo::host().modelId())) , CpuInfo(asmjit::CpuInfo::host()) , Vendor(CpuInfo.vendor()) { { std::stringstream Ss; - Ss << "Family " << familyId() << ", Model " << modelId() << ", Stepping " << stepping(); + Ss << "Family " << CpuInfo.familyId() << ", Model " << CpuInfo.modelId() << ", Stepping " << CpuInfo.stepping(); Model = Ss.str(); } diff --git a/test/UnitTests/CMakeLists.txt b/test/UnitTests/CMakeLists.txt index 1106a517..738a8988 100644 --- a/test/UnitTests/CMakeLists.txt +++ b/test/UnitTests/CMakeLists.txt @@ -2,7 +2,9 @@ add_executable(UnitTests CpuBindTest.cpp InstructionGroupsTest.cpp X86CpuFeaturesTest.cpp + X86CpuModelTest.cpp X86PayloadTest.cpp + X86PlatformConfigTest.cpp ) target_link_libraries(UnitTests diff --git a/test/UnitTests/X86CpuFeaturesTest.cpp b/test/UnitTests/X86CpuFeaturesTest.cpp index a9657133..5b45d923 100644 --- a/test/UnitTests/X86CpuFeaturesTest.cpp +++ b/test/UnitTests/X86CpuFeaturesTest.cpp @@ -24,10 +24,14 @@ #include #include +namespace { + class InvalidCpuFeatures : public firestarter::CpuFeatures { [[nodiscard]] auto hasAll(const CpuFeatures& /*Features*/) const -> bool override { return true; }; }; +} // namespace + TEST(X86CpuFeatures, X86CpuFeaturesAllowed) { firestarter::x86::X86CpuFeatures Features{}; diff --git a/test/UnitTests/X86CpuModelTest.cpp b/test/UnitTests/X86CpuModelTest.cpp new file mode 100644 index 00000000..0c634aa5 --- /dev/null +++ b/test/UnitTests/X86CpuModelTest.cpp @@ -0,0 +1,66 @@ +/****************************************************************************** + * FIRESTARTER - A Processor Stress Test Utility + * Copyright (C) 2024 TU Dresden, Center for Information Services and High + * Performance Computing + * + * This program 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. + * + * This program 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 this program. If not, see . + * + * Contact: daniel.hackenberg@tu-dresden.de + *****************************************************************************/ + +#include "firestarter/X86/X86CpuModel.hpp" + +#include + +namespace { + +class InvalidCpuModel : public firestarter::CpuModel { + [[nodiscard]] auto operator<(const CpuModel& /*Other*/) const -> bool override { return true; } + + [[nodiscard]] auto operator==(const CpuModel& /*Other*/) const -> bool override { return true; } +}; + +} // namespace + +TEST(X86CpuModel, X86CpuModelAllowed) { + firestarter::x86::X86CpuModel Model(/*FamilyId=*/1, /*ModelId=*/2); + + EXPECT_NO_THROW((void)(Model == Model)); + EXPECT_ANY_THROW((void)(Model == InvalidCpuModel())); +} + +TEST(X86CpuModel, CheckEqual) { + firestarter::x86::X86CpuModel Model(/*FamilyId=*/1, /*ModelId=*/2); + + EXPECT_TRUE(Model == Model); + EXPECT_FALSE(Model == firestarter::x86::X86CpuModel(/*FamilyId=*/1, /*ModelId=*/0)); + EXPECT_FALSE(Model == firestarter::x86::X86CpuModel(/*FamilyId=*/0, /*ModelId=*/2)); + EXPECT_FALSE(Model == firestarter::x86::X86CpuModel(/*FamilyId=*/3, /*ModelId=*/4)); +} + +TEST(X86CpuModel, CheckLess) { + firestarter::x86::X86CpuModel Model(/*FamilyId=*/1, /*ModelId=*/2); + + EXPECT_TRUE(firestarter::x86::X86CpuModel(/*FamilyId=*/0, /*ModelId=*/1) < Model); + EXPECT_TRUE(firestarter::x86::X86CpuModel(/*FamilyId=*/0, /*ModelId=*/2) < Model); + EXPECT_TRUE(firestarter::x86::X86CpuModel(/*FamilyId=*/0, /*ModelId=*/3) < Model); + + EXPECT_TRUE(firestarter::x86::X86CpuModel(/*FamilyId=*/1, /*ModelId=*/1) < Model); + EXPECT_FALSE(Model < Model); + EXPECT_FALSE(firestarter::x86::X86CpuModel(/*FamilyId=*/1, /*ModelId=*/3) < Model); + + EXPECT_FALSE(firestarter::x86::X86CpuModel(/*FamilyId=*/2, /*ModelId=*/1) < Model); + EXPECT_FALSE(firestarter::x86::X86CpuModel(/*FamilyId=*/2, /*ModelId=*/2) < Model); + EXPECT_FALSE(firestarter::x86::X86CpuModel(/*FamilyId=*/2, /*ModelId=*/3) < Model); +} \ No newline at end of file diff --git a/test/UnitTests/X86PayloadTest.cpp b/test/UnitTests/X86PayloadTest.cpp index 23cf48af..3861628f 100644 --- a/test/UnitTests/X86PayloadTest.cpp +++ b/test/UnitTests/X86PayloadTest.cpp @@ -24,6 +24,8 @@ #include #include +namespace { + class X86PayloadTest : public firestarter::x86::payload::X86Payload { public: X86PayloadTest() @@ -54,6 +56,8 @@ class FalseCpuFeatures : public firestarter::CpuFeatures { [[nodiscard]] auto hasAll(const CpuFeatures& /*Features*/) const -> bool override { return false; }; }; +} // namespace + TEST(X86PayloadTest, CpuFeatureHasAllReturned) { EXPECT_TRUE(X86PayloadTest().isAvailable(TrueCpuFeatures())); EXPECT_FALSE(X86PayloadTest().isAvailable(FalseCpuFeatures())); diff --git a/test/UnitTests/X86PlatformConfigTest.cpp b/test/UnitTests/X86PlatformConfigTest.cpp new file mode 100644 index 00000000..912cf34d --- /dev/null +++ b/test/UnitTests/X86PlatformConfigTest.cpp @@ -0,0 +1,83 @@ +/****************************************************************************** + * FIRESTARTER - A Processor Stress Test Utility + * Copyright (C) 2024 TU Dresden, Center for Information Services and High + * Performance Computing + * + * This program 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. + * + * This program 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 this program. If not, see . + * + * Contact: daniel.hackenberg@tu-dresden.de + *****************************************************************************/ + +#include "firestarter/X86/Platform/X86PlatformConfig.hpp" +#include "firestarter/X86/Payload/X86Payload.hpp" + +#include + +namespace { + +class X86PayloadTest : public firestarter::x86::payload::X86Payload { +public: + X86PayloadTest() + : firestarter::x86::payload::X86Payload( + /*FeatureRequests=*/firestarter::x86::X86CpuFeatures(), + /*Name=*/"X86Payload", /*RegisterSize=*/0, + /*RegisterCount=*/0, + /*InstructionFlops=*/ + {}, + /*InstructionMemory=*/{}) {} + + void init(double* /*MemoryAddr*/, uint64_t /*BufferSize*/) const override {} + + [[nodiscard]] auto compilePayload(const firestarter::payload::PayloadSettings& /*Settings*/, bool /*DumpRegisters*/, + bool /*ErrorDetection*/, bool /*PrintAssembler*/) const + -> firestarter::payload::CompiledPayload::UniquePtr override { + return {nullptr, nullptr}; + } +}; + +class X86PlafromConfigTest : public firestarter::x86::platform::X86PlatformConfig { +public: + inline static const auto Model1 = firestarter::x86::X86CpuModel(/*FamilyId=*/1, /*ModelId=*/2); + inline static const auto Model2 = firestarter::x86::X86CpuModel(/*FamilyId=*/3, /*ModelId=*/4); + inline static const auto InvalidModel = firestarter::x86::X86CpuModel(/*FamilyId=*/5, /*ModelId=*/6); + + X86PlafromConfigTest() + : firestarter::x86::platform::X86PlatformConfig( + "X86PlatformConfig", {Model1, Model2}, + firestarter::payload::PayloadSettings( + /*Threads=*/{}, /*DataCacheBufferSize=*/{}, /*RamBufferSize=*/0, + /*Lines=*/0, /*Groups=*/firestarter::InstructionGroups(firestarter::InstructionGroups::InternalType())), + std::make_shared()) {} +}; + +class TrueCpuFeatures : public firestarter::CpuFeatures { + [[nodiscard]] auto hasAll(const CpuFeatures& /*Features*/) const -> bool override { return true; }; +}; + +class FalseCpuFeatures : public firestarter::CpuFeatures { + [[nodiscard]] auto hasAll(const CpuFeatures& /*Features*/) const -> bool override { return false; }; +}; + +} // namespace + +TEST(X86PlafromConfigTest, CheckIsDefault) { + EXPECT_TRUE(X86PlafromConfigTest().isDefault(X86PlafromConfigTest::Model1, TrueCpuFeatures())); + EXPECT_FALSE(X86PlafromConfigTest().isDefault(X86PlafromConfigTest::Model1, FalseCpuFeatures())); + + EXPECT_TRUE(X86PlafromConfigTest().isDefault(X86PlafromConfigTest::Model2, TrueCpuFeatures())); + EXPECT_FALSE(X86PlafromConfigTest().isDefault(X86PlafromConfigTest::Model2, FalseCpuFeatures())); + + EXPECT_FALSE(X86PlafromConfigTest().isDefault(X86PlafromConfigTest::InvalidModel, TrueCpuFeatures())); + EXPECT_FALSE(X86PlafromConfigTest().isDefault(X86PlafromConfigTest::InvalidModel, FalseCpuFeatures())); +} \ No newline at end of file