diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index d1806bac..81be32c1 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1 +1,2 @@ 9732bdb59717274f666e9c1497289d1f9a0d7858 +57259a1c5dce3b90a71520abc068af8aab37bb56 diff --git a/include/firestarter/CPUTopology.hpp b/include/firestarter/CPUTopology.hpp index d0371dfe..d4919932 100644 --- a/include/firestarter/CPUTopology.hpp +++ b/include/firestarter/CPUTopology.hpp @@ -22,7 +22,6 @@ #pragma once #include -#include #include extern "C" { @@ -64,10 +63,10 @@ class CPUTopology { virtual ~CPUTopology(); /// Print information about the number of packages, cores and threads. - void printSystemSummary(std::ostream& Stream) const; + void printSystemSummary() const; /// Print information about the cache hierarchy. - void printCacheSummary(std::ostream& Stream) const; + void printCacheSummary() const; /// Get the size of the first instruction cache. [[nodiscard]] auto instructionCacheSize() const -> std::optional; diff --git a/include/firestarter/Config/Config.hpp b/include/firestarter/Config/Config.hpp index 977ef4ec..08524f98 100644 --- a/include/firestarter/Config/Config.hpp +++ b/include/firestarter/Config/Config.hpp @@ -21,6 +21,8 @@ #pragma once +#include "firestarter/Config/InstructionGroups.hpp" + #include #include #include @@ -70,7 +72,7 @@ struct Config { /// The optional cpu bind that allow pinning to specific cpus. std::optional> CpuBinding; /// The optional selected instruction groups. If this is empty the default will be choosen. - std::string InstructionGroups; + std::optional Groups; /// The file where the dump register feature will safe its output to. std::string DumpRegistersOutpath; /// The name of the optimization algorithm. @@ -82,10 +84,10 @@ struct Config { int Argc; /// The requested number of threads firestarter should run with. 0 means all threads. std::optional RequestedNumThreads; - /// The selected function id. 0 means automatic selection. - unsigned FunctionId; - /// The line count of the payload. 0 means default. - unsigned LineCount = 0; + /// The selected function id. + std::optional FunctionId; + /// The optional line count of the payload. + std::optional LineCount; /// The number of gpus firestarter should stress. Default is -1 means all gpus. int Gpus = 0; /// The matrix size which should be used. 0 means automatic detections. diff --git a/include/firestarter/Config/InstructionGroups.hpp b/include/firestarter/Config/InstructionGroups.hpp new file mode 100644 index 00000000..6eb5b4da --- /dev/null +++ b/include/firestarter/Config/InstructionGroups.hpp @@ -0,0 +1,81 @@ +/****************************************************************************** + * 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 +#include +#include +#include + +namespace firestarter { + +/// Struct to parse selected from a string. The format is a comma delimited list of instruction value pairs. The values +/// are unsigned integers. +struct InstructionGroups { + using InternalType = std::vector>; + + InstructionGroups() = default; + + explicit InstructionGroups(InternalType Groups) + : Groups(std::move(Groups)) {} + + explicit operator const InternalType&() const noexcept { return Groups; } + + friend auto operator<<(std::ostream& Stream, const InstructionGroups& IGroups) -> std::ostream&; + + /// Parse the instruction group string. It is a comma delimited list of instruction value pairs. The values are + /// unsigned integers. + /// \arg Groups The instruction groups as a string. + [[nodiscard]] static auto fromString(const std::string& Groups) -> InstructionGroups; + + /// Combine instructions and values for these instructions into the combined instruction groups. + /// \arg Instructions The vector of instructions + /// \arg Values The vector of values + /// \returns The combined instruction groups + [[nodiscard]] static auto fromInstructionAndValues(const std::vector& Instructions, + const std::vector& Values) -> InstructionGroups; + + /// The vector of used instructions that are saved in the instruction groups + [[nodiscard]] auto intructions() const -> std::vector; + +private: + /// The parsed instruction groups + std::vector> Groups; +}; + +inline auto operator<<(std::ostream& Stream, const InstructionGroups& Groups) -> std::ostream& { + std::stringstream Ss; + + for (auto const& [Key, Value] : static_cast(Groups)) { + Ss << Key << ":" << Value << ","; + } + + auto S = Ss.str(); + if (!S.empty()) { + S.pop_back(); + } + + Stream << S; + return Stream; +} + +} // namespace firestarter \ No newline at end of file diff --git a/include/firestarter/CpuFeatures.hpp b/include/firestarter/CpuFeatures.hpp new file mode 100644 index 00000000..57b49917 --- /dev/null +++ b/include/firestarter/CpuFeatures.hpp @@ -0,0 +1,38 @@ +/****************************************************************************** + * 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 cpu features are available. +class CpuFeatures { +public: + CpuFeatures() = default; + virtual ~CpuFeatures() = default; + + /// Check if this class has all features which are given in the argument. + /// \arg Features The features which should be check if they are available. + /// \returns true if this class has all features given in the argument. + [[nodiscard]] virtual auto hasAll(const CpuFeatures& Features) const -> bool = 0; +}; + +} // namespace firestarter 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/Environment/Environment.hpp b/include/firestarter/Environment/Environment.hpp deleted file mode 100644 index 03631166..00000000 --- a/include/firestarter/Environment/Environment.hpp +++ /dev/null @@ -1,101 +0,0 @@ -/****************************************************************************** - * FIRESTARTER - A Processor Stress Test Utility - * Copyright (C) 2020 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/CPUTopology.hpp" -#include "firestarter/Environment/Platform/PlatformConfig.hpp" -#include "firestarter/Environment/ProcessorInformation.hpp" - -#include -#include - -namespace firestarter::environment { - -/// This class handles parsing of user input to FIRESTARTER, namely the number of threads used, the thread affinity, the -/// selection of the correct high-load function, selection of the instruction groups and number of lines. It also -/// handles printing useful information, provides interfaces to the PlatformConfig and the number of threads. It -/// facilitates setting the cpu affinity in further parts of FIRESTARTER. -class Environment { -public: - Environment() = delete; - explicit Environment(std::unique_ptr&& Topology) - : ProcessorInfos(std::move(Topology)) {} - virtual ~Environment() = default; - - /// Select a PlatformConfig based on its generated id. This function will throw if a payload is not available or the - /// id is incorrect. If id is zero we automatically select a matching PlatformConfig. - /// \arg FunctionId The id of the PlatformConfig that should be selected. - /// \arg Topology The topology which contains information about the cpu requied to select the correct function. - /// \arg AllowUnavailablePayload If true we will not throw if the PlatformConfig is not available. - virtual void selectFunction(unsigned FunctionId, const CPUTopology& Topology, bool AllowUnavailablePayload) = 0; - - /// Parse the selected payload instruction groups and save the in the selected function. Throws if the input is - /// invalid. - /// \arg Groups The list of instruction groups that is in the format: multiple INSTRUCTION:VALUE pairs - /// comma-seperated. - virtual void selectInstructionGroups(std::string Groups) = 0; - - /// Print the available instruction groups of the selected function. - virtual void printAvailableInstructionGroups() = 0; - - /// Set the line count in the selected function. - /// \arg LineCount The maximum number of instruction that should be in the high-load loop. - virtual void setLineCount(unsigned LineCount) = 0; - - /// Print a summary of the settings of the selected config. - virtual void printSelectedCodePathSummary() = 0; - - /// Print a list of available high-load function and if they are available on the current system. - /// \arg ForceYes Force all functions to be shown as avaialable - virtual void printFunctionSummary(bool ForceYes) = 0; - - /// Getter (which allows modifying) for the current platform config containing the payload, settings and the - /// associated name. - [[nodiscard]] virtual auto config() -> platform::PlatformConfig& { - assert(Config && "No PlatformConfig selected"); - return *Config; - } - - /// Const getter for the current platform config containing the payload, settings and the associated name. - [[nodiscard]] virtual auto config() const -> const platform::PlatformConfig& { - assert(Config && "No PlatformConfig selected"); - return *Config; - } - - /// Const getter for the current processor information. - [[nodiscard]] virtual auto processorInfos() const -> const ProcessorInformation& { - assert(ProcessorInfos && "ProcessorInfos is a nullptr"); - return *ProcessorInfos; - } - -protected: - /// This function sets the config based on the - void setConfig(std::unique_ptr&& Config) { this->Config = std::move(Config); } - -private: - /// The selected config that contains the payload, settings and the associated name. - std::unique_ptr Config; - /// The description of the current CPU. - std::unique_ptr ProcessorInfos; -}; - -} // namespace firestarter::environment diff --git a/include/firestarter/Environment/X86/Platform/SkylakeConfig.hpp b/include/firestarter/Environment/X86/Platform/SkylakeConfig.hpp deleted file mode 100644 index 8a109d11..00000000 --- a/include/firestarter/Environment/X86/Platform/SkylakeConfig.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/****************************************************************************** - * FIRESTARTER - A Processor Stress Test Utility - * Copyright (C) 2020 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/Environment/X86/Payload/FMAPayload.hpp" -#include "firestarter/Environment/X86/Platform/X86PlatformConfig.hpp" - -namespace firestarter::environment::x86::platform { -class SkylakeConfig final : public X86PlatformConfig { -public: - SkylakeConfig() noexcept - : X86PlatformConfig(/*Name=*/"SKL_COREI", /*Family=*/6, /*Models=*/{78, 94}, - /*Settings=*/ - environment::payload::PayloadSettings( - /*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{32768, 262144, 1572864}, - /*RamBufferSize=*/104857600, /*Lines=*/1536, - /*InstructionGroups=*/ - {{"RAM_L", 3}, {"L3_LS_256", 5}, {"L2_LS_256", 18}, {"L1_2LS_256", 78}, {"REG", 40}}), - /*Payload=*/std::make_shared()) {} -}; -} // namespace firestarter::environment::x86::platform \ No newline at end of file diff --git a/include/firestarter/Environment/X86/Platform/X86PlatformConfig.hpp b/include/firestarter/Environment/X86/Platform/X86PlatformConfig.hpp deleted file mode 100644 index a45078ce..00000000 --- a/include/firestarter/Environment/X86/Platform/X86PlatformConfig.hpp +++ /dev/null @@ -1,102 +0,0 @@ -/****************************************************************************** - * FIRESTARTER - A Processor Stress Test Utility - * Copyright (C) 2020 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/Environment/Platform/PlatformConfig.hpp" -#include "firestarter/Environment/ProcessorInformation.hpp" -#include "firestarter/Environment/X86/X86ProcessorInformation.hpp" - -namespace firestarter::environment::x86::platform { - -/// Models a platform config that is the default based on x86 CPU family and model ids. -class X86PlatformConfig : public environment::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; - -public: - X86PlatformConfig(std::string Name, unsigned Family, std::list&& Models, - environment::payload::PayloadSettings&& Settings, - std::shared_ptr&& Payload) noexcept - : PlatformConfig(std::move(Name), std::move(Settings), std::move(Payload)) - , Family(Family) - , Models(std::move(Models)) {} - - /// Check if this platform is available on the current system. This transloate to if the cpu extensions are - /// available for the payload that is used. - /// \arg Topology The reference to the X86CPUTopology that is used to check agains if this platform is supported. - /// \returns true if the platform is supported on the given X86CPUTopology. - [[nodiscard]] auto isAvailable(const X86ProcessorInformation& Topology) const -> bool { - return isAvailable(&Topology); - } - - /// Check if this platform is available and the default on the current system. - /// \arg Topology The reference to the X86CPUTopology that is used to check agains if this payload is supported. - /// \returns true if the platform is the default one for a given X86CPUTopology. - [[nodiscard]] auto isDefault(const X86ProcessorInformation& Topology) const -> bool { return isDefault(&Topology); } - - /// Clone a the platform config. - [[nodiscard]] auto clone() const -> std::unique_ptr final { - auto Ptr = std::make_unique(name(), Family, std::list(Models), - environment::payload::PayloadSettings(settings()), - std::shared_ptr(payload())); - return Ptr; - } - - /// Clone a concreate platform config. - /// \arg InstructionCacheSize The detected size of the instructions cache. - /// \arg ThreadPerCore The number of threads per pysical CPU. - [[nodiscard]] auto cloneConcreate(std::optional InstructionCacheSize, unsigned ThreadsPerCore) const - -> std::unique_ptr final { - auto Ptr = clone(); - Ptr->settings().concretize(InstructionCacheSize, ThreadsPerCore); - return Ptr; - } - -private: - /// Check if this platform is available on the current system. This tranlates to if the cpu extensions are - /// available for the payload that is used. - /// \arg Topology The pointer to the CPUTopology that is used to check agains if this platform is supported. - /// \returns true if the platform is supported on the given CPUTopology. - [[nodiscard]] auto isAvailable(const ProcessorInformation* Topology) const -> bool final { - return environment::platform::PlatformConfig::isAvailable(Topology); - } - - /// 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()) && isAvailable(Topology); - } -}; - -} // namespace firestarter::environment::x86::platform diff --git a/include/firestarter/Environment/X86/X86Environment.hpp b/include/firestarter/Environment/X86/X86Environment.hpp deleted file mode 100644 index c0e65ab1..00000000 --- a/include/firestarter/Environment/X86/X86Environment.hpp +++ /dev/null @@ -1,124 +0,0 @@ -/****************************************************************************** - * FIRESTARTER - A Processor Stress Test Utility - * Copyright (C) 2020 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/Environment/Environment.hpp" -#include "firestarter/Environment/X86/Platform/BulldozerConfig.hpp" -#include "firestarter/Environment/X86/Platform/HaswellConfig.hpp" -#include "firestarter/Environment/X86/Platform/HaswellEPConfig.hpp" -#include "firestarter/Environment/X86/Platform/KnightsLandingConfig.hpp" -#include "firestarter/Environment/X86/Platform/NaplesConfig.hpp" -#include "firestarter/Environment/X86/Platform/NehalemConfig.hpp" -#include "firestarter/Environment/X86/Platform/NehalemEPConfig.hpp" -#include "firestarter/Environment/X86/Platform/RomeConfig.hpp" -#include "firestarter/Environment/X86/Platform/SandyBridgeConfig.hpp" -#include "firestarter/Environment/X86/Platform/SandyBridgeEPConfig.hpp" -#include "firestarter/Environment/X86/Platform/SkylakeConfig.hpp" -#include "firestarter/Environment/X86/Platform/SkylakeSPConfig.hpp" -#include "firestarter/Environment/X86/Platform/X86PlatformConfig.hpp" - -namespace firestarter::environment::x86 { - -class X86Environment final : public Environment { -public: - X86Environment() - : Environment(std::make_unique()) {} - - /// Getter (which allows modifying) for the current platform config containing the payload, settings, the - /// associated name and the default X86 family and models. - [[nodiscard]] auto config() -> platform::X86PlatformConfig& final { - auto* X86PlatformConfig = dynamic_cast(&Environment::config()); - assert(X86PlatformConfig && "X86PlatformConfig is a nullptr"); - return *X86PlatformConfig; - } - - /// Const getter for the current platform config containing the payload, settings, the associated name and the default - /// X86 family and models. - [[nodiscard]] auto config() const -> const platform::X86PlatformConfig& final { - const auto* X86PlatformConfig = dynamic_cast(&Environment::config()); - assert(X86PlatformConfig && "X86PlatformConfig is a nullptr"); - return *X86PlatformConfig; - } - - /// Const getter for the current processor information with X86 specific modifications. - [[nodiscard]] auto processorInfos() const -> const X86ProcessorInformation& final { - const auto* X86Topology = dynamic_cast(&Environment::processorInfos()); - assert(X86Topology && "X86Topology is a nullptr"); - return *X86Topology; - } - - /// Select a PlatformConfig based on its generated id. This function will throw if a payload is not available or the - /// id is incorrect. If id is zero we automatically select a matching PlatformConfig. - /// \arg FunctionId The id of the PlatformConfig that should be selected. - /// \arg Topology The topology which contains information about the cpu requied to select the correct function. - /// \arg AllowUnavailablePayload If true we will not throw if the PlatformConfig is not available. - void selectFunction(unsigned FunctionId, const CPUTopology& Topology, bool AllowUnavailablePayload) override; - - /// Parse the selected payload instruction groups and save the in the selected function. Throws if the input is - /// invalid. - /// \arg Groups The list of instruction groups that is in the format: multiple INSTRUCTION:VALUE pairs - /// comma-seperated. - void selectInstructionGroups(std::string Groups) override; - - /// Print the available instruction groups of the selected function. - void printAvailableInstructionGroups() override; - - /// Set the line count in the selected function. - /// \arg LineCount The maximum number of instruction that should be in the high-load loop. - void setLineCount(unsigned LineCount) override; - - /// Print a summary of the settings of the selected config. - void printSelectedCodePathSummary() override; - - /// Print a list of available high-load function and if they are available on the current system. This includes all - /// PlatformConfigs in combination with all thread per core counts. - /// \arg ForceYes Force all functions to be shown as avaialable - void printFunctionSummary(bool ForceYes) override; - -private: - /// The list of availabe platform configs that is printed when supplying the --avail command line argument. The IDs - /// for these configs are generated by iterating through this list starting with 1. To maintain stable IDs in - /// FIRESTARTER new configs should be added to the bottom of the list. - const std::list> PlatformConfigs = { - std::make_shared(), std::make_shared(), - std::make_shared(), std::make_shared(), - std::make_shared(), std::make_shared(), - std::make_shared(), std::make_shared(), - std::make_shared(), std::make_shared(), - std::make_shared(), std::make_shared()}; - - /// The list of configs that are fallbacks. If none of the PlatformConfigs is the default one on the current CPU, we - /// select the first one from this list that is available on the current system. If multiple configs can be available - /// on one system the one with higher priority should be at the top of this list. Modern X86 CPUs will support SSE2 - /// therefore it is the last on the list. CPUs that support AVX512 will most certainly also support FMA and AVX, - /// AVX512 takes precedence. This list should contain one entry for each of the supported CPU extensions by the - /// FIRESTARTER payloads. - const std::list> FallbackPlatformConfigs = { - std::make_shared(), // AVX512 - std::make_shared(), // FMA4 - std::make_shared(), // FMA - std::make_shared(), // AVX - std::make_shared() // SSE2 - }; -}; - -} // namespace firestarter::environment::x86 diff --git a/include/firestarter/Firestarter.hpp b/include/firestarter/Firestarter.hpp index 4a8e5e7d..03335b73 100644 --- a/include/firestarter/Firestarter.hpp +++ b/include/firestarter/Firestarter.hpp @@ -21,6 +21,7 @@ #pragma once +#include "firestarter/CPUTopology.hpp" #include "firestarter/Config/Config.hpp" #include "firestarter/Constants.hpp" #include "firestarter/Cuda/Cuda.hpp" @@ -31,13 +32,13 @@ #include "firestarter/Optimizer/Algorithm.hpp" #include "firestarter/Optimizer/OptimizerWorker.hpp" #include "firestarter/Optimizer/Population.hpp" +#include "firestarter/ProcessorInformation.hpp" #include "firestarter/ThreadAffinity.hpp" #include #include #include #include -#include #include #if defined(linux) || defined(__linux__) @@ -67,9 +68,11 @@ class Firestarter { const Config Cfg; /// This class handles getting the topology information of the processor and is used to set thread binding. - std::unique_ptr Topology; - /// The class that handles setting up the payload for firestarter - std::unique_ptr Environment; + CPUTopology Topology; + /// This class holds the information about the current processor which is specific to one architecture. + std::shared_ptr ProcessorInfos; + /// The selection function. + std::unique_ptr FunctionPtr; /// The class for execution of the gemm routine on Cuda or HIP GPUs. std::unique_ptr Cuda; /// The class for execution of the gemm routine on OneAPI GPUs. @@ -131,7 +134,7 @@ class Firestarter { /// Set the load workers to the ThreadWork state. /// \arg Setting The new setting to switch to. - void signalSwitch(std::vector> const& Setting) { + void signalSwitch(const InstructionGroups& Setting) { struct SwitchLoad { static void func() { LoadVar = LoadThreadWorkType::LoadSwitch; }; }; @@ -139,7 +142,7 @@ class Firestarter { for (auto& Thread : LoadThreads) { auto Td = Thread.second; - Td->config().settings().selectInstructionGroups(Setting); + Td->Config->selectInstructionGroups(Setting); } signalLoadWorkers(LoadThreadState::ThreadSwitch, SwitchLoad::func); diff --git a/include/firestarter/FunctionSelection.hpp b/include/firestarter/FunctionSelection.hpp new file mode 100644 index 00000000..55a38bec --- /dev/null +++ b/include/firestarter/FunctionSelection.hpp @@ -0,0 +1,85 @@ +/****************************************************************************** + * FIRESTARTER - A Processor Stress Test Utility + * Copyright (C) 2020 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/CPUTopology.hpp" +#include "firestarter/Platform/PlatformConfig.hpp" +#include "firestarter/ProcessorInformation.hpp" + +#include +#include + +namespace firestarter { + +class FunctionSelection { +public: + FunctionSelection() = default; + virtual ~FunctionSelection() = default; + + /// Select a PlatformConfig based on its generated id. This function will throw if a payload is not available or the + /// id is incorrect. + /// \arg FunctionId The id of the PlatformConfig that should be selected or automatically select a matching + /// PlatformConfig. + /// \arg ProcessorInfos Information about the processor which is specific to the current ISA. + /// \arg Topology The topology which contains information about the cpu requied to select the correct function. + /// \arg AllowUnavailablePayload If true we will not throw if the PlatformConfig is not available. + [[nodiscard]] auto selectFunction(std::optional FunctionId, const ProcessorInformation& ProcessorInfos, + const CPUTopology& Topology, bool AllowUnavailablePayload) const + -> std::unique_ptr; + + /// Select a PlatformConfig based on its generated id. This function will throw if a payload is not available or the + /// id is incorrect. + /// \arg FunctionId The id of the PlatformConfig that should be selected. + /// \arg Features The CPU features of the current processor. + /// \arg InstructionCacheSize The optional size of the instruction cache. + /// \arg AllowUnavailablePayload If true we will not throw if the PlatformConfig is not available. + [[nodiscard]] auto selectAvailableFunction(unsigned FunctionId, const CpuFeatures& Features, + std::optional InstructionCacheSize, + bool AllowUnavailablePayload) const + -> std::unique_ptr; + + /// Select the fallback PlatformConfig if no id is given. + /// \arg Model The class that identifies the cpu model. + /// \arg Features The CPU features of the current processor. + /// \arg VendorString The string of the cpu vendor. + /// \arg ModelString The string of the cpu model. + /// \arg InstructionCacheSize The optional size of the instruction cache. + /// \arg NumThreadsPerCore The number of threads per core. + [[nodiscard]] auto selectDefaultOrFallbackFunction(const CpuModel& Model, const CpuFeatures& Features, + const std::string& VendorString, const std::string& ModelString, + std::optional InstructionCacheSize, + unsigned NumThreadsPerCore) const + -> std::unique_ptr; + + /// Print a list of available high-load function and if they are available on the current system. + /// \arg ProcessorInfos Information about the processor which is specific to the current ISA. + /// \arg ForceYes Force all functions to be shown as avaialable + void printFunctionSummary(const ProcessorInformation& ProcessorInfos, bool ForceYes) const; + + [[nodiscard]] virtual auto platformConfigs() const + -> const std::vector>& = 0; + + [[nodiscard]] virtual auto fallbackPlatformConfigs() const + -> const std::vector>& = 0; +}; + +} // namespace firestarter diff --git a/include/firestarter/LoadWorkerData.hpp b/include/firestarter/LoadWorkerData.hpp index b64f0697..e3153f54 100644 --- a/include/firestarter/LoadWorkerData.hpp +++ b/include/firestarter/LoadWorkerData.hpp @@ -23,9 +23,9 @@ #include "firestarter/CPUTopology.hpp" #include "firestarter/Constants.hpp" -#include "firestarter/Environment/Environment.hpp" -#include "firestarter/Environment/Platform/PlatformConfig.hpp" #include "firestarter/LoadWorkerMemory.hpp" +#include "firestarter/Platform/PlatformConfig.hpp" +#include "firestarter/ProcessorInformation.hpp" #include #include @@ -64,7 +64,8 @@ class LoadWorkerData { /// Create the datastructure that is shared between a load worker thread and firestarter. /// \arg Id The id of the load worker thread. They are counted from 0 to the maximum number of threads - 1. /// \arg OsIndex The os index to which this thread should be bound. - /// \arg Environment The reference to the environment which allows getting the current timestamp. + /// \arg ProcessorInfos The reference to the ProcessorInfos which allows getting the current timestamp. + /// \arg FunctionPtr The config that is cloned for this specific load worker. /// \arg Topology The reference to the processor topology abstraction which allows setting thread affinity. /// \arg LoadVar The variable that controls the execution of the load worker. /// \arg Period Is used in combination with the LoadVar for the low load routine. @@ -72,18 +73,19 @@ class LoadWorkerData { /// compiled payload. /// \arg ErrorDetection Should the code to support error detection between thread be baked into the high load routine /// of the compiled payload. - LoadWorkerData(uint64_t Id, uint64_t OsIndex, const environment::Environment& Environment, - const CPUTopology& Topology, volatile LoadThreadWorkType& LoadVar, std::chrono::microseconds Period, - bool DumpRegisters, bool ErrorDetection) + LoadWorkerData(uint64_t Id, uint64_t OsIndex, std::shared_ptr ProcessorInfos, + const std::unique_ptr& FunctionPtr, const CPUTopology& Topology, + volatile LoadThreadWorkType& LoadVar, std::chrono::microseconds Period, bool DumpRegisters, + bool ErrorDetection) : LoadVar(LoadVar) , Period(Period) , DumpRegisters(DumpRegisters) , ErrorDetection(ErrorDetection) , Id(Id) , OsIndex(OsIndex) - , Environment(Environment) + , ProcessorInfos(std::move(ProcessorInfos)) , Topology(Topology) - , Config(Environment.config().clone()) {} + , Config(FunctionPtr->clone()) {} ~LoadWorkerData() = default; @@ -99,10 +101,8 @@ class LoadWorkerData { /// Gettter for the id of the thread. [[nodiscard]] auto id() const -> uint64_t { return Id; } - /// Const getter for the environment. - [[nodiscard]] auto environment() const -> const environment::Environment& { return Environment; } /// Getter for the current platform config. - [[nodiscard]] auto config() const -> environment::platform::PlatformConfig& { return *Config; } + [[nodiscard]] auto config() const -> const platform::PlatformConfig& { return *Config; } /// Access the DumpRegisterStruct. Asserts when dumping registers is not enabled. /// \returns a reference to the DumpRegisterStruct @@ -132,7 +132,7 @@ class LoadWorkerData { LoadWorkerMemory::UniquePtr Memory = {nullptr, nullptr}; /// The compiled payload which contains the pointers to the specific functions which are executed and some stats. - environment::payload::CompiledPayload::UniquePtr CompiledPayloadPtr = {nullptr, nullptr}; + payload::CompiledPayload::UniquePtr CompiledPayloadPtr = {nullptr, nullptr}; /// The variable that controls the execution of the load worker. volatile LoadThreadWorkType& LoadVar; @@ -166,11 +166,11 @@ class LoadWorkerData { /// The os index to which this thread should be bound. const uint64_t OsIndex; /// The reference to the environment which allows getting the current timestamp. - const environment::Environment& Environment; + std::shared_ptr ProcessorInfos; /// The reference to the processor topology abstraction which allows setting thread affinity. const CPUTopology& Topology; /// The config that is cloned from the environment for this specfic load worker. - std::unique_ptr Config; + std::unique_ptr Config; }; } // namespace firestarter diff --git a/include/firestarter/Optimizer/Problem/CLIArgumentProblem.hpp b/include/firestarter/Optimizer/Problem/CLIArgumentProblem.hpp index 4335a4f9..59da7b23 100644 --- a/include/firestarter/Optimizer/Problem/CLIArgumentProblem.hpp +++ b/include/firestarter/Optimizer/Problem/CLIArgumentProblem.hpp @@ -21,6 +21,7 @@ #pragma once +#include "firestarter/Config/InstructionGroups.hpp" #include "firestarter/Measurement/MeasurementWorker.hpp" #include "firestarter/Optimizer/Problem.hpp" @@ -38,7 +39,7 @@ class CLIArgumentProblem final : public firestarter::optimizer::Problem { private: /// The function which takes instruction groups and switches the payload in the high load function to the supplied /// ones. - std::function> const&)> ChangePayloadFunction; + std::function ChangePayloadFunction; /// The shared pointer to the measurement infrastructure which will be used to get metric values. std::shared_ptr MeasurementWorker; /// The metrics that are used in the optimization. They may have a dash at the start to allow them to be changed from @@ -51,7 +52,7 @@ class CLIArgumentProblem final : public firestarter::optimizer::Problem { /// The time to skip from the measurement stop std::chrono::milliseconds StopDelta; /// The vector of instruction that is used in the optimization for the payload. - std::vector InstructionGroups; + std::vector Instructions; public: /// Constructor for the problem of optimizing firestarter on the fly. @@ -64,19 +65,19 @@ class CLIArgumentProblem final : public firestarter::optimizer::Problem { /// \arg Timeout The duration of the measurement. /// \arg StartDelta The time to skip from the measurement start /// \arg StopDelta The time to skip from the measurement stop - /// \arg InstructionGroups The vector of instruction that is used in the optimization for the payload. - CLIArgumentProblem(std::function> const&)>&& ChangePayloadFunction, + /// \arg Instructions The vector of instruction that is used in the optimization for the payload. + CLIArgumentProblem(std::function&& ChangePayloadFunction, std::shared_ptr MeasurementWorker, std::vector const& Metrics, std::chrono::seconds Timeout, std::chrono::milliseconds StartDelta, std::chrono::milliseconds StopDelta, - std::vector InstructionGroups) + std::vector Instructions) : ChangePayloadFunction(std::move(ChangePayloadFunction)) , MeasurementWorker(std::move(MeasurementWorker)) , Metrics(Metrics) , Timeout(Timeout) , StartDelta(StartDelta) , StopDelta(StopDelta) - , InstructionGroups(std::move(InstructionGroups)) { + , Instructions(std::move(Instructions)) { assert(!Metrics.empty()); } @@ -90,15 +91,10 @@ class CLIArgumentProblem final : public firestarter::optimizer::Problem { // increment evaluation idx incrementFevals(); + const auto Groups = firestarter::InstructionGroups::fromInstructionAndValues(Instructions, Individual); + // change the payload - assert(InstructionGroups.size() == Individual.size()); - std::vector> Payload = {}; - auto It1 = InstructionGroups.begin(); - auto It2 = Individual.begin(); - for (; It1 != InstructionGroups.end(); ++It1, ++It2) { - Payload.emplace_back(*It1, *It2); - } - ChangePayloadFunction(Payload); + ChangePayloadFunction(Groups); // start the measurement // NOTE: starting the measurement must happen after switching to not @@ -111,7 +107,7 @@ class CLIArgumentProblem final : public firestarter::optimizer::Problem { // TODO(Issue #82): This is an ugly workaround for the ipc-estimate metric. // Changing the payload triggers a write of the iteration counter of // the last payload, which we use to estimate the ipc. - ChangePayloadFunction(Payload); + ChangePayloadFunction(Groups); // return the results return MeasurementWorker->getValues(StartDelta, StopDelta); @@ -155,8 +151,7 @@ class CLIArgumentProblem final : public firestarter::optimizer::Problem { /// Get the bounds of the problem. We currently set these bounds fix to a range from 0 to 100 for every instruction. /// \returns A vector the size of the number of instruction groups containing a tuple(0, 100). [[nodiscard]] auto getBounds() const -> std::vector> override { - std::vector> Vec(InstructionGroups.size(), - std::make_tuple(0, 100)); + std::vector> Vec(Instructions.size(), std::make_tuple(0, 100)); return Vec; } diff --git a/include/firestarter/Environment/Payload/CompiledPayload.hpp b/include/firestarter/Payload/CompiledPayload.hpp similarity index 96% rename from include/firestarter/Environment/Payload/CompiledPayload.hpp rename to include/firestarter/Payload/CompiledPayload.hpp index 488c6c8d..ba78a580 100644 --- a/include/firestarter/Environment/Payload/CompiledPayload.hpp +++ b/include/firestarter/Payload/CompiledPayload.hpp @@ -22,13 +22,13 @@ #pragma once #include "firestarter/Constants.hpp" -#include "firestarter/Environment/Payload/PayloadStats.hpp" +#include "firestarter/Payload/PayloadStats.hpp" #include #include #include -namespace firestarter::environment::payload { +namespace firestarter::payload { class Payload; @@ -98,4 +98,4 @@ class CompiledPayload { HighLoadFunctionPtr HighLoadFunction; }; -} // namespace firestarter::environment::payload \ No newline at end of file +} // namespace firestarter::payload \ No newline at end of file diff --git a/include/firestarter/Environment/Payload/Payload.hpp b/include/firestarter/Payload/Payload.hpp similarity index 83% rename from include/firestarter/Environment/Payload/Payload.hpp rename to include/firestarter/Payload/Payload.hpp index 10bf0e03..7b2819b9 100644 --- a/include/firestarter/Environment/Payload/Payload.hpp +++ b/include/firestarter/Payload/Payload.hpp @@ -22,16 +22,17 @@ #pragma once #include "firestarter/Constants.hpp" -#include "firestarter/Environment/Payload/CompiledPayload.hpp" -#include "firestarter/Environment/Payload/PayloadSettings.hpp" -#include "firestarter/Environment/ProcessorInformation.hpp" +#include "firestarter/CpuFeatures.hpp" +#include "firestarter/Logging/Log.hpp" +#include "firestarter/Payload/CompiledPayload.hpp" +#include "firestarter/Payload/PayloadSettings.hpp" #include #include #include #include -namespace firestarter::environment::payload { +namespace firestarter::payload { class Payload { private: @@ -84,9 +85,9 @@ class Payload { /// Check if this payload is available on the current system. This usally translates if the cpu extensions are /// available. - /// \arg Topology The CPUTopology that is used to check agains if this payload is supported. - /// \returns true if the payload is supported on the given CPUTopology. - [[nodiscard]] virtual auto isAvailable(const ProcessorInformation& Topology) const -> bool = 0; + /// \arg CpuFeatures Features that this payload requires to check agains if this payload is supported. + /// \returns true if the payload is supported on the system with the given features. + [[nodiscard]] virtual auto isAvailable(const CpuFeatures& Features) const -> bool = 0; /// Compile this payload with supplied settings and optional features. /// \arg Settings The settings for this payload e.g., the number of lines or the size of the caches. @@ -102,6 +103,23 @@ class Payload { /// Get the available instruction items that are supported by this payload. /// \returns The available instruction items that are supported by this payload. [[nodiscard]] virtual auto getAvailableInstructions() const -> std::list = 0; + + /// Print the available instruction groups of this payload + void printAvailableInstructionGroups() const { + std::stringstream Ss; + + for (auto const& Item : getAvailableInstructions()) { + Ss << Item << ","; + } + + auto S = Ss.str(); + if (!S.empty()) { + S.pop_back(); + } + + log::info() << " available instruction-groups for payload " << name() << ":\n" + << " " << S; + } }; -} // namespace firestarter::environment::payload +} // namespace firestarter::payload diff --git a/include/firestarter/Environment/Payload/PayloadSettings.hpp b/include/firestarter/Payload/PayloadSettings.hpp similarity index 86% rename from include/firestarter/Environment/Payload/PayloadSettings.hpp rename to include/firestarter/Payload/PayloadSettings.hpp index 8438e9a6..73827427 100644 --- a/include/firestarter/Environment/Payload/PayloadSettings.hpp +++ b/include/firestarter/Payload/PayloadSettings.hpp @@ -21,22 +21,20 @@ #pragma once +#include "firestarter/Config/InstructionGroups.hpp" + #include #include #include #include #include -#include #include #include -namespace firestarter::environment::payload { +namespace firestarter::payload { /// This class represents the settings that can be changed in the high load routine of a payload. struct PayloadSettings { -public: - using InstructionWithProportion = std::pair; - private: /// The number of threads for which this payload is available. Multiple ones may exsists. The PayloadSettings are /// concreate once this is set to contain only one element. @@ -56,7 +54,7 @@ struct PayloadSettings { /// This represents the instructions in combination with the number of times they should appear in the generated /// sequence. - std::vector InstructionGroups; + InstructionGroups Groups; /// Get the number of items in the sequence that start with a given string. /// \arg Sequence The sequence that is analyzed. @@ -69,20 +67,19 @@ struct PayloadSettings { PayloadSettings() = delete; PayloadSettings(std::initializer_list Threads, std::initializer_list DataCacheBufferSize, - unsigned RamBufferSize, unsigned Lines, std::vector&& InstructionGroups) + unsigned RamBufferSize, unsigned Lines, InstructionGroups&& Groups) : Threads(Threads) , DataCacheBufferSize(DataCacheBufferSize) , RamBufferSize(RamBufferSize) , Lines(Lines) - , InstructionGroups(std::move(InstructionGroups)) {} + , Groups(std::move(Groups)) {} /// Generate a sequence of items interleaved with one another based on a supplied number how many times each items /// should appear in the resulting sequence. /// \arg Proportion The mapping of items defined by a string and the number of times this item should apear in the /// resuling sequence. /// \returns The sequence that is generated from the supplied propotions - [[nodiscard]] static auto generateSequence(const std::vector& Proportion) - -> std::vector; + [[nodiscard]] static auto generateSequence(const InstructionGroups& Proportion) -> std::vector; /// Get the number of items in the sequence that start with "L2". /// \arg Sequence The sequence that is analyzed. @@ -214,38 +211,11 @@ struct PayloadSettings { [[nodiscard]] auto linesPerThread() const -> auto{ return Lines / thread(); } /// The vector of instruction groups with proportions. - [[nodiscard]] auto instructionGroups() const -> const auto& { return InstructionGroups; } + [[nodiscard]] auto groups() const -> const auto& { return Groups; } /// Generate a sequence of items interleaved with one another based on the instruction groups. /// \returns The sequence that is generated from the supplied propotions in the instruction groups. - [[nodiscard]] auto sequence() const -> std::vector { return generateSequence(instructionGroups()); } - - /// The vector of used instructions that are saved in the instruction groups - [[nodiscard]] auto instructionGroupItems() const -> std::vector { - std::vector Items; - Items.reserve(InstructionGroups.size()); - for (auto const& Pair : InstructionGroups) { - Items.push_back(Pair.first); - } - return Items; - } - - /// Get the string that represents the instructions in combination with the number of times they should appear in the - /// sequence. - [[nodiscard]] auto getInstructionGroupsString() const -> std::string { - std::stringstream Ss; - - for (auto const& [Name, Value] : InstructionGroups) { - Ss << Name << ":" << Value << ","; - } - - auto Str = Ss.str(); - if (!Str.empty()) { - Str.pop_back(); - } - - return Str; - } + [[nodiscard]] auto sequence() const -> std::vector { return generateSequence(groups()); } /// Make the settings concreate. /// \arg InstructionCacheSize The detected size of the instructions cache. @@ -256,13 +226,11 @@ struct PayloadSettings { } /// Save the supplied instruction groups with their proportion in the payload settings. - /// \arg InstructionGroups The vector with pairs of instructions and proportions - void selectInstructionGroups(std::vector const& InstructionGroups) { - this->InstructionGroups = InstructionGroups; - } + /// \arg Groups The vector with pairs of instructions and proportions + void selectInstructionGroups(InstructionGroups const& Groups) { this->Groups = Groups; } /// Save the line count in the payload settings. void setLineCount(unsigned LineCount) { this->Lines = LineCount; } }; -} // namespace firestarter::environment::payload +} // namespace firestarter::payload diff --git a/include/firestarter/Environment/Payload/PayloadStats.hpp b/include/firestarter/Payload/PayloadStats.hpp similarity index 93% rename from include/firestarter/Environment/Payload/PayloadStats.hpp rename to include/firestarter/Payload/PayloadStats.hpp index 79b2b1e3..d240743f 100644 --- a/include/firestarter/Environment/Payload/PayloadStats.hpp +++ b/include/firestarter/Payload/PayloadStats.hpp @@ -21,7 +21,7 @@ #pragma once -namespace firestarter::environment::payload { +namespace firestarter::payload { /// This struct represents the stats a compiled payload has. struct PayloadStats { @@ -35,4 +35,4 @@ struct PayloadStats { unsigned Instructions = 0; }; -} // namespace firestarter::environment::payload +} // namespace firestarter::payload diff --git a/include/firestarter/Environment/Platform/PlatformConfig.hpp b/include/firestarter/Platform/PlatformConfig.hpp similarity index 58% rename from include/firestarter/Environment/Platform/PlatformConfig.hpp rename to include/firestarter/Platform/PlatformConfig.hpp index e077ce21..b83034ce 100644 --- a/include/firestarter/Environment/Platform/PlatformConfig.hpp +++ b/include/firestarter/Platform/PlatformConfig.hpp @@ -21,11 +21,15 @@ #pragma once -#include "firestarter/Environment/Payload/Payload.hpp" -#include "firestarter/Environment/ProcessorInformation.hpp" +#include "firestarter/Config/InstructionGroups.hpp" +#include "firestarter/CpuModel.hpp" #include "firestarter/Logging/Log.hpp" +#include "firestarter/Payload/Payload.hpp" -namespace firestarter::environment::platform { +#include +#include + +namespace firestarter::platform { /// The payload in combination with settings and a short hand name for the specific microarchitecture this payload is /// designed for. @@ -42,42 +46,27 @@ class PlatformConfig { std::shared_ptr Payload; public: + /// Getter for const ref to this type + [[nodiscard]] auto constRef() const -> const auto& { return *this; } + /// Getter for the name of the platform. [[nodiscard]] auto name() const -> const auto& { return Name; } /// Getter for the settings of the platform. - [[nodiscard]] auto settings() const -> const auto& { return Settings; } - - /// Reference to the settings. This allows them to be overriden. - [[nodiscard]] auto settings() -> auto& { return Settings; } + [[nodiscard]] auto settings() const -> const payload::PayloadSettings& { return Settings; } /// Getter for the payload of the platform. [[nodiscard]] auto payload() const -> const auto& { return Payload; } - /// Check if this platform is available on the current system. This transloate to if the cpu extensions are - /// available for the payload that is used. - /// \arg Topology The reference to the CPUTopology that is used to check agains if this platform is supported. - /// \returns true if the platform is supported on the given CPUTopology. - [[nodiscard]] auto isAvailable(const ProcessorInformation& Topology) const -> bool { return isAvailable(&Topology); } - /// 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: - /// Check if this platform is available on the current system. This transloate to if the cpu extensions are - /// available for the payload that is used. - /// \arg Topology The pointer to the CPUTopology that is used to check agains if this platform is supported. - /// \returns true if the platform is supported on the given CPUTopology. - [[nodiscard]] virtual auto isAvailable(const ProcessorInformation* Topology) const -> bool { - return payload()->isAvailable(*Topology); - } - - /// 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; + /// Non const Getter for the settings of the platform. + [[nodiscard]] auto settings() -> payload::PayloadSettings& { return Settings; } public: PlatformConfig() = delete; @@ -99,6 +88,27 @@ class PlatformConfig { [[nodiscard]] virtual auto cloneConcreate(std::optional InstructionCacheSize, unsigned ThreadsPerCore) const -> std::unique_ptr = 0; + /// Parse the selected payload instruction groups and save the in the selected function. Throws if the input is + /// invalid. + /// \arg Groups The list of instruction groups that is in the format: multiple INSTRUCTION:VALUE pairs + /// comma-seperated. + void selectInstructionGroups(const InstructionGroups& Groups) { + const auto& AvailableInstructionGroups = payload()->getAvailableInstructions(); + for (const auto& [Instruction, Value] : static_cast(Groups)) { + if (std::find(AvailableInstructionGroups.begin(), AvailableInstructionGroups.end(), Instruction) == + AvailableInstructionGroups.end()) { + throw std::invalid_argument("Invalid instruction-group: " + Instruction + + "\n --run-instruction-groups format: multiple INST:VAL " + "pairs comma-seperated"); + } + } + + settings().selectInstructionGroups(Groups); + } + + /// Save the line count in the payload settings. + void setLineCount(unsigned LineCount) { settings().setLineCount(LineCount); } + /// The function name for this platform config given a specific thread per core count. /// \arg ThreadsPerCore The number of threads per core. /// \returns The name of the function (a platform name, payload name and a specific thread per core count) @@ -108,31 +118,31 @@ class PlatformConfig { /// Get the concreate functions name. [[nodiscard]] auto functionName() const -> std::string { - assert(Settings.isConcreate() && "Settings must be concreate for a concreate function name"); - return functionName(Settings.thread()); + assert(settings().isConcreate() && "Settings must be concreate for a concreate function name"); + return functionName(settings().thread()); }; /// Print a summary for the selected platform/payload with given settings. void printCodePathSummary() const { - assert(Settings.isConcreate() && "Setting must be concreate to print the code path summary."); + assert(settings().isConcreate() && "Setting must be concreate to print the code path summary."); log::info() << "\n" - << " Taking " << Payload->name() << " path optimized for " << Name << " - " << Settings.thread() + << " Taking " << Payload->name() << " path optimized for " << Name << " - " << settings().thread() << " thread(s) per core\n" << " Used buffersizes per thread:"; - if (Settings.instructionCacheSizePerThread()) { - log::info() << " - L1i-Cache: " << *Settings.instructionCacheSizePerThread() << " Bytes"; + if (settings().instructionCacheSizePerThread()) { + log::info() << " - L1i-Cache: " << *settings().instructionCacheSizePerThread() << " Bytes"; } unsigned I = 1; - for (auto const& Bytes : Settings.dataCacheBufferSizePerThread()) { + for (auto const& Bytes : settings().dataCacheBufferSizePerThread()) { log::info() << " - L" << I << "d-Cache: " << Bytes << " Bytes"; I++; } - log::info() << " - Memory: " << Settings.ramBufferSizePerThread() << " Bytes"; + log::info() << " - Memory: " << settings().ramBufferSizePerThread() << " Bytes"; } }; -} // namespace firestarter::environment::platform +} // namespace firestarter::platform diff --git a/include/firestarter/Platform/PlatformConfigAndThreads.hpp b/include/firestarter/Platform/PlatformConfigAndThreads.hpp new file mode 100644 index 00000000..d650779e --- /dev/null +++ b/include/firestarter/Platform/PlatformConfigAndThreads.hpp @@ -0,0 +1,68 @@ +/****************************************************************************** + * 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/Platform/PlatformConfig.hpp" + +namespace firestarter::platform { + +/// This struct is used to iterate over the possible thread configurations available on each platform. +struct PlatformConfigAndThreads { +public: + PlatformConfigAndThreads() = delete; + + /// The shared pointer to the platform config + std::shared_ptr Config; + /// One concreate thread count which is available in the given config + unsigned ThreadCount; + + /// Get the vector of available configurations for a specific platform config. + /// \arg Config The reference to the platform config + /// \returns The vector of available configurations for this platform config. + [[nodiscard]] static auto fromPlatformConfig(const std::shared_ptr& Config) + -> std::vector { + std::vector Vec; + + for (const auto& Thread : Config->constRef().settings().threads()) { + Vec.emplace_back(PlatformConfigAndThreads{Config, Thread}); + } + + return Vec; + } + + /// Get the vector of available configurations for a vector of platform configs. + /// \arg Configs The reference to the vector of platform config + /// \returns The vector of available configurations for the supplied platform config. + [[nodiscard]] static auto fromPlatformConfigs(const std::vector>& Configs) + -> std::vector { + std::vector Vec; + + for (const auto& Config : Configs) { + const auto ConfigAndThreads = fromPlatformConfig(Config); + Vec.insert(Vec.end(), ConfigAndThreads.cbegin(), ConfigAndThreads.cend()); + } + + return Vec; + } +}; + +} // namespace firestarter::platform diff --git a/include/firestarter/Environment/ProcessorInformation.hpp b/include/firestarter/ProcessorInformation.hpp similarity index 80% rename from include/firestarter/Environment/ProcessorInformation.hpp rename to include/firestarter/ProcessorInformation.hpp index 25520260..c2c1c46f 100644 --- a/include/firestarter/Environment/ProcessorInformation.hpp +++ b/include/firestarter/ProcessorInformation.hpp @@ -21,9 +21,12 @@ #pragma once +#include "firestarter/CpuFeatures.hpp" +#include "firestarter/CpuModel.hpp" + #include #include -#include +#include #include #include @@ -31,43 +34,54 @@ extern "C" { #include } -namespace firestarter::environment { +namespace firestarter { /// This class models the properties of a processor. class ProcessorInformation { public: - explicit ProcessorInformation(std::string Architecture); + explicit ProcessorInformation(std::string Architecture, std::unique_ptr&& Features, + std::unique_ptr&& Model); virtual ~ProcessorInformation() = default; - friend auto operator<<(std::ostream& Stream, ProcessorInformation const& CpuTopologyRef) -> std::ostream&; - /// Getter for the clockrate in Hz [[nodiscard]] virtual auto clockrate() const -> uint64_t { return Clockrate; } /// Get the current hardware timestamp [[nodiscard]] virtual auto timestamp() const -> uint64_t = 0; + /// The CPU vendor i.e., Intel or AMD. + [[nodiscard]] virtual auto vendor() const -> std::string const& { return Vendor; } + + /// The model of the processor. With X86 this is the the string of Family, Model and Stepping. + [[nodiscard]] virtual auto model() const -> std::string const& = 0; + + /// 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; + protected: /// The CPU architecture e.g., x86_64 [[nodiscard]] auto architecture() const -> std::string const& { return Architecture; } - /// The CPU vendor i.e., Intel or AMD. - [[nodiscard]] virtual auto vendor() const -> std::string const& { return Vendor; } /// The processor name, this includes the vendor specific name [[nodiscard]] virtual auto processorName() const -> std::string const& { return ProcessorName; } - /// The model of the processor. With X86 this is the the string of Family, Model and Stepping. - [[nodiscard]] virtual auto model() const -> std::string const& = 0; /// Getter for the list of CPU features [[nodiscard]] virtual auto features() const -> std::list const& = 0; /// Read the scaling_govenor file of cpu0 on linux and return the contents as a string. [[nodiscard]] static auto scalingGovernor() -> std::string; - /// Print the information about this process to a stream. - [[nodiscard]] auto print(std::ostream& Stream) const -> std::ostream&; - private: /// The CPU vendor i.e., Intel or AMD. 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 @@ -82,8 +96,4 @@ class ProcessorInformation { uint64_t Clockrate = 0; }; -inline auto operator<<(std::ostream& Stream, ProcessorInformation const& CpuTopologyRef) -> std::ostream& { - return CpuTopologyRef.print(Stream); -} - -} // namespace firestarter::environment +} // namespace firestarter diff --git a/include/firestarter/WindowsCompat.hpp b/include/firestarter/WindowsCompat.hpp index 11ef1329..41e12296 100644 --- a/include/firestarter/WindowsCompat.hpp +++ b/include/firestarter/WindowsCompat.hpp @@ -35,11 +35,15 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" #endif + #if defined(__clang__) #include #elif not(defined(__MINGW32__) || defined(__MINGW64__)) void _mm_mfence() noexcept; +#else +#include #endif + #if not(defined(__INTEL_LLVM_COMPILER)) void __cpuid(int* /*unused*/, int /*unused*/) noexcept; #endif diff --git a/include/firestarter/Environment/X86/Payload/AVX512Payload.hpp b/include/firestarter/X86/Payload/AVX512Payload.hpp similarity index 65% rename from include/firestarter/Environment/X86/Payload/AVX512Payload.hpp rename to include/firestarter/X86/Payload/AVX512Payload.hpp index d783b984..8c102401 100644 --- a/include/firestarter/Environment/X86/Payload/AVX512Payload.hpp +++ b/include/firestarter/X86/Payload/AVX512Payload.hpp @@ -21,34 +21,36 @@ #pragma once -#include "firestarter/Environment/X86/Payload/X86Payload.hpp" +#include "firestarter/X86/Payload/X86Payload.hpp" -namespace firestarter::environment::x86::payload { +namespace firestarter::x86::payload { /// This payload is designed for the AVX512 foundation CPU extension. class AVX512Payload final : public X86Payload { public: AVX512Payload() noexcept - : X86Payload(/*FeatureRequests=*/{asmjit::CpuFeatures::X86::kAVX512_F}, /*Name=*/"AVX512", /*RegisterSize=*/8, - /*RegisterCount=*/32, - /*InstructionFlops=*/ - {{"REG", 32}, - {"L1_L", 32}, - {"L1_BROADCAST", 16}, - {"L1_S", 16}, - {"L1_LS", 16}, - {"L2_L", 32}, - {"L2_S", 16}, - {"L2_LS", 16}, - {"L3_L", 32}, - {"L3_S", 16}, - {"L3_LS", 16}, - {"L3_P", 16}, - {"RAM_L", 32}, - {"RAM_S", 16}, - {"RAM_LS", 16}, - {"RAM_P", 16}}, - /*InstructionMemory=*/{{"RAM_L", 64}, {"RAM_S", 128}, {"RAM_LS", 128}, {"RAM_P", 64}}) {} + : X86Payload( + /*FeatureRequests=*/X86CpuFeatures().add(asmjit::CpuFeatures::X86::Id::kAVX512_F), + /*Name=*/"AVX512", /*RegisterSize=*/8, + /*RegisterCount=*/32, + /*InstructionFlops=*/ + {{"REG", 32}, + {"L1_L", 32}, + {"L1_BROADCAST", 16}, + {"L1_S", 16}, + {"L1_LS", 16}, + {"L2_L", 32}, + {"L2_S", 16}, + {"L2_LS", 16}, + {"L3_L", 32}, + {"L3_S", 16}, + {"L3_LS", 16}, + {"L3_P", 16}, + {"RAM_L", 32}, + {"RAM_S", 16}, + {"RAM_LS", 16}, + {"RAM_P", 16}}, + /*InstructionMemory=*/{{"RAM_L", 64}, {"RAM_S", 128}, {"RAM_LS", 128}, {"RAM_P", 64}}) {} /// Compile this payload with supplied settings and optional features. /// \arg Settings The settings for this payload e.g., the number of lines or the size of the caches. @@ -58,9 +60,9 @@ class AVX512Payload final : public X86Payload { /// of the compiled payload. /// \arg PrintAssembler Should the generated assembler code be logged. /// \returns The compiled payload that provides access to the init and load functions. - [[nodiscard]] auto compilePayload(const environment::payload::PayloadSettings& Settings, bool DumpRegisters, + [[nodiscard]] auto compilePayload(const firestarter::payload::PayloadSettings& Settings, bool DumpRegisters, bool ErrorDetection, bool PrintAssembler) const - -> environment::payload::CompiledPayload::UniquePtr override; + -> firestarter::payload::CompiledPayload::UniquePtr override; private: /// Function to initialize the memory used by the high load function. @@ -68,4 +70,4 @@ class AVX512Payload final : public X86Payload { /// \arg BufferSize The number of doubles that is allocated in MemoryAddr. void init(double* MemoryAddr, uint64_t BufferSize) const override; }; -} // namespace firestarter::environment::x86::payload +} // namespace firestarter::x86::payload diff --git a/include/firestarter/Environment/X86/Payload/AVXPayload.hpp b/include/firestarter/X86/Payload/AVXPayload.hpp similarity index 66% rename from include/firestarter/Environment/X86/Payload/AVXPayload.hpp rename to include/firestarter/X86/Payload/AVXPayload.hpp index db9c1a42..e7066f3a 100644 --- a/include/firestarter/Environment/X86/Payload/AVXPayload.hpp +++ b/include/firestarter/X86/Payload/AVXPayload.hpp @@ -21,33 +21,35 @@ #pragma once -#include "firestarter/Environment/X86/Payload/X86Payload.hpp" +#include "firestarter/X86/Payload/X86Payload.hpp" -namespace firestarter::environment::x86::payload { +namespace firestarter::x86::payload { /// This payload is designed for the AVX CPU extension. class AVXPayload final : public X86Payload { public: AVXPayload() - : X86Payload(/*FeatureRequests=*/{asmjit::CpuFeatures::X86::kAVX}, /*Name=*/"AVX", /*RegisterSize=*/4, - /*RegisterCount=*/16, - /*InstructionFlops=*/ - {{"REG", 4}, - {"L1_L", 4}, - {"L1_S", 4}, - {"L1_LS", 4}, - {"L2_L", 4}, - {"L2_S", 4}, - {"L2_LS", 4}, - {"L3_L", 4}, - {"L3_S", 4}, - {"L3_LS", 4}, - {"L3_P", 4}, - {"RAM_L", 4}, - {"RAM_S", 4}, - {"RAM_LS", 4}, - {"RAM_P", 4}}, - /*InstructionMemory=*/{{"RAM_L", 64}, {"RAM_S", 128}, {"RAM_LS", 128}, {"RAM_P", 64}}) {} + : X86Payload( + /*FeatureRequests=*/X86CpuFeatures().add(asmjit::CpuFeatures::X86::Id::kAVX), + /*Name=*/"AVX", /*RegisterSize=*/4, + /*RegisterCount=*/16, + /*InstructionFlops=*/ + {{"REG", 4}, + {"L1_L", 4}, + {"L1_S", 4}, + {"L1_LS", 4}, + {"L2_L", 4}, + {"L2_S", 4}, + {"L2_LS", 4}, + {"L3_L", 4}, + {"L3_S", 4}, + {"L3_LS", 4}, + {"L3_P", 4}, + {"RAM_L", 4}, + {"RAM_S", 4}, + {"RAM_LS", 4}, + {"RAM_P", 4}}, + /*InstructionMemory=*/{{"RAM_L", 64}, {"RAM_S", 128}, {"RAM_LS", 128}, {"RAM_P", 64}}) {} /// Compile this payload with supplied settings and optional features. /// \arg Settings The settings for this payload e.g., the number of lines or the size of the caches. @@ -57,9 +59,9 @@ class AVXPayload final : public X86Payload { /// of the compiled payload. /// \arg PrintAssembler Should the generated assembler code be logged. /// \returns The compiled payload that provides access to the init and load functions. - [[nodiscard]] auto compilePayload(const environment::payload::PayloadSettings& Settings, bool DumpRegisters, + [[nodiscard]] auto compilePayload(const firestarter::payload::PayloadSettings& Settings, bool DumpRegisters, bool ErrorDetection, bool PrintAssembler) const - -> environment::payload::CompiledPayload::UniquePtr override; + -> firestarter::payload::CompiledPayload::UniquePtr override; private: /// Function to initialize the memory used by the high load function. @@ -67,4 +69,4 @@ class AVXPayload final : public X86Payload { /// \arg BufferSize The number of doubles that is allocated in MemoryAddr. void init(double* MemoryAddr, uint64_t BufferSize) const override; }; -} // namespace firestarter::environment::x86::payload +} // namespace firestarter::x86::payload diff --git a/include/firestarter/Environment/X86/Payload/CompiledX86Payload.hpp b/include/firestarter/X86/Payload/CompiledX86Payload.hpp similarity index 89% rename from include/firestarter/Environment/X86/Payload/CompiledX86Payload.hpp rename to include/firestarter/X86/Payload/CompiledX86Payload.hpp index 776f83f4..9a08f9c1 100644 --- a/include/firestarter/Environment/X86/Payload/CompiledX86Payload.hpp +++ b/include/firestarter/X86/Payload/CompiledX86Payload.hpp @@ -21,17 +21,17 @@ #pragma once -#include "firestarter/Environment/Payload/CompiledPayload.hpp" #include "firestarter/Logging/Log.hpp" +#include "firestarter/Payload/CompiledPayload.hpp" #include #include -namespace firestarter::environment::x86::payload { +namespace firestarter::x86::payload { /// This class provides the functionality to compile a payload created with asmjit and create a unique pointer to the /// CompiledPayload class which can be used to execute the functions of this payload. -class CompiledX86Payload final : public environment::payload::CompiledPayload { +class CompiledX86Payload final : public firestarter::payload::CompiledPayload { private: // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) inline static asmjit::JitRuntime Runtime = asmjit::JitRuntime(); @@ -52,8 +52,8 @@ class CompiledX86Payload final : public environment::payload::CompiledPayload { /// \arg PayloadPtr A unique pointer to the payload class to allow calling the init and low load functions which do /// not change based on different payload settings. /// \arg HighLoadFunction The pointer to the compiled high load function. - CompiledX86Payload(const environment::payload::PayloadStats& Stats, - std::unique_ptr&& PayloadPtr, HighLoadFunctionPtr HighLoadFunction) + CompiledX86Payload(const firestarter::payload::PayloadStats& Stats, + std::unique_ptr&& PayloadPtr, HighLoadFunctionPtr HighLoadFunction) : CompiledPayload(Stats, std::move(PayloadPtr), HighLoadFunction) {} public: @@ -67,7 +67,7 @@ class CompiledX86Payload final : public environment::payload::CompiledPayload { /// JitRuntime and a pointer to the function will be provided to the CompiledPayload class. /// \returns The unique pointer to the compiled payload. template - [[nodiscard]] static auto create(environment::payload::PayloadStats Stats, asmjit::CodeHolder& Code) -> UniquePtr { + [[nodiscard]] static auto create(firestarter::payload::PayloadStats Stats, asmjit::CodeHolder& Code) -> UniquePtr { HighLoadFunctionPtr HighLoadFunction{}; const auto Err = Runtime.add(&HighLoadFunction, &Code); if (Err) { @@ -78,4 +78,4 @@ class CompiledX86Payload final : public environment::payload::CompiledPayload { } }; -} // namespace firestarter::environment::x86::payload +} // namespace firestarter::x86::payload diff --git a/include/firestarter/Environment/X86/Payload/FMA4Payload.hpp b/include/firestarter/X86/Payload/FMA4Payload.hpp similarity index 86% rename from include/firestarter/Environment/X86/Payload/FMA4Payload.hpp rename to include/firestarter/X86/Payload/FMA4Payload.hpp index 13e66550..35629b3b 100644 --- a/include/firestarter/Environment/X86/Payload/FMA4Payload.hpp +++ b/include/firestarter/X86/Payload/FMA4Payload.hpp @@ -21,15 +21,17 @@ #pragma once -#include "firestarter/Environment/X86/Payload/X86Payload.hpp" +#include "firestarter/X86/Payload/X86Payload.hpp" -namespace firestarter::environment::x86::payload { +namespace firestarter::x86::payload { /// This payload is designed for the FMA4 CPU extension. class FMA4Payload final : public X86Payload { public: FMA4Payload() noexcept - : X86Payload(/*FeatureRequests=*/{asmjit::CpuFeatures::X86::kAVX, asmjit::CpuFeatures::X86::kFMA4}, + : X86Payload(/*FeatureRequests=*/X86CpuFeatures() + .add(asmjit::CpuFeatures::X86::Id::kAVX) + .add(asmjit::CpuFeatures::X86::Id::kFMA4), /*Name=*/"FMA4", /*RegisterSize=*/4, /*RegisterCount=*/16, /*InstructionFlops=*/ {{"REG", 8}, @@ -57,9 +59,9 @@ class FMA4Payload final : public X86Payload { /// of the compiled payload. /// \arg PrintAssembler Should the generated assembler code be logged. /// \returns The compiled payload that provides access to the init and load functions. - [[nodiscard]] auto compilePayload(const environment::payload::PayloadSettings& Settings, bool DumpRegisters, + [[nodiscard]] auto compilePayload(const firestarter::payload::PayloadSettings& Settings, bool DumpRegisters, bool ErrorDetection, bool PrintAssembler) const - -> environment::payload::CompiledPayload::UniquePtr override; + -> firestarter::payload::CompiledPayload::UniquePtr override; private: /// Function to initialize the memory used by the high load function. @@ -67,4 +69,4 @@ class FMA4Payload final : public X86Payload { /// \arg BufferSize The number of doubles that is allocated in MemoryAddr. void init(double* MemoryAddr, uint64_t BufferSize) const override; }; -} // namespace firestarter::environment::x86::payload \ No newline at end of file +} // namespace firestarter::x86::payload \ No newline at end of file diff --git a/include/firestarter/Environment/X86/Payload/FMAPayload.hpp b/include/firestarter/X86/Payload/FMAPayload.hpp similarity index 64% rename from include/firestarter/Environment/X86/Payload/FMAPayload.hpp rename to include/firestarter/X86/Payload/FMAPayload.hpp index 1bfe361b..dbb11c0c 100644 --- a/include/firestarter/Environment/X86/Payload/FMAPayload.hpp +++ b/include/firestarter/X86/Payload/FMAPayload.hpp @@ -21,23 +21,26 @@ #pragma once -#include "firestarter/Environment/X86/Payload/X86Payload.hpp" +#include "firestarter/X86/Payload/X86Payload.hpp" -namespace firestarter::environment::x86::payload { +namespace firestarter::x86::payload { /// This payload is designed for the FMA CPU extension. class FMAPayload final : public X86Payload { public: FMAPayload() noexcept - : X86Payload(/*FeatureRequests=*/{asmjit::CpuFeatures::X86::kAVX, asmjit::CpuFeatures::X86::kFMA}, /*Name=*/"FMA", - /*RegisterSize=*/4, /*RegisterCount=*/16, - /*InstructionFlops=*/{{"REG", 16}, {"L1_L", 16}, {"L1_2L", 16}, {"L1_S", 8}, - {"L1_LS", 8}, {"L1_LS_256", 8}, {"L1_2LS_256", 16}, {"L2_L", 16}, - {"L2_S", 8}, {"L2_LS", 8}, {"L2_LS_256", 8}, {"L2_2LS_256", 16}, - {"L3_L", 16}, {"L3_S", 8}, {"L3_LS", 8}, {"L3_LS_256", 8}, - {"L3_P", 8}, {"RAM_L", 16}, {"RAM_S", 8}, {"RAM_LS", 8}, - {"RAM_P", 8}}, - /*InstructionMemory=*/{{"RAM_L", 64}, {"RAM_S", 128}, {"RAM_LS", 128}, {"RAM_P", 64}}) {} + : X86Payload( + /*FeatureRequests=*/X86CpuFeatures() + .add(asmjit::CpuFeatures::X86::Id::kAVX) + .add(asmjit::CpuFeatures::X86::Id::kFMA), + /*Name=*/"FMA", + /*RegisterSize=*/4, /*RegisterCount=*/16, + /*InstructionFlops=*/{{"REG", 16}, {"L1_L", 16}, {"L1_2L", 16}, {"L1_S", 8}, {"L1_LS", 8}, + {"L1_LS_256", 8}, {"L1_2LS_256", 16}, {"L2_L", 16}, {"L2_S", 8}, {"L2_LS", 8}, + {"L2_LS_256", 8}, {"L2_2LS_256", 16}, {"L3_L", 16}, {"L3_S", 8}, {"L3_LS", 8}, + {"L3_LS_256", 8}, {"L3_P", 8}, {"RAM_L", 16}, {"RAM_S", 8}, {"RAM_LS", 8}, + {"RAM_P", 8}}, + /*InstructionMemory=*/{{"RAM_L", 64}, {"RAM_S", 128}, {"RAM_LS", 128}, {"RAM_P", 64}}) {} /// Compile this payload with supplied settings and optional features. /// \arg Settings The settings for this payload e.g., the number of lines or the size of the caches. @@ -47,9 +50,9 @@ class FMAPayload final : public X86Payload { /// of the compiled payload. /// \arg PrintAssembler Should the generated assembler code be logged. /// \returns The compiled payload that provides access to the init and load functions. - [[nodiscard]] auto compilePayload(const environment::payload::PayloadSettings& Settings, bool DumpRegisters, + [[nodiscard]] auto compilePayload(const firestarter::payload::PayloadSettings& Settings, bool DumpRegisters, bool ErrorDetection, bool PrintAssembler) const - -> environment::payload::CompiledPayload::UniquePtr override; + -> firestarter::payload::CompiledPayload::UniquePtr override; private: /// Function to initialize the memory used by the high load function. @@ -57,4 +60,4 @@ class FMAPayload final : public X86Payload { /// \arg BufferSize The number of doubles that is allocated in MemoryAddr. void init(double* MemoryAddr, uint64_t BufferSize) const override; }; -} // namespace firestarter::environment::x86::payload +} // namespace firestarter::x86::payload diff --git a/include/firestarter/Environment/X86/Payload/SSE2Payload.hpp b/include/firestarter/X86/Payload/SSE2Payload.hpp similarity index 66% rename from include/firestarter/Environment/X86/Payload/SSE2Payload.hpp rename to include/firestarter/X86/Payload/SSE2Payload.hpp index f6d667be..cf0ae57c 100644 --- a/include/firestarter/Environment/X86/Payload/SSE2Payload.hpp +++ b/include/firestarter/X86/Payload/SSE2Payload.hpp @@ -21,33 +21,35 @@ #pragma once -#include "firestarter/Environment/X86/Payload/X86Payload.hpp" +#include "firestarter/X86/Payload/X86Payload.hpp" -namespace firestarter::environment::x86::payload { +namespace firestarter::x86::payload { /// This payload is designed for the SSE2 CPU extension. class SSE2Payload final : public X86Payload { public: SSE2Payload() noexcept - : X86Payload(/*FeatureRequests=*/{asmjit::CpuFeatures::X86::kSSE2}, /*Name=*/"SSE2", /*RegisterSize=*/2, - /*RegisterCount=*/16, - /*InstructionFlops=*/ - {{"REG", 2}, - {"L1_L", 2}, - {"L1_S", 2}, - {"L1_LS", 2}, - {"L2_L", 2}, - {"L2_S", 2}, - {"L2_LS", 2}, - {"L3_L", 2}, - {"L3_S", 2}, - {"L3_LS", 2}, - {"L3_P", 2}, - {"RAM_L", 2}, - {"RAM_S", 2}, - {"RAM_LS", 2}, - {"RAM_P", 2}}, - /*InstructionMemory=*/{{"RAM_L", 64}, {"RAM_S", 128}, {"RAM_LS", 128}, {"RAM_P", 64}}) {} + : X86Payload( + /*FeatureRequests=*/X86CpuFeatures().add(asmjit::CpuFeatures::X86::Id::kSSE2), + /*Name=*/"SSE2", /*RegisterSize=*/2, + /*RegisterCount=*/16, + /*InstructionFlops=*/ + {{"REG", 2}, + {"L1_L", 2}, + {"L1_S", 2}, + {"L1_LS", 2}, + {"L2_L", 2}, + {"L2_S", 2}, + {"L2_LS", 2}, + {"L3_L", 2}, + {"L3_S", 2}, + {"L3_LS", 2}, + {"L3_P", 2}, + {"RAM_L", 2}, + {"RAM_S", 2}, + {"RAM_LS", 2}, + {"RAM_P", 2}}, + /*InstructionMemory=*/{{"RAM_L", 64}, {"RAM_S", 128}, {"RAM_LS", 128}, {"RAM_P", 64}}) {} /// Compile this payload with supplied settings and optional features. /// \arg Settings The settings for this payload e.g., the number of lines or the size of the caches. @@ -57,9 +59,9 @@ class SSE2Payload final : public X86Payload { /// of the compiled payload. /// \arg PrintAssembler Should the generated assembler code be logged. /// \returns The compiled payload that provides access to the init and load functions. - [[nodiscard]] auto compilePayload(const environment::payload::PayloadSettings& Settings, bool DumpRegisters, + [[nodiscard]] auto compilePayload(const firestarter::payload::PayloadSettings& Settings, bool DumpRegisters, bool ErrorDetection, bool PrintAssembler) const - -> environment::payload::CompiledPayload::UniquePtr override; + -> firestarter::payload::CompiledPayload::UniquePtr override; private: /// Function to initialize the memory used by the high load function. @@ -67,4 +69,4 @@ class SSE2Payload final : public X86Payload { /// \arg BufferSize The number of doubles that is allocated in MemoryAddr. void init(double* MemoryAddr, uint64_t BufferSize) const override; }; -} // namespace firestarter::environment::x86::payload +} // namespace firestarter::x86::payload diff --git a/include/firestarter/Environment/X86/Payload/X86Payload.hpp b/include/firestarter/X86/Payload/X86Payload.hpp similarity index 94% rename from include/firestarter/Environment/X86/Payload/X86Payload.hpp rename to include/firestarter/X86/Payload/X86Payload.hpp index cfb997f7..fd123731 100644 --- a/include/firestarter/Environment/X86/Payload/X86Payload.hpp +++ b/include/firestarter/X86/Payload/X86Payload.hpp @@ -23,10 +23,10 @@ #include "firestarter/Constants.hpp" // IWYU pragma: keep #include "firestarter/DumpRegisterStruct.hpp" // IWYU pragma: keep -#include "firestarter/Environment/Payload/Payload.hpp" -#include "firestarter/Environment/X86/X86ProcessorInformation.hpp" #include "firestarter/LoadWorkerMemory.hpp" #include "firestarter/Logging/Log.hpp" // IWYU pragma: keep +#include "firestarter/Payload/Payload.hpp" +#include "firestarter/X86/X86CpuFeatures.hpp" #include #include @@ -38,12 +38,12 @@ constexpr const auto InitBlocksize = 1024; /// This abstract class models a payload that can be compiled with settings and executed for X86 CPUs. -namespace firestarter::environment::x86::payload { +namespace firestarter::x86::payload { -class X86Payload : public environment::payload::Payload { +class X86Payload : public firestarter::payload::Payload { private: /// This list contains the features (cpu extenstions) that are requied to execute the payload. - std::list FeatureRequests; + X86CpuFeatures FeatureRequests; /// The mapping from instructions to the number of flops per instruction. This map is required to have an entry for /// every instruction. @@ -63,32 +63,25 @@ class X86Payload : public environment::payload::Payload { /// to have an entry for every instruction. /// \arg InstructionMemory The mapping from instructions to the size of main memory accesses for this instuction. This /// map is not required to contain all instructions. - X86Payload(std::initializer_list FeatureRequests, std::string Name, - unsigned RegisterSize, unsigned RegisterCount, std::map&& InstructionFlops, + X86Payload(X86CpuFeatures FeatureRequests, std::string Name, unsigned RegisterSize, unsigned RegisterCount, + std::map&& InstructionFlops, std::map&& InstructionMemory) noexcept : Payload(std::move(Name), RegisterSize, RegisterCount) - , FeatureRequests(FeatureRequests) + , FeatureRequests(std::move(FeatureRequests)) , InstructionFlops(std::move(InstructionFlops)) , InstructionMemory(std::move(InstructionMemory)) {} -private: - /// Check if this payload is available on the current system. This is equivalent to checking if the supplied Topology - /// contains all features that are in FeatureRequests. - /// \arg Topology The CPUTopology that is used to check agains if this payload is supported. - /// \returns true if the payload is supported on the given CPUTopology. - [[nodiscard]] auto isAvailable(const ProcessorInformation& Topology) const -> bool final { - const auto* FinalTopology = dynamic_cast(&Topology); - assert(FinalTopology && "isAvailable not called with const X86CPUTopology*"); - - bool Available = true; - - for (auto const& Feature : FeatureRequests) { - Available &= FinalTopology->featuresAsmjit().has(Feature); - } - - return Available; + /// Check if this payload is available on the current system. This is equivalent to checking if the supplied features + /// contains all that are requested by this payload. + /// \arg CpuFeatures Features that this payload requires to check agains if this payload is supported. + /// \returns true if the payload is supported on the system with the given features. + [[nodiscard]] auto isAvailable(const CpuFeatures& Features) const -> bool final { + return Features.hasAll(FeatureRequests); }; + /// The features that are required for this payload + [[nodiscard]] auto featureRequests() const -> const auto& { return FeatureRequests; } + protected: /// Print the generated assembler Code of asmjit /// \arg Builder The builder that contains the assembler code. @@ -572,4 +565,4 @@ class X86Payload : public environment::payload::Payload { [[nodiscard]] auto instructionMemory() const -> const auto& { return InstructionMemory; } }; -} // namespace firestarter::environment::x86::payload +} // namespace firestarter::x86::payload diff --git a/include/firestarter/Environment/X86/Payload/ZENFMAPayload.hpp b/include/firestarter/X86/Payload/ZENFMAPayload.hpp similarity index 84% rename from include/firestarter/Environment/X86/Payload/ZENFMAPayload.hpp rename to include/firestarter/X86/Payload/ZENFMAPayload.hpp index 777e6587..b9aa0f77 100644 --- a/include/firestarter/Environment/X86/Payload/ZENFMAPayload.hpp +++ b/include/firestarter/X86/Payload/ZENFMAPayload.hpp @@ -21,15 +21,18 @@ #pragma once -#include "firestarter/Environment/X86/Payload/X86Payload.hpp" +#include "asmjit/core/cpuinfo.h" +#include "firestarter/X86/Payload/X86Payload.hpp" -namespace firestarter::environment::x86::payload { +namespace firestarter::x86::payload { /// This payload is designed for the FMA CPU extension in combination with the first generation Zen microarchitecture. class ZENFMAPayload final : public X86Payload { public: ZENFMAPayload() noexcept - : X86Payload(/*FeatureRequests=*/{asmjit::CpuFeatures::X86::Id::kAVX, asmjit::CpuFeatures::X86::Id::kFMA}, + : X86Payload(/*FeatureRequests=*/X86CpuFeatures() + .add(asmjit::CpuFeatures::X86::Id::kAVX) + .add(asmjit::CpuFeatures::X86::Id::kFMA), /*Name=*/"ZENFMA", /*RegisterSize=*/4, /*RegisterCount=*/16, /*InstructionFlops=*/{{"REG", 8}, {"L1_LS", 8}, {"L2_L", 8}, {"L3_L", 8}, {"RAM_L", 8}}, /*InstructionMemory=*/{{"RAM_L", 64}}) {} @@ -42,9 +45,9 @@ class ZENFMAPayload final : public X86Payload { /// of the compiled payload. /// \arg PrintAssembler Should the generated assembler code be logged. /// \returns The compiled payload that provides access to the init and load functions. - [[nodiscard]] auto compilePayload(const environment::payload::PayloadSettings& Settings, bool DumpRegisters, + [[nodiscard]] auto compilePayload(const firestarter::payload::PayloadSettings& Settings, bool DumpRegisters, bool ErrorDetection, bool PrintAssembler) const - -> environment::payload::CompiledPayload::UniquePtr override; + -> firestarter::payload::CompiledPayload::UniquePtr override; private: /// Function to initialize the memory used by the high load function. @@ -52,4 +55,4 @@ class ZENFMAPayload final : public X86Payload { /// \arg BufferSize The number of doubles that is allocated in MemoryAddr. void init(double* MemoryAddr, uint64_t BufferSize) const override; }; -} // namespace firestarter::environment::x86::payload +} // namespace firestarter::x86::payload diff --git a/include/firestarter/Environment/X86/Platform/BulldozerConfig.hpp b/include/firestarter/X86/Platform/BulldozerConfig.hpp similarity index 69% rename from include/firestarter/Environment/X86/Platform/BulldozerConfig.hpp rename to include/firestarter/X86/Platform/BulldozerConfig.hpp index 936b3601..89209824 100644 --- a/include/firestarter/Environment/X86/Platform/BulldozerConfig.hpp +++ b/include/firestarter/X86/Platform/BulldozerConfig.hpp @@ -21,20 +21,24 @@ #pragma once -#include "firestarter/Environment/X86/Payload/FMA4Payload.hpp" -#include "firestarter/Environment/X86/Platform/X86PlatformConfig.hpp" +#include "firestarter/X86/Payload/FMA4Payload.hpp" +#include "firestarter/X86/Platform/X86PlatformConfig.hpp" -namespace firestarter::environment::x86::platform { +namespace firestarter::x86::platform { 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=*/ - environment::payload::PayloadSettings( + firestarter::payload::PayloadSettings( /*Threads=*/{1}, /*DataCacheBufferSize=*/{16384, 1048576, 786432}, /*RamBufferSize=*/104857600, /*Lines=*/1536, - /*InstructionGroups=*/{{"RAM_L", 1}, {"L3_L", 1}, {"L2_LS", 5}, {"L1_L", 90}, {"REG", 45}}), + /*Groups=*/ + InstructionGroups{{{"RAM_L", 1}, {"L3_L", 1}, {"L2_LS", 5}, {"L1_L", 90}, {"REG", 45}}}), /*Payload=*/std::make_shared()) {} }; -} // namespace firestarter::environment::x86::platform +} // namespace firestarter::x86::platform diff --git a/include/firestarter/Environment/X86/Platform/HaswellConfig.hpp b/include/firestarter/X86/Platform/HaswellConfig.hpp similarity index 66% rename from include/firestarter/Environment/X86/Platform/HaswellConfig.hpp rename to include/firestarter/X86/Platform/HaswellConfig.hpp index 768d3597..09c390e5 100644 --- a/include/firestarter/Environment/X86/Platform/HaswellConfig.hpp +++ b/include/firestarter/X86/Platform/HaswellConfig.hpp @@ -21,20 +21,24 @@ #pragma once -#include "firestarter/Environment/X86/Payload/FMAPayload.hpp" -#include "firestarter/Environment/X86/Platform/X86PlatformConfig.hpp" +#include "firestarter/X86/Payload/FMAPayload.hpp" +#include "firestarter/X86/Platform/X86PlatformConfig.hpp" -namespace firestarter::environment::x86::platform { +namespace firestarter::x86::platform { 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=*/ - environment::payload::PayloadSettings( + firestarter::payload::PayloadSettings( /*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{32768, 262144, 1572864}, /*RamBufferSize=*/104857600, /*Lines=*/1536, - /*InstructionGroups=*/{{"RAM_L", 2}, {"L3_LS", 3}, {"L2_LS", 9}, {"L1_LS", 90}, {"REG", 40}}), + /*Groups=*/ + InstructionGroups{{{"RAM_L", 2}, {"L3_LS", 3}, {"L2_LS", 9}, {"L1_LS", 90}, {"REG", 40}}}), /*Payload=*/std::make_shared()) {} }; -} // namespace firestarter::environment::x86::platform +} // namespace firestarter::x86::platform diff --git a/include/firestarter/Environment/X86/Platform/HaswellEPConfig.hpp b/include/firestarter/X86/Platform/HaswellEPConfig.hpp similarity index 72% rename from include/firestarter/Environment/X86/Platform/HaswellEPConfig.hpp rename to include/firestarter/X86/Platform/HaswellEPConfig.hpp index 23d2518f..977eab72 100644 --- a/include/firestarter/Environment/X86/Platform/HaswellEPConfig.hpp +++ b/include/firestarter/X86/Platform/HaswellEPConfig.hpp @@ -21,20 +21,22 @@ #pragma once -#include "firestarter/Environment/X86/Payload/FMAPayload.hpp" -#include "firestarter/Environment/X86/Platform/X86PlatformConfig.hpp" +#include "firestarter/X86/Payload/FMAPayload.hpp" +#include "firestarter/X86/Platform/X86PlatformConfig.hpp" -namespace firestarter::environment::x86::platform { +namespace firestarter::x86::platform { 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=*/ - environment::payload::PayloadSettings( + firestarter::payload::PayloadSettings( /*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{32768, 262144, 2621440}, /*RamBufferSize=*/104857600, /*Lines=*/1536, - /*InstructionGroups=*/{{"RAM_L", 8}, {"L3_LS", 1}, {"L2_LS", 29}, {"L1_LS", 100}, {"REG", 100}}), + /*Groups=*/ + InstructionGroups{{{"RAM_L", 8}, {"L3_LS", 1}, {"L2_LS", 29}, {"L1_LS", 100}, {"REG", 100}}}), /*Payload=*/std::make_shared()) {} }; -} // namespace firestarter::environment::x86::platform +} // namespace firestarter::x86::platform diff --git a/include/firestarter/Environment/X86/Platform/KnightsLandingConfig.hpp b/include/firestarter/X86/Platform/KnightsLandingConfig.hpp similarity index 72% rename from include/firestarter/Environment/X86/Platform/KnightsLandingConfig.hpp rename to include/firestarter/X86/Platform/KnightsLandingConfig.hpp index f849c07b..ac020436 100644 --- a/include/firestarter/Environment/X86/Platform/KnightsLandingConfig.hpp +++ b/include/firestarter/X86/Platform/KnightsLandingConfig.hpp @@ -21,19 +21,21 @@ #pragma once -#include "firestarter/Environment/X86/Payload/AVX512Payload.hpp" -#include "firestarter/Environment/X86/Platform/X86PlatformConfig.hpp" +#include "firestarter/X86/Payload/AVX512Payload.hpp" +#include "firestarter/X86/Platform/X86PlatformConfig.hpp" -namespace firestarter::environment::x86::platform { +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=*/ - environment::payload::PayloadSettings( + firestarter::payload::PayloadSettings( /*Threads=*/{4}, /*DataCacheBufferSize=*/{32768, 524288, 236279125}, /*RamBufferSize=*/26214400, /*Lines=*/1536, - /*InstructionGroups=*/{{"RAM_P", 3}, {"L2_S", 8}, {"L1_L", 40}, {"REG", 10}}), + /*Groups=*/ + InstructionGroups{{{"RAM_P", 3}, {"L2_S", 8}, {"L1_L", 40}, {"REG", 10}}}), /*Payload=*/std::make_shared()) {} }; -} // namespace firestarter::environment::x86::platform +} // namespace firestarter::x86::platform diff --git a/include/firestarter/Environment/X86/Platform/NaplesConfig.hpp b/include/firestarter/X86/Platform/NaplesConfig.hpp similarity index 68% rename from include/firestarter/Environment/X86/Platform/NaplesConfig.hpp rename to include/firestarter/X86/Platform/NaplesConfig.hpp index abef11da..7411899e 100644 --- a/include/firestarter/Environment/X86/Platform/NaplesConfig.hpp +++ b/include/firestarter/X86/Platform/NaplesConfig.hpp @@ -21,20 +21,23 @@ #pragma once -#include "firestarter/Environment/X86/Payload/ZENFMAPayload.hpp" -#include "firestarter/Environment/X86/Platform/X86PlatformConfig.hpp" +#include "firestarter/X86/Payload/ZENFMAPayload.hpp" +#include "firestarter/X86/Platform/X86PlatformConfig.hpp" -namespace firestarter::environment::x86::platform { +namespace firestarter::x86::platform { 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=*/ - environment::payload::PayloadSettings( + firestarter::payload::PayloadSettings( /*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{65536, 524288, 2097152}, /*RamBufferSize=*/104857600, /*Lines=*/1536, - /*InstructionGroups=*/{{"RAM_L", 3}, {"L3_L", 14}, {"L2_L", 75}, {"L1_LS", 81}, {"REG", 100}}), + /*Groups=*/ + InstructionGroups{{{"RAM_L", 3}, {"L3_L", 14}, {"L2_L", 75}, {"L1_LS", 81}, {"REG", 100}}}), /*Payload=*/std::make_shared()) {} }; -} // namespace firestarter::environment::x86::platform +} // namespace firestarter::x86::platform diff --git a/include/firestarter/Environment/X86/Platform/NehalemConfig.hpp b/include/firestarter/X86/Platform/NehalemConfig.hpp similarity index 68% rename from include/firestarter/Environment/X86/Platform/NehalemConfig.hpp rename to include/firestarter/X86/Platform/NehalemConfig.hpp index 31374061..638ec27a 100644 --- a/include/firestarter/Environment/X86/Platform/NehalemConfig.hpp +++ b/include/firestarter/X86/Platform/NehalemConfig.hpp @@ -21,19 +21,22 @@ #pragma once -#include "firestarter/Environment/X86/Payload/SSE2Payload.hpp" -#include "firestarter/Environment/X86/Platform/X86PlatformConfig.hpp" +#include "firestarter/X86/Payload/SSE2Payload.hpp" +#include "firestarter/X86/Platform/X86PlatformConfig.hpp" -namespace firestarter::environment::x86::platform { +namespace firestarter::x86::platform { 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=*/ - environment::payload::PayloadSettings(/*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{32768, 262144, 1572864}, + firestarter::payload::PayloadSettings(/*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{32768, 262144, 1572864}, /*RamBufferSize=*/104857600, /*Lines=*/1536, - /*InstructionGroups=*/{{"RAM_P", 1}, {"L1_LS", 70}, {"REG", 2}}), + /*Groups=*/ + InstructionGroups{{{"RAM_P", 1}, {"L1_LS", 70}, {"REG", 2}}}), /*Payload=*/std::make_shared()) {} }; -} // namespace firestarter::environment::x86::platform +} // namespace firestarter::x86::platform diff --git a/include/firestarter/Environment/X86/Platform/NehalemEPConfig.hpp b/include/firestarter/X86/Platform/NehalemEPConfig.hpp similarity index 71% rename from include/firestarter/Environment/X86/Platform/NehalemEPConfig.hpp rename to include/firestarter/X86/Platform/NehalemEPConfig.hpp index 9a6a08bb..648dd681 100644 --- a/include/firestarter/Environment/X86/Platform/NehalemEPConfig.hpp +++ b/include/firestarter/X86/Platform/NehalemEPConfig.hpp @@ -21,19 +21,21 @@ #pragma once -#include "firestarter/Environment/X86/Payload/SSE2Payload.hpp" -#include "firestarter/Environment/X86/Platform/X86PlatformConfig.hpp" +#include "firestarter/X86/Payload/SSE2Payload.hpp" +#include "firestarter/X86/Platform/X86PlatformConfig.hpp" -namespace firestarter::environment::x86::platform { +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=*/ - environment::payload::PayloadSettings( + firestarter::payload::PayloadSettings( /*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{32768, 262144, 2097152}, /*RamBufferSize=*/104857600, /*Lines=*/1536, - /*InstructionGroups=*/{{"RAM_P", 1}, {"L1_LS", 60}, {"REG", 2}}), + /*Groups=*/ + InstructionGroups{{{"RAM_P", 1}, {"L1_LS", 60}, {"REG", 2}}}), /*Payload=*/std::make_shared()) {} }; -} // namespace firestarter::environment::x86::platform +} // namespace firestarter::x86::platform diff --git a/include/firestarter/Environment/X86/Platform/RomeConfig.hpp b/include/firestarter/X86/Platform/RomeConfig.hpp similarity index 71% rename from include/firestarter/Environment/X86/Platform/RomeConfig.hpp rename to include/firestarter/X86/Platform/RomeConfig.hpp index e70161d7..bd0e156f 100644 --- a/include/firestarter/Environment/X86/Platform/RomeConfig.hpp +++ b/include/firestarter/X86/Platform/RomeConfig.hpp @@ -21,21 +21,23 @@ #pragma once -#include "firestarter/Environment/X86/Payload/FMAPayload.hpp" -#include "firestarter/Environment/X86/Platform/X86PlatformConfig.hpp" +#include "firestarter/X86/Payload/FMAPayload.hpp" +#include "firestarter/X86/Platform/X86PlatformConfig.hpp" -namespace firestarter::environment::x86::platform { +namespace firestarter::x86::platform { 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=*/ - environment::payload::PayloadSettings( + firestarter::payload::PayloadSettings( /*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{32768, 524288, 2097152}, /*RamBufferSize=*/104857600, /*Lines=*/1536, - /*InstructionGroups=*/ - {{"RAM_L", 10}, {"L3_L", 25}, {"L2_L", 91}, {"L1_2LS_256", 72}, {"L1_LS_256", 82}, {"REG", 75}}), + /*Groups=*/ + InstructionGroups{ + {{"RAM_L", 10}, {"L3_L", 25}, {"L2_L", 91}, {"L1_2LS_256", 72}, {"L1_LS_256", 82}, {"REG", 75}}}), /*Payload=*/std::make_shared()) {} }; -} // namespace firestarter::environment::x86::platform +} // namespace firestarter::x86::platform diff --git a/include/firestarter/Environment/X86/Platform/SandyBridgeConfig.hpp b/include/firestarter/X86/Platform/SandyBridgeConfig.hpp similarity index 72% rename from include/firestarter/Environment/X86/Platform/SandyBridgeConfig.hpp rename to include/firestarter/X86/Platform/SandyBridgeConfig.hpp index b5c5b1c4..ec08244f 100644 --- a/include/firestarter/Environment/X86/Platform/SandyBridgeConfig.hpp +++ b/include/firestarter/X86/Platform/SandyBridgeConfig.hpp @@ -21,20 +21,22 @@ #pragma once -#include "firestarter/Environment/X86/Payload/AVXPayload.hpp" -#include "firestarter/Environment/X86/Platform/X86PlatformConfig.hpp" +#include "firestarter/X86/Payload/AVXPayload.hpp" +#include "firestarter/X86/Platform/X86PlatformConfig.hpp" -namespace firestarter::environment::x86::platform { +namespace firestarter::x86::platform { 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=*/ - environment::payload::PayloadSettings( + firestarter::payload::PayloadSettings( /*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{32768, 262144, 1572864}, /*RamBufferSize=*/104857600, /*Lines=*/1536, - /*InstructionGroups=*/{{"RAM_L", 2}, {"L3_LS", 4}, {"L2_LS", 10}, {"L1_LS", 90}, {"REG", 45}}), + /*Groups=*/ + InstructionGroups{{{"RAM_L", 2}, {"L3_LS", 4}, {"L2_LS", 10}, {"L1_LS", 90}, {"REG", 45}}}), /*Payload=*/std::make_shared()) {} }; -} // namespace firestarter::environment::x86::platform +} // namespace firestarter::x86::platform diff --git a/include/firestarter/Environment/X86/Platform/SandyBridgeEPConfig.hpp b/include/firestarter/X86/Platform/SandyBridgeEPConfig.hpp similarity index 72% rename from include/firestarter/Environment/X86/Platform/SandyBridgeEPConfig.hpp rename to include/firestarter/X86/Platform/SandyBridgeEPConfig.hpp index 67048ba5..3b9625b6 100644 --- a/include/firestarter/Environment/X86/Platform/SandyBridgeEPConfig.hpp +++ b/include/firestarter/X86/Platform/SandyBridgeEPConfig.hpp @@ -21,20 +21,22 @@ #pragma once -#include "firestarter/Environment/X86/Payload/AVXPayload.hpp" -#include "firestarter/Environment/X86/Platform/X86PlatformConfig.hpp" +#include "firestarter/X86/Payload/AVXPayload.hpp" +#include "firestarter/X86/Platform/X86PlatformConfig.hpp" -namespace firestarter::environment::x86::platform { +namespace firestarter::x86::platform { 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=*/ - environment::payload::PayloadSettings( + firestarter::payload::PayloadSettings( /*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{32768, 262144, 2621440}, /*RamBufferSize=*/104857600, /*Lines=*/1536, - /*InstructionGroups=*/{{"RAM_L", 3}, {"L3_LS", 2}, {"L2_LS", 10}, {"L1_LS", 90}, {"REG", 30}}), + /*Groups=*/ + InstructionGroups{{{"RAM_L", 3}, {"L3_LS", 2}, {"L2_LS", 10}, {"L1_LS", 90}, {"REG", 30}}}), /*Payload=*/std::make_shared()) {} }; -} // namespace firestarter::environment::x86::platform \ No newline at end of file +} // namespace firestarter::x86::platform \ No newline at end of file diff --git a/include/firestarter/X86/Platform/SkylakeConfig.hpp b/include/firestarter/X86/Platform/SkylakeConfig.hpp new file mode 100644 index 00000000..3d0b38f1 --- /dev/null +++ b/include/firestarter/X86/Platform/SkylakeConfig.hpp @@ -0,0 +1,43 @@ +/****************************************************************************** + * FIRESTARTER - A Processor Stress Test Utility + * Copyright (C) 2020 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/X86/Payload/FMAPayload.hpp" +#include "firestarter/X86/Platform/X86PlatformConfig.hpp" + +namespace firestarter::x86::platform { +class SkylakeConfig final : public X86PlatformConfig { +public: + SkylakeConfig() noexcept + : X86PlatformConfig( + /*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}, + /*RamBufferSize=*/104857600, /*Lines=*/1536, + /*Groups=*/ + InstructionGroups{ + {{"RAM_L", 3}, {"L3_LS_256", 5}, {"L2_LS_256", 18}, {"L1_2LS_256", 78}, {"REG", 40}}}), + /*Payload=*/std::make_shared()) {} +}; +} // namespace firestarter::x86::platform \ No newline at end of file diff --git a/include/firestarter/Environment/X86/Platform/SkylakeSPConfig.hpp b/include/firestarter/X86/Platform/SkylakeSPConfig.hpp similarity index 75% rename from include/firestarter/Environment/X86/Platform/SkylakeSPConfig.hpp rename to include/firestarter/X86/Platform/SkylakeSPConfig.hpp index 864ebec9..0703c223 100644 --- a/include/firestarter/Environment/X86/Platform/SkylakeSPConfig.hpp +++ b/include/firestarter/X86/Platform/SkylakeSPConfig.hpp @@ -21,28 +21,29 @@ #pragma once -#include "firestarter/Environment/X86/Payload/AVX512Payload.hpp" -#include "firestarter/Environment/X86/Platform/X86PlatformConfig.hpp" +#include "firestarter/X86/Payload/AVX512Payload.hpp" +#include "firestarter/X86/Platform/X86PlatformConfig.hpp" -namespace firestarter::environment::x86::platform { +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=*/ - environment::payload::PayloadSettings(/*Threads=*/{1, 2}, + firestarter::payload::PayloadSettings(/*Threads=*/{1, 2}, /*DataCacheBufferSize=*/{32768, 1048576, 1441792}, /*RamBufferSize=*/1048576000, /*Lines=*/1536, - /*InstructionGroups=*/ - {{"RAM_S", 3}, - {"RAM_P", 1}, - {"L3_S", 1}, - {"L3_P", 1}, - {"L2_S", 4}, - {"L2_L", 70}, - {"L1_S", 0}, - {"L1_L", 40}, - {"REG", 140}}), + /*Groups=*/ + InstructionGroups{{{"RAM_S", 3}, + {"RAM_P", 1}, + {"L3_S", 1}, + {"L3_P", 1}, + {"L2_S", 4}, + {"L2_L", 70}, + {"L1_S", 0}, + {"L1_L", 40}, + {"REG", 140}}}), /*Payload=*/std::make_shared()) {} }; -} // namespace firestarter::environment::x86::platform +} // namespace firestarter::x86::platform diff --git a/include/firestarter/X86/Platform/X86PlatformConfig.hpp b/include/firestarter/X86/Platform/X86PlatformConfig.hpp new file mode 100644 index 00000000..af909a4d --- /dev/null +++ b/include/firestarter/X86/Platform/X86PlatformConfig.hpp @@ -0,0 +1,73 @@ +/****************************************************************************** + * FIRESTARTER - A Processor Stress Test Utility + * Copyright (C) 2020 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/Platform/PlatformConfig.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 set of requested cpu models + std::set RequestedModels; + +public: + 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)) + , RequestedModels(std::move(RequestedModels)) {} + + /// Clone a the platform config. + [[nodiscard]] auto clone() const -> std::unique_ptr final { + auto Ptr = std::make_unique(name(), std::set(RequestedModels), + firestarter::payload::PayloadSettings(settings()), + std::shared_ptr(payload())); + return Ptr; + } + + /// Clone a concreate platform config. + /// \arg InstructionCacheSize The detected size of the instructions cache. + /// \arg ThreadPerCore The number of threads per pysical CPU. + [[nodiscard]] auto cloneConcreate(std::optional InstructionCacheSize, unsigned ThreadsPerCore) const + -> std::unique_ptr final { + auto Ptr = clone(); + auto* DerivedPtr = dynamic_cast(Ptr.get()); + DerivedPtr->settings().concretize(InstructionCacheSize, ThreadsPerCore); + return Ptr; + } + + /// 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); + } +}; + +} // namespace firestarter::x86::platform diff --git a/include/firestarter/X86/X86CpuFeatures.hpp b/include/firestarter/X86/X86CpuFeatures.hpp new file mode 100644 index 00000000..8a303d5f --- /dev/null +++ b/include/firestarter/X86/X86CpuFeatures.hpp @@ -0,0 +1,63 @@ +/****************************************************************************** + * 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/CpuFeatures.hpp" + +#include +#include +#include + +namespace firestarter::x86 { + +/// This class models the cpu features on the x86_64 platform. +class X86CpuFeatures : public CpuFeatures { +private: + /// This list contains the features (cpu extenstions) that are requied to execute the payload. + asmjit::CpuFeatures AsmjitFeatures; + +public: + X86CpuFeatures() = default; + explicit X86CpuFeatures(const asmjit::CpuFeatures& FeatureRequests) + : AsmjitFeatures(FeatureRequests) {} + + explicit operator const asmjit::CpuFeatures&() const noexcept { return AsmjitFeatures; } + + [[nodiscard]] auto add(asmjit::CpuFeatures::X86::Id Id) -> X86CpuFeatures& { + AsmjitFeatures.add(Id); + return *this; + } + + /// Check if this class has all features which are given in the argument. + /// \arg Features The features which should be check if they are available. + /// \returns true if this class has all features given in the argument. + [[nodiscard]] auto hasAll(const CpuFeatures& Features) const -> bool override { + const auto* DerivedFeatures = dynamic_cast(&Features); + if (!DerivedFeatures) { + throw std::runtime_error("Features is not of the correct type X86CpuFeatures"); + } + + return AsmjitFeatures.hasAll(DerivedFeatures->AsmjitFeatures); + } +}; + +} // namespace firestarter::x86 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/X86FunctionSelection.hpp b/include/firestarter/X86/X86FunctionSelection.hpp new file mode 100644 index 00000000..fdc5e350 --- /dev/null +++ b/include/firestarter/X86/X86FunctionSelection.hpp @@ -0,0 +1,83 @@ +/****************************************************************************** + * FIRESTARTER - A Processor Stress Test Utility + * Copyright (C) 2020 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/FunctionSelection.hpp" +#include "firestarter/X86/Platform/BulldozerConfig.hpp" +#include "firestarter/X86/Platform/HaswellConfig.hpp" +#include "firestarter/X86/Platform/HaswellEPConfig.hpp" +#include "firestarter/X86/Platform/KnightsLandingConfig.hpp" +#include "firestarter/X86/Platform/NaplesConfig.hpp" +#include "firestarter/X86/Platform/NehalemConfig.hpp" +#include "firestarter/X86/Platform/NehalemEPConfig.hpp" +#include "firestarter/X86/Platform/RomeConfig.hpp" +#include "firestarter/X86/Platform/SandyBridgeConfig.hpp" +#include "firestarter/X86/Platform/SandyBridgeEPConfig.hpp" +#include "firestarter/X86/Platform/SkylakeConfig.hpp" +#include "firestarter/X86/Platform/SkylakeSPConfig.hpp" + +#include + +namespace firestarter::x86 { + +class X86FunctionSelection final : public FunctionSelection { +public: + X86FunctionSelection() = default; + + [[nodiscard]] auto platformConfigs() const + -> const std::vector>& override { + return PlatformConfigs; + } + + [[nodiscard]] auto fallbackPlatformConfigs() const + -> const std::vector>& override { + return FallbackPlatformConfigs; + } + +private: + /// The list of availabe platform configs that is printed when supplying the --avail command line argument. The IDs + /// for these configs are generated by iterating through this list starting with 1. To maintain stable IDs in + /// FIRESTARTER new configs should be added to the bottom of the list. + std::vector> PlatformConfigs = { + std::make_shared(), std::make_shared(), + std::make_shared(), std::make_shared(), + std::make_shared(), std::make_shared(), + std::make_shared(), std::make_shared(), + std::make_shared(), std::make_shared(), + std::make_shared(), std::make_shared()}; + + /// The list of configs that are fallbacks. If none of the PlatformConfigs is the default one on the current CPU, we + /// select the first one from this list that is available on the current system. If multiple configs can be available + /// on one system the one with higher priority should be at the top of this list. Modern X86 CPUs will support SSE2 + /// therefore it is the last on the list. CPUs that support AVX512 will most certainly also support FMA and AVX, + /// AVX512 takes precedence. This list should contain one entry for each of the supported CPU extensions by the + /// FIRESTARTER payloads. + std::vector> FallbackPlatformConfigs = { + std::make_shared(), // AVX512 + std::make_shared(), // FMA4 + std::make_shared(), // FMA + std::make_shared(), // AVX + std::make_shared() // SSE2 + }; +}; + +} // namespace firestarter::x86 diff --git a/include/firestarter/Environment/X86/X86ProcessorInformation.hpp b/include/firestarter/X86/X86ProcessorInformation.hpp similarity index 74% rename from include/firestarter/Environment/X86/X86ProcessorInformation.hpp rename to include/firestarter/X86/X86ProcessorInformation.hpp index 60b924b4..d282a38a 100644 --- a/include/firestarter/Environment/X86/X86ProcessorInformation.hpp +++ b/include/firestarter/X86/X86ProcessorInformation.hpp @@ -21,23 +21,19 @@ #pragma once -#include "firestarter/Environment/ProcessorInformation.hpp" +#include "firestarter/ProcessorInformation.hpp" #include -namespace firestarter::environment::x86 { +namespace firestarter::x86 { /// This class models the properties of a x86_64 processor. class X86ProcessorInformation final : public ProcessorInformation { public: X86ProcessorInformation(); - friend auto operator<<(std::ostream& Stream, X86ProcessorInformation const& CpuTopology) -> std::ostream&; - /// 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; @@ -45,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. @@ -81,8 +71,4 @@ class X86ProcessorInformation final : public ProcessorInformation { std::string Model; }; -inline auto operator<<(std::ostream& Stream, X86ProcessorInformation const& CpuTopology) -> std::ostream& { - return CpuTopology.print(Stream); -} - -} // namespace firestarter::environment::x86 \ No newline at end of file +} // namespace firestarter::x86 \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6361218c..928ef7f3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,27 +6,28 @@ add_library(firestartercore STATIC firestarter/DumpRegisterWorker.cpp firestarter/CPUTopology.cpp firestarter/ThreadAffinity.cpp + firestarter/FunctionSelection.cpp + firestarter/ProcessorInformation.cpp firestarter/Config/Config.cpp + firestarter/Config/InstructionGroups.cpp firestarter/Config/CpuBind.cpp - - firestarter/Environment/X86/Platform/X86PlatformConfig.cpp - firestarter/Environment/ProcessorInformation.cpp - firestarter/Environment/Payload/CompiledPayload.cpp - firestarter/Environment/Payload/PayloadSettings.cpp + firestarter/Payload/CompiledPayload.cpp + firestarter/Payload/PayloadSettings.cpp # here starts the x86 specific code - firestarter/Environment/X86/X86Environment.cpp - firestarter/Environment/X86/X86ProcessorInformation.cpp - - firestarter/Environment/X86/Payload/X86Payload.cpp - firestarter/Environment/X86/Payload/AVX512Payload.cpp - firestarter/Environment/X86/Payload/FMA4Payload.cpp - firestarter/Environment/X86/Payload/FMAPayload.cpp - firestarter/Environment/X86/Payload/ZENFMAPayload.cpp - firestarter/Environment/X86/Payload/AVXPayload.cpp - firestarter/Environment/X86/Payload/SSE2Payload.cpp + firestarter/X86/X86ProcessorInformation.cpp + + firestarter/X86/Platform/X86PlatformConfig.cpp + + firestarter/X86/Payload/X86Payload.cpp + firestarter/X86/Payload/AVX512Payload.cpp + firestarter/X86/Payload/FMA4Payload.cpp + firestarter/X86/Payload/FMAPayload.cpp + firestarter/X86/Payload/ZENFMAPayload.cpp + firestarter/X86/Payload/AVXPayload.cpp + firestarter/X86/Payload/SSE2Payload.cpp ) target_link_libraries(firestartercore diff --git a/src/firestarter/CPUTopology.cpp b/src/firestarter/CPUTopology.cpp index e0d834a0..dbda519a 100644 --- a/src/firestarter/CPUTopology.cpp +++ b/src/firestarter/CPUTopology.cpp @@ -60,20 +60,20 @@ CPUTopology::CPUTopology() { CPUTopology::~CPUTopology() { hwloc_topology_destroy(Topology); } -void CPUTopology::printSystemSummary(std::ostream& Stream) const { +void CPUTopology::printSystemSummary() const { auto Resouces = homogenousResourceCount(); - Stream << " system summary:\n" - << " number of processors: " << Resouces.NumPackagesTotal << "\n" - << " number of cores (total)): " << Resouces.NumCoresTotal << "\n" - << " (this includes only cores in the cgroup)" - << "\n" - << " number of threads per core: " << Resouces.NumThreadsPerCore << "\n" - << " total number of threads: " << hardwareThreadsInfo().MaxNumThreads << "\n"; + log::info() << " system summary:\n" + << " number of processors: " << Resouces.NumPackagesTotal << "\n" + << " number of cores (total)): " << Resouces.NumCoresTotal << "\n" + << " (this includes only cores in the cgroup)" + << "\n" + << " number of threads per core: " << Resouces.NumThreadsPerCore << "\n" + << " total number of threads: " << hardwareThreadsInfo().MaxNumThreads; } -void CPUTopology::printCacheSummary(std::ostream& Stream) const { - Stream << " Caches:"; +void CPUTopology::printCacheSummary() const { + log::info() << " Caches:"; const std::vector Caches = { HWLOC_OBJ_L1CACHE, HWLOC_OBJ_L1ICACHE, HWLOC_OBJ_L2CACHE, HWLOC_OBJ_L2ICACHE, @@ -86,7 +86,7 @@ void CPUTopology::printCacheSummary(std::ostream& Stream) const { auto Width = hwloc_get_nbobjs_by_type(Topology, Cache); if (Width >= 1) { - Ss << "\n - "; + Ss << " - "; auto* CacheObj = hwloc_get_obj_by_type(Topology, Cache, 0); std::array String{}; @@ -131,7 +131,7 @@ void CPUTopology::printCacheSummary(std::ostream& Stream) const { Ss << "per thread."; } - Stream << Ss.str(); + log::info() << Ss.str(); } } } diff --git a/src/firestarter/Config/Config.cpp b/src/firestarter/Config/Config.cpp index 6a6dbc3b..c144bd72 100644 --- a/src/firestarter/Config/Config.cpp +++ b/src/firestarter/Config/Config.cpp @@ -143,7 +143,7 @@ Config::Config(int Argc, const char** Argv) Parser.add_options("general") ("i,function", "Specify integer ID of the load-function to be\nused (as listed by --avail)", - cxxopts::value()->default_value("0"), "ID"); + cxxopts::value(), "ID"); if (firestarter::OptionalFeatures.gpuEnabled()) { Parser.add_options("general") @@ -171,7 +171,7 @@ Config::Config(int Argc, const char** Argv) Parser.add_options("specialized-workloads") ("list-instruction-groups", "List the available instruction groups for the\npayload of the current platform.") ("run-instruction-groups", "Run the payload with the specified\ninstruction groups. GROUPS format: multiple INST:VAL\npairs comma-seperated.", - cxxopts::value()->default_value(""), "GROUPS") + cxxopts::value(), "GROUPS") ("set-line-count", "Set the number of lines for a payload.", cxxopts::value()); @@ -326,10 +326,14 @@ Config::Config(int Argc, const char** Argv) PrintFunctionSummary = static_cast(Options.count("avail")); - FunctionId = Options["function"].as(); + if (static_cast(Options.count("function"))) { + FunctionId = Options["function"].as(); + } ListInstructionGroups = static_cast(Options.count("list-instruction-groups")); - InstructionGroups = Options["run-instruction-groups"].as(); + if (static_cast(Options.count("run-instruction-groups"))) { + Groups = InstructionGroups::fromString(Options["run-instruction-groups"].as()); + } if (static_cast(Options.count("set-line-count"))) { LineCount = Options["set-line-count"].as(); } diff --git a/src/firestarter/Config/InstructionGroups.cpp b/src/firestarter/Config/InstructionGroups.cpp new file mode 100644 index 00000000..e12698cb --- /dev/null +++ b/src/firestarter/Config/InstructionGroups.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/Config/InstructionGroups.hpp" + +#include +#include + +namespace firestarter { + +auto InstructionGroups::fromString(const std::string& Groups) -> InstructionGroups { + const auto Delimiter = ','; + const std::regex Re("^(\\w+):(\\d+)$"); + + std::stringstream Ss(Groups); + std::vector> ParsedGroups; + + while (Ss.good()) { + std::string Token; + std::smatch M; + std::getline(Ss, Token, Delimiter); + + if (std::regex_match(Token, M, Re)) { + auto Num = std::stoul(M[2].str()); + if (Num == 0) { + throw std::invalid_argument("instruction-group VAL may not contain number 0" + "\n --run-instruction-groups format: multiple INST:VAL " + "pairs comma-seperated"); + } + ParsedGroups.emplace_back(M[1].str(), Num); + } else { + throw std::invalid_argument("Invalid symbols in instruction-group: " + Token + + "\n --run-instruction-groups format: multiple INST:VAL " + "pairs comma-seperated"); + } + } + + return InstructionGroups{ParsedGroups}; +} + +auto InstructionGroups::fromInstructionAndValues(const std::vector& Instructions, + const std::vector& Values) -> InstructionGroups { + assert(Instructions.size() == Values.size()); + + std::vector> Groups; + + auto It1 = Instructions.begin(); + auto It2 = Values.begin(); + for (; It1 != Instructions.end(); ++It1, ++It2) { + Groups.emplace_back(*It1, *It2); + } + + return InstructionGroups{Groups}; +} + +auto InstructionGroups::intructions() const -> std::vector { + std::vector Items; + Items.reserve(Groups.size()); + for (auto const& Pair : Groups) { + Items.push_back(Pair.first); + } + return Items; +} + +} // namespace firestarter \ No newline at end of file diff --git a/src/firestarter/Environment/X86/X86Environment.cpp b/src/firestarter/Environment/X86/X86Environment.cpp deleted file mode 100644 index eae5c7ee..00000000 --- a/src/firestarter/Environment/X86/X86Environment.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/****************************************************************************** - * FIRESTARTER - A Processor Stress Test Utility - * Copyright (C) 2020-2023 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/Environment/X86/X86Environment.hpp" -#include "firestarter/Logging/Log.hpp" - -#include -#include -#include -#include - -namespace firestarter::environment::x86 { - -void X86Environment::selectFunction(unsigned FunctionId, const CPUTopology& Topology, bool AllowUnavailablePayload) { - unsigned Id = 1; - std::optional DefaultPayloadName; - const auto ProcessorICacheSize = Topology.instructionCacheSize(); - const auto ProcessorThreadsPerCore = Topology.homogenousResourceCount().NumThreadsPerCore; - - // if functionId is 0 get the default or fallback - for (const auto& PlatformConfigPtr : PlatformConfigs) { - for (auto const& ThreadsPerCore : PlatformConfigPtr->settings().threads()) { - // the selected function - if (Id == FunctionId) { - if (!PlatformConfigPtr->isAvailable(processorInfos())) { - const auto ErrorString = "Function " + std::to_string(FunctionId) + " (\"" + - PlatformConfigPtr->functionName(ThreadsPerCore) + "\") requires " + - PlatformConfigPtr->payload()->name() + ", which is not supported by the processor."; - if (AllowUnavailablePayload) { - log::warn() << ErrorString; - } else { - throw std::invalid_argument(ErrorString); - } - } - // found function - setConfig(PlatformConfigPtr->cloneConcreate(ProcessorICacheSize, ThreadsPerCore)); - return; - } - // default function - if (0 == FunctionId && PlatformConfigPtr->isDefault(processorInfos())) { - if (ThreadsPerCore == ProcessorThreadsPerCore) { - setConfig(PlatformConfigPtr->cloneConcreate(ProcessorICacheSize, ThreadsPerCore)); - return; - } - DefaultPayloadName = PlatformConfigPtr->payload()->name(); - } - Id++; - } - } - - // no default found - // use fallback - if (0 == FunctionId) { - if (DefaultPayloadName) { - // default payload available, but number of threads per core is not - // supported - log::warn() << "No " << *DefaultPayloadName << " code path for " << ProcessorThreadsPerCore - << " threads per core!"; - } - log::warn() << processorInfos().vendor() << " " << processorInfos().model() - << " is not supported by this version of FIRESTARTER!\n" - << "Check project website for updates."; - - // loop over available implementation and check if they are marked as - // fallback - for (const auto& FallbackPlatformConfigPtr : FallbackPlatformConfigs) { - if (FallbackPlatformConfigPtr->isAvailable(processorInfos())) { - std::optional SelectedThreadsPerCore; - // find the fallback implementation with the correct thread per core count - for (auto const& ThreadsPerCore : FallbackPlatformConfigPtr->settings().threads()) { - if (ThreadsPerCore == ProcessorThreadsPerCore) { - SelectedThreadsPerCore = ThreadsPerCore; - } - } - // Otherwise select the first available thread per core count - if (!SelectedThreadsPerCore) { - SelectedThreadsPerCore = FallbackPlatformConfigPtr->settings().threads().front(); - } - setConfig(FallbackPlatformConfigPtr->cloneConcreate(ProcessorICacheSize, *SelectedThreadsPerCore)); - log::warn() << "Using function " << FallbackPlatformConfigPtr->functionName(*SelectedThreadsPerCore) - << " as fallback.\n" - << "You can use the parameter --function to try other " - "functions."; - return; - } - } - - // no fallback found - throw std::invalid_argument("No fallback implementation found for available ISA " - "extensions."); - } - - throw std::invalid_argument("unknown function id: " + std::to_string(FunctionId) + ", see --avail for available ids"); -} - -void X86Environment::selectInstructionGroups(std::string Groups) { - const auto Delimiter = ','; - const std::regex Re("^(\\w+):(\\d+)$"); - const auto AvailableInstructionGroups = config().payload()->getAvailableInstructions(); - - std::stringstream Ss(Groups); - std::vector> PayloadSettings = {}; - - while (Ss.good()) { - std::string Token; - std::smatch M; - std::getline(Ss, Token, Delimiter); - - if (std::regex_match(Token, M, Re)) { - if (std::find(AvailableInstructionGroups.begin(), AvailableInstructionGroups.end(), M[1].str()) == - AvailableInstructionGroups.end()) { - throw std::invalid_argument("Invalid instruction-group: " + M[1].str() + - "\n --run-instruction-groups format: multiple INST:VAL " - "pairs comma-seperated"); - } - auto Num = std::stoul(M[2].str()); - if (Num == 0) { - throw std::invalid_argument("instruction-group VAL may not contain number 0" - "\n --run-instruction-groups format: multiple INST:VAL " - "pairs comma-seperated"); - } - PayloadSettings.emplace_back(M[1].str(), Num); - } else { - throw std::invalid_argument("Invalid symbols in instruction-group: " + Token + - "\n --run-instruction-groups format: multiple INST:VAL " - "pairs comma-seperated"); - } - } - - config().settings().selectInstructionGroups(PayloadSettings); - - log::info() << " Running custom instruction group: " << Groups; -} - -void X86Environment::printAvailableInstructionGroups() { - std::stringstream Ss; - - for (auto const& Item : config().payload()->getAvailableInstructions()) { - Ss << Item << ","; - } - - auto S = Ss.str(); - if (!S.empty()) { - S.pop_back(); - } - - log::info() << " available instruction-groups for payload " << config().payload()->name() << ":\n" - << " " << S; -} - -void X86Environment::setLineCount(unsigned LineCount) { config().settings().setLineCount(LineCount); } - -void X86Environment::printSelectedCodePathSummary() { config().printCodePathSummary(); } - -void X86Environment::printFunctionSummary(bool ForceYes) { - log::info() << " available load-functions:\n" - << " ID | NAME | available on this " - "system | payload default setting\n" - << " " - "-------------------------------------------------------------" - "-------------------------------------------------------------" - "-----------------------------"; - - auto Id = 1U; - - for (auto const& Config : PlatformConfigs) { - for (auto const& ThreadsPerCore : Config->settings().threads()) { - const char* Available = (Config->isAvailable(processorInfos()) || ForceYes) ? "yes" : "no"; - const auto& FunctionName = Config->functionName(ThreadsPerCore); - const auto& InstructionGroupsString = Config->settings().getInstructionGroupsString(); - - log::info() << " " << std::right << std::setw(4) << Id << " | " << std::left << std::setw(30) << FunctionName - << " | " << std::left << std::setw(24) << Available << " | " << InstructionGroupsString; - Id++; - } - } -} - -} // namespace firestarter::environment::x86 \ No newline at end of file diff --git a/src/firestarter/Firestarter.cpp b/src/firestarter/Firestarter.cpp index 05d5acfe..9e664158 100644 --- a/src/firestarter/Firestarter.cpp +++ b/src/firestarter/Firestarter.cpp @@ -20,12 +20,14 @@ *****************************************************************************/ #include "firestarter/Firestarter.hpp" -#include "firestarter/Environment/X86/X86Environment.hpp" #include "firestarter/Logging/Log.hpp" #include "firestarter/Measurement/Metric/IPCEstimate.hpp" #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 @@ -34,20 +36,21 @@ namespace firestarter { Firestarter::Firestarter(Config&& ProvidedConfig) - : Cfg(std::move(ProvidedConfig)) - , Topology(std::make_unique()) { + : Cfg(std::move(ProvidedConfig)) { + std::unique_ptr FunctionSelectionPtr; + if constexpr (firestarter::OptionalFeatures.IsX86) { - Environment = std::make_unique(); + ProcessorInfos = std::make_shared(); + FunctionSelectionPtr = std::make_unique(); } const auto Affinity = - ThreadAffinity::fromCommandLine(Topology->hardwareThreadsInfo(), Cfg.RequestedNumThreads, Cfg.CpuBinding); + ThreadAffinity::fromCommandLine(Topology.hardwareThreadsInfo(), Cfg.RequestedNumThreads, Cfg.CpuBinding); if constexpr (firestarter::OptionalFeatures.IsX86) { // Error detection uses crc32 instruction added by the SSE4.2 extension to x86 if (Cfg.ErrorDetection) { - const auto& X86Env = *dynamic_cast(Environment.get()); - if (!X86Env.processorInfos().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"); } @@ -61,23 +64,25 @@ Firestarter::Firestarter(Config&& ProvidedConfig) } if (Cfg.PrintFunctionSummary) { - Environment->printFunctionSummary(/*ForceYes=*/false); + FunctionSelectionPtr->printFunctionSummary(*ProcessorInfos, /*ForceYes=*/false); safeExit(EXIT_SUCCESS); } - Environment->selectFunction(Cfg.FunctionId, *Topology, Cfg.AllowUnavailablePayload); + FunctionPtr = + FunctionSelectionPtr->selectFunction(Cfg.FunctionId, *ProcessorInfos, Topology, Cfg.AllowUnavailablePayload); if (Cfg.ListInstructionGroups) { - Environment->printAvailableInstructionGroups(); + FunctionPtr->payload()->printAvailableInstructionGroups(); + safeExit(EXIT_SUCCESS); } - - if (!Cfg.InstructionGroups.empty()) { - Environment->selectInstructionGroups(Cfg.InstructionGroups); + if (Cfg.Groups) { + FunctionPtr->selectInstructionGroups(*Cfg.Groups); + log::info() << " Running custom instruction group: " << *Cfg.Groups; } - if (Cfg.LineCount != 0) { - Environment->setLineCount(Cfg.LineCount); + if (Cfg.LineCount) { + FunctionPtr->setLineCount(*Cfg.LineCount); } if constexpr (firestarter::OptionalFeatures.OptimizationEnabled) { @@ -116,7 +121,7 @@ Firestarter::Firestarter(Config&& ProvidedConfig) } if (Cfg.Optimize) { - auto ApplySettings = [this](std::vector> const& Setting) { + auto ApplySettings = [this](InstructionGroups const& Setting) { using Clock = std::chrono::high_resolution_clock; auto Start = Clock::now(); @@ -152,7 +157,7 @@ Firestarter::Firestarter(Config&& ProvidedConfig) auto Prob = std::make_shared( std::move(ApplySettings), MeasurementWorker, Cfg.OptimizationMetrics, Cfg.EvaluationDuration, Cfg.StartDelta, - Cfg.StopDelta, Environment->config().settings().instructionGroupItems()); + Cfg.StopDelta, FunctionPtr->constRef().settings().groups().intructions()); Population = std::make_unique(std::move(Prob)); @@ -167,20 +172,14 @@ Firestarter::Firestarter(Config&& ProvidedConfig) } } - Environment->printSelectedCodePathSummary(); + FunctionPtr->printCodePathSummary(); - { - std::stringstream Ss; - - Topology->printSystemSummary(Ss); - Ss << "\n"; - Ss << Environment->processorInfos(); - Topology->printCacheSummary(Ss); - - log::info() << Ss.str(); - } + Topology.printSystemSummary(); + log::info(); + ProcessorInfos->print(); + Topology.printCacheSummary(); - Affinity.printThreadSummary(*Topology); + Affinity.printThreadSummary(Topology); // setup thread with either high or low load configured at the start // low loads has to know the length of the period @@ -229,7 +228,7 @@ void Firestarter::mainThread() { Firestarter::Optimizer->join(); Firestarter::Optimizer.reset(); - auto PayloadItems = Environment->config().settings().instructionGroupItems(); + const auto PayloadItems = FunctionPtr->constRef().settings().groups().intructions(); firestarter::optimizer::History::save(Cfg.OptimizeOutfile, StartTime, PayloadItems, Cfg.Argc, Cfg.Argv); diff --git a/src/firestarter/FunctionSelection.cpp b/src/firestarter/FunctionSelection.cpp new file mode 100644 index 00000000..755165d0 --- /dev/null +++ b/src/firestarter/FunctionSelection.cpp @@ -0,0 +1,154 @@ +/****************************************************************************** + * FIRESTARTER - A Processor Stress Test Utility + * Copyright (C) 2020-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/FunctionSelection.hpp" +#include "firestarter/Logging/Log.hpp" +#include "firestarter/Platform/PlatformConfigAndThreads.hpp" + +#include +#include +#include + +namespace firestarter { + +auto FunctionSelection::selectAvailableFunction(unsigned FunctionId, const CpuFeatures& Features, + std::optional InstructionCacheSize, + bool AllowUnavailablePayload) const + -> std::unique_ptr { + unsigned Id = 1; + std::optional DefaultPayloadName; + + for (const auto& Platform : platform::PlatformConfigAndThreads::fromPlatformConfigs(platformConfigs())) { + // the selected function + if (Id == FunctionId) { + if (!Platform.Config->payload()->isAvailable(Features)) { + const auto ErrorString = "Function " + std::to_string(FunctionId) + " (\"" + + Platform.Config->functionName(Platform.ThreadCount) + "\") requires " + + Platform.Config->payload()->name() + ", which is not supported by the processor."; + if (AllowUnavailablePayload) { + log::warn() << ErrorString; + } else { + throw std::invalid_argument(ErrorString); + } + } + // found function + return Platform.Config->cloneConcreate(InstructionCacheSize, Platform.ThreadCount); + } + Id++; + } + + throw std::invalid_argument("unknown function id: " + std::to_string(FunctionId) + ", see --avail for available ids"); +} + +auto FunctionSelection::selectDefaultOrFallbackFunction(const CpuModel& Model, const CpuFeatures& Features, + const std::string& VendorString, const std::string& ModelString, + std::optional InstructionCacheSize, + unsigned NumThreadsPerCore) const + -> std::unique_ptr { + std::optional DefaultPayloadName; + + for (const auto& Platform : platform::PlatformConfigAndThreads::fromPlatformConfigs(platformConfigs())) { + // default function + if (Platform.Config->isDefault(Model, Features)) { + if (Platform.ThreadCount == NumThreadsPerCore) { + return Platform.Config->cloneConcreate(InstructionCacheSize, Platform.ThreadCount); + } + DefaultPayloadName = Platform.Config->payload()->name(); + } + } + + // no default found + // use fallback + if (DefaultPayloadName) { + // default payload available, but number of threads per core is not + // supported + log::warn() << "No " << *DefaultPayloadName << " code path for " << NumThreadsPerCore << " threads per core!"; + } + log::warn() << VendorString << " " << ModelString << " is not supported by this version of FIRESTARTER!\n" + << "Check project website for updates."; + + // loop over available implementation and check if they are marked as + // fallback + for (const auto& FallbackPlatformConfigPtr : fallbackPlatformConfigs()) { + if (FallbackPlatformConfigPtr->payload()->isAvailable(Features)) { + unsigned SelectedThreadsPerCore{}; + + // find the fallback implementation with the correct thread per core count or select the first available thread + // per core count + { + const auto& Threads = FallbackPlatformConfigPtr->constRef().settings().threads(); + const auto& ThreadIt = std::find(Threads.cbegin(), Threads.cend(), NumThreadsPerCore); + if (ThreadIt == Threads.cend()) { + SelectedThreadsPerCore = Threads.front(); + } else { + SelectedThreadsPerCore = *ThreadIt; + } + } + + log::warn() << "Using function " << FallbackPlatformConfigPtr->functionName(SelectedThreadsPerCore) + << " as fallback.\n" + << "You can use the parameter --function to try other " + "functions."; + return FallbackPlatformConfigPtr->cloneConcreate(InstructionCacheSize, SelectedThreadsPerCore); + } + } + + // no fallback found + throw std::invalid_argument("No fallback implementation found for available ISA " + "extensions."); +} + +auto FunctionSelection::selectFunction(std::optional FunctionId, const ProcessorInformation& ProcessorInfos, + const CPUTopology& Topology, bool AllowUnavailablePayload) const + -> std::unique_ptr { + if (FunctionId) { + return selectAvailableFunction(*FunctionId, ProcessorInfos.cpuFeatures(), Topology.instructionCacheSize(), + AllowUnavailablePayload); + } + return selectDefaultOrFallbackFunction( + ProcessorInfos.cpuModel(), ProcessorInfos.cpuFeatures(), ProcessorInfos.vendor(), ProcessorInfos.model(), + Topology.instructionCacheSize(), Topology.homogenousResourceCount().NumThreadsPerCore); +} + +void FunctionSelection::printFunctionSummary(const ProcessorInformation& ProcessorInfos, bool ForceYes) const { + log::info() << " available load-functions:\n" + << " ID | NAME | available on this " + "system | payload default setting\n" + << " " + "-------------------------------------------------------------" + "-------------------------------------------------------------" + "-----------------------------"; + + auto Id = 1U; + + for (const auto& Platform : platform::PlatformConfigAndThreads::fromPlatformConfigs(platformConfigs())) { + const char* Available = + (Platform.Config->payload()->isAvailable(ProcessorInfos.cpuFeatures()) || ForceYes) ? "yes" : "no"; + const auto& FunctionName = Platform.Config->functionName(Platform.ThreadCount); + const auto& InstructionGroupsString = Platform.Config->constRef().settings().groups(); + + log::info() << " " << std::right << std::setw(4) << Id << " | " << std::left << std::setw(30) << FunctionName + << " | " << std::left << std::setw(24) << Available << " | " << InstructionGroupsString; + Id++; + } +} + +} // namespace firestarter \ No newline at end of file diff --git a/src/firestarter/LoadWorker.cpp b/src/firestarter/LoadWorker.cpp index ab5cf13f..4cd6769f 100644 --- a/src/firestarter/LoadWorker.cpp +++ b/src/firestarter/LoadWorker.cpp @@ -49,7 +49,7 @@ namespace firestarter { void Firestarter::initLoadWorkers(const ThreadAffinity& Affinity) { // Bind this thread to the first available CPU. - Topology->bindCallerToOsIndex(*Affinity.CpuBind.cbegin()); + Topology.bindCallerToOsIndex(*Affinity.CpuBind.cbegin()); // setup load variable to execute low or high load once the threads switch to // work. @@ -72,8 +72,9 @@ void Firestarter::initLoadWorkers(const ThreadAffinity& Affinity) { uint64_t I = 0; for (const auto& OsIndex : Affinity.CpuBind) { - auto Td = std::make_shared(I, OsIndex, std::cref(*Environment), std::cref(*Topology), - std::ref(LoadVar), Cfg.Period, Cfg.DumpRegisters, Cfg.ErrorDetection); + auto Td = std::make_shared(I, OsIndex, std::cref(ProcessorInfos), std::cref(FunctionPtr), + std::cref(Topology), std::ref(LoadVar), Cfg.Period, Cfg.DumpRegisters, + Cfg.ErrorDetection); if (Cfg.ErrorDetection) { // distribute pointers for error deteciton. (set threads in a ring) @@ -195,8 +196,8 @@ void Firestarter::printPerformanceReport() { Iterations += Td->LastRun.Iterations.load(); } - double const Runtime = static_cast(StopTimestamp - StartTimestamp) / - static_cast(Environment->processorInfos().clockrate()); + double const Runtime = + static_cast(StopTimestamp - StartTimestamp) / static_cast(ProcessorInfos->clockrate()); double const GFlops = static_cast(LoadThreads.front().second->CompiledPayloadPtr->stats().Flops) * 0.000000001 * static_cast(Iterations) / Runtime; double const Bandwidth = static_cast(LoadThreads.front().second->CompiledPayloadPtr->stats().Bytes) * @@ -307,7 +308,7 @@ void Firestarter::loadThreadWorker(const std::shared_ptr& Td) { case LoadThreadState::ThreadWork: Td->CurrentRun.Iterations = 0; // record threads start timestamp - Td->CurrentRun.StartTsc = Td->environment().processorInfos().timestamp(); + Td->CurrentRun.StartTsc = Td->ProcessorInfos->timestamp(); // will be terminated by watchdog for (;;) { @@ -340,14 +341,14 @@ void Firestarter::loadThreadWorker(const std::shared_ptr& Td) { // terminate if master signals end of run and record stop timestamp if (Td->LoadVar == LoadThreadWorkType::LoadStop) { - Td->CurrentRun.StopTsc = Td->environment().processorInfos().timestamp(); + Td->CurrentRun.StopTsc = Td->ProcessorInfos->timestamp(); Td->LastRun = Td->CurrentRun; return; } if (Td->LoadVar == LoadThreadWorkType::LoadSwitch) { - Td->CurrentRun.StopTsc = Td->environment().processorInfos().timestamp(); + Td->CurrentRun.StopTsc = Td->ProcessorInfos->timestamp(); Td->LastRun = Td->CurrentRun; break; diff --git a/src/firestarter/Environment/Payload/CompiledPayload.cpp b/src/firestarter/Payload/CompiledPayload.cpp similarity index 85% rename from src/firestarter/Environment/Payload/CompiledPayload.cpp rename to src/firestarter/Payload/CompiledPayload.cpp index 33183d7a..596332ff 100644 --- a/src/firestarter/Environment/Payload/CompiledPayload.cpp +++ b/src/firestarter/Payload/CompiledPayload.cpp @@ -19,10 +19,10 @@ * Contact: daniel.hackenberg@tu-dresden.de *****************************************************************************/ -#include "firestarter/Environment/Payload/CompiledPayload.hpp" -#include "firestarter/Environment/Payload/Payload.hpp" +#include "firestarter/Payload/CompiledPayload.hpp" +#include "firestarter/Payload/Payload.hpp" -namespace firestarter::environment::payload { +namespace firestarter::payload { void CompiledPayload::init(double* MemoryAddr, uint64_t BufferSize) { PayloadPtr->init(MemoryAddr, BufferSize); } @@ -30,4 +30,4 @@ void CompiledPayload::lowLoadFunction(volatile LoadThreadWorkType& LoadVar, std: PayloadPtr->lowLoadFunction(LoadVar, Period); }; -}; // namespace firestarter::environment::payload \ No newline at end of file +}; // namespace firestarter::payload \ No newline at end of file diff --git a/src/firestarter/Environment/Payload/PayloadSettings.cpp b/src/firestarter/Payload/PayloadSettings.cpp similarity index 89% rename from src/firestarter/Environment/Payload/PayloadSettings.cpp rename to src/firestarter/Payload/PayloadSettings.cpp index 25ca4ea4..560ce787 100644 --- a/src/firestarter/Environment/Payload/PayloadSettings.cpp +++ b/src/firestarter/Payload/PayloadSettings.cpp @@ -19,12 +19,13 @@ * Contact: daniel.hackenberg@tu-dresden.de *****************************************************************************/ -#include "firestarter/Environment/Payload/PayloadSettings.hpp" +#include "firestarter/Payload/PayloadSettings.hpp" +#include "firestarter/Config/InstructionGroups.hpp" #include #include -namespace firestarter::environment::payload { +namespace firestarter::payload { auto PayloadSettings::getSequenceStartCount(const std::vector& Sequence, const std::string& Start) -> unsigned { @@ -39,9 +40,8 @@ auto PayloadSettings::getSequenceStartCount(const std::vector& Sequ return I; } -auto PayloadSettings::generateSequence(std::vector const& Proportions) - -> std::vector { - std::vector> Prop = Proportions; +auto PayloadSettings::generateSequence(InstructionGroups const& Proportions) -> std::vector { + auto Prop = static_cast(Proportions); Prop.erase(std::remove_if(Prop.begin(), Prop.end(), [](auto const& Pair) { return Pair.second == 0; }), Prop.end()); @@ -95,4 +95,4 @@ auto PayloadSettings::getRAMLoopCount(const std::vector& Sequence, (1.0 * Size / 64 / (getRAMSequenceCount(Sequence) * getNumberOfSequenceRepetitions(Sequence, NumberOfLines)))); } -}; // namespace firestarter::environment::payload \ No newline at end of file +}; // namespace firestarter::payload \ No newline at end of file diff --git a/src/firestarter/Environment/ProcessorInformation.cpp b/src/firestarter/ProcessorInformation.cpp similarity index 86% rename from src/firestarter/Environment/ProcessorInformation.cpp rename to src/firestarter/ProcessorInformation.cpp index 9f99daa7..ad86b4d2 100644 --- a/src/firestarter/Environment/ProcessorInformation.cpp +++ b/src/firestarter/ProcessorInformation.cpp @@ -19,7 +19,7 @@ * Contact: daniel.hackenberg@tu-dresden.de *****************************************************************************/ -#include "firestarter/Environment/ProcessorInformation.hpp" +#include "firestarter/ProcessorInformation.hpp" #include "firestarter/Logging/Log.hpp" #include @@ -30,28 +30,29 @@ #include #endif -namespace firestarter::environment { +namespace firestarter { -auto ProcessorInformation::print(std::ostream& Stream) const -> std::ostream& { +void ProcessorInformation::print() const { std::stringstream Ss; for (auto const& Entry : features()) { Ss << Entry << " "; } - Stream << " processor characteristics:\n" - << " architecture: " << architecture() << "\n" - << " vendor: " << vendor() << "\n" - << " processor-name: " << processorName() << "\n" - << " model: " << model() << "\n" - << " frequency: " << clockrate() / 1000000 << " MHz\n" - << " supported features: " << Ss.str() << "\n"; - - return Stream; + log::info() << " processor characteristics:\n" + << " architecture: " << architecture() << "\n" + << " vendor: " << vendor() << "\n" + << " processor-name: " << processorName() << "\n" + << " model: " << model() << "\n" + << " frequency: " << clockrate() / 1000000 << " MHz\n" + << " supported features: " << Ss.str(); } -ProcessorInformation::ProcessorInformation(std::string Architecture) - : Architecture(std::move(Architecture)) { +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 #if defined(linux) || defined(__linux__) @@ -188,4 +189,4 @@ auto ProcessorInformation::scalingGovernor() -> std::string { return getFileAsStream("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor").str(); } -}; // namespace firestarter::environment \ No newline at end of file +}; // namespace firestarter \ No newline at end of file diff --git a/src/firestarter/Environment/X86/Payload/AVX512Payload.cpp b/src/firestarter/X86/Payload/AVX512Payload.cpp similarity index 94% rename from src/firestarter/Environment/X86/Payload/AVX512Payload.cpp rename to src/firestarter/X86/Payload/AVX512Payload.cpp index 88d02440..6ddc3a8f 100644 --- a/src/firestarter/Environment/X86/Payload/AVX512Payload.cpp +++ b/src/firestarter/X86/Payload/AVX512Payload.cpp @@ -19,14 +19,14 @@ * Contact: daniel.hackenberg@tu-dresden.de *****************************************************************************/ -#include "firestarter/Environment/X86/Payload/AVX512Payload.hpp" -#include "firestarter/Environment/X86/Payload/CompiledX86Payload.hpp" +#include "firestarter/X86/Payload/AVX512Payload.hpp" +#include "firestarter/X86/Payload/CompiledX86Payload.hpp" -namespace firestarter::environment::x86::payload { +namespace firestarter::x86::payload { -auto AVX512Payload::compilePayload(const environment::payload::PayloadSettings& Settings, bool DumpRegisters, +auto AVX512Payload::compilePayload(const firestarter::payload::PayloadSettings& Settings, bool DumpRegisters, bool ErrorDetection, bool PrintAssembler) const - -> environment::payload::CompiledPayload::UniquePtr { + -> firestarter::payload::CompiledPayload::UniquePtr { using Imm = asmjit::Imm; using Zmm = asmjit::x86::Zmm; // NOLINTBEGIN(readability-identifier-naming) @@ -40,10 +40,10 @@ auto AVX512Payload::compilePayload(const environment::payload::PayloadSettings& // to reach the desired size auto Sequence = Settings.sequence(); auto Repetitions = - environment::payload::PayloadSettings::getNumberOfSequenceRepetitions(Sequence, Settings.linesPerThread()); + firestarter::payload::PayloadSettings::getNumberOfSequenceRepetitions(Sequence, Settings.linesPerThread()); // compute count of flops and memory access for performance report - environment::payload::PayloadStats Stats; + firestarter::payload::PayloadStats Stats; for (const auto& Item : Sequence) { auto It = instructionFlops().find(Item); @@ -78,11 +78,11 @@ auto AVX512Payload::compilePayload(const environment::payload::PayloadSettings& // calculate the reset counters for the buffers const auto L2LoopCount = - environment::payload::PayloadSettings::getL2LoopCount(Sequence, Settings.linesPerThread(), L2Size); + firestarter::payload::PayloadSettings::getL2LoopCount(Sequence, Settings.linesPerThread(), L2Size); const auto L3LoopCount = - environment::payload::PayloadSettings::getL3LoopCount(Sequence, Settings.linesPerThread(), L3Size); + firestarter::payload::PayloadSettings::getL3LoopCount(Sequence, Settings.linesPerThread(), L3Size); const auto RamLoopCount = - environment::payload::PayloadSettings::getRAMLoopCount(Sequence, Settings.linesPerThread(), RamSize); + firestarter::payload::PayloadSettings::getRAMLoopCount(Sequence, Settings.linesPerThread(), RamSize); asmjit::CodeHolder Code; Code.init(asmjit::Environment::host()); @@ -303,7 +303,7 @@ auto AVX512Payload::compilePayload(const environment::payload::PayloadSettings& } Cb.movq(TempReg, IterReg); // restore iteration counter - if (environment::payload::PayloadSettings::getRAMSequenceCount(Sequence) > 0) { + if (firestarter::payload::PayloadSettings::getRAMSequenceCount(Sequence) > 0) { // reset RAM counter auto NoRamReset = Cb.newLabel(); @@ -317,7 +317,7 @@ auto AVX512Payload::compilePayload(const environment::payload::PayloadSettings& Stats.Instructions += 2; } Cb.inc(TempReg); // increment iteration counter - if (environment::payload::PayloadSettings::getL2SequenceCount(Sequence) > 0) { + if (firestarter::payload::PayloadSettings::getL2SequenceCount(Sequence) > 0) { // reset L2-Cache counter auto NoL2Reset = Cb.newLabel(); @@ -331,7 +331,7 @@ auto AVX512Payload::compilePayload(const environment::payload::PayloadSettings& Stats.Instructions += 2; } Cb.movq(IterReg, TempReg); // store iteration counter - if (environment::payload::PayloadSettings::getL3SequenceCount(Sequence) > 0) { + if (firestarter::payload::PayloadSettings::getL3SequenceCount(Sequence) > 0) { // reset L3-Cache counter auto NoL3Reset = Cb.newLabel(); @@ -393,4 +393,4 @@ void AVX512Payload::init(double* MemoryAddr, uint64_t BufferSize) const { X86Payload::initMemory(MemoryAddr, BufferSize, 0.27948995982e-4, 0.27948995982e-4); } -} // namespace firestarter::environment::x86::payload \ No newline at end of file +} // namespace firestarter::x86::payload \ No newline at end of file diff --git a/src/firestarter/Environment/X86/Payload/AVXPayload.cpp b/src/firestarter/X86/Payload/AVXPayload.cpp similarity index 94% rename from src/firestarter/Environment/X86/Payload/AVXPayload.cpp rename to src/firestarter/X86/Payload/AVXPayload.cpp index 82ded951..a403acd1 100644 --- a/src/firestarter/Environment/X86/Payload/AVXPayload.cpp +++ b/src/firestarter/X86/Payload/AVXPayload.cpp @@ -19,14 +19,14 @@ * Contact: daniel.hackenberg@tu-dresden.de *****************************************************************************/ -#include "firestarter/Environment/X86/Payload/AVXPayload.hpp" -#include "firestarter/Environment/X86/Payload/CompiledX86Payload.hpp" +#include "firestarter/X86/Payload/AVXPayload.hpp" +#include "firestarter/X86/Payload/CompiledX86Payload.hpp" -namespace firestarter::environment::x86::payload { +namespace firestarter::x86::payload { -auto AVXPayload::compilePayload(const environment::payload::PayloadSettings& Settings, bool DumpRegisters, +auto AVXPayload::compilePayload(const firestarter::payload::PayloadSettings& Settings, bool DumpRegisters, bool ErrorDetection, bool PrintAssembler) const - -> environment::payload::CompiledPayload::UniquePtr { + -> firestarter::payload::CompiledPayload::UniquePtr { using Imm = asmjit::Imm; using Mm = asmjit::x86::Mm; using Xmm = asmjit::x86::Xmm; @@ -38,10 +38,10 @@ auto AVXPayload::compilePayload(const environment::payload::PayloadSettings& Set // to reach the desired size auto Sequence = Settings.sequence(); auto Repetitions = - environment::payload::PayloadSettings::getNumberOfSequenceRepetitions(Sequence, Settings.linesPerThread()); + firestarter::payload::PayloadSettings::getNumberOfSequenceRepetitions(Sequence, Settings.linesPerThread()); // compute count of flops and memory access for performance report - environment::payload::PayloadStats Stats; + firestarter::payload::PayloadStats Stats; for (const auto& Item : Sequence) { auto It = instructionFlops().find(Item); @@ -76,11 +76,11 @@ auto AVXPayload::compilePayload(const environment::payload::PayloadSettings& Set // calculate the reset counters for the buffers const auto L2LoopCount = - environment::payload::PayloadSettings::getL2LoopCount(Sequence, Settings.linesPerThread(), L2Size); + firestarter::payload::PayloadSettings::getL2LoopCount(Sequence, Settings.linesPerThread(), L2Size); const auto L3LoopCount = - environment::payload::PayloadSettings::getL3LoopCount(Sequence, Settings.linesPerThread(), L3Size); + firestarter::payload::PayloadSettings::getL3LoopCount(Sequence, Settings.linesPerThread(), L3Size); const auto RamLoopCount = - environment::payload::PayloadSettings::getRAMLoopCount(Sequence, Settings.linesPerThread(), RamSize); + firestarter::payload::PayloadSettings::getRAMLoopCount(Sequence, Settings.linesPerThread(), RamSize); asmjit::CodeHolder Code; Code.init(asmjit::Environment::host()); @@ -334,7 +334,7 @@ auto AVXPayload::compilePayload(const environment::payload::PayloadSettings& Set } } - if (environment::payload::PayloadSettings::getRAMSequenceCount(Sequence) > 0) { + if (firestarter::payload::PayloadSettings::getRAMSequenceCount(Sequence) > 0) { // reset RAM counter auto NoRamReset = Cb.newLabel(); @@ -347,7 +347,7 @@ auto AVXPayload::compilePayload(const environment::payload::PayloadSettings& Set // adds always two instruction Stats.Instructions += 2; } - if (environment::payload::PayloadSettings::getL2SequenceCount(Sequence) > 0) { + if (firestarter::payload::PayloadSettings::getL2SequenceCount(Sequence) > 0) { // reset L2-Cache counter auto NoL2Reset = Cb.newLabel(); @@ -360,7 +360,7 @@ auto AVXPayload::compilePayload(const environment::payload::PayloadSettings& Set // adds always two instruction Stats.Instructions += 2; } - if (environment::payload::PayloadSettings::getL3SequenceCount(Sequence) > 0) { + if (firestarter::payload::PayloadSettings::getL3SequenceCount(Sequence) > 0) { // reset L3-Cache counter auto NoL3Reset = Cb.newLabel(); @@ -423,4 +423,4 @@ void AVXPayload::init(double* MemoryAddr, uint64_t BufferSize) const { X86Payload::initMemory(MemoryAddr, BufferSize, 1.654738925401e-10, 1.654738925401e-15); } -} // namespace firestarter::environment::x86::payload \ No newline at end of file +} // namespace firestarter::x86::payload \ No newline at end of file diff --git a/src/firestarter/Environment/X86/Payload/FMA4Payload.cpp b/src/firestarter/X86/Payload/FMA4Payload.cpp similarity index 94% rename from src/firestarter/Environment/X86/Payload/FMA4Payload.cpp rename to src/firestarter/X86/Payload/FMA4Payload.cpp index 91f3479a..9344212d 100644 --- a/src/firestarter/Environment/X86/Payload/FMA4Payload.cpp +++ b/src/firestarter/X86/Payload/FMA4Payload.cpp @@ -19,14 +19,14 @@ * Contact: daniel.hackenberg@tu-dresden.de *****************************************************************************/ -#include "firestarter/Environment/X86/Payload/FMA4Payload.hpp" -#include "firestarter/Environment/X86/Payload/CompiledX86Payload.hpp" +#include "firestarter/X86/Payload/FMA4Payload.hpp" +#include "firestarter/X86/Payload/CompiledX86Payload.hpp" -namespace firestarter::environment::x86::payload { +namespace firestarter::x86::payload { -auto FMA4Payload::compilePayload(const environment::payload::PayloadSettings& Settings, bool DumpRegisters, +auto FMA4Payload::compilePayload(const firestarter::payload::PayloadSettings& Settings, bool DumpRegisters, bool ErrorDetection, bool PrintAssembler) const - -> environment::payload::CompiledPayload::UniquePtr { + -> firestarter::payload::CompiledPayload::UniquePtr { using Imm = asmjit::Imm; using Xmm = asmjit::x86::Xmm; // NOLINTBEGIN(readability-identifier-naming) @@ -39,10 +39,10 @@ auto FMA4Payload::compilePayload(const environment::payload::PayloadSettings& Se // to reach the desired size auto Sequence = Settings.sequence(); auto Repetitions = - environment::payload::PayloadSettings::getNumberOfSequenceRepetitions(Sequence, Settings.linesPerThread()); + firestarter::payload::PayloadSettings::getNumberOfSequenceRepetitions(Sequence, Settings.linesPerThread()); // compute count of flops and memory access for performance report - environment::payload::PayloadStats Stats; + firestarter::payload::PayloadStats Stats; for (const auto& Item : Sequence) { auto It = instructionFlops().find(Item); @@ -77,11 +77,11 @@ auto FMA4Payload::compilePayload(const environment::payload::PayloadSettings& Se // calculate the reset counters for the buffers const auto L2LoopCount = - environment::payload::PayloadSettings::getL2LoopCount(Sequence, Settings.linesPerThread(), L2Size); + firestarter::payload::PayloadSettings::getL2LoopCount(Sequence, Settings.linesPerThread(), L2Size); const auto L3LoopCount = - environment::payload::PayloadSettings::getL3LoopCount(Sequence, Settings.linesPerThread(), L3Size); + firestarter::payload::PayloadSettings::getL3LoopCount(Sequence, Settings.linesPerThread(), L3Size); const auto RamLoopCount = - environment::payload::PayloadSettings::getRAMLoopCount(Sequence, Settings.linesPerThread(), RamSize); + firestarter::payload::PayloadSettings::getRAMLoopCount(Sequence, Settings.linesPerThread(), RamSize); asmjit::CodeHolder Code; Code.init(asmjit::Environment::host()); @@ -305,7 +305,7 @@ auto FMA4Payload::compilePayload(const environment::payload::PayloadSettings& Se } Cb.movq(TempReg, IterReg); // restore iteration counter - if (environment::payload::PayloadSettings::getRAMSequenceCount(Sequence) > 0) { + if (firestarter::payload::PayloadSettings::getRAMSequenceCount(Sequence) > 0) { // reset RAM counter auto NoRamReset = Cb.newLabel(); @@ -319,7 +319,7 @@ auto FMA4Payload::compilePayload(const environment::payload::PayloadSettings& Se Stats.Instructions += 2; } Cb.inc(TempReg); // increment iteration counter - if (environment::payload::PayloadSettings::getL2SequenceCount(Sequence) > 0) { + if (firestarter::payload::PayloadSettings::getL2SequenceCount(Sequence) > 0) { // reset L2-Cache counter auto NoL2Reset = Cb.newLabel(); @@ -333,7 +333,7 @@ auto FMA4Payload::compilePayload(const environment::payload::PayloadSettings& Se Stats.Instructions += 2; } Cb.movq(IterReg, TempReg); // store iteration counter - if (environment::payload::PayloadSettings::getL3SequenceCount(Sequence) > 0) { + if (firestarter::payload::PayloadSettings::getL3SequenceCount(Sequence) > 0) { // reset L3-Cache counter auto NoL3Reset = Cb.newLabel(); @@ -396,4 +396,4 @@ void FMA4Payload::init(double* MemoryAddr, uint64_t BufferSize) const { X86Payload::initMemory(MemoryAddr, BufferSize, 0.27948995982e-4, 0.27948995982e-4); } -} // namespace firestarter::environment::x86::payload \ No newline at end of file +} // namespace firestarter::x86::payload \ No newline at end of file diff --git a/src/firestarter/Environment/X86/Payload/FMAPayload.cpp b/src/firestarter/X86/Payload/FMAPayload.cpp similarity index 94% rename from src/firestarter/Environment/X86/Payload/FMAPayload.cpp rename to src/firestarter/X86/Payload/FMAPayload.cpp index 03b8995c..86953aa3 100644 --- a/src/firestarter/Environment/X86/Payload/FMAPayload.cpp +++ b/src/firestarter/X86/Payload/FMAPayload.cpp @@ -19,14 +19,14 @@ * Contact: daniel.hackenberg@tu-dresden.de *****************************************************************************/ -#include "firestarter/Environment/X86/Payload/FMAPayload.hpp" -#include "firestarter/Environment/X86/Payload/CompiledX86Payload.hpp" +#include "firestarter/X86/Payload/FMAPayload.hpp" +#include "firestarter/X86/Payload/CompiledX86Payload.hpp" -namespace firestarter::environment::x86::payload { +namespace firestarter::x86::payload { -auto FMAPayload::compilePayload(const environment::payload::PayloadSettings& Settings, bool DumpRegisters, +auto FMAPayload::compilePayload(const firestarter::payload::PayloadSettings& Settings, bool DumpRegisters, bool ErrorDetection, bool PrintAssembler) const - -> environment::payload::CompiledPayload::UniquePtr { + -> firestarter::payload::CompiledPayload::UniquePtr { using Imm = asmjit::Imm; using Xmm = asmjit::x86::Xmm; using Ymm = asmjit::x86::Ymm; @@ -41,10 +41,10 @@ auto FMAPayload::compilePayload(const environment::payload::PayloadSettings& Set // to reach the desired size auto Sequence = Settings.sequence(); auto Repetitions = - environment::payload::PayloadSettings::getNumberOfSequenceRepetitions(Sequence, Settings.linesPerThread()); + firestarter::payload::PayloadSettings::getNumberOfSequenceRepetitions(Sequence, Settings.linesPerThread()); // compute count of flops and memory access for performance report - environment::payload::PayloadStats Stats; + firestarter::payload::PayloadStats Stats; for (const auto& Item : Sequence) { auto It = instructionFlops().find(Item); @@ -79,11 +79,11 @@ auto FMAPayload::compilePayload(const environment::payload::PayloadSettings& Set // calculate the reset counters for the buffers const auto L2LoopCount = - environment::payload::PayloadSettings::getL2LoopCount(Sequence, Settings.linesPerThread(), L2Size); + firestarter::payload::PayloadSettings::getL2LoopCount(Sequence, Settings.linesPerThread(), L2Size); const auto L3LoopCount = - environment::payload::PayloadSettings::getL3LoopCount(Sequence, Settings.linesPerThread(), L3Size); + firestarter::payload::PayloadSettings::getL3LoopCount(Sequence, Settings.linesPerThread(), L3Size); const auto RamLoopCount = - environment::payload::PayloadSettings::getRAMLoopCount(Sequence, Settings.linesPerThread(), RamSize); + firestarter::payload::PayloadSettings::getRAMLoopCount(Sequence, Settings.linesPerThread(), RamSize); asmjit::CodeHolder Code; Code.init(asmjit::Environment::host()); @@ -341,7 +341,7 @@ auto FMAPayload::compilePayload(const environment::payload::PayloadSettings& Set } Cb.movq(TempReg, IterReg); // restore iteration counter - if (environment::payload::PayloadSettings::getRAMSequenceCount(Sequence) > 0) { + if (firestarter::payload::PayloadSettings::getRAMSequenceCount(Sequence) > 0) { // reset RAM counter auto NoRamReset = Cb.newLabel(); @@ -355,7 +355,7 @@ auto FMAPayload::compilePayload(const environment::payload::PayloadSettings& Set Stats.Instructions += 2; } Cb.inc(TempReg); // increment iteration counter - if (environment::payload::PayloadSettings::getL2SequenceCount(Sequence) > 0) { + if (firestarter::payload::PayloadSettings::getL2SequenceCount(Sequence) > 0) { // reset L2-Cache counter auto NoL2Reset = Cb.newLabel(); @@ -369,7 +369,7 @@ auto FMAPayload::compilePayload(const environment::payload::PayloadSettings& Set Stats.Instructions += 2; } Cb.movq(IterReg, TempReg); // store iteration counter - if (environment::payload::PayloadSettings::getL3SequenceCount(Sequence) > 0) { + if (firestarter::payload::PayloadSettings::getL3SequenceCount(Sequence) > 0) { // reset L3-Cache counter auto NoL3Reset = Cb.newLabel(); @@ -431,4 +431,4 @@ void FMAPayload::init(double* MemoryAddr, uint64_t BufferSize) const { X86Payload::initMemory(MemoryAddr, BufferSize, 0.27948995982e-4, 0.27948995982e-4); } -} // namespace firestarter::environment::x86::payload \ No newline at end of file +} // namespace firestarter::x86::payload \ No newline at end of file diff --git a/src/firestarter/Environment/X86/Payload/SSE2Payload.cpp b/src/firestarter/X86/Payload/SSE2Payload.cpp similarity index 94% rename from src/firestarter/Environment/X86/Payload/SSE2Payload.cpp rename to src/firestarter/X86/Payload/SSE2Payload.cpp index 8f443781..076f7083 100644 --- a/src/firestarter/Environment/X86/Payload/SSE2Payload.cpp +++ b/src/firestarter/X86/Payload/SSE2Payload.cpp @@ -19,14 +19,14 @@ * Contact: daniel.hackenberg@tu-dresden.de *****************************************************************************/ -#include "firestarter/Environment/X86/Payload/SSE2Payload.hpp" -#include "firestarter/Environment/X86/Payload/CompiledX86Payload.hpp" +#include "firestarter/X86/Payload/SSE2Payload.hpp" +#include "firestarter/X86/Payload/CompiledX86Payload.hpp" -namespace firestarter::environment::x86::payload { +namespace firestarter::x86::payload { -auto SSE2Payload::compilePayload(const environment::payload::PayloadSettings& Settings, bool DumpRegisters, +auto SSE2Payload::compilePayload(const firestarter::payload::PayloadSettings& Settings, bool DumpRegisters, bool ErrorDetection, bool PrintAssembler) const - -> environment::payload::CompiledPayload::UniquePtr { + -> firestarter::payload::CompiledPayload::UniquePtr { using Imm = asmjit::Imm; using Mm = asmjit::x86::Mm; using Xmm = asmjit::x86::Xmm; @@ -37,10 +37,10 @@ auto SSE2Payload::compilePayload(const environment::payload::PayloadSettings& Se // to reach the desired size auto Sequence = Settings.sequence(); auto Repetitions = - environment::payload::PayloadSettings::getNumberOfSequenceRepetitions(Sequence, Settings.linesPerThread()); + firestarter::payload::PayloadSettings::getNumberOfSequenceRepetitions(Sequence, Settings.linesPerThread()); // compute count of flops and memory access for performance report - environment::payload::PayloadStats Stats; + firestarter::payload::PayloadStats Stats; for (const auto& Item : Sequence) { auto It = instructionFlops().find(Item); @@ -75,11 +75,11 @@ auto SSE2Payload::compilePayload(const environment::payload::PayloadSettings& Se // calculate the reset counters for the buffers const auto L2LoopCount = - environment::payload::PayloadSettings::getL2LoopCount(Sequence, Settings.linesPerThread(), L2Size); + firestarter::payload::PayloadSettings::getL2LoopCount(Sequence, Settings.linesPerThread(), L2Size); const auto L3LoopCount = - environment::payload::PayloadSettings::getL3LoopCount(Sequence, Settings.linesPerThread(), L3Size); + firestarter::payload::PayloadSettings::getL3LoopCount(Sequence, Settings.linesPerThread(), L3Size); const auto RamLoopCount = - environment::payload::PayloadSettings::getRAMLoopCount(Sequence, Settings.linesPerThread(), RamSize); + firestarter::payload::PayloadSettings::getRAMLoopCount(Sequence, Settings.linesPerThread(), RamSize); asmjit::CodeHolder Code; Code.init(asmjit::Environment::host()); @@ -325,7 +325,7 @@ auto SSE2Payload::compilePayload(const environment::payload::PayloadSettings& Se } } - if (environment::payload::PayloadSettings::getRAMSequenceCount(Sequence) > 0) { + if (firestarter::payload::PayloadSettings::getRAMSequenceCount(Sequence) > 0) { // reset RAM counter auto NoRamReset = Cb.newLabel(); @@ -338,7 +338,7 @@ auto SSE2Payload::compilePayload(const environment::payload::PayloadSettings& Se // adds always two instruction Stats.Instructions += 2; } - if (environment::payload::PayloadSettings::getL2SequenceCount(Sequence) > 0) { + if (firestarter::payload::PayloadSettings::getL2SequenceCount(Sequence) > 0) { // reset L2-Cache counter auto NoL2Reset = Cb.newLabel(); @@ -351,7 +351,7 @@ auto SSE2Payload::compilePayload(const environment::payload::PayloadSettings& Se // adds always two instruction Stats.Instructions += 2; } - if (environment::payload::PayloadSettings::getL3SequenceCount(Sequence) > 0) { + if (firestarter::payload::PayloadSettings::getL3SequenceCount(Sequence) > 0) { // reset L3-Cache counter auto NoL3Reset = Cb.newLabel(); @@ -414,4 +414,4 @@ void SSE2Payload::init(double* MemoryAddr, uint64_t BufferSize) const { X86Payload::initMemory(MemoryAddr, BufferSize, 1.654738925401e-10, 1.654738925401e-15); } -} // namespace firestarter::environment::x86::payload \ No newline at end of file +} // namespace firestarter::x86::payload \ No newline at end of file diff --git a/src/firestarter/Environment/X86/Payload/X86Payload.cpp b/src/firestarter/X86/Payload/X86Payload.cpp similarity index 95% rename from src/firestarter/Environment/X86/Payload/X86Payload.cpp rename to src/firestarter/X86/Payload/X86Payload.cpp index 296d1052..a70b423e 100644 --- a/src/firestarter/Environment/X86/Payload/X86Payload.cpp +++ b/src/firestarter/X86/Payload/X86Payload.cpp @@ -19,7 +19,7 @@ * Contact: daniel.hackenberg@tu-dresden.de *****************************************************************************/ -#include "firestarter/Environment/X86/Payload/X86Payload.hpp" +#include "firestarter/X86/Payload/X86Payload.hpp" #include "firestarter/Constants.hpp" #include "firestarter/WindowsCompat.hpp" @@ -27,7 +27,7 @@ #include #include -namespace firestarter::environment::x86::payload { +namespace firestarter::x86::payload { void X86Payload::lowLoadFunction(volatile LoadThreadWorkType& LoadVar, std::chrono::microseconds Period) const { auto Nap = Period / 100; @@ -91,4 +91,4 @@ auto X86Payload::getAvailableInstructions() const -> std::list { return Instructions; } -}; // namespace firestarter::environment::x86::payload \ No newline at end of file +}; // namespace firestarter::x86::payload \ No newline at end of file diff --git a/src/firestarter/Environment/X86/Payload/ZENFMAPayload.cpp b/src/firestarter/X86/Payload/ZENFMAPayload.cpp similarity index 93% rename from src/firestarter/Environment/X86/Payload/ZENFMAPayload.cpp rename to src/firestarter/X86/Payload/ZENFMAPayload.cpp index f12dca1d..93e2b4a8 100644 --- a/src/firestarter/Environment/X86/Payload/ZENFMAPayload.cpp +++ b/src/firestarter/X86/Payload/ZENFMAPayload.cpp @@ -19,14 +19,14 @@ * Contact: daniel.hackenberg@tu-dresden.de *****************************************************************************/ -#include "firestarter/Environment/X86/Payload/ZENFMAPayload.hpp" -#include "firestarter/Environment/X86/Payload/CompiledX86Payload.hpp" +#include "firestarter/X86/Payload/ZENFMAPayload.hpp" +#include "firestarter/X86/Payload/CompiledX86Payload.hpp" -namespace firestarter::environment::x86::payload { +namespace firestarter::x86::payload { -auto ZENFMAPayload::compilePayload(const environment::payload::PayloadSettings& Settings, bool DumpRegisters, +auto ZENFMAPayload::compilePayload(const firestarter::payload::PayloadSettings& Settings, bool DumpRegisters, bool ErrorDetection, bool PrintAssembler) const - -> environment::payload::CompiledPayload::UniquePtr { + -> firestarter::payload::CompiledPayload::UniquePtr { using Imm = asmjit::Imm; using Xmm = asmjit::x86::Xmm; using Ymm = asmjit::x86::Ymm; @@ -37,10 +37,10 @@ auto ZENFMAPayload::compilePayload(const environment::payload::PayloadSettings& // to reach the desired size auto Sequence = Settings.sequence(); auto Repetitions = - environment::payload::PayloadSettings::getNumberOfSequenceRepetitions(Sequence, Settings.linesPerThread()); + firestarter::payload::PayloadSettings::getNumberOfSequenceRepetitions(Sequence, Settings.linesPerThread()); // compute count of flops and memory access for performance report - environment::payload::PayloadStats Stats; + firestarter::payload::PayloadStats Stats; for (const auto& Item : Sequence) { auto It = instructionFlops().find(Item); @@ -75,11 +75,11 @@ auto ZENFMAPayload::compilePayload(const environment::payload::PayloadSettings& // calculate the reset counters for the buffers const auto L2LoopCount = - environment::payload::PayloadSettings::getL2LoopCount(Sequence, Settings.linesPerThread(), L2Size); + firestarter::payload::PayloadSettings::getL2LoopCount(Sequence, Settings.linesPerThread(), L2Size); const auto L3LoopCount = - environment::payload::PayloadSettings::getL3LoopCount(Sequence, Settings.linesPerThread(), L3Size); + firestarter::payload::PayloadSettings::getL3LoopCount(Sequence, Settings.linesPerThread(), L3Size); const auto RamLoopCount = - environment::payload::PayloadSettings::getRAMLoopCount(Sequence, Settings.linesPerThread(), RamSize); + firestarter::payload::PayloadSettings::getRAMLoopCount(Sequence, Settings.linesPerThread(), RamSize); asmjit::CodeHolder Code; Code.init(asmjit::Environment::host()); @@ -291,7 +291,7 @@ auto ZENFMAPayload::compilePayload(const environment::payload::PayloadSettings& } Cb.movq(TempReg, IterReg); // restore iteration counter - if (environment::payload::PayloadSettings::getRAMSequenceCount(Sequence) > 0) { + if (firestarter::payload::PayloadSettings::getRAMSequenceCount(Sequence) > 0) { // reset RAM counter auto NoRamReset = Cb.newLabel(); @@ -305,7 +305,7 @@ auto ZENFMAPayload::compilePayload(const environment::payload::PayloadSettings& Stats.Instructions += 2; } Cb.inc(TempReg); // increment iteration counter - if (environment::payload::PayloadSettings::getL2SequenceCount(Sequence) > 0) { + if (firestarter::payload::PayloadSettings::getL2SequenceCount(Sequence) > 0) { // reset L2-Cache counter auto NoL2Reset = Cb.newLabel(); @@ -319,7 +319,7 @@ auto ZENFMAPayload::compilePayload(const environment::payload::PayloadSettings& Stats.Instructions += 2; } Cb.movq(IterReg, TempReg); // store iteration counter - if (environment::payload::PayloadSettings::getL3SequenceCount(Sequence) > 0) { + if (firestarter::payload::PayloadSettings::getL3SequenceCount(Sequence) > 0) { // reset L3-Cache counter auto NoL3Reset = Cb.newLabel(); @@ -381,4 +381,4 @@ void ZENFMAPayload::init(double* MemoryAddr, uint64_t BufferSize) const { X86Payload::initMemory(MemoryAddr, BufferSize, 0.27948995982e-4, 0.27948995982e-4); } -} // namespace firestarter::environment::x86::payload \ No newline at end of file +} // namespace firestarter::x86::payload \ No newline at end of file diff --git a/src/firestarter/Environment/X86/Platform/X86PlatformConfig.cpp b/src/firestarter/X86/Platform/X86PlatformConfig.cpp similarity index 95% rename from src/firestarter/Environment/X86/Platform/X86PlatformConfig.cpp rename to src/firestarter/X86/Platform/X86PlatformConfig.cpp index fa4d4399..cddd3af8 100644 --- a/src/firestarter/Environment/X86/Platform/X86PlatformConfig.cpp +++ b/src/firestarter/X86/Platform/X86PlatformConfig.cpp @@ -24,4 +24,4 @@ // included header. Therefore we should not see any errors in this file for missing includes. For more infomation // look in the LLVM code base: clang/lib/Tooling/InterpolatingCompilationDatabase.cpp -#include "firestarter/Environment/X86/Platform/X86PlatformConfig.hpp" \ No newline at end of file +#include "firestarter/X86/Platform/X86PlatformConfig.hpp" \ No newline at end of file diff --git a/src/firestarter/Environment/X86/X86ProcessorInformation.cpp b/src/firestarter/X86/X86ProcessorInformation.cpp similarity index 92% rename from src/firestarter/Environment/X86/X86ProcessorInformation.cpp rename to src/firestarter/X86/X86ProcessorInformation.cpp index 466c25db..451083de 100644 --- a/src/firestarter/Environment/X86/X86ProcessorInformation.cpp +++ b/src/firestarter/X86/X86ProcessorInformation.cpp @@ -19,10 +19,13 @@ * Contact: daniel.hackenberg@tu-dresden.de *****************************************************************************/ -#include "firestarter/Environment/X86/X86ProcessorInformation.hpp" +#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 @@ -31,16 +34,18 @@ #pragma intrinsic(__rdtsc) #endif -namespace firestarter::environment::x86 { +namespace firestarter::x86 { X86ProcessorInformation::X86ProcessorInformation() - : ProcessorInformation("x86_64") + : 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(); } @@ -254,4 +259,4 @@ void X86ProcessorInformation::cpuid(uint64_t* Rax, uint64_t* Rbx, uint64_t* Rcx, #endif } -} // namespace firestarter::environment::x86 \ No newline at end of file +} // namespace firestarter::x86 \ No newline at end of file diff --git a/test/DumpCPUTopology/Main.cpp b/test/DumpCPUTopology/Main.cpp index 4b1a0671..314e5d39 100644 --- a/test/DumpCPUTopology/Main.cpp +++ b/test/DumpCPUTopology/Main.cpp @@ -29,12 +29,8 @@ auto main(int /*argc*/, const char** /*argv*/) -> int { firestarter::CPUTopology Topology; - { - std::stringstream Ss; - Topology.printSystemSummary(Ss); - Topology.printCacheSummary(Ss); - firestarter::log::info() << Ss.str(); - } + Topology.printSystemSummary(); + Topology.printCacheSummary(); { auto ICacheSize = Topology.instructionCacheSize(); diff --git a/test/DumpPayloads/Main.cpp b/test/DumpPayloads/Main.cpp index 7f7986f3..329a6ad4 100644 --- a/test/DumpPayloads/Main.cpp +++ b/test/DumpPayloads/Main.cpp @@ -19,36 +19,35 @@ * Contact: daniel.hackenberg@tu-dresden.de *****************************************************************************/ -#include "firestarter/Environment/Payload/Payload.hpp" -#include "firestarter/Environment/X86/Payload/AVX512Payload.hpp" -#include "firestarter/Environment/X86/Payload/AVXPayload.hpp" -#include "firestarter/Environment/X86/Payload/FMA4Payload.hpp" -#include "firestarter/Environment/X86/Payload/FMAPayload.hpp" -#include "firestarter/Environment/X86/Payload/SSE2Payload.hpp" -#include "firestarter/Environment/X86/Payload/ZENFMAPayload.hpp" +#include "firestarter/Payload/Payload.hpp" +#include "firestarter/X86/Payload/AVX512Payload.hpp" +#include "firestarter/X86/Payload/AVXPayload.hpp" +#include "firestarter/X86/Payload/FMA4Payload.hpp" +#include "firestarter/X86/Payload/FMAPayload.hpp" +#include "firestarter/X86/Payload/SSE2Payload.hpp" +#include "firestarter/X86/Payload/ZENFMAPayload.hpp" namespace { /// Take a list of instructions and return a list with a pair containing the each instruction in the first element of /// the pair and a one in the second. -auto oneEach(const std::list& Instructions) - -> std::vector { - std::vector OneEach; +auto oneEach(const std::list& Instructions) -> firestarter::InstructionGroups { + std::vector> OneEach; for (const auto& Instruction : Instructions) { OneEach.emplace_back(Instruction, 1); } - return OneEach; + return firestarter::InstructionGroups{OneEach}; } /// Dump the generated assembler code of the payload with some given settings. Each item is printed once. -void dumpPayload(firestarter::environment::payload::Payload& PayloadPtr) { +void dumpPayload(firestarter::payload::Payload& PayloadPtr) { const auto& Instuctions = PayloadPtr.getAvailableInstructions(); - firestarter::environment::payload::PayloadSettings Settings(/*Threads=*/{1}, - /*DataCacheBufferSize=*/{32768, 1048576, 1441792}, - /*RamBufferSize=*/1048576000, - /*Lines=*/3 * Instuctions.size(), - /*InstructionGroups=*/oneEach(Instuctions)); + firestarter::payload::PayloadSettings Settings(/*Threads=*/{1}, + /*DataCacheBufferSize=*/{32768, 1048576, 1441792}, + /*RamBufferSize=*/1048576000, + /*Lines=*/3 * Instuctions.size(), + /*Groups=*/oneEach(Instuctions)); (void)PayloadPtr.compilePayload(Settings, /*DumpRegisters=*/false, /*ErrorDetection=*/false, /*PrintAssembler=*/true); @@ -57,13 +56,13 @@ void dumpPayload(firestarter::environment::payload::Payload& PayloadPtr) { } // namespace auto main(int /*argc*/, const char** /*argv*/) -> int { - const std::vector> PayloadPtrs = { - std::make_unique(), - std::make_unique(), - std::make_unique(), - std::make_unique(), - std::make_unique(), - std::make_unique()}; + const std::vector> PayloadPtrs = { + std::make_unique(), + std::make_unique(), + std::make_unique(), + std::make_unique(), + std::make_unique(), + std::make_unique()}; for (const auto& PayloadPtr : PayloadPtrs) { firestarter::log::info() << "Payload " << PayloadPtr->name(); diff --git a/test/UnitTests/CMakeLists.txt b/test/UnitTests/CMakeLists.txt index fd23745d..e54ae21d 100644 --- a/test/UnitTests/CMakeLists.txt +++ b/test/UnitTests/CMakeLists.txt @@ -1,5 +1,11 @@ add_executable(UnitTests CpuBindTest.cpp + FunctionSelectionTest.cpp + InstructionGroupsTest.cpp + X86CpuFeaturesTest.cpp + X86CpuModelTest.cpp + X86PayloadTest.cpp + X86PlatformConfigTest.cpp ) target_link_libraries(UnitTests @@ -8,4 +14,4 @@ target_link_libraries(UnitTests ) include(GoogleTest) -gtest_discover_tests(UnitTests) \ No newline at end of file +gtest_discover_tests(UnitTests DISCOVERY_MODE PRE_TEST) \ No newline at end of file diff --git a/test/UnitTests/FunctionSelectionTest.cpp b/test/UnitTests/FunctionSelectionTest.cpp new file mode 100644 index 00000000..9c66e704 --- /dev/null +++ b/test/UnitTests/FunctionSelectionTest.cpp @@ -0,0 +1,447 @@ +/****************************************************************************** + * 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/FunctionSelection.hpp" + +#include + +namespace { + +class FakeCpuFeatures : public firestarter::CpuFeatures { + [[nodiscard]] auto hasAll(const CpuFeatures& /*Features*/) const -> bool override { return true; }; +}; + +class FakeCpuModel : 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; } +}; + +template class FakePayload : public firestarter::payload::Payload { +public: + FakePayload() + : firestarter::payload::Payload( + /*Name=*/"AvailablePayload", /*RegisterSize=*/0, /*RegisterCount=*/0) {} + + void init(double* /*MemoryAddr*/, uint64_t /*BufferSize*/) const override {} + + void lowLoadFunction(volatile firestarter::LoadThreadWorkType& /*LoadVar*/, + std::chrono::microseconds /*Period*/) const override {} + + [[nodiscard]] auto isAvailable(const firestarter::CpuFeatures& /*Features*/) const -> bool override { + return PayloadIsAvailable; + } + + [[nodiscard]] auto compilePayload(const firestarter::payload::PayloadSettings& /*Settings*/, + bool + /*DumpRegisters*/, + bool /*ErrorDetection*/, bool /*PrintAssembler*/) const + -> firestarter::payload::CompiledPayload::UniquePtr override { + return {nullptr, nullptr}; + } + + [[nodiscard]] auto getAvailableInstructions() const -> std::list override { return {}; } +}; + +constexpr const unsigned ThreadCount1 = 1; +constexpr const unsigned ThreadCount2 = 2; +constexpr const unsigned InvalidThreadCount = 3; + +template +class FakePlatfromConfig : public firestarter::platform::PlatformConfig { +private: + unsigned Id; + +public: + explicit FakePlatfromConfig(unsigned Id) + : firestarter::platform::PlatformConfig( + /*Name=*/"PlatfromConfigTest", + /*Settings=*/ + firestarter::payload::PayloadSettings( + /*Threads=*/{ThreadCount1, ThreadCount2}, /*DataCacheBufferSize=*/{}, /*RamBufferSize=*/0, + /*Lines=*/0, + /*Groups=*/firestarter::InstructionGroups(firestarter::InstructionGroups::InternalType())), + /*Payload=*/std::make_shared>()) + , Id(Id) {} + + [[nodiscard]] auto getId() const -> auto{ return Id; } + +private: + [[nodiscard]] auto isDefault(const firestarter::CpuModel& /*Model*/, + const firestarter::CpuFeatures& /*Features*/) const -> bool override { + return IsDefault; + } + + [[nodiscard]] auto clone() const -> std::unique_ptr override { return nullptr; } + + [[nodiscard]] auto cloneConcreate(std::optional InstructionCacheSize, unsigned ThreadsPerCore) const + -> std::unique_ptr override { + auto Config = std::make_unique>(Id); + Config->settings().concretize(InstructionCacheSize, ThreadsPerCore); + return Config; + } +}; + +constexpr const unsigned PayloadId1 = 4; +constexpr const unsigned PayloadId2 = 5; + +constexpr const std::optional InstructionCacheSize = 6; + +template +class FunctionSelectionTest : public firestarter::FunctionSelection { + std::vector> PlatformConfigs; + std::vector> FallbackPlatformConfigs; + +public: + FunctionSelectionTest() { + if constexpr (WithPlatformConfigs) { + PlatformConfigs = { + std::make_shared>(PayloadId1), + std::make_shared>(PayloadId2)}; + } + if constexpr (WithFallbackPlatformConfigs) { + FallbackPlatformConfigs = { + std::make_shared>(PayloadId1), + std::make_shared>(PayloadId2)}; + } + } + + [[nodiscard]] auto selectAvailableFunction(unsigned FunctionId, std::optional InstructionCacheSize, + bool AllowUnavailablePayload) const + -> std::unique_ptr { + return firestarter::FunctionSelection::selectAvailableFunction(FunctionId, FakeCpuFeatures(), InstructionCacheSize, + AllowUnavailablePayload); + } + + [[nodiscard]] auto selectDefaultOrFallbackFunction(std::optional InstructionCacheSize, + unsigned NumThreadsPerCore) const + -> std::unique_ptr { + return firestarter::FunctionSelection::selectDefaultOrFallbackFunction( + FakeCpuModel(), FakeCpuFeatures(), "VendorString", "ModelString", InstructionCacheSize, NumThreadsPerCore); + } + + [[nodiscard]] auto platformConfigs() const + -> const std::vector>& override { + return PlatformConfigs; + } + + [[nodiscard]] auto fallbackPlatformConfigs() const + -> const std::vector>& override { + return FallbackPlatformConfigs; + } +}; + +template +using FunctionSelectionWithPlatformConfigsTest = + FunctionSelectionTest; + +template +using FunctionSelectionWithFallbackPlatformConfigsTest = + FunctionSelectionTest; + +template +void checkSelectAvailableFunctionThrowWithPlatformConfigs(const unsigned FunctionId, + const std::optional InstructionCacheSize, + const bool AllowUnavailablePayload) { + EXPECT_ANY_THROW((void)(FunctionSelectionWithPlatformConfigsTest() + .selectAvailableFunction( + /*FunctionId=*/FunctionId, InstructionCacheSize, AllowUnavailablePayload))); +} + +/// Check that the function with the given id selects the correct available payload, thread count and instruction cache +/// size. +template +void checkSelectAvailableFunctionNoThrowWithPlatformConfigs(const unsigned FunctionId, const unsigned PayloadId, + const unsigned ThreadCount, + const std::optional InstructionCacheSize, + const bool AllowUnavailablePayload) { + std::unique_ptr Config; + + EXPECT_NO_THROW(Config = + (FunctionSelectionWithPlatformConfigsTest() + .selectAvailableFunction(FunctionId, InstructionCacheSize, AllowUnavailablePayload))); + + const auto* FakeConfg = dynamic_cast*>(Config.get()); + // Id describes the nth element in the list of platform configs. + EXPECT_EQ(FakeConfg->getId(), PayloadId); + EXPECT_EQ(FakeConfg->settings().thread(), ThreadCount); + EXPECT_EQ(FakeConfg->settings().instructionCacheSize(), InstructionCacheSize); +} + +/// Check that the correct fallback function is selected +template +void checkSelectDefaultOrFallbackFunctionNoThrowWithFallbackPlatformConfigs( + const unsigned PayloadId, const unsigned InputThreadCount, const unsigned OutputThreadCount, + const std::optional InstructionCacheSize) { + std::unique_ptr Config; + EXPECT_NO_THROW( + Config = (FunctionSelectionWithFallbackPlatformConfigsTest() + .selectDefaultOrFallbackFunction(InstructionCacheSize, + /*NumThreadsPerCore=*/InputThreadCount))); + { + const auto* FakeConfg = dynamic_cast*>(Config.get()); + // Id describes the nth element in the list of platform configs. + EXPECT_EQ(FakeConfg->getId(), PayloadId); + EXPECT_EQ(FakeConfg->settings().thread(), OutputThreadCount); + EXPECT_EQ(FakeConfg->settings().instructionCacheSize(), InstructionCacheSize); + } +} + +/// Check that the default fallback function is selected +template +void checkSelectDefaultOrFallbackFunctionNoThrowWithPlatformConfigs( + const unsigned PayloadId, const unsigned ThreadCount, const std::optional InstructionCacheSize) { + std::unique_ptr Config; + EXPECT_NO_THROW( + Config = + (FunctionSelectionWithPlatformConfigsTest() + .selectDefaultOrFallbackFunction(InstructionCacheSize, + /*NumThreadsPerCore=*/ThreadCount))); + { + const auto* FakeConfg = dynamic_cast*>(Config.get()); + // Id describes the nth element in the list of platform configs. + EXPECT_EQ(FakeConfg->getId(), PayloadId); + EXPECT_EQ(FakeConfg->settings().thread(), ThreadCount); + EXPECT_EQ(FakeConfg->settings().instructionCacheSize(), InstructionCacheSize); + } +} + +template +void checkSelectDefaultOrFallbackFunctionThrowWithPlatformConfigs(const unsigned ThreadCount, + const std::optional InstructionCacheSize) { + EXPECT_ANY_THROW((void)(FunctionSelectionWithPlatformConfigsTest() + .selectDefaultOrFallbackFunction(InstructionCacheSize, + /*NumThreadsPerCore=*/ThreadCount))); +} + +} // namespace + +TEST(FunctionSelectionTest, CheckInvalidFunctionIds) { + // Id 0 is not valid. + checkSelectAvailableFunctionThrowWithPlatformConfigs( + /*FunctionId=*/0, InstructionCacheSize, + /*AllowUnavailablePayload=*/true); + checkSelectAvailableFunctionThrowWithPlatformConfigs( + /*FunctionId=*/0, InstructionCacheSize, + /*AllowUnavailablePayload=*/false); + + checkSelectAvailableFunctionThrowWithPlatformConfigs( + /*FunctionId=*/0, InstructionCacheSize, + /*AllowUnavailablePayload=*/true); + checkSelectAvailableFunctionThrowWithPlatformConfigs( + /*FunctionId=*/0, InstructionCacheSize, + /*AllowUnavailablePayload=*/false); + + // Id is too big. + checkSelectAvailableFunctionThrowWithPlatformConfigs( + /*FunctionId=*/5, InstructionCacheSize, + /*AllowUnavailablePayload=*/true); + checkSelectAvailableFunctionThrowWithPlatformConfigs( + /*FunctionId=*/5, InstructionCacheSize, + /*AllowUnavailablePayload=*/false); + + checkSelectAvailableFunctionThrowWithPlatformConfigs( + /*FunctionId=*/5, InstructionCacheSize, + /*AllowUnavailablePayload=*/true); + checkSelectAvailableFunctionThrowWithPlatformConfigs( + /*FunctionId=*/5, InstructionCacheSize, + /*AllowUnavailablePayload=*/false); +} + +TEST(FunctionSelectionTest, CheckFunctionIds) { + // Ids starting from 1 are valid + checkSelectAvailableFunctionNoThrowWithPlatformConfigs( + 1, PayloadId1, ThreadCount1, InstructionCacheSize, /*AllowUnavailablePayload=*/false); + checkSelectAvailableFunctionNoThrowWithPlatformConfigs( + 1, PayloadId1, ThreadCount1, InstructionCacheSize, /*AllowUnavailablePayload=*/true); + + checkSelectAvailableFunctionThrowWithPlatformConfigs( + 1, InstructionCacheSize, /*AllowUnavailablePayload=*/false); + checkSelectAvailableFunctionNoThrowWithPlatformConfigs( + 1, PayloadId1, ThreadCount1, InstructionCacheSize, /*AllowUnavailablePayload=*/true); + + checkSelectAvailableFunctionNoThrowWithPlatformConfigs( + 2, PayloadId1, ThreadCount2, InstructionCacheSize, /*AllowUnavailablePayload=*/false); + checkSelectAvailableFunctionNoThrowWithPlatformConfigs( + 2, PayloadId1, ThreadCount2, InstructionCacheSize, /*AllowUnavailablePayload=*/true); + + checkSelectAvailableFunctionThrowWithPlatformConfigs( + 2, InstructionCacheSize, /*AllowUnavailablePayload=*/false); + checkSelectAvailableFunctionNoThrowWithPlatformConfigs( + 2, PayloadId1, ThreadCount2, InstructionCacheSize, /*AllowUnavailablePayload=*/true); + + checkSelectAvailableFunctionNoThrowWithPlatformConfigs( + 3, PayloadId2, ThreadCount1, InstructionCacheSize, /*AllowUnavailablePayload=*/false); + checkSelectAvailableFunctionNoThrowWithPlatformConfigs( + 3, PayloadId2, ThreadCount1, InstructionCacheSize, /*AllowUnavailablePayload=*/true); + + checkSelectAvailableFunctionThrowWithPlatformConfigs( + 3, InstructionCacheSize, /*AllowUnavailablePayload=*/false); + checkSelectAvailableFunctionNoThrowWithPlatformConfigs( + 3, PayloadId2, ThreadCount1, InstructionCacheSize, /*AllowUnavailablePayload=*/true); + + checkSelectAvailableFunctionNoThrowWithPlatformConfigs( + 4, PayloadId2, ThreadCount2, InstructionCacheSize, /*AllowUnavailablePayload=*/false); + checkSelectAvailableFunctionNoThrowWithPlatformConfigs( + 4, PayloadId2, ThreadCount2, InstructionCacheSize, /*AllowUnavailablePayload=*/true); + + checkSelectAvailableFunctionThrowWithPlatformConfigs( + 4, InstructionCacheSize, /*AllowUnavailablePayload=*/false); + checkSelectAvailableFunctionNoThrowWithPlatformConfigs( + 4, PayloadId2, ThreadCount2, InstructionCacheSize, /*AllowUnavailablePayload=*/true); +} + +TEST(FunctionSelectionTest, NoFallbackFound) { + EXPECT_ANY_THROW((void)(FunctionSelectionWithFallbackPlatformConfigsTest() + .selectDefaultOrFallbackFunction( + /*InstructionCacheSize=*/{}, + /*NumThreadsPerCore=*/1))); +} + +TEST(FunctionSelectionTest, CheckFallbackThreadCount) { + checkSelectDefaultOrFallbackFunctionNoThrowWithFallbackPlatformConfigs( + PayloadId1, /*InputThreadCount=*/ThreadCount1, /*OutputThreadCount=*/ThreadCount1, InstructionCacheSize); + checkSelectDefaultOrFallbackFunctionNoThrowWithFallbackPlatformConfigs( + PayloadId1, /*InputThreadCount=*/ThreadCount1, /*OutputThreadCount=*/ThreadCount1, InstructionCacheSize); + + checkSelectDefaultOrFallbackFunctionNoThrowWithFallbackPlatformConfigs( + PayloadId1, /*InputThreadCount=*/ThreadCount2, /*OutputThreadCount=*/ThreadCount2, InstructionCacheSize); + checkSelectDefaultOrFallbackFunctionNoThrowWithFallbackPlatformConfigs( + PayloadId1, /*InputThreadCount=*/ThreadCount2, /*OutputThreadCount=*/ThreadCount2, InstructionCacheSize); + + checkSelectDefaultOrFallbackFunctionNoThrowWithFallbackPlatformConfigs( + PayloadId1, /*InputThreadCount=*/InvalidThreadCount, /*OutputThreadCount=*/ThreadCount1, InstructionCacheSize); + checkSelectDefaultOrFallbackFunctionNoThrowWithFallbackPlatformConfigs( + PayloadId1, /*InputThreadCount=*/InvalidThreadCount, /*OutputThreadCount=*/ThreadCount1, InstructionCacheSize); + + checkSelectDefaultOrFallbackFunctionNoThrowWithFallbackPlatformConfigs( + PayloadId2, /*InputThreadCount=*/ThreadCount1, /*OutputThreadCount=*/ThreadCount1, InstructionCacheSize); + + checkSelectDefaultOrFallbackFunctionNoThrowWithFallbackPlatformConfigs( + PayloadId2, /*InputThreadCount=*/ThreadCount2, /*OutputThreadCount=*/ThreadCount2, InstructionCacheSize); + + checkSelectDefaultOrFallbackFunctionNoThrowWithFallbackPlatformConfigs( + PayloadId2, /*InputThreadCount=*/InvalidThreadCount, /*OutputThreadCount=*/ThreadCount1, InstructionCacheSize); +} + +TEST(FunctionSelectionTest, NoDefaultFound) { + // non of the configs are the default, no fallbacks available -> throw + checkSelectDefaultOrFallbackFunctionThrowWithPlatformConfigs(ThreadCount1, + InstructionCacheSize); + checkSelectDefaultOrFallbackFunctionThrowWithPlatformConfigs(ThreadCount2, + InstructionCacheSize); + checkSelectDefaultOrFallbackFunctionThrowWithPlatformConfigs(InvalidThreadCount, + InstructionCacheSize); +} + +TEST(FunctionSelectionTest, DefaultThreadCountFound) { + // default config with correct thread count found -> no throw + checkSelectDefaultOrFallbackFunctionNoThrowWithPlatformConfigs( + PayloadId1, ThreadCount1, InstructionCacheSize); + checkSelectDefaultOrFallbackFunctionNoThrowWithPlatformConfigs( + PayloadId1, ThreadCount2, InstructionCacheSize); + + checkSelectDefaultOrFallbackFunctionNoThrowWithPlatformConfigs( + PayloadId1, ThreadCount1, InstructionCacheSize); + checkSelectDefaultOrFallbackFunctionNoThrowWithPlatformConfigs( + PayloadId1, ThreadCount2, InstructionCacheSize); + + checkSelectDefaultOrFallbackFunctionNoThrowWithPlatformConfigs( + PayloadId2, ThreadCount1, InstructionCacheSize); + checkSelectDefaultOrFallbackFunctionNoThrowWithPlatformConfigs( + PayloadId2, ThreadCount2, InstructionCacheSize); +} + +TEST(FunctionSelectionTest, DefaultThreadCountNotFound) { + // default config found but not the correct number of thread, no fallbacks available -> throw + checkSelectDefaultOrFallbackFunctionThrowWithPlatformConfigs(InvalidThreadCount, + InstructionCacheSize); + checkSelectDefaultOrFallbackFunctionThrowWithPlatformConfigs(InvalidThreadCount, + InstructionCacheSize); + checkSelectDefaultOrFallbackFunctionThrowWithPlatformConfigs(InvalidThreadCount, + InstructionCacheSize); +} \ No newline at end of file diff --git a/test/UnitTests/InstructionGroupsTest.cpp b/test/UnitTests/InstructionGroupsTest.cpp new file mode 100644 index 00000000..2e565644 --- /dev/null +++ b/test/UnitTests/InstructionGroupsTest.cpp @@ -0,0 +1,86 @@ +/****************************************************************************** + * 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/Config/InstructionGroups.hpp" + +#include + +TEST(InstructionGroupsTest, ParseValidInput) { + const auto StringToParsed = std::map>>({ + {"Inst:1", {{"Inst", 1}}}, + {"Inst_2:2", {{"Inst_2", 2}}}, + }); + + // Check if the individual ones work. + for (const auto& [Input, Output] : StringToParsed) { + const auto Groups = firestarter::InstructionGroups::fromString(Input); + const auto ConvertedGroups = static_cast>>(Groups); + EXPECT_EQ(ConvertedGroups, Output); + + { + std::stringstream Ss; + Ss << Groups; + EXPECT_EQ(Ss.str(), Input); + } + } + + // Check combinations with two comma seperated values. + for (const auto& [Input1, Output1] : StringToParsed) { + for (const auto& [Input2, Output2] : StringToParsed) { + auto Input = Input1; + Input += ","; + Input += Input2; + + auto Output = Output1; + Output.insert(Output.end(), Output2.cbegin(), Output2.cend()); + + const auto Groups = firestarter::InstructionGroups::fromString(Input); + const auto ConvertedGroups = static_cast>>(Groups); + EXPECT_EQ(ConvertedGroups, Output); + + { + std::stringstream Ss; + Ss << Groups; + EXPECT_EQ(Ss.str(), Input); + } + } + } +} + +TEST(InstructionGroupsTest, ParseInvalidInput) { + const auto ThrowStrings = std::vector({"Inst", "$:1", "Inst:0", "Inst:-1", "Inst:$", "Inst:A"}); + + // Check if the individual ones fail. + for (const auto& Input : ThrowStrings) { + EXPECT_ANY_THROW((void)firestarter::InstructionGroups::fromString(Input)); + } + + // Check if the combinations with two comma seperated values fail. + for (const auto& Input1 : ThrowStrings) { + for (const auto& Input2 : ThrowStrings) { + auto Input = Input1; + Input += ","; + Input += Input2; + + EXPECT_ANY_THROW((void)firestarter::InstructionGroups::fromString(Input)); + } + } +} \ No newline at end of file diff --git a/test/UnitTests/X86CpuFeaturesTest.cpp b/test/UnitTests/X86CpuFeaturesTest.cpp new file mode 100644 index 00000000..5b45d923 --- /dev/null +++ b/test/UnitTests/X86CpuFeaturesTest.cpp @@ -0,0 +1,50 @@ +/****************************************************************************** + * 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/X86CpuFeatures.hpp" + +#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{}; + + EXPECT_NO_THROW((void)Features.hasAll(Features)); + EXPECT_ANY_THROW((void)Features.hasAll(InvalidCpuFeatures())); +} + +TEST(X86CpuFeatures, CheckHasAll) { + const auto Features = + firestarter::x86::X86CpuFeatures().add(asmjit::CpuFeatures::X86::kAVX2).add(asmjit::CpuFeatures::X86::kAVX512_F); + + EXPECT_FALSE(Features.hasAll(firestarter::x86::X86CpuFeatures().add(asmjit::CpuFeatures::X86::kAVX))); + EXPECT_TRUE(Features.hasAll(firestarter::x86::X86CpuFeatures().add(asmjit::CpuFeatures::X86::kAVX2))); + EXPECT_TRUE(Features.hasAll(firestarter::x86::X86CpuFeatures().add(asmjit::CpuFeatures::X86::kAVX512_F))); + EXPECT_TRUE(Features.hasAll(Features)); +} \ No newline at end of file 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 new file mode 100644 index 00000000..3861628f --- /dev/null +++ b/test/UnitTests/X86PayloadTest.cpp @@ -0,0 +1,76 @@ +/****************************************************************************** + * 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/Payload/X86Payload.hpp" + +#include +#include + +namespace { + +class X86PayloadTest : public firestarter::x86::payload::X86Payload { +public: + X86PayloadTest() + : firestarter::x86::payload::X86Payload( + /*FeatureRequests=*/firestarter::x86::X86CpuFeatures() + .add(asmjit::CpuFeatures::X86::kAVX2) + .add(asmjit::CpuFeatures::X86::kAVX512_F), + /*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 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(X86PayloadTest, CpuFeatureHasAllReturned) { + EXPECT_TRUE(X86PayloadTest().isAvailable(TrueCpuFeatures())); + EXPECT_FALSE(X86PayloadTest().isAvailable(FalseCpuFeatures())); +} + +TEST(X86CpuFeatures, CheckIsAvailable) { + EXPECT_FALSE(X86PayloadTest().isAvailable(firestarter::x86::X86CpuFeatures().add(asmjit::CpuFeatures::X86::kAVX))); + EXPECT_FALSE(X86PayloadTest().isAvailable(firestarter::x86::X86CpuFeatures().add(asmjit::CpuFeatures::X86::kAVX2))); + EXPECT_FALSE( + X86PayloadTest().isAvailable(firestarter::x86::X86CpuFeatures().add(asmjit::CpuFeatures::X86::kAVX512_F))); + EXPECT_TRUE(X86PayloadTest().isAvailable(X86PayloadTest().featureRequests())); + EXPECT_TRUE(X86PayloadTest().isAvailable(firestarter::x86::X86CpuFeatures() + .add(asmjit::CpuFeatures::X86::kAVX) + .add(asmjit::CpuFeatures::X86::kAVX2) + .add(asmjit::CpuFeatures::X86::kAVX512_F))); +} \ No newline at end of file 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 diff --git a/test/X86Functions/Main.cpp b/test/X86Functions/Main.cpp index 4b35389a..37579348 100644 --- a/test/X86Functions/Main.cpp +++ b/test/X86Functions/Main.cpp @@ -19,14 +19,16 @@ * Contact: daniel.hackenberg@tu-dresden.de *****************************************************************************/ -#include "firestarter/Environment/X86/X86Environment.hpp" +#include "firestarter/X86/X86FunctionSelection.hpp" +#include "firestarter/X86/X86ProcessorInformation.hpp" auto main(int /*argc*/, const char** /*argv*/) -> int { firestarter::logging::Filter::set_severity(nitro::log::severity_level::info); - firestarter::environment::x86::X86Environment Env; + firestarter::x86::X86FunctionSelection Env; + const firestarter::x86::X86ProcessorInformation ProcessorInfos{}; - Env.printFunctionSummary(/*ForceYes=*/true); + Env.printFunctionSummary(ProcessorInfos, /*ForceYes=*/true); return EXIT_SUCCESS; } \ No newline at end of file