2010-05-19 12 views
14

Mã Java đơn giản kèm theo sẽ tải tất cả lõi cpu có sẵn khi khởi động nó bằng các tham số phù hợp. Vì vậy, ví dụ, bạn bắt đầu nó vớiTại sao mã Java này không sử dụng tất cả các lõi CPU?

java VMTEST 8 int 0

và nó sẽ bắt đầu 8 chủ đề mà không phải làm gì khác hơn là lặp và thêm 2 đến một số nguyên. Một cái gì đó chạy trong sổ đăng ký và thậm chí không phân bổ bộ nhớ mới.

Vấn đề chúng ta đang gặp phải là chúng tôi không nhận được một máy 24 lõi được nạp (ổ cắm AMD 2 với 12 lõi), khi chạy chương trình đơn giản này (với 24 luồng khóa học). Những điều tương tự xảy ra với 2 chương trình mỗi 12 chủ đề hoặc máy nhỏ hơn.

Vì vậy, sự nghi ngờ của chúng tôi là JVM (Sun JDK 6u20 trên Linux x64) không mở rộng tốt.

Có ai nhìn thấy những thứ tương tự hoặc có khả năng chạy và báo cáo có chạy tốt trên máy của mình không (> = 8 lõi chỉ)? Ý tưởng?

Tôi đã thử trên Amazon EC2 với 8 lõi quá, nhưng máy ảo dường như chạy khác với một hộp thực, do đó tải hoạt động hoàn toàn lạ.

package com.test; 

import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.Future; 
import java.util.concurrent.TimeUnit; 

public class VMTest 
{ 
    public class IntTask implements Runnable 
    { 
     @Override 
     public void run() 
     { 
      int i = 0; 

      while (true) 
      { 
       i = i + 2; 
      } 
     } 
    } 
    public class StringTask implements Runnable 
    { 
     @Override 
     public void run() 
     { 
      int i = 0; 

      String s; 
      while (true) 
      { 
       i++; 
       s = "s" + Integer.valueOf(i); 
      } 
     } 
    } 
    public class ArrayTask implements Runnable 
    { 
     private final int size; 
     public ArrayTask(int size) 
     { 
      this.size = size; 
     } 
     @Override 
     public void run() 
     { 
      int i = 0; 

      String[] s; 
      while (true) 
      { 
       i++; 
       s = new String[size]; 
      } 
     } 
    } 

    public void doIt(String[] args) throws InterruptedException 
    { 
     final String command = args[1].trim(); 

     ExecutorService executor = Executors.newFixedThreadPool(Integer.valueOf(args[0])); 
     for (int i = 0; i < Integer.valueOf(args[0]); i++) 
     { 
      Runnable runnable = null; 
      if (command.equalsIgnoreCase("int")) 
      { 
       runnable = new IntTask(); 
      } 
      else if (command.equalsIgnoreCase("string")) 
      { 
       runnable = new StringTask(); 
      } 
      Future<?> submit = executor.submit(runnable); 
     } 
     executor.awaitTermination(1, TimeUnit.HOURS); 
    } 

    public static void main(String[] args) throws InterruptedException 
    { 
     if (args.length < 3) 
     { 
      System.err.println("Usage: VMTest threadCount taskDef size"); 
      System.err.println("threadCount: Number 1..n"); 
      System.err.println("taskDef: int string array"); 
      System.err.println("size: size of memory allocation for array, "); 
      System.exit(-1); 
     } 

     new VMTest().doIt(args); 
    } 
} 
+0

Thông tin bổ sung. Chỉ cần phát hiện ra rằng phiên bản 64bit của JDK tải lõi tốt hơn (khoảng 90%) so với phiên bản 32bit (khoảng 45%). Đó là lạ, bởi vì hệ điều hành và CPU cpu hỗ trợ 32bit và tôi không chạy bất kỳ hoạt động bộ nhớ trong thử nghiệm đó. – ReneS

+1

Chỉ để hiểu - tại sao bạn không sử dụng phương thức invokeAll (..)? Và tại sao bạn không sử dụng callables, theo như tôi biết, runnable không phải là một phần của java.concurrent? – InsertNickHere

+0

Bạn cũng nên xem các quy trình đang chạy khác. Bạn đã thực hiện một "sạch" chạy, không có progamms khác/quá trình lấy cpu thời gian? – InsertNickHere

Trả lời

10

Tôi không thấy điều gì sai với mã của bạn.

Tuy nhiên, thật không may, bạn không thể chỉ định mối quan hệ bộ vi xử lý trong Java. Vì vậy, điều này thực sự là trái với hệ điều hành, không phải là JVM. Đó là tất cả về cách hệ điều hành của bạn xử lý các luồng.

Bạn có thể chia chuỗi Java của mình thành các quy trình riêng biệt và gói chúng trong mã gốc, để đặt một quy trình cho mỗi lõi. Điều này không, tất nhiên, giao tiếp phức tạp, vì nó sẽ được liên quá trình hơn là liên thread. Dù sao, đây là cách ứng dụng điện toán lưới phổ biến như công việc boink.

Nếu không, bạn đang ở lòng thương xót của Hệ điều hành để lên lịch các chuỗi.

+0

Đây không phải là câu hỏi và chạy 2 máy ảo với ít chủ đề không thay đổi trò chơi nhiều. – ReneS

+0

Làm thế nào về việc chạy một JVM mỗi lõi, với hai chủ đề mỗi? Bạn có thể muốn thay đổi câu hỏi của mình vì tôi đã trả lời "Tại sao mã Java này không sử dụng tất cả các lõi CPU?" –

+0

Xin lỗi về sự hiểu lầm, nhưng câu hỏi là: "... Mã Java này ...". Nó là đơn giản, không khóa, không đồng bộ, không có cấp phát bộ nhớ và vẫn không sử dụng 100% cpu. Điều này sẽ tạo ra X chủ đề đồng thời và độc lập. – ReneS

4

Tôi đoán đây là vốn có của JVM/OS và không nhất thiết phải là mã của bạn. Kiểm tra các tài liệu điều chỉnh hiệu suất JVM khác nhau từ Sun, ví dụ: http://ch.sun.com/sunnews/events/2009/apr/adworkshop/pdf/5-1-Java-Performance.pdf đề xuất sử dụng numactl trên Linux để đặt mối quan hệ.

Chúc may mắn!

+0

Tùy chọn này sẽ giải quyết vấn đề afinity (nếu được thực hiện) – Justin

+0

Cảm ơn gợi ý cho trang trình bày và chương trình. Sẽ thử điều đó. – ReneS

+0

Dường như làm một số thứ, nhưng rất khó. Có thêm các cờ như -XX: + UseTLAB và -XX: + UseNUMA có thể được áp dụng cho VM để làm việc với kiến ​​trúc cơ bản tốt hơn. – ReneS

0

Tôi đã nhận thấy ngay cả trên C rằng vòng lặp chặt chẽ thường có vấn đề như vậy. Bạn cũng sẽ thấy sự khác biệt khá lớn tùy thuộc vào hệ điều hành.

Tùy thuộc vào công cụ báo cáo bạn đang sử dụng, nó có thể không báo cáo CPU được một số dịch vụ cốt lõi sử dụng.

Java có xu hướng khá thân thiện. Bạn có thể thử cùng một điều trong linux nhưng đặt ưu tiên quá trình cho một số số âm và xem nó hoạt động như thế nào.

Đặt mức độ ưu tiên của luồng trong ứng dụng cũng có thể giúp ích một chút nếu jvm của bạn không sử dụng chuỗi màu xanh lục.

Rất nhiều biến.

+1

Cảm ơn, nhưng không có máy ảo nào đang sử dụng các chuỗi màu xanh lá cây nữa ít nhất là kiến ​​thức của tôi trên các nền tảng điển hình như Windows, Linux, Solaris, MacOS. – ReneS

+0

@ReneS Trong vài năm qua tôi đã làm việc trên Java được nhúng trong các hộp cáp và máy phân tích phổ - tôi đưa ra một vài giả định như thế - tôi vừa mới nói rằng có rất nhiều điều cần xem xét. –

+0

Không có vấn đề và cảm ơn cho bình luận của bạn, chỉ cần chưa bao giờ nhìn thấy chủ đề màu xanh lá cây trong thế giới Java của tôi cho các lứa tuổi. – ReneS

1

uname -a 2.6.18-194.11.4.el5 # 1 SMP Tue 21 tháng 9 05:04:09 EDT 2010 x86_64 x86_64 x86_64 GNU/Linux

Intel (R) Xeon (R) CPU E5530 @ 2.40GHz http://browse.geekbench.ca/geekbench2/view/182101

Java 1.6.0_20-b02

16cores, chương trình tiêu thụ 100% cpu như thể hiện bởi vmstat

Điều thú vị là tôi đến bài viết này bởi vì tôi đang nghi ngờ ứng dụng của tôi không được sử dụng tất cả các lõi như việc sử dụng CPU không bao giờ tăng nhưng thời gian phản ứng bắt đầu xấu đi

2

Dường như máy ảo của bạn đang chạy trong chế độ "máy khách", trong đó tất cả các luồng Java được ánh xạ tới một chuỗi hệ điều hành gốc và do đó được chạy bởi một lõi CPU đơn. Hãy thử gọi JVM bằng công tắc -server, điều này sẽ khắc phục sự cố.

Nếu bạn nhận được: Error: no 'server' JVM được tìm thấy, bạn sẽ phải sao chép thư mục server từ thư mục jre\bin của JDK vào số bin của JRE.