Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Too Low CPU Usage of Multithreaded Java Application on Windows

I am working on a Java application for solving a class of numerical optimization problems - large-scale linear programming problems to be more precise. A single problem can be split up into smaller subproblems that can solved in parallel. Since there are more subproblems than CPU cores, I use an ExecutorService and define each subproblem as a Callable that gets submitted to the ExecutorService. Solving a subproblem requires calling a native library - a linear programming solver in this case.

Problem

I can run the application on Unix and on Windows systems with up to 44 physical cores and up to 256g memory, but computation times on Windows are an order of magnitude higher than on Linux for large problems. Windows not only requires substantially more memory, but CPU utilization over time drops from 25% in the beginning to 5% after a few hours. Here is a screenshot of the task manager in Windows:

Task Manager CPU utilization

Observations

  • Solution times for large instances of the overall problem range from hours to days and consume up to 32g of memory (on Unix). Solution times for a subproblem are in the ms range.
  • I do not encounter this issue on small problems that take only a few minutes to solve.
  • Linux uses both sockets out-of-the-box, whereas Windows requires me to explicitly activate memory interleaving in the BIOS so that the application utilizes both cores. Whether of not I do this has no effect on the deterioration of overall CPU utilization over time though.
  • When I look at the threads in VisualVM all pool threads are running, none are on wait or else.
  • According to VisualVM, 90% CPU time is spend on a native function call (solving a small linear program)
  • Garbage Collection is not an issue since the application does not create and de-reference a lot of objects. Also, most memory seems to be allocated off-heap. 4g of heap are sufficient on Linux and 8g on Windows for the largest instance.

What I've tried

  • all sorts of JVM args, high XMS, high metaspace, UseNUMA flag, other GCs.
  • different JVMs (Hotspot 8, 9, 10, 11).
  • different native libraries of different linear programming solvers (CLP, Xpress, Cplex, Gurobi).

Questions

  • What drives the performance difference between Linux and Windows of a large multi-threaded Java application that makes heavy use of native calls?
  • Is there anything that I can change in the implementation that would help Windows, for example, should I avoid using an ExecutorService that receives thousands of Callables and do what instead?
like image 904
Nils Avatar asked Nov 14 '19 20:11

Nils


People also ask

Does multithreading reduce CPU usage?

Although you can take advantage of multithreading to perform several tasks simultaneously and increase the application's throughput, it should be used judiciously. Incorrect usage of multithreading may result in high CPU usages or increased CPU cycles and can drastically reduce your application's performance.

How can you maximize CPU utilization using Java programming?

You can modify the CPU load incurred by a Java program by inserting sleep statements (e.g. Thread. sleep() ) in your code, using variable delays to change the load. The simplest case would be a sleep statement in a loop, executed in a separate thread for each CPU core that you want to load.

Does waiting thread consume CPU?

None. See above, but the CPU overhead used to manage the threads does not change based on the thread context.

Why CPU usage is high in Java application?

Java applications may take high CPU resources for many reasons: Poorly designed application code with inefficient or infinite loops. Inefficient algorithms (poor application logic) Recursive method calls (causing hundreds of recursions)


Video Answer


1 Answers

For Windows the number of threads per process is limited by the address space of the process (see also Mark Russinovich - Pushing the Limits of Windows: Processes and Threads). Think this causes side effects when it comes close to the limits (slow down of context switches, fragmentation...). For Windows I would try to divide the work load to a set of processes. For a similar issue that I had years ago I implemented a Java library to do this more conveniently (Java 8), have a look if you like: Library to spawn tasks in an external process.

like image 151
geri Avatar answered Oct 17 '22 06:10

geri