0

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?

Faisal Bahadur
  • 498
  • 3
  • 19
  • Notes: 1) either merge `CpuBoundJob` and `TaskRunner` or remove `implements Runnable` `CpuBoundJob`. (`Runnable` is for submitting to an Executor.) 2) Please format your code correctly. The location of the curly brackets makes it difficult to read. – Stu Thompson Jan 12 '16 at 02:23

3 Answers3

4

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
Stu Thompson
  • 38,370
  • 19
  • 110
  • 156
  • What code i should use in CpuBoundJob that cant be optimized by JIT. i need to have a fixed amount of work that always executes in fixed amount of time. – Faisal Bahadur Jan 11 '16 at 16:49
  • You could sleep the thread. It's not work, but it takes a fixed amount of time before returning. Simulating CPU-bound. Unless you want that CPU usage for some other reason. Maybe better to not use JAVA, but have your Java thread call a system process like a pi-computing binary. – Karl Jan 11 '16 at 18:02
  • Excellent! I have accepted ur answer. This is part of my final year project and I am really in trouble because of JIT interference. i like ur idea of not to use java and calling some system process but i never did this .And i realy need more help regarding this and i appreciate if u plz provide me the liknks that can teach me to do this sort of thing. Or if u can give some example code of java (ur examples) that can not be optimized – Faisal Bahadur Jan 12 '16 at 00:23
  • @FaisalBahadur 1) use `System.nanoTime()` as the argument for `BigInteger.valueOf()`. 2) use `(System.currentMiliseconds() % 1000) + 10000` as the loop count. – Stu Thompson Jan 12 '16 at 02:26
  • oh thanks alot! I also warm up my code alot to get optimized time .But only last question plz! why is it that after warmup when I run single task it always run for about 35ms but when i run 2 task they run for about 70ms and so on ie on 3 tasks it becomes 3 times. i.e. why is it that when I increase the number of tasks I see it takes slightly longer. I have i5-dual core system. – Faisal Bahadur Jan 12 '16 at 08:39
  • @FaisalBahadur Do you mean total time? – Stu Thompson Jan 13 '16 at 02:30
  • no! For two tasks each task take 70ms .And when i run 3 taks each task takes about 105ms for each single task. – Faisal Bahadur Jan 25 '16 at 04:48
  • @FaisalBahadur On average, I could see that making sense on a two-core system. One core is running thread, the other core is running two threads. So one thread runs in ~70ms, and the other two run for ~140ms because there the CPU is flipping between the two, for a total of ~350ms. 350/3=116ms on average. Understand that there is a difference between execution time and run time. Each thread is taking 70ms of execution time, but the two threads sharing the one CPU are taking their execution time + the other threads execution time, effectively doubling their overall run time. – Stu Thompson Jan 25 '16 at 16:23
1

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 i.e. for N iterations (you will need to experiment what is a good value of N) run the system without measuring - then measure e.g:

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.

David Soroko
  • 8,521
  • 2
  • 39
  • 51
  • What code i should use in CpuBoundJob that cant be optimized by JIT. i need to have a fixed amount of work that always executes in fixed amount of time – Faisal Bahadur Jan 11 '16 at 16:50
-1

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().

Tudor
  • 61,523
  • 12
  • 102
  • 142