我正在尝试在 SLURM 管理的 HPC 集群上运行单进程多线程作业。我打算为我的线程使用多核。
当我将资源分配给 HPC 时,我使用命令:
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=8
这应该为同一台机器上的一个进程分配 8 个 CPU,对吗?
但是,当我尝试使用以下代码检测可用核心数量时:
#include <iostream>
#include <thread>
int main() {
unsigned int n = std::thread::hardware_concurrency();
std::cout << n << " concurrent threads are supported.\n";
}
它输出:
32 concurrent threads are supported.
这很奇怪,因为我期望它输出支持 8 个并发线程。我怀疑,尽管 SLURM 只为任务分配了 8 个 CPU,但机器总共有 32 个 CPU。
但是,我使用的某些软件包依赖于 hardware_concurrency
命令来获取 CPU 数量。因此,这可能会导致某些包因线程过多而导致系统过载。
- 知道为什么吗?
- 您认为我的帐户会因该作业而被收取 32 个 CPU 时钟而不是 8 个吗?
- 我是否应该将应用程序中的线程数限制为我分配的核心数 (8),而不是 C++ 检测到的核心数 (32),以实现最高效率?
- 您是否知道任何 C++ 代码可以报告 SLURM 分配的正确可用 CPU 数量(而不是计算机中的 CPU 总数)?
最佳答案
即使一个包依赖于硬件并发性,通常它也会获得线程数的默认值。它很可能还为您提供了一种自行设置所需值的方法。如果是这种情况,那么您可以使用环境变量从 slurm 获取分配给您作业的 CPU 数量。在您的特定情况下,环境变量为 SLURM_CPUS_PER_TASK
。
您可以使用std::getenv
获取环境变量的值。它返回一个 char *
并且您需要诸如 std::atoi
之类的东西。将其转换为 int
。
#include <iostream>
#include <thread>
#include <cstdlib>
int main() {
unsigned int n = std::thread::hardware_concurrency();
std::cout << n << " concurrent threads are supported.\n";
std::cout << "CPUS_PER_TASK: " << std::atoi(std::getenv("SLURM_CPUS_PER_TASK")) << std::endl;
}
如果您不这样做,那么 C++ 程序将创建 32 个线程,但 slurm 仍应将您的作业限制为 8 个核心。因此,每个线程仅使用大约 25% 的 CPU。
关于c++ - SLURM C++ 发现可用内核多于分配的内核,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57834339/