El código Java simple adjunto debería cargar todo el núcleo de la CPU disponible al iniciarlo con los parámetros correctos. Así, por ejemplo, se inicia con¿Por qué este código Java no utiliza todos los núcleos de la CPU?
java VMTest 8 int 0
y comenzará 8 hilos que no hacen nada más que un bucle y la adición de 2 a un entero. Algo que se ejecuta en registros y ni siquiera asigna memoria nueva.
El problema al que nos enfrentamos ahora es que no tenemos una máquina con 24 núcleos cargados (sockets AMD 2 con 12 núcleos cada uno), cuando se ejecuta este sencillo programa (con 24 subprocesos, por supuesto). Cosas similares suceden con 2 programas cada 12 hilos o máquinas más pequeñas.
Así que nuestra sospecha es que la JVM (Sun JDK 6u20 en Linux x64) no escala bien.
¿Alguien ha visto cosas similares o tiene la capacidad de ejecutarlo e informar si funciona bien o no en su máquina (> = 8 núcleos solo por favor)? Ideas?
Lo intenté en Amazon EC2 con 8 núcleos también, pero la máquina virtual parece ser diferente de una caja real, por lo que la carga se comporta de forma totalmente extraña.
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);
}
}
Información adicional. Acabo de descubrir que la versión de 64 bits del JDK carga los núcleos mucho mejor (alrededor del 90%) que la versión de 32 bits (aproximadamente el 45%). Lo cual es extraño, porque el sistema operativo y la CPU AMD admiten 32 bits y no ejecuto ninguna operación de memoria durante esa prueba. – ReneS
Solo para entender: ¿por qué no usa el método invokeAll (..)? ¿Y por qué no usas callables, por lo que sé, ejecutable no es parte de java.concurrent? – InsertNickHere
También debe observar otros procesos en ejecución. ¿Hizo una ejecución "limpia", sin ningún otro programa/proceso que tomara tiempo de CPU? – InsertNickHere