Why does this Java code not use all CPU cores?

The attached simple Java code should load all available processor cores at startup with the correct parameters. For example, you start with

java VMTest 8 int 0

and it will start 8 threads that will do nothing more than a loop and add 2 to the whole. Something that works in registers and doesn't even allocate new memory.

The problem we are facing right now is that we do not get a bootable 24-core machine (AMD 2 connectors with 12 cores) when starting this simple program (with 24 threads, of course). Similar things happen with 2 programs of 12 threads or fewer machines.

Therefore, our suspicion that the JVM (Sun JDK 6u20 on Linux x64) does not scale well.

Has anyone seen similar things or have the ability to run it and tell if it works well on his machine (> = 8 cores only, please)? Ideas?

I tried this on Amazon EC2 with 8 cores, but the virtual machine seems to be different from the real one, so the loading behaves quite strange.

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
java cpu multicore scalability scaling
May 19 '10 at 16:03
source share
5 answers

I do not see anything wrong with your code.

However, unfortunately, you cannot specify processor affinity in Java. So this is actually left up to the OS, not the JVM. All about how your OS handles threads.

You can split Java threads into separate processes and wrap them in your own code to put one process on the core. This, of course, complicates the communication, as it will be interprocess rather than inter-thread. In any case, network computing applications such as real-time work are so popular.

Otherwise, you can fix the OS to schedule threads.

+10
May 19 '10 at 16:23
source share

I would suggest that this is inherent in the JVM / OS, and not necessarily your code. Check out various Sun JVM performance tuning documents, for example. http://ch.sun.com/sunnews/events/2009/apr/adworkshop/pdf/5-1-Java-Performance.pdf , which suggests using numactl on Linux to set an affinity.

Good luck

+4
May 19 '10 at 17:03
source share

Obviously, your virtual machine operates in the so-called "client" mode, where all Java threads are mapped to one OS thread and, therefore, are controlled by the same CPU core. Try -server JVM with the -server switch, this should fix the problem.

If you get the found Error: no 'server' JVM , you will have to copy the server directory from the JDK directory jre\bin to the JRE bin .

+2
Apr 21 '13 at 20:22
source share

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, the program consumed 100% of the processor, as shown by vmstat

Interestingly, I came to this article because I suspect that my application does not use all the cores, as CPU usage never increases, but the response time starts to deteriorate

+1
Oct. 20 '10 at 5:51
source share

I noticed even in C that a narrow loop often has such problems. You will also see quite significant differences depending on the OS.

Depending on the reporting tool used, it may not tell the CPU used by some core services.

Java is generally very friendly. You can try the same thing on linux, but set the process priority to some negative number and see how it works.

Prioritizing threads within the application can help a little if your jvm does not use green threads.

A lot of variables.

0
May 19 '10 at 17:52
source share



All Articles