2012-11-08 3 views
14

리눅스 퓨 텍스가 경합 할 때 시스템이 스핀 록에 많은 시간을 소비한다는 것을 관찰했습니다. 퓨 텍스가 직접적으로 사용되지 않더라도, malloc/free, rand, glib 뮤텍스 호출, 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"로 수집 된 데이터는 spinlock이 __lll_lock_wait_private 및 __lll_unlock_wake_private에서 호출되는 futex에서 호출되고 CPU 시간의 50 %를 소비하고 있음을 보여줍니다. gdb로 프로세스를 멈추었을 때 backtraces는 malloc과 free에서 __lll_lock_wait_private __lll_unlock_wake_private에 대한 호출이 이루어진다는 것을 보여주었습니다.

나는이 문제를 줄이려고 했으므로, 실제로 스핀 록 문제를 일으키는 퓨 텍스를 보여주는 간단한 프로그램을 작성했습니다.

시작 다음을 수행 각 스레드 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 %라는 것을 관찰했습니다. 나는 퓨 텍스 코드가 퓨 텍스 대기 큐를 취득해야하기 때문에이 코드는, 스핀 록에 일부 시간을 보내고 기대

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 

:

은 "반환 한 최고"를 사용하여, 나는 다음과 같은 관찰했다. 이 코드 스 니펫에서는 사용자 공간에서 실행되는 코드가 거의 없기 때문에 코드가 시스템에서 약간의 시간을 소비 할 것으로 기대합니다. 그러나 스핀 록에서 보낸 시간의 50 %는 과도한 것으로 보이는데 특히이 CPU 시간이 다른 유용한 작업을 수행하는 데 필요할 때입니다.

+1

당신이보고 싶은 행동에 대해 몇 마디 말하고 싶을 것입니다. 나는 이것이 완전히 명확하지 않다고 느낀다. – NPE

+0

mutex 또는 futex를 사용하여 위 예제 에서처럼 변수를 동시에 증가시키는 것은 원자량 증가 (50 ~ 500 배 정도 더 효율적)로 직접 수행 할 수 있으므로 약간 바보입니다. "실제"코드, 즉 실제로 무언가를하는 코드에서 혼잡과 시간이 낭비되는 세부 사항을 낭비하는 것을 낭비합니다. 실제 코드는 한 번에 6 개의 스레드에서 잠금을 위해 경쟁하지 않습니다. – Damon

+1

원래, 퓨 텍스가 사용자 코드에서 직접 호출되지 않아도 문제가되는 것으로 나타났습니다. 이것은 malloc/free, rand, glib 뮤텍스 호출 및 futex를 호출하는 다른 시스템/라이브러리 호출을 호출 할 때 발생합니다. 문제 설명에 제공된 코드 스 니펫은 문제의 발생을 보여주기위한 것으로 아무런 유용한 작업을 의미하지는 않습니다. 사실 뮤텍스 호출 사이의 코드는 모든 사용자 코드가 될 수 있습니다. –

답변

3

비슷한 문제가 발생했습니다. libc 버전과 다른 많은 모호한 것들 (예 : here과 같은 fork() 호출)에 따라 많이 잠기거나 잠금 해제 할 때 성능이 저하되거나 심지어 교착 상태가 발생할 수도 있습니다.

This guy은 사용 사례에 따라 좋은 아이디어 일 수있는 tcmalloc으로 전환하여 성능 문제를 해결했습니다. 그것은 당신을위한 시도 가치가있을 수 있습니다.

많은 스레드를 잠금 및 잠금 해제하는 다중 스레드가있을 때 재현 가능한 교착 상태가 발생했습니다. 2010 년부터 libc에서 Debian 5.0 rootfs (임베디드 시스템)를 사용하고 있었는데이 문제는 Debian 6.0으로 업그레이드하여 해결되었습니다.

+0

jemalloc을 사용해 보았는데 문제가 더 이상 발생하지 않습니다. jemalloc은 glibc보다 경기장을 잠그는 데 훨씬 덜 의존하기 때문에 이것은 놀라운 일이 아닙니다. 그러나 문제의 근본 원인은 퓨 텍스의 스핀 록이 너무 길게 유지되어 다른 모든 실행 스레드가 스핀 록이 해제 될 때까지 대기하게되므로 문제를 완전히 해결하지 못합니다 (문제의 원래 설명에서 코드의 작은 조각으로 설명). –

관련 문제