简体   繁体   中英

Simulating CPU-intensive Task having fixed amount of work

I am simulating a CPU-Bound task. Each CPU-bound task calculate factorial of 800. Each CPU-bound task is a Runnable object executed by Thread. When i increases number of threads(Each thread runs a Runnable tak) then i found some threads runs so fast in such a way that service times tends to Zero.I could not understand this behaviour.The codes are as follows.

import java.math.BigInteger;    
public class CpuBoundJob  implements Runnable {     
    public void run() {    
         BigInteger factValue = BigInteger.ONE;
            long t1=System.nanoTime();      
            for ( int i = 2; i <= 800; i++){
              factValue = factValue.multiply(BigInteger.valueOf(i));
            }
        long t2=System.nanoTime();              
        System.out.println("Service Time(ms)="+((double)(t2-t1)/1000000));
    }    
}

public class TaskRunner extends Thread {
    CpuBoundJob job=new CpuBoundJob();
    public void run(){

    job.run();  
    }
}

public class Test {
int numberOfThreads=5;
public Test(){
    for(int i=1;i<=numberOfThreads;i++){
        TaskRunner t=new TaskRunner();
        t.start();
        }
}
public static void main(String[] args) {
    new Test(); 
    }
}

In case of 5 Threads the output is as below.

Service Time(ns)=28.765821
Service Time(ns)=33.489663
Service Time(ns)=29.19727
Service Time(ns)=34.259404
Service Time(ns)=37.347448

In case of 10 Threads the output is as below.

Service Time(ns)=45.647232
Service Time(ns)=3.972654
Service Time(ns)=23.494475
Service Time(ns)=12.210069
Service Time(ns)=19.382478
Service Time(ns)=15.34706
Service Time(ns)=54.769652
Service Time(ns)=20.646827
Service Time(ns)=3.28936
Service Time(ns)=29.809905
Service Time(ns)=60.798897
Service Time(ns)=50.718839
Service Time(ns)=2.727253
Service Time(ns)=2.882779
Service Time(ns)=63.864835
Service Time(ns)=42.601425
Service Time(ns)=4.029496
Service Time(ns)=4.339761
Service Time(ns)=79.396239
Service Time(ns)=2.923832
Service Time(ns)=5.773848
Service Time(ns)=3.064359
Service Time(ns)=2.446592
Service Time(ns)=2.205802
Service Time(ns)=2.212513
Service Time(ns)=2.265408
Service Time(ns)=82.51073
Service Time(ns)=2.200276
Service Time(ns)=2.289487
Service Time(ns)=2.322645
Service Time(ns)=2.201459
Service Time(ns)=2.217644
Service Time(ns)=2.197908
Service Time(ns)=2.252381
Service Time(ns)=13.564814
Service Time(ns)=2.238171
Service Time(ns)=2.199486
Service Time(ns)=2.179355
Service Time(ns)=2.237381
Service Time(ns)=2.593041
Service Time(ns)=2.444225
Service Time(ns)=2.42054
Service Time(ns)=38.745219
Service Time(ns)=81.232565
Service Time(ns)=19.612216
Service Time(ns)=22.31381
Service Time(ns)=59.521916
Service Time(ns)=59.511258
Service Time(ns)=54.439255
Service Time(ns)=11.582434

i could not understand service times of 2.4 etc and sometimes service times drop to 0.8 . why does threads running a fixed amount of work executes so fastly?

How are you starting these tests? If you are running starting them cold each time, I suspect the JVM is " warming up " and Just In Time compiling the code. If this is the case, the tests with a few threads are running as interpreted code, and later runs are compiled, and even later runs are optimized based upon previous runs. The JVM is magic that way .

Ideas to make the optimizations less likely to hit:

  • use a random number as a working parameter (and not the loop index)
  • use the time as a working parameter (ditto)
  • throw in some string concatenation
  • vary the length of the loop by with the working parameters

It is possible that at some point the JIT kicks in and optimizes the code. Try running the experiment by first "warming up" the system ie for N iterations (you will need to experiment what is a good value of N) run the system without measuring - then measure eg:

public class Test {

private int numberOfThreads;
private int warmUpIterations;

public Test(int numberOfThreads, int warmUpIterations) {
    this.numberOfThreads = numberOfThreads;
    this.warmUpIterations = warmUpIterations;
}

public void runTests() {
    for (int i = 0; i < warmUpIterations; i++) {
        test(); // don't collect timing here
    }

    test(); // collect timing here
}

private void test() {
    for (int i = 0; i < numberOfThreads; i++) {
        TaskRunner t = new TaskRunner();
        t.start();
    }
}

public static void main(String[] args) {
    new Test(10, 10000).runTests();
}

}

Also printing the statistics from within run() is problematic, consider accumulating them in some collection and print them once the test is done.

Most likely the timing functions are too inaccurate to measure such a quick operation. Try the factorial of 100000 or something similar.

The docs of the nanotime method say that it's not guaranteed to provide nanosecond accuracy:

This method provides nanosecond precision, but not necessarily nanosecond resolution (that is, how frequently the value changes) - no guarantees are made except that the resolution is at least as good as that of currentTimeMillis().

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM