2012-11-08 25 views
14

Tôi đã quan sát thấy rằng khi các futexes Linux được tranh luận, hệ thống dành rất nhiều thời gian trong các vòng quay. Tôi nhận thấy điều này là một vấn đề ngay cả khi futexes không được sử dụng trực tiếp, mà còn khi gọi các cuộc gọi md/free, rand, glib mutex và các cuộc gọi hệ thống/thư viện khác thực hiện cuộc gọi đến futex. Có ANY cách loại bỏ hành vi này không?Sử dụng CPU hệ thống cao khi cạnh tranh với futex

Tôi đang sử dụng CentOS 6.3 với hạt nhân 2.6.32-279.9.1.el6.x86_64. Tôi cũng đã thử phiên bản 3.6.6 mới nhất được tải xuống trực tiếp từ kernel.org.

Ban đầu, sự cố xảy ra trên máy chủ 24 lõi có RAM 16 GB. Quá trình này có 700 chủ đề. Các dữ liệu thu thập với "hồ sơ perf" cho thấy rằng spinlock được gọi là từ futex được gọi là từ __lll_lock_wait_private và __lll_unlock_wake_private, và đang ăn đi 50% thời gian CPU. Khi tôi ngừng quá trình với gdb, backtraces cho thấy các cuộc gọi đến __lll_lock_wait_private __lll_unlock_wake_private được làm từ malloc và miễn phí.

Tôi đã cố gắng giảm vấn đề, vì vậy tôi đã viết một chương trình đơn giản cho thấy đó thực sự là các futexes đang gây ra vấn đề spinlock.

Bắt đầu 8 chủ đề, mỗi chủ đề cách làm như sau:

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

Tôi đang chạy này trên một máy 8-core, với nhiều RAM.

Sử dụng "trên cùng", tôi quan sát thấy máy đang ở chế độ không hoạt động 10%, 10% ở chế độ người dùng và 90% ở chế độ hệ thống.

Sử dụng "Perf top", tôi quan sát thấy như sau:

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 

Tôi mong chờ mã này để dành một số thời gian trong spinlock, vì mã futex có để có được hàng đợi futex chờ đợi. Tôi cũng sẽ mong đợi mã để dành một số thời gian trong hệ thống, vì trong đoạn mã này có rất ít mã đang chạy trong không gian người dùng. Tuy nhiên, 50% thời gian dành cho spinlock dường như quá mức, đặc biệt khi thời gian cpu này là cần thiết để thực hiện các công việc hữu ích khác.

+1

Bạn có thể muốn nói một vài từ về hành vi bạn muốn xem. Tôi cảm thấy rằng điều này không hoàn toàn rõ ràng. – NPE

+0

Sử dụng một mutex hoặc futex để đồng thời tăng một biến như trong ví dụ trên là một chút ngớ ngẩn, vì điều này có thể được thực hiện trực tiếp với tăng nguyên tử (ở đâu đó từ 50 đến 500 lần hiệu quả hơn). Trong mã "thực", tức là mã thực sự làm một điều gì đó, tôi thấy tắc nghẽn và lãng phí thời gian xoay theo các chi tiết khá rõ ràng. Mã thực không cạnh tranh cho một khóa từ một nửa tá chủ đề tại một thời điểm. – Damon

+1

Ban đầu, tôi nhận thấy đây là một vấn đề ngay cả khi futexes không được gọi trực tiếp từ mã người dùng; điều này xảy ra khi gọi các cuộc gọi mutoc/free, rand, glib mutex và các cuộc gọi hệ thống/thư viện khác thực hiện cuộc gọi đến futex. Đoạn mã được đưa ra trong mô tả sự cố chỉ là để chứng minh sự xuất hiện của vấn đề và không có nghĩa là nó đại diện cho bất kỳ công việc hữu ích nào. Trong thực tế, mã giữa các cuộc gọi đến mutex có thể là bất kỳ mã người dùng nào. –

Trả lời

3

Tôi cũng đã gặp phải sự cố tương tự. Trải nghiệm của tôi là bạn có thể thấy hiệu suất hay thậm chí là bế tắc khi khóa và mở khóa rất nhiều, tùy thuộc vào phiên bản libc và rất nhiều thứ không rõ ràng khác (ví dụ: gọi tới ngã ba() như here).

This guy giải quyết các vấn đề về hiệu suất của mình bằng cách chuyển sang tcmalloc, có thể là một ý tưởng hay, tùy thuộc vào trường hợp sử dụng. Nó có thể là giá trị một thử cho bạn là tốt.

Đối với tôi, tôi thấy một bế tắc lặp lại khi tôi có nhiều chuỗi thực hiện rất nhiều khóa và mở khóa. Tôi đang sử dụng rootfs Debian 5.0 (hệ thống nhúng) với libc từ năm 2010 và sự cố đã được khắc phục bằng cách nâng cấp lên Debian 6.0.

+0

Tôi đã thử jemalloc, và vấn đề không xảy ra nữa. Điều này không có gì đáng ngạc nhiên, vì jemalloc phụ thuộc ít hơn vào việc khóa các đấu trường hơn là glibc. Điều này, tuy nhiên, không hoàn toàn giải quyết được vấn đề, vì nguyên nhân gốc rễ của vấn đề là spinlock của futex được giữ quá lâu, khiến cho tất cả các chuỗi thực thi khác chồng chất chờ đợi spinlock được giải phóng (như được minh họa bằng đoạn mã nhỏ của tôi trong mô tả ban đầu của vấn đề). –

Các vấn đề liên quan