2012-11-08 17 views
14

Linuxのフューテックスが競合すると、システムはスピンロックに多くの時間を費やすことがわかりました。フューテックスが直接使われていなくても、malloc/free、rand、glib mutex呼び出し、futexを呼び出すシステム/ライブラリ呼び出しを呼び出すときにも問題であることに気付きました。 ありますか?この動作を取り除く方法はですか?futexを競合するときのシステムCPU使用率が高い

カーネル2.6.32-279.9.1.el6.x86_64でCentOS 6.3を使用しています。私はkernel.orgから直接ダウンロードした最新の安定版カーネル3.6.6も試しました。

元はで、16GBのRAMを搭載した24コアサーバーで問題が発生しました。プロセスには700スレッドがあります。 "perf record"で収集されたデータは、スピンロックが__lll_lock_wait_privateと__lll_unlock_wake_privateから呼び出されたフューテックスから呼び出され、CPU時間の50%を奪っていることを示しています。 gdbでプロセスを停止したとき、backtracesはmallocとfreeから__lll_lock_wait_private __lll_unlock_wake_privateの呼び出しが行われたことを示しました。

私はこの問題を軽減しようとしていたので、スピンロック問題の原因となっているのは実際にはfutexesであることを示す簡単なプログラムを書きました。

スタート次の操作を行って、各スレッドと8つのスレッド、:私はRAMをたっぷり使って、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); 
    } 
    //... 

"top"を使用して、マシンが10%アイドル状態、10%がユーザモード、90%がシステムモードであることがわかりました。私はのfutexコードはのfutex待ちキューを取得することがあるので、このコードは、スピンロックで一部の時間を費やすことを期待する

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 

は「PERFトップ」を使用して、私は次のように観察しました。このコードのスニペットでは、ユーザー空間で実行されるコードはほとんどないため、コードをシステムに費やすことも期待しています。しかし、スピンロックで費やされる時間の50%は、特にこのCPU時間が他の有用な作業を行うために必要な場合には、過剰と思われます。

+1

あなたは、どのような振る舞いが見たいか、いくつか言いたいことがあります。私はこれが完全にはっきりしていないと感じています。 – NPE

+0

上記の例のようにmutexまたはfutexを使用して変数を同時にインクリメントすると、アトミックなインクリメント(50〜500倍効率的)で直接行うことができます。 「実際の」コード、すなわち実際に何かを行うコードでは、渋滞と時間がむしろ無視できるほどの詳細を浪費していることがわかります。実際のコードは、一度に6ダースのスレッドからのロックを競合しません。 – Damon

+1

元々は、フューテックスがユーザコードから直接呼び出されない場合でも、これは問題であることに気付きました。これは、malloc/free、rand、glib mutex呼び出し、およびfutexを呼び出すシステム/ライブラリ呼び出しを呼び出すときに発生します。問題の説明に記載されているコードスニペットは、問題が発生したことを示すためのものであり、決して有用な作業ではありません。実際、mutexへの呼び出しの間のコードは、任意のユーザーコードにすることができます。 –

答えて

3

私も同様の問題に遭遇しました。私の経験では、libcのバージョンや他の不明なもの(例えば、hereのようなfork()の呼び出しなど)に応じて、多くのロックやロック解除時にパフォーマンスの低下やデッドロックが発生することがあります。

This guyは、tcmallocに切り替えることでパフォーマンスの問題を解決しましたが、これはユースケースによっては良い考えです。あなたのために試してみる価値があるかもしれません。

私にとっては、ロックとロック解除を頻繁に行うスレッドが複数ある場合、再現性のあるデッドロックが発生しました。私は2010年からDebian 5.0 rootfs(組み込みシステム)をlibcで使用していましたが、この問題はDebian 6.0にアップグレードすることで修正されました。

+0

私はjemallocを試しましたが、問題はもう起こっていません。これは驚くべきことではありません。なぜなら、jemallocはglibcよりもアリーナのロックに頼っているからです。 しかし、この問題の根本的な原因は、フューテックスのスピンロックが長すぎるため、他のすべての実行スレッドがスピンロックの解放を待っているためです(問題の元の説明で私の少しのコードスニペットで示されているように)。 –

関連する問題