2010-05-19 8 views
14

Der beigefügte einfache Java-Code sollte alle verfügbaren CPU-Kerne laden, wenn er mit den richtigen Parametern gestartet wird. So zum Beispiel, starten Sie es mitWarum verwendet dieser Java-Code nicht alle CPU-Kerne?

java VMTest 8 int 0

und es wird 8 Threads beginnen, die nichts anderes tun, als Looping und das Hinzufügen von 2 auf eine ganze Zahl. Etwas, das in Registern läuft und nicht einmal neuen Speicher zuweist.

Das Problem, das wir jetzt haben, ist, dass wir keine 24-Kern-Maschine (AMD 2 Sockel mit je 12 Kernen) bekommen, wenn wir dieses einfache Programm (mit 24 Threads natürlich) laufen lassen. Ähnliches passiert mit 2 Programmen zu je 12 Threads oder kleineren Maschinen.

Also unser Verdacht ist, dass die JVM (Sun JDK 6u20 auf Linux x64) nicht gut skaliert.

Hat jemand ähnliche Dinge gesehen oder hat die Fähigkeit, es auszuführen und zu melden, ob es auf seinem Rechner gut läuft (> = nur 8 Kerne)? Ideen?

Ich habe das auf Amazon EC2 mit 8 Kernen auch versucht, aber die virtuelle Maschine scheint anders als eine echte Box zu laufen, so dass das Laden völlig seltsam verhält.

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

Zusätzliche Informationen. Habe gerade herausgefunden, dass die 64bit-Version des JDK die Kerne wesentlich besser lädt (ca. 90%) als die 32bit-Version (ca. 45%). Das ist seltsam, weil das Betriebssystem und die AMD-CPU 32bit unterstützen und ich während dieses Tests keine Speicheroperationen ausführe. – ReneS

+1

Nur zum Verständnis - warum verwenden Sie nicht die Methode invokeAll (..)? Und warum benutzt du keine callables, soweit ich weiß, runnable ist nicht Teil von java.concurrent? – InsertNickHere

+0

Sie sollten auch nach anderen laufenden Prozessen Ausschau halten. Haben Sie einen "sauberen" Lauf gemacht, ohne dass andere Programme/Prozesse CPU-Zeit benötigen? – InsertNickHere

Antwort

10

Ich sehe nichts falsch mit Ihrem Code.

Leider können Sie die Prozessoraffinität in Java jedoch nicht angeben. Also, das ist tatsächlich dem Betriebssystem überlassen, nicht der JVM. Es geht darum, wie Ihr Betriebssystem Threads behandelt.

Sie könnten Ihre Java-Threads in separate Prozesse aufteilen und sie in nativen Code einbinden, um einen Prozess pro Kern zu erstellen. Dies erschwert natürlich die Kommunikation, da es interprozessual statt inter-thread ist. Wie auch immer, so funktionieren Grid-Computing-Anwendungen wie Boink.

Andernfalls sind Sie dem Betriebssystem ausgesetzt, um die Threads zu planen.

+0

Das war nicht die Frage und das Laufen von 2 VMs mit weniger Threads ändert das Spiel nicht so sehr. – ReneS

+0

Wie wäre es mit einer JVM pro Kern, mit jeweils zwei Threads? Vielleicht möchten Sie Ihre Frage ändern, weil ich geantwortet habe: "Warum verwendet dieser Java-Code nicht alle CPU-Kerne?" –

+0

Sorry über das Missverständnis, aber die Frage ist: "... DIESER Java-Code ...". Es ist einfach, kein Sperren, keine Synchronisation, keine Speicherzuweisung und immer noch nicht 100% CPU-Nutzung. Dies sollte X gleichzeitige und unabhängige Threads erstellen. – ReneS

4

Ich denke, das ist in der JVM/OS und nicht unbedingt Ihr Code inhärent. Überprüfen Sie die verschiedenen JVM-Leistungsoptimierungsdokumente von Sun, z. http://ch.sun.com/sunnews/events/2009/apr/adworkshop/pdf/5-1-Java-Performance.pdf, die unter Verwendung numactl unter Linux schlägt die Affinität festlegen.

Viel Glück!

+0

Diese Option sollte das afinity-Problem beheben (falls implementiert) – Justin

+0

Danke für den Hinweis auf Folien und Programm. Werde das versuchen. – ReneS

+0

Scheint, etwas zu tun, aber es ist schwierig. Es gibt zusätzliche Flags wie -XX: + UseTLAB und -XX: + UseNUMA, die auf die VM angewendet werden können, um besser mit der zugrunde liegenden Architektur zu arbeiten. – ReneS

0

Ich habe sogar auf C bemerkt, dass eine enge Schleife oft solche Probleme hat. Je nach Betriebssystem werden Sie auch große Unterschiede feststellen.

Je nach dem von Ihnen verwendeten Berichtstool meldet es möglicherweise nicht die von einigen Kerndiensten verwendete CPU.

Java neigt dazu, ziemlich freundlich zu sein. Sie könnten dasselbe in Linux versuchen, aber setzen Sie die Prozesspriorität auf eine negative Zahl und sehen Sie, wie es sich verhält.

Das Setzen von Thread-Prioritäten innerhalb der App kann auch ein wenig helfen, wenn Ihr jvm keine grünen Threads verwendet.

Viele Variablen.

+1

Danke, aber keine VM benutzt mehr grüne Threads, jedenfalls nicht auf typischen Plattformen wie Windows, Linux, Solaris, MacOS. – ReneS

+0

@ReneS In den letzten Jahren habe ich an Java gearbeitet, das in Kabelboxen und Spektrumanalysatoren eingebettet ist - ich mache einige Annahmen wie diese - ich wollte nur sagen, dass es eine Menge zu beachten gab. –

+0

Kein Problem und danke für deinen Kommentar, habe noch nie grüne Threads in meiner Java-Welt seit Ewigkeiten gesehen. – ReneS

1

uname -a 2.6.18-194.11.4.EL5 # 1 SMP Di 21. September 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, verbraucht das Programm 100% cpu als

von vmstat gezeigt

Interessanter zu diesem Artikel ich kam, weil ich meine Anwendung verwendet, ist nicht alle Kerne ich zu ahnen, wie die CPU-Auslastung beginnt nie erhöht, aber die Reaktionszeit

verschlechtert
2

Anscheinend läuft Ihre VM im sogenannten "Client" -Modus, in dem alle Java-Threads einem nativen OS-Thread zugeordnet sind und folglich von einem einzigen CPU-Kern ausgeführt werden. Versuchen Sie, die JVM mit -server Schalter aufzurufen, dies sollte das Problem beheben.

Wenn Sie eine bekommen: Error: no 'server' JVM gefunden, werden Sie das server Verzeichnis von einem binjre\bin Verzeichnis JRE JDK kopieren.

Verwandte Themen