2015-02-11 55 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

相關問題