CPU Intensive Process - 1 Thread per CPU

This section provides a tutorial example on how to test the overall productivity of multithreading CPU intensive processe. Running 1 thread per CPU gives the most effective outcome.

Now, I can easily write a multithreading controlling program to run multiple instances of PrimeCalculator.java concurrently.

/* MultithreadingCpuRunner.java
 * Copyright (c) 2014, HerongYang.com, All Rights Reserved.
 */
public class MultithreadingCpuRunner {
   public static void main(String[] a) {

// Setting configuration
      long param = 1000; // Default parameter for the working thread
      int size = 1; // Default number of working threads
      int interval = 1; // Default monitoring interval in seconds
      if (a.length>0) param = Long.parseLong(a[0]);
      if (a.length>1) size = Integer.parseInt(a[1]);
      if (a.length>2) interval = Integer.parseInt(a[2]);
      System.out.println("Thread parameter: "+param);
      System.out.println("Number of threads: "+size);

// Launching all threads
      PrimeCalculator[] threads = new PrimeCalculator[size];
      long[] counts = new long[size];
      for (int i=0; i<size; i++) {
          PrimeCalculator t = new PrimeCalculator(param);
          t.start();
          threads[i] = t;
          counts[i] = 0;
      }
      
// Monitoring overall productivity
      long startTime = System.currentTimeMillis();
      long lastTime = startTime;
      long grandTotal = 0;
      System.out.println(
         "Seconds | Productivity per thread | Total | Average");
      while (true) {
         try {
            Thread.sleep(interval*1000);
         } catch (InterruptedException e) {
            System.out.println("Monitor interrupted.");
         }
         long curTime = System.currentTimeMillis();
         long delta = (curTime - lastTime);
         long duration = (curTime - startTime);
         System.out.print(duration/1000+" | ");
         long total = 0;
         for (int i=0; i<size; i++) {
             long c = threads[i].jobCount;
             long d = c - counts[i];
             total += d;
             System.out.print((1000*d)/delta+" ");
             counts[i] = c;
         }
         grandTotal += total;
         System.out.println("| "+(1000*total)/delta
            +" | "+(1000*grandTotal)/duration);
         lastTime = curTime;
      }
   }
}

Some notes on MultithreadingCpuRunner.java:

Now, let's run MultithreadingCpuRunner.java with different numbers of threads:

C:\>"\Program Files\Java\jdk1.7.0_45\bin\java" 
   MultithreadingCpuRunner 1000 1

Thread parameter: 1000
Number of threads: 1
Seconds | Productivity per thread | Total | Average
...
181 | 883 | 883 | 885
182 | 890 | 890 | 885
183 | 886 | 886 | 885
184 | 882 | 882 | 885
185 | 888 | 888 | 885
...

C:\>"\Program Files\Java\jdk1.7.0_45\bin\java"
   MultithreadingCpuRunner 1000 2

Thread parameter: 1000
Number of threads: 2
Seconds | Productivity per thread | Total | Average
...
201 | 841 841 | 1682 | 1665
202 | 840 840 | 1680 | 1665
203 | 841 840 | 1681 | 1665
204 | 830 819 | 1649 | 1665
205 | 841 841 | 1682 | 1665
...

C:\>"\Program Files\Java\jdk1.7.0_45\bin\java" 
   MultithreadingCpuRunner 1000 4

Thread parameter: 1000
Number of threads: 4
Seconds | Productivity per thread | Total | Average
...
211 | 462 463 467 468 | 1861 | 1857
212 | 450 463 467 467 | 1849 | 1857
213 | 464 464 468 469 | 1866 | 1857
214 | 466 466 466 466 | 1865 | 1857
215 | 466 464 467 466 | 1865 | 1857
...

C:\>"\Program Files\Java\jdk1.7.0_45\bin\java" 
   MultithreadingCpuRunner 1000 8

Thread parameter: 1000
Number of threads: 8
Seconds | Productivity per thread | Total | Average
...
235 | 159 467 143 470 158 158 164 145 | 1868 | 1855
236 | 150 462 142 466 157 152 153 154 | 1840 | 1855
237 | 143 461 156 464 155 152 144 164 | 1845 | 1855
238 | 158 464 149 465 142 163 171 142 | 1858 | 1855
239 | 177 465 146 466 149 142 166 143 | 1858 | 1855
...

C:\>"\Program Files\Java\jdk1.7.0_45\bin\java" 
   MultithreadingCpuRunner 1000 16

Thread parameter: 1000
Number of threads: 16
Seconds | Productivity per thread | Total | Average
...
126 | 120 70 70 34 106 60 96 30 141 151 90 35 116 35... | 1545 | 1855
127 | 128 50 45 65 99 42 135 94 99 157 171 46 135 49... | 1854 | 1855
128 | 100 85 50 84 142 50 112 43 106 142 149 49 171 ... | 1853 | 1855
129 | 136 57 50 50 96 64 92 42 140 171 149 50 143 98... | 1859 | 1855
130 | 100 50 50 50 121 85 149 50 91 137 172 78 156 5... | 1860 | 1855
...

If we take the average value in each test, we will get the following trend:

Threads   Productivity   Percent
      1            885   100.00%
      2           1665   188.14%
      4           1857   209.83%
      8           1855   209.60%
     16           1855   209.60%

Here are my notes on these test results:

Conclusion: Multithreading CPU intensive processes does not improve overall productivity unless the JVM is running on a multi-CPU processor. In other words, if you have a 2-CPU processor, you should only run 2 CPU intensive processes concurrently.

Last update: 2014.

Table of Contents

 About This Book

 Downloading and Installing JDK 1.8.0 on Windows

 Downloading and Installing JDK 1.7.0 on Windows

 java.lang.Runtime Class - The JVM Instance

 java.lang.System Class - The Operating System

 ClassLoader Class - Class Loaders

 Class Class - Class Reflections

 Sun's JVM - Java HotSpot VM

 JRockit JVM 28.2.7 by Oracle Corporation

 JVM Runtime Data Areas

 Memory Management and Garbage Collectors

 Garbage Collection Tests

 JVM Stack, Frame and Stack Overflow

 Thread Testing Program and Result

CPU Impact of Multi-Thread Applications

 PrimeCalculator.java - CPU Intensive Process

CPU Intensive Process - 1 Thread per CPU

 Single Thread Process on 2-CPU-4-Thread Machine

 Two-Thread Process on 2-CPU-4-Thread Machine

 Multi-Thread Process on 2-CPU-4-Thread Machine

 Multi-Thread Process Slows Down System Response Time

 Multi-Thread Process Running on JRockit JVM

 I/O Impact of Multi-Thread Applications

 CDS (Class Data Sharing)

 Micro Benchmark Runner and JVM Options

 Micro Benchmark Tests on "int" Operations

 Micro Benchmark Tests on "long" Operations

 Micro Benchmark Tests in JIT Compilation Mode

 Micro Benchmark Tests on "float" and "double" Operations

 Outdated Tutorials

 References

 PDF Printing Version