2015-02-11 57 views
3

我有4个可执行文件,它们执行一些非常复杂的任务,这些程序中的每一个都可能占用四核CPU的单个核心几乎100%的功率,因此导致几乎占CPU总功率的25%。由于所有这些程序都使用不能在多个进程之间共享的硬件资源,因此我希望运行一个生成3个子进程的可执行文件,而这3个子进程占用另外3个内核。我在Linux上,我正在使用C++ 11。大多数复杂的代码都在自己的类中运行,而最难的部分运行在我通常称为Process()的函数中,所以我有4个对象,每个对象都有自己的Process(),运行时占用单个内核的100%。四核上的Linux:单个可执行文件,四个进程

我尝试过使用OpenMP,但我不认为这是最好的解决方案,因为我无法控制CPU亲和力。同样使用std::thread不是一个好主意,因为线程会继承主进程的CPU关联。在Linux中,我认为我可以用fork()来做到这一点,但我不知道整个结构是如何制作的。

这可能与my other question有关,可能是因为我在尝试在某些情况下有效的错误方法,但在我的情况下不起作用。

的伪代码的一个例子可能是这样的:

int main() 
{ 
    // ...init everything... 

    // This alone takes 100% of a single core 
    float out1 = object1->Process(); 

    // This should be spawned as a child process running on another core 
    float out2 = object2->Process(); 

    // on another core... 
    float out3 ... 

    // yet another core... 
    float out4 ... 

    // This should still run in the parent process 
    float total_output = out1 + out2 + out3 + out4; 
} 
+2

我相信你仍然可以通过在该线程内调用'gettid()'来使用'std :: thread',然后将'pid'参数传递给'sched_setaffinity()'。编辑:实际上,你甚至不需要调用'gettid()',只需将'pid'保留为零,'sched_setaffinity()'将修改调用线程*的亲和性。 – inetknght 2015-02-11 16:03:44

回答

1

您可以使用std::thread,这是一个前端pthread_create()。 然后从线程本身设置与sched_setaffinity()的亲和性。

至于你问,在这里工作存根:

#include <sched.h> 
#include <thread> 
#include <list> 

void thread_func(int cpu_index) { 
    cpu_set_t cpuSet; 
    CPU_ZERO(&cpuSet); 
    CPU_SET(cpu_index, &cpuSet); 
    sched_setaffinity(0, sizeof(cpu_set_t), &cpuSet); 
    /* the rest of the thread body here */ 
} 

using namespace std; 

int main(int argc, char **argv) { 
    if (argc != 2) exit(1); 
    int n_cpus = atoi(argv[1]); 

    list< shared_ptr<thread> > lot; 
    for (int i=0; i<n_cpus; ++i) { 
    lot.push_back(shared_ptr<thread>(new thread(thread_func, i))); 
    } 

    for(auto tptr = lot.begin(); tptr != lot.end(); ++tptr) { 
    (*tptr)->join(); 
    } 
} 

请注意,以获得最佳性能,重要的是每个线程初始化它的内存(也就是构造它的对象)的线状体,如果你想要的您的代码也在多处理器上进行了优化,因为如果您正在使用NUMA系统,则会在使用它们的CPU附近的内存上分配内存页。

例如,您可以看看this blog

然而,这是不是在你的具体情况下的问题,因为你是在处理一个单处理器系统,或者更具体的系统只有一个NUMA节点(目前很多AMD处理器确实包含两个NUMA节点,即使内单一的物理包),并且所有的存储库都附在那里。

在这种情况下使用sched_setaffinity()的最终效果就是将每个线程固定到特定的核心。

+0

准确地说,我正在研发一款四核Cortex A9 ARMv7 CPU,它是一个嵌入式Linux平台。 – 2015-02-11 16:25:07

+0

好的,我认为这当然不是SMP!我报告的信息适用于所有AMD SMP和MIPS SMP以及从放弃其前端总线(FSB)时开始的英特尔SMP。 – Sigismondo 2015-02-11 16:38:14

+0

所以,你认为它可以用于'std :: thread'和'sched_setaffinity()'吗?你能提供一些我可以测试的代码示例吗? – 2015-02-11 19:46:37

1

您不必编程任何东西。命令taskset将更改当前正在运行的进程的CPU关联,或者为新进程创建并设置它。

运行产生其他程序的单个可执行文件与直接执行程序没有区别,除了存根中的注释隐含的通用初始化。

taskset 1 program_for_cpu_0 arg1 arg2 arg3... 
taskset 2 program_for_cpu_1 arg1 arg2 arg3... 
taskset 4 program_for_cpu_2 arg1 arg2 arg3... 
taskset 8 program_for_cpu_3 arg1 arg2 arg3... 

我怀疑设置CPU的亲和力。我还没有找到实际的用途(除了满足一些内在的控制需求外)。

除非CPU在某些方面不相同,否则不应该将进程限制到特定的CPU。

  1. Linux内核通常保持在同一个CPU上的过程,除非它进入一个扩展等待I/O,一个信号量,等等
  2. 切换的处理从一个CPU到另一个不产生任何特别的额外开销除了每个CPU具有本地内存的NUMA配置。 AFAIK,ARM实现不这样做。
  3. 如果进程应该表现出非CPU绑定行为,允许内核调度程序灵活地将进程重新分配给现在可用的CPU,应该可以提高系统性能。绑定到CPU的进程无法参与资源可用性。
+0

1.或者需要执行另一个进程,而不是线程开始在核心上跳舞。 2.除了在旧内核中留下缓存行外,即使内核位于同一处理器内,切换内核也会导致代价高昂且无用的缓存未命中。这是当前内核试图强制执行线程核心关联的最终原因。 3.我同意你松散的灵活性,但它会在你优化的时候发生,正如OP所要做的那样。 – Sigismondo 2015-02-12 20:03:01

+0

@Sigismondo:关于缓存的好处,但在多核ARM上,level0缓存是统一的。我所使用的系统都没有level1或更高的缓存。 – wallyk 2015-02-12 20:27:56

+0

是level0 ARM的L2名称?我不是ARM的专家:)但是L1对于内核来说是本地的 - 或者我错了吗?例如http://www.arm.com/products/processors/cortex-a/cortex-a9.php – Sigismondo 2015-02-13 05:05:26

相关问题