--- /dev/null
+BasedOnStyle: Microsoft
+ColumnLimit: 79
--- /dev/null
+/build*
+/.cache
+/compile_commands.json
\ No newline at end of file
--- /dev/null
+{
+ "cmake.buildDirectory": "${workspaceFolder}/build-x86_64",
+ "cmake.configureArgs": [
+ "-DCMAKE_TOOLCHAIN_FILE=toolchain-x86_64-linux-gnu.cmake"
+ ],
+ "cmake.copyCompileCommands": "${workspaceFolder}/compile_commands.json",
+}
\ No newline at end of file
--- /dev/null
+cmake_minimum_required(VERSION 3.11.0)
+project(atomic-benchmarks VERSION 0.1.0)
+
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+add_compile_options(-Wall -Wextra -Wimplicit-fallthrough)
+add_executable(atomic-benchmarks main.cpp harness.cpp)
+
+set(CPACK_PROJECT_NAME ${PROJECT_NAME})
+set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
+include(CPack)
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
--- /dev/null
+.PHONY: all clean configure
+all: build-ppc64le/atomic-benchmarks build-aarch64/atomic-benchmarks build-x86_64/atomic-benchmarks
+
+common_cmake_flags = -S .
+common_cmake_flags += -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE
+
+reset_make_env = "MAKEFLAGS=" "MFLAGS=" "MAKELEVEL=" "MAKE_TERMERR=" "MAKE_TERMOUT="
+
+build-ppc64le/Makefile: toolchain-powerpc64le-linux-gnu.cmake CMakeLists.txt
+ ./install-deps.sh
+ rm -fr build-ppc64le
+ env $(reset_make_env) cmake $(common_cmake_flags) -B build-ppc64le -DCMAKE_TOOLCHAIN_FILE=toolchain-powerpc64le-linux-gnu.cmake
+
+build-aarch64/Makefile: toolchain-aarch64-linux-gnu.cmake CMakeLists.txt
+ ./install-deps.sh
+ rm -fr build-aarch64
+ env $(reset_make_env) cmake $(common_cmake_flags) -B build-aarch64 -DCMAKE_TOOLCHAIN_FILE=toolchain-aarch64-linux-gnu.cmake
+
+build-x86_64/Makefile: toolchain-x86_64-linux-gnu.cmake CMakeLists.txt
+ ./install-deps.sh
+ rm -fr build-x86_64
+ env $(reset_make_env) cmake $(common_cmake_flags) -B build-x86_64 -DCMAKE_TOOLCHAIN_FILE=toolchain-x86_64-linux-gnu.cmake
+
+configure: build-ppc64le/Makefile build-aarch64/Makefile build-x86_64/Makefile
+
+.PHONY: __force-run
+
+build-ppc64le/atomic-benchmarks: build-ppc64le/Makefile __force-run
+ $(MAKE) -C build-ppc64le atomic-benchmarks
+
+build-aarch64/atomic-benchmarks: build-aarch64/Makefile __force-run
+ $(MAKE) -C build-aarch64 atomic-benchmarks
+
+build-x86_64/atomic-benchmarks: build-x86_64/Makefile __force-run
+ $(MAKE) -C build-x86_64 atomic-benchmarks
+
+clean:
+ rm -fr build-ppc64le build-aarch64 build-x86_64
+
--- /dev/null
+# Tool for benchmarking atomic operations
+
+# Building (installs dependencies and configures cmake builds for all 3 targets):
+
+```
+make
+```
\ No newline at end of file
--- /dev/null
+#include "harness.h"
+
+void BenchHarnessBase::base_run(
+ Config config, void (*fn)(BenchHarnessBase *bench_harness_base,
+ std::uint64_t iteration_count))
+{
+ // FIXME: finish
+}
\ No newline at end of file
--- /dev/null
+#pragma once
+
+#include <chrono>
+#include <cstdint>
+#include <optional>
+#include <type_traits>
+#include <utility>
+
+struct Config final
+{
+ std::optional<std::uint32_t> thread_count;
+ std::optional<std::uint64_t> iteration_count;
+};
+
+template <typename Fn, typename Input,
+ typename Output = std::invoke_result_t<Fn, Input>>
+class BenchHarness;
+
+class BenchHarnessBase
+{
+ template <typename Fn, typename Input, typename Output>
+ friend class BenchHarness;
+
+ private:
+ void base_run(Config config,
+ void (*fn)(BenchHarnessBase *bench_harness_base,
+ std::uint64_t iteration_count));
+};
+
+template <typename Fn, typename Input>
+class BenchHarness<Fn, Input, std::invoke_result_t<Fn, Input>> final
+ : private BenchHarnessBase
+{
+ private:
+ Fn fn;
+
+ public:
+ void run(Config config)
+ {
+ base_run(config, [](BenchHarnessBase *bench_harness_base,
+ std::uint64_t iteration_count) {
+ auto &fn = static_cast<BenchHarness *>(bench_harness_base)->fn;
+ for (std::uint64_t i = 0; i < iteration_count; i++)
+ {
+ Input input;
+
+ // optimization barrier
+ asm("" : : "r"(std::addressof(input)) : "memory");
+
+ auto output = fn(input);
+
+ // optimization barrier
+ asm("" : : "r"(std::addressof(output)) : "memory");
+ }
+ });
+ }
+};
\ No newline at end of file
--- /dev/null
+#!/bin/bash
+set -e
+
+# need to install g++ first so the local arch will get filtered out later
+which g++ > /dev/null || (set -x; sudo apt install build-essential g++)
+
+needed=()
+
+which x86_64-linux-gnu-g++ > /dev/null || needed+=(g++-x86_64-linux-gnu)
+which aarch64-linux-gnu-g++ > /dev/null || needed+=(g++-aarch64-linux-gnu)
+which powerpc64le-linux-gnu-g++ > /dev/null || needed+=(g++-powerpc64le-linux-gnu)
+which clang++-11 > /dev/null || needed+=(clang-11)
+which make > /dev/null || needed+=(make)
+which cmake > /dev/null || needed+=(cmake)
+which ccache > /dev/null || needed+=(ccache)
+
+if ((${#needed[@]})); then
+ (set -x; sudo apt install "${needed[@]}")
+fi
--- /dev/null
+#include "harness.h"
+#include <charconv>
+#include <cstdlib>
+#include <functional>
+#include <initializer_list>
+#include <iostream>
+#include <map>
+#include <optional>
+#include <ostream>
+#include <string_view>
+#include <system_error>
+#include <type_traits>
+#include <vector>
+
+using namespace std::literals;
+
+enum class OptionValueKind
+{
+ None,
+ Required,
+};
+
+class OptionsParser;
+
+struct Option final
+{
+ char short_name = '\0';
+ std::string_view long_name = "", description = "";
+ bool required = false;
+ bool all_other_args_not_required = false;
+ OptionValueKind value_kind = OptionValueKind::None;
+ std::function<void(OptionsParser &parser,
+ std::optional<std::string_view> value)>
+ parse_value;
+ bool has_short_name() const
+ {
+ return short_name != '\0';
+ }
+ bool has_long_name() const
+ {
+ return !long_name.empty();
+ }
+ friend std::ostream &operator<<(std::ostream &os, const Option &option)
+ {
+ if (option.has_long_name())
+ {
+ os << "--" << option.long_name;
+ }
+ else if (option.has_short_name())
+ {
+ os << "-" << option.short_name;
+ }
+ else
+ {
+ os << "--<unnamed>";
+ }
+ return os;
+ }
+};
+
+class Options final
+{
+ friend class OptionsParser;
+
+ private:
+ std::vector<Option> options;
+ std::map<char, std::size_t> short_options;
+ std::map<std::string_view, std::size_t> long_options;
+
+ public:
+ Options(std::initializer_list<Option> options_)
+ : options(options_), short_options(), long_options()
+ {
+ for (std::size_t i = 0; i < options.size(); i++)
+ {
+ auto &option = options[i];
+ if (option.has_short_name())
+ short_options[option.short_name] = i;
+ if (option.has_long_name())
+ long_options[option.long_name] = i;
+ }
+ }
+
+ public:
+ std::vector<std::string_view> parse(const char *const *argv) const;
+};
+
+class OptionsParser final
+{
+ private:
+ const Options &options;
+ const char *const *argv;
+ std::string_view argv0;
+ std::vector<bool> seen_options;
+ bool check_required = true;
+ std::optional<std::size_t> current_option_index;
+
+ private:
+ const Option ¤t_option()
+ {
+ static const Option default_option{};
+ if (current_option_index)
+ {
+ return options.options[*current_option_index];
+ }
+ else
+ {
+ return default_option;
+ }
+ }
+
+ public:
+ OptionsParser(const Options &options, const char *const *argv)
+ : options(options), argv(argv + 1),
+ argv0(argv[0] ? argv[0] : "<none>"),
+ seen_options(options.options.size(), false), current_option_index()
+ {
+ if (!argv[0])
+ {
+ static const char *null[] = {nullptr};
+ this->argv = null;
+ help_and_exit("missing program name");
+ }
+ }
+
+ private:
+ void parse_option(std::size_t option_index, std::string_view prefix,
+ std::string_view name,
+ std::optional<std::string_view> value)
+ {
+ auto &option = options.options[option_index];
+ switch (option.value_kind)
+ {
+ case OptionValueKind::None:
+ if (value)
+ {
+ help_and_exit("value not allowed for ", prefix, name);
+ }
+ break;
+ case OptionValueKind::Required:
+ if (!value)
+ {
+ if (*argv)
+ {
+ value = *argv++;
+ }
+ else
+ {
+ help_and_exit("missing value for ", prefix, name);
+ }
+ }
+ break;
+ }
+ seen_options[option_index] = true;
+ if (option.all_other_args_not_required)
+ check_required = false;
+ current_option_index = option_index;
+ option.parse_value(*this, value);
+ current_option_index = std::nullopt;
+ }
+
+ public:
+ std::vector<std::string_view> parse()
+ {
+ std::vector<std::string_view> retval;
+ constexpr auto npos = std::string_view::npos;
+ while (*argv)
+ {
+ std::string_view arg = *argv++;
+ static constexpr std::string_view long_prefix = "--"sv;
+ static constexpr std::string_view short_prefix = "-"sv;
+ if (arg.rfind(long_prefix, 0) == 0) // it starts with `--`
+ {
+ arg.remove_prefix(long_prefix.size());
+ auto eq = arg.find('=');
+ if (eq == 0)
+ {
+ eq = npos;
+ }
+ if (arg.empty()) // just `--`
+ {
+ while (*argv)
+ {
+ retval.push_back(*argv++);
+ }
+ break;
+ }
+ auto name = arg.substr(0, eq);
+ std::optional<std::string_view> value;
+ if (eq != npos)
+ {
+ value = arg.substr(eq + 1);
+ }
+ auto iter = options.long_options.find(name);
+ if (iter == options.long_options.end())
+ {
+ help_and_exit("unknown option: ", long_prefix, name);
+ }
+ auto option_index = iter->second;
+ parse_option(option_index, long_prefix, name, value);
+ continue;
+ }
+ else if (arg.rfind(short_prefix, 0) == 0) // it starts with `-`
+ {
+ arg.remove_prefix(short_prefix.size());
+ if (arg.empty()) // just `-`
+ {
+ retval.push_back(short_prefix);
+ continue;
+ }
+ while (!arg.empty())
+ {
+ auto name = arg.substr(0, 1);
+ arg.remove_prefix(1);
+ auto iter = options.short_options.find(name[0]);
+ if (iter == options.short_options.end())
+ {
+ help_and_exit("unknown option: ", short_prefix, name);
+ }
+ auto option_index = iter->second;
+ std::optional<std::string_view> value;
+ switch (options.options[option_index].value_kind)
+ {
+ case OptionValueKind::None:
+ break;
+ case OptionValueKind::Required:
+ auto eq = arg.rfind('=', 0);
+ if (eq != npos)
+ {
+ value = arg.substr(eq + 1);
+ }
+ else if (!arg.empty())
+ {
+ value = arg;
+ }
+ arg = "";
+ break;
+ }
+ parse_option(option_index, short_prefix, name, value);
+ }
+ continue;
+ }
+ else
+ {
+ retval.push_back(arg);
+ }
+ }
+ if (check_required)
+ {
+ for (std::size_t i = 0; i < options.options.size(); i++)
+ {
+ auto &option = options.options[i];
+ if (option.required && !seen_options[i])
+ {
+ help_and_exit("missing required option ", option);
+ }
+ }
+ }
+ return retval;
+ }
+ template <typename... Options>
+ [[noreturn]] void help_and_exit(const Options &...error_msg) const
+ {
+ auto &os = sizeof...(error_msg) == 0 ? std::cout : std::cerr;
+ if (sizeof...(error_msg) != 0)
+ {
+ ((os << "Error: ") << ... << error_msg) << std::endl;
+ }
+ os << "Usage: " << argv0;
+ for (auto &option : options.options)
+ {
+ if (!option.required)
+ {
+ os << "[";
+ }
+ auto sep = "";
+ if (option.has_short_name())
+ {
+ os << "-" << option.short_name;
+ sep = "|";
+ }
+ if (option.has_long_name())
+ {
+ os << sep << "--" << option.long_name;
+ }
+ switch (option.value_kind)
+ {
+ case OptionValueKind::None:
+ break;
+ // TODO: case OptionValueKind::Optional:
+ case OptionValueKind::Required:
+ os << " <value>";
+ break;
+ }
+ if (!option.required)
+ {
+ os << "]";
+ }
+ }
+ os << std::endl << "Options:" << std::endl;
+ for (auto &option : options.options)
+ {
+ auto sep = "";
+ if (option.has_short_name())
+ {
+ os << "-" << option.short_name;
+ sep = "|";
+ }
+ if (option.has_long_name())
+ {
+ os << sep << "--" << option.long_name;
+ }
+ os << " " << option.description << std::endl;
+ }
+ std::exit(sizeof...(error_msg) == 0 ? 0 : 1);
+ }
+ template <typename Int>
+ std::enable_if_t<std::is_integral_v<Int>, void> parse_int(
+ std::optional<std::string_view> value, Int &i_value)
+ {
+ i_value = Int();
+ if (!value)
+ {
+ help_and_exit("missing value for ", current_option());
+ }
+ auto str = *value;
+ int base = 10;
+ if (0 == str.rfind("0x", 0) || 0 == str.rfind("0X", 0))
+ {
+ base = 16;
+ str.remove_prefix(2);
+ }
+ else if (0 == str.rfind("0o", 0) || 0 == str.rfind("0O", 0))
+ {
+ base = 8;
+ str.remove_prefix(2);
+ }
+ else if (0 == str.rfind("0b", 0) || 0 == str.rfind("0B", 0))
+ {
+ base = 2;
+ str.remove_prefix(2);
+ }
+ std::from_chars_result result = std::from_chars(
+ str.data(), str.data() + str.size(), i_value, base);
+ if (result.ptr != str.data() + str.size())
+ {
+ result.ec = std::errc::invalid_argument;
+ }
+ if (result.ec == std::errc::result_out_of_range)
+ {
+ help_and_exit("value out of range: ", current_option(), "=",
+ *value);
+ }
+ else if (result.ec != std::errc())
+ {
+ help_and_exit("invalid value for: ", current_option());
+ }
+ }
+ template <typename Int>
+ std::enable_if_t<std::is_integral_v<Int>, void> parse_int(
+ std::optional<std::string_view> value, std::optional<Int> &i_value,
+ bool required = true)
+ {
+ if (!required && !value)
+ {
+ i_value = std::nullopt;
+ return;
+ }
+ i_value.emplace();
+ this->parse_int(value, i_value.value());
+ }
+};
+
+inline std::vector<std::string_view> Options::parse(
+ const char *const *argv) const
+{
+ return OptionsParser(*this, argv).parse();
+}
+
+int main(int, char **argv)
+{
+ Config config{};
+ Options options{
+ Option{
+ .short_name = 'h',
+ .long_name = "help",
+ .description = "Display usage and exit.",
+ .all_other_args_not_required = true,
+ .parse_value = [](OptionsParser &parser,
+ auto) { parser.help_and_exit(); },
+ },
+ Option{.short_name = 'j',
+ .long_name = "thread-count",
+ .description = "Number of threads to run on",
+ .value_kind = OptionValueKind::Required,
+ .parse_value =
+ [&](OptionsParser &parser, auto value) {
+ parser.parse_int(value, config.thread_count);
+ }},
+ Option{.short_name = 'n',
+ .long_name = "iter-count",
+ .description = "Number of iterations to run per thread",
+ .value_kind = OptionValueKind::Required,
+ .parse_value =
+ [&](OptionsParser &parser, auto value) {
+ parser.parse_int(value, config.iteration_count);
+ }},
+ };
+ OptionsParser parser(options, argv);
+ auto args = parser.parse();
+ if (!args.empty())
+ {
+ parser.help_and_exit("unexpected argument");
+ }
+ // TODO: invoke benchmarks
+ return 0;
+}
--- /dev/null
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_PROCESSOR aarch64)
+set(CMAKE_C_COMPILER /usr/lib/ccache/aarch64-linux-gnu-gcc)
+set(CMAKE_CXX_COMPILER /usr/lib/ccache/aarch64-linux-gnu-g++)
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
--- /dev/null
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_PROCESSOR ppc64le)
+set(CMAKE_C_COMPILER /usr/lib/ccache/powerpc64le-linux-gnu-gcc)
+set(CMAKE_CXX_COMPILER /usr/lib/ccache/powerpc64le-linux-gnu-g++)
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
--- /dev/null
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_PROCESSOR x86_64)
+set(CMAKE_C_COMPILER /usr/lib/ccache/clang-11)
+set(CMAKE_C_COMPILER_TARGET x86_64-linux-gnu)
+set(CMAKE_CXX_COMPILER /usr/lib/ccache/clang++-11)
+set(CMAKE_CXX_COMPILER_TARGET x86_64-linux-gnu)
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)