Skip to content

File threadsettings.h

File List > code_source > templat > include > TempLat > parallel > threadsettings.h

Go to the documentation of this file

#ifndef TEMPLAT_PARALLEL_THREADS_THREADSETTINGS_H
#define TEMPLAT_PARALLEL_THREADS_THREADSETTINGS_H

/* This file is part of TempLat, available at https://cosmolattice.github.io/templat .
   Copyright 2021-2026 The TempLat authors, see AUTHORS.md.
   Released under the MIT license, see LICENSE.md. */

// File info: Main contributor(s): Wessel Valkenburg, Franz R. Sattler, Year: 2025

#include <thread>
#include <algorithm>

#include "TempLat/parallel/device.h"

#include "TempLat/util/log/saycomplete.h"

namespace TempLat
{
  class ThreadSettings
  {
  public:
    // Put public methods here. These should change very little over time.

    static inline ThreadSettings &getInstance()
    {
      static ThreadSettings store;
      return store;
    }

    static void setMPILocalSize(device::Idx newSize) { getInstance().pSetMPILocalSize(newSize); }

    static device::Idx getMPILocalSize() { return getInstance().pGetMPILocalSize(); }

    static void setMPIThreadsNotOK() { getInstance().pSetMPIThreadsNotOK(); }

    static device::Idx getMaxThreadCount() { return getInstance().pGetMaxThreadCount(); }

    friend std::ostream &operator<<(std::ostream &stream, const ThreadSettings &fts)
    {
      stream << "Threading information:\n";
      stream << " - number of cores on machine:                               " << fts.mHardwareNumCores << "\n";
      stream << " - number of mpi processes for this session on this machine: " << fts.mMPILocalSize << "\n";
      stream << " - user specified number of threads per process:             " << fts.mUserAllowedThreadsPerProcess
             << "\n";
      stream << " - resulting maximum number of threads per process:          " << fts.mHardwareAllowedThreadsPerProcess
             << "\n";
      return stream;
    }

  private:
    /* Put all member variables and private methods here. These may change arbitrarily. */
    device::Idx mMPILocalSize;
    device::Idx mHardwareNumCores;
    device::Idx mHardwareAllowedThreadsPerProcess;
    device::Idx mUserAllowedThreadsPerProcess;

    ThreadSettings()
        : mMPILocalSize(1), mHardwareNumCores(std::thread::hardware_concurrency()),
          mHardwareAllowedThreadsPerProcess(mHardwareNumCores / mMPILocalSize),
          mUserAllowedThreadsPerProcess(mHardwareAllowedThreadsPerProcess)
    {
      mHardwareAllowedThreadsPerProcess = std::max(mHardwareAllowedThreadsPerProcess, device::Idx{1});

      device::Idx kokkosThreads = 0;
      if (const char *env_p = std::getenv("KOKKOS_NUM_THREADS")) kokkosThreads = std::stoi(env_p);

      device::Idx ompThreads = 0;
      if (const char *env_p = std::getenv("OMP_NUM_THREADS")) ompThreads = std::stoi(env_p);

      mUserAllowedThreadsPerProcess = std::max(kokkosThreads, ompThreads);
      if (kokkosThreads > 0 && ompThreads > 0 && kokkosThreads != ompThreads) {
        sayShort << "Warning: both KOKKOS_NUM_THREADS and OMP_NUM_THREADS are set, but to different values. Using the "
                    "largest value.\n    KOKKOS_NUM_THREADS = "
                 << kokkosThreads << ", OMP_NUM_THREADS = " << ompThreads << ".\n";
      }

      if (mUserAllowedThreadsPerProcess > 0)
        mHardwareAllowedThreadsPerProcess = std::min(mUserAllowedThreadsPerProcess, mHardwareAllowedThreadsPerProcess);

      // std::cout << "Result: mHardwareNumCores = " << mHardwareNumCores << ", mMPILocalSize = " << mMPILocalSize
      //           << ", mUserAllowedThreadsPerProcess = " << mUserAllowedThreadsPerProcess
      //           << ", mHardwareAllowedThreadsPerProcess = " << mHardwareAllowedThreadsPerProcess << "\n";
    }

    void pSetMPILocalSize(device::Idx newSize)
    {
      mMPILocalSize = newSize > 0 ? newSize : 1;
      mHardwareAllowedThreadsPerProcess = std::max(mHardwareNumCores / mMPILocalSize, device::Idx{1});

      if (mUserAllowedThreadsPerProcess > 0)
        mHardwareAllowedThreadsPerProcess = std::min(mUserAllowedThreadsPerProcess, mHardwareAllowedThreadsPerProcess);
    }

    device::Idx pGetMPILocalSize() const { return mMPILocalSize; }

    void pSetMPIThreadsNotOK() { mUserAllowedThreadsPerProcess = 1; }

    device::Idx pGetMaxThreadCount() const { return mHardwareAllowedThreadsPerProcess; }
  };
} // namespace TempLat

#endif