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