2012-11-08 1 views
14

J'ai observé que lorsque les futex Linux sont en conflit, le système passe beaucoup de temps dans les verrous d'attente. J'ai remarqué que c'était un problème même quand les futex ne sont pas utilisés directement, mais aussi lors de l'appel de malloc/free, de rand, de glib mutex, et d'autres appels système/bibliothèque qui font des appels au futex. Y at-il ANY comment se débarrasser de ce comportement? J'utilise CentOS 6.3 avec le noyau 2.6.32-279.9.1.el6.x86_64. J'ai également essayé le dernier noyau stable 3.6.6 téléchargé directement sur kernel.org.Utilisation élevée de l'UC système lors de la contestation du futex

À l'origine, le problème s'est produit sur un serveur 24-core avec 16 Go de RAM. Le processus a 700 threads. Les données collectées avec "perf record" montrent que le spinlock est appelé depuis le futex appelé depuis __lll_lock_wait_private et __lll_unlock_wake_private, et qu'il ronge 50% du temps CPU. Quand j'ai arrêté le processus avec gdb, les backtraces ont montré que les appels à __lll_lock_wait_private __lll_unlock_wake_private sont faits à partir de malloc et gratuits. J'essayais de réduire le problème, alors j'ai écrit un programme simple qui montre que ce sont les futex qui provoquent le problème du spinlock.

Démarrer 8 fils, chaque fil procédant comme suit:

//... 
    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); 
    } 
    //... 

Je TOURNE, sur une machine 8-core, avec beaucoup de RAM. En utilisant "top", j'ai observé que la machine est inactive de 10%, de 10% en mode utilisateur et de 90% en mode système.

En utilisant "top perf", j'observé ce qui suit:

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 

Je me attends à ce code pour passer quelque temps dans le spinlock, puisque le code futex doit acquérir la file d'attente futex. Je m'attendrais également à ce que le code passe du temps dans le système, car dans ce fragment de code, il y a très peu de code qui s'exécute dans l'espace utilisateur. Cependant, 50% du temps passé dans le spinlock semble être excessif, surtout quand ce temps CPU est nécessaire pour faire un autre travail utile.

+1

Vous voudrez peut-être dire quelques mots sur le comportement que vous aimeriez voir. Je pense que ce n'est pas tout à fait clair. – NPE

+0

Utiliser un mutex ou un futex pour incrémenter simultanément une variable comme dans l'exemple ci-dessus est un peu bête, car cela peut être fait directement avec un incrément atomique (de 50 à 500 fois plus efficace). Dans le code "réel", c'est-à-dire le code qui fait réellement quelque chose, je trouve la congestion et le temps gaspillé à tourner des détails plutôt illisibles. Le code réel n'est pas en concurrence pour un verrou d'une demi-douzaine de threads à la fois. – Damon

+1

A l'origine, j'ai remarqué que c'était un problème même lorsque les futex ne sont pas appelés directement à partir du code utilisateur; Cela se produit lorsque vous appelez les appels malloc/free, rand, glib mutex et d'autres appels système/bibliothèque qui effectuent des appels au futex. L'extrait de code donné dans la description du problème est juste pour démontrer l'occurrence du problème, et ne représente en aucun cas un travail utile. En fait, le code entre les appels à mutex peut être n'importe quel code utilisateur. –

Répondre

3

J'ai également rencontré des problèmes similaires. Mon expérience est que vous pouvez voir une performance frapper ou même des blocages lorsque vous verrouillez et déverrouillez beaucoup, selon la version de la libc et beaucoup d'autres choses obscures (par exemple les appels à fork() comme here).

This guy a résolu ses problèmes de performances en passant à tcmalloc, ce qui peut être une bonne idée de toute façon selon le cas d'utilisation. Cela pourrait valoir la peine d'essayer pour vous aussi. Pour moi, j'ai vu une impasse reproductible quand j'avais plusieurs threads qui bloquaient et débloquaient beaucoup de choses. J'utilisais un rootfs Debian 5.0 (système embarqué) avec une libc à partir de 2010, et le problème a été corrigé en passant à Debian 6.0.

+0

J'ai essayé jemalloc, et le problème ne se produit plus. Ce n'est pas surprenant, puisque jemalloc repose beaucoup moins sur le verrouillage des arènes que sur la glibc. Cependant, cela ne résout pas complètement le problème, car la cause première du problème est que le spinlock du futex est maintenu trop longtemps, provoquant l'accumulation de tous les autres threads en attente de libération du spinlock. (comme démontré par mon petit extrait de code dans la description originale du problème). –

Questions connexes