2012-11-08 59 views
14

我觀察到,當linux futexes競爭時,系統花費了很多時間在自旋鎖中。我注意到即使不直接使用futexes也是一個問題,而且在調用malloc/free,rand,glib mutex調用以及調用futex的其他系統/庫調用時也會出現問題。有沒有ANY擺脫這種行爲的方法?競爭futex時高系統CPU使用率

我正在使用內核2.6.32-279.9.1.el6.x86_64的CentOS 6.3。我也嘗試了從kernel.org直接下載的最新的穩定內核3.6.6。

本來,問題發生在一臺配備16GB RAM的24核心服務器上。該進程有700個線程。使用「perf記錄」收集的數據顯示自旋鎖是從__lll_lock_wait_private和__lll_unlock_wake_private調用的futex中調用的,正在佔用50%的CPU時間。當我用gdb停止進程時,回溯顯示調用__lll_lock_wait_private __lll_unlock_wake_private是由malloc和free創建的。

我試圖減少這個問題,所以我寫了一個簡單的程序,顯示它確實是導致螺旋鎖問題的futexes。

啓動8個線程,每個線程執行以下操作:

//... 
    static GMutex *lMethodMutex = g_mutex_new(); 
    while (true) 
    { 
     static guint64 i = 0; 
     g_mutex_lock (lMethodMutex); 
     // Perform any operation in the user space that needs to be protected. 
     // The operation itself is not important. It's the taking and releasing 
     // of the mutex that matters. 
     ++i; 
     g_mutex_unlock (lMethodMutex); 
    } 
    //... 

我是一個8核的機器上運行這個,用大量的RAM。

使用「頂部」,我發現機器空閒10%,用戶模式下10%,系統模式下90%。

使用「PERF頂部」,我觀察到以下:

50.73% [kernel]    [k] _spin_lock 
11.13% [kernel]    [k] hpet_msi_next_event 
    2.98% libpthread-2.12.so  [.] pthread_mutex_lock 
    2.90% libpthread-2.12.so  [.] pthread_mutex_unlock 
    1.94% libpthread-2.12.so  [.] __lll_lock_wait 
    1.59% [kernel]    [k] futex_wake 
    1.43% [kernel]    [k] __audit_syscall_exit 
    1.38% [kernel]    [k] copy_user_generic_string 
    1.35% [kernel]    [k] system_call 
    1.07% [kernel]    [k] schedule 
    0.99% [kernel]    [k] hash_futex 

我希望這段代碼花費一些時間在自旋鎖,因爲futex的代碼必須獲得futex的等待隊列。我也希望代碼在系統中花費一些時間,因爲在這段代碼中,用戶空間中運行的代碼非常少。然而,花費在自旋鎖上的時間有50%似乎過多,特別是當這個CPU時間需要做其他有用的工作時。

+1

您可能想談談您希望看到的行爲。我覺得這並不完全清楚。 – NPE

+0

使用互斥鎖或futex來同時增加變量(如上例所示)有點愚蠢,因爲這可以直接使用原子增量(效率高出50至500倍)完成。在「真實」代碼中,即實際上做了某些事情的代碼,我發現擁擠和浪費的時間浪費在旋轉而非可忽略的細節上。實時代碼不會同時爭奪六個線程的鎖定。 – Damon

+1

最初,我注意到這是一個問題,即使futexes不是直接從用戶代碼調用;調用malloc/free,rand,glib mutex調用以及調用futex的其他系統/庫調用時會發生這種情況。問題描述中給出的代碼片段僅僅是爲了展示問題的發生,而絕不代表任何有用的工作。實際上,互斥調用之間的代碼可以是任何用戶代碼。 –

回答

3

我也碰到類似的問題。我的經驗是,當鎖定和解鎖很多時,您可能會看到性能下降甚至死鎖,具體取決於libc版本和許多其他模糊的內容(例如調用fork(),如here)。

This guy通過切換到tcmalloc解決了他的性能問題,無論如何,這取決於用例可能是一個好主意。對你來說這也值得一試。

對我來說,當我有多個線程進行大量的鎖定和解鎖操作時,我看到了可重複的死鎖。我從2010年開始使用帶有libc的Debian 5.0 rootfs(嵌入式系統),並通過升級到Debian 6.0來解決該問題。

+0

我嘗試了jemalloc,問題不再發生。這並不奇怪,因爲jemalloc對glibc的競技場鎖定的依賴要少得多。 但是,這並不能完全解決問題,因爲問題的根本原因是futex的螺旋鎖持續時間過長,導致所有其他正在執行的線程堆積等待螺旋鎖釋放(正如我在問題的原始描述中的一小段代碼所展示的那樣)。 –