它的工作方式非常简单——DRM(分布式资源管理器)在进程启动之前限制了进程的 CPU 关联掩码。关联掩码告诉 OS 调度程序可以在哪些逻辑 CPU 上调度进程。默认 CPU 关联掩码仅包含所有可用的逻辑 CPU。如果没有另行指示,大多数 OpenMP 运行时会在程序启动时获取该掩码,并在生成新线程时遵守该掩码。GNU 和英特尔 OpenMP 运行时都检查关联掩码以确定默认线程数(如果未OMP_NUM_THREADS
指定)。大多数 OpenMP 运行时还支持它们自己的绑定机制(也称为每线程关联),例如KMP_AFFINITY
Intel OpenMP 的变量或GOMP_CPU_AFFINITY
GNU OpenMP 的变量。其中一些可以被指示尊重原始掩码,例如KMP_AFFINITY="respect,granularity=core"
,将使英特尔 OpenMP 将其线程仅绑定到在启动进程的关联掩码中启用的 CPU。
Linux 下有两种关联掩码。一个可以被认为是软的,由sched_setaffinity(2)
系统调用设置。这个蒙版是软的,因为它可以随时被覆盖和扩展。但 Linux 也提供了所谓的 cpusets(cgroups 框架的一部分),其功能或多或少类似于轻量级容器。可以创建一个 cpuset 并仅为其分配某些逻辑 CPU,然后将该集合与请求的任何掩码进行与运算,sched_setaffinity()
以获得实际应用的最终掩码。因此 cpusets 提供了一个硬掩码——它不能被扩展,而是只能使用它或它的一个子集(但不是超集)。sched_setaffinity()
在 Linux 上采用 PID 或 TID,因此可用于设置各个线程的亲和性,这就是 OpenMP 运行时实现每个线程亲和性的方式。更便携的调用是 POSIX pthread_setaffinity_np()
。
LSF(9.1.1 及更高版本)支持使用 Linux cpuset 的关联性。如果您是 LSF 管理员,请参阅此处的文档,了解如何设置它,或者如果您是用户,如何为您的作业请求某些关联设置。
如果我没记错的话,Sun(错误……我的意思是 Oracle)Grid Engine 从 6.2u5 版本开始支持进程关联。