Pourquoi ce code Java n'utilise-t-il pas tous les cœurs CPU?

le code Java simple ci-joint devrait charger tout le noyau cpu disponible au démarrage avec les bons paramètres. Ainsi, par exemple, vous commencez avec

java VMTest 8 int 0

et il va démarrer 8 threads qui ne font rien d'autre que boucler et ajouter 2 à un entier. Quelque chose qui fonctionne dans les registres et qui n'alloue même pas de nouvelle mémoire.

le problème auquel nous sommes confrontés maintenant est que nous ne chargez une machine 24 core (AMD 2 sockets avec 12 core chacun), en exécutant ce programme simple (avec 24 threads bien sûr). Des choses semblables se produisent avec 2 programmes chaque 12 threads ou des machines plus petites.

ainsi notre soupçon est que la JVM (Sun JDK 6u20 sur Linux x64) ne se balance pas bien.

quelqu'voir des choses semblables ou a la possibilité d'exécuter et de le signaler si oui ou non il fonctionne bien sur sa machine (>= 8 cœurs seulement s'il vous plaît)? Des idées?

j'ai essayé cela sur Amazon EC2 avec 8 cœurs aussi, mais la machine virtuelle semble fonctionner différemment d'une vraie boîte, donc le chargement se comporte totalement étrange.

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);
    }
}
14
demandé sur Robert Harvey 2010-05-19 20:03:28

5 réponses

Je ne vois rien qui cloche avec votre code.

cependant, malheureusement, vous ne pouvez pas spécifier l'affinité du processeur en Java. Donc, c'est laissé à L'OS, pas à la JVM. Il s'agit de la façon dont votre système d'exploitation gère les fils.

vous pouvez diviser vos threads Java en processus séparés et les envelopper dans du code natif, pour mettre un processus par noyau. Cela complique évidemment la communication, car il s'agit d'un processus inter- inter-thread. Bref, c'est comme ça que les applications de calcul grid populaires comme boink fonctionnent.

sinon, vous êtes à la merci de L'OS pour programmer les fils.

10
répondu Marcus Adams 2010-05-20 12:25:01

je suppose que c'est inhérent à la JVM/OS et pas nécessairement votre code. Vérifier les différents réglages de performance JVM de Sun, par exemple http://ch.sun.com/sunnews/events/2009/apr/adworkshop/pdf/5-1-Java-Performance.pdf qui suggère d'utiliser numactl sur Linux pour définir l'affinité.

bonne chance!

4
répondu ShiDoiSi 2010-05-19 17:03:33

apparemment, votre VM tourne en mode" client", où tous les threads Java sont mappés à un seul thread OS natif et sont par conséquent exécutés par un seul noyau CPU. Essayez d'invoquer le JVM avec -server commutateur, cela devrait corriger le problème.

si vous obtenez un: Error: no 'server' JVM trouvé, vous devrez copier le répertoire server à partir du répertoire jre\bin de JDK vers le répertoire bin de JRE .

2
répondu johnidis 2013-04-21 20:22:41

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

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

Java 1.6.0_20-B02

16cores, le programme consommé 100% cpu comme indiqué par vmstat

fait intéressant, je suis venu à cet article parce que je soupçonne ma demande n'est pas utiliser tous les noyaux car l'utilisation du cpu n'augmente jamais mais le temps de réponse commence à se détériorer

1
répondu Nikhil 2010-10-20 05:51:24

j'ai remarqué même sur C qu'une boucle serrée a souvent des problèmes comme ça. Vous verrez également de grandes différences selon OS.

selon l'outil de rapport que vous utilisez, il peut ne pas déclarer le CPU utilisé par certains services de base.

Java a tendance à être plutôt amical. Vous pouvez essayer la même chose avec linux, mais mettez la priorité du processus à un nombre négatif et voyez comment il agit.

établir les priorités du fil de discussion à l'intérieur de l'application peut aider un peu trop si votre jvm n'utilise pas des fils verts.

beaucoup de variables.

0
répondu Bill K 2010-05-19 17:52:30