diff --git a/emper/Runtime.cpp b/emper/Runtime.cpp index 8798bc84e5336a2c43496b90f2feac2f2343c3c5..cadd6ed41ab6e3de4784f9fc320c5728ea7d3b44 100644 --- a/emper/Runtime.cpp +++ b/emper/Runtime.cpp @@ -102,10 +102,16 @@ Runtime::Runtime(workerid_t workerCount, RuntimeStrategyFactory& strategyFactory } } + bool pinWorkers = shouldPinWorkers(); + // Core id we start the worker pinning workerid_t pinningOffset = 0; char* pinningOffsetEnv = std::getenv("EMPER_PINNING_OFFSET"); if (pinningOffsetEnv) { + if (!pinWorkers) { + DIE_MSG("EMPER_PIN_WORKERS=false and EMPER_PINNING_OFFSET are mutual exclusive"); + } + int pinningOffsetInt = std::stoi(pinningOffsetEnv); if (pinningOffsetInt > UINT8_MAX) { DIE_MSG("Pinning offset " << pinningOffsetInt << " to big for its datatype"); @@ -118,14 +124,16 @@ Runtime::Runtime(workerid_t workerCount, RuntimeStrategyFactory& strategyFactory errno = pthread_attr_init(&attr); if (errno) DIE; - // Start non portable. - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - CPU_SET((i + pinningOffset) % nprocs, &cpuset); + if (pinWorkers) { + // Start non portable. + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET((i + pinningOffset) % nprocs, &cpuset); - errno = pthread_attr_setaffinity_np(&attr, sizeof(cpuset), &cpuset); - if (errno) DIE_MSG_ERRNO("pthread_attr_setaffinity_np() failed"); - // End non portable. + errno = pthread_attr_setaffinity_np(&attr, sizeof(cpuset), &cpuset); + if (errno) DIE_MSG_ERRNO("pthread_attr_setaffinity_np() failed"); + // End non portable. + } // This is not done by each thread individually because the randomEngine is // mutated and therefore produces data races. diff --git a/emper/Runtime.hpp b/emper/Runtime.hpp index 0837ec35fcf3861e2a5f823818590e8bab673791..1fc424eb4705ddc18d7c2832fcde05cb25308cbc 100644 --- a/emper/Runtime.hpp +++ b/emper/Runtime.hpp @@ -11,6 +11,7 @@ #include <functional> // for function #include <memory> #include <mutex> +#include <optional> #include <random> #include <vector> // for vector @@ -20,7 +21,8 @@ #include "NextFiberResult.hpp" #include "Scheduler.hpp" // for Scheduler #include "Worker.hpp" -#include "emper-common.h" // for workerid_t +#include "emper-common.h" // for workerid_t +#include "lib/env.hpp" #include "lib/sync/Latch.hpp" // for Latch #include "lib/sync/Semaphore.hpp" #include "sleep_strategy/WorkerSleepStrategy.hpp" @@ -83,6 +85,10 @@ class Runtime : public Logger<LogSubsystem::RUNTI> { static auto getDefaultWorkerCount() -> workerid_t; + static auto shouldPinWorkers() -> bool { + return emper::lib::env::getBoolFromEnv("EMPER_PIN_WORKERS").value_or(true); + } + protected: void addNewWorkerHook(const std::function<void(workerid_t)>& hook) { newWorkerHooks.push_back(hook); diff --git a/emper/lib/env.hpp b/emper/lib/env.hpp new file mode 100644 index 0000000000000000000000000000000000000000..65b6c4fc2dcefe3421286f64ff27ea1114de4709 --- /dev/null +++ b/emper/lib/env.hpp @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright © 2021 Florian Fischer +#pragma once + +#include <string> + +#include "Debug.hpp" + +namespace emper::lib::env { + +static auto getBoolFromEnv(const std::string&& key) -> std::optional<bool> { + DBG("parse " << key << " environment variable"); + char* envVar = std::getenv(key.c_str()); + if (!envVar) { + return std::nullopt; + } + + std::string envStr(envVar); + if (envStr == "true") { + return true; + } + + if (envStr == "false") { + return false; + } + + DIE_MSG(key << " has invalid value: " << envStr << " (expected true or false)"); +} + +} // namespace emper::lib::env