21

As I know JVM before launching a Java application it allocates some piece of RAM for it, and this memory could be controlled by user before launching. But there is another problem when I launch an app it has a different time execution each time.

Here is a very simple example with for loop:

package timespent;

public class Main {

    public static void main(String[] args) {

        long startTime = System.nanoTime();

        int j = 0;

        for (int i = 0; i < 1.E6; i++) {
            j = i + 1;
        }

        long endTime = System.nanoTime();

        long duration = (endTime - startTime);

        System.out.println("duration = " + duration);
    }
}

It prints different results:

duration = 5720542
duration = 7331307
duration = 7737946
duration = 6899173

Let's say I want it to be executed exact 10,000,000 nanoseconds or 10 milliseconds.

What do I want?

I want java app to be executed with exact time execution.

Why do I need this?

When I launch an app I want to show exact execution time left on application startup window before it loads all components.

I suppose this is kind of CPU manipulation and I wanted to know if it is possible or not.

Q1: Is it possible in Java?
Q2: If it is not possible in Java then is there any way achieving this by accessing OS native methods. e.g. by prioritizing the Java application or something else?
Q3: How about saving the state of an application to the file and loading it into memory?

Community
  • 1
  • 1
Asad Ganiev
  • 449
  • 4
  • 16
  • 18
    It can never be same, it depends on the state of the system at that particular instance. – Saif Ahmad Nov 09 '17 at 07:25
  • 13
    Note that `7737946ns` is `0.007737946` seconds so the variance you are seeing in your results is around `0.002` seconds - that's not noticeable on a startup screen. You may be better off posting some more realistic demonstration of what you are looking for. – OldCurmudgeon Nov 09 '17 at 08:20
  • 2
    @OldCurmudgeon This was just primitive example. What if an application executes e.g. 12m34s? – Asad Ganiev Nov 09 '17 at 08:23
  • 2
    Exactly! So to achieve what you are looking for you need to take into account many more factors than just CPU processing time - or do you? Is there disk I/O involved? Are you accessing any servers during startup? etc. etc. – OldCurmudgeon Nov 09 '17 at 08:55
  • 31
    It seems to me like an X/Y problem. If your intent is for your app "to be executed with exact time execution." then your solution is a timer, not trying to fine-tune your code execution time. – ris8_allo_zen0 Nov 09 '17 at 09:29
  • 7
    What is your [actual problem](https://meta.stackexchange.com/q/66377)? – Bergi Nov 09 '17 at 10:00
  • If you want it to take exactly one second then use `Thread.sleep(1000);` – user253751 Nov 09 '17 at 22:59
  • 2
    @ris8_allo_zen0 Timer is not solution, firstly you don't know how long does your program execution take beforehand, because each time it will take different time, secondly timer also doesn't work precisely, even `Thread.sleep(1000);` doesn't sleep precisely 1000 ms. it could be different each time you may check it if you want. – Asad Ganiev Nov 10 '17 at 05:47

7 Answers7

40

There are a number of sources of uncertainty in your time measurement. And all of these sources are not just influencing your measurements, it's the runtime itself that is uncertain. Among the sources of uncertainty are:

  • Cache usage (what parts of memory are cached within the CPU). Your data can be evicted from the cache by your CPU executing a background task.

  • Memory placement (is the memory directly connected to the executing CPU core?). This may change over time as your process may be migrated to another core at any time.

  • Software interrupts (your OS preempting your process to run a different one). Can be somewhat mitigated by running on a quiet machine, but there is no guarantee that you won't get interrupted.

  • Thermal throttling (your CPU decides that it's too hot and turns down its clock speed). There's really not much you can do about this unless you are prepared to work on some embedded processor with a fixed clock speed.

  • Hardware interrupts (your network connector received some data from another machine on the internet). You have no influence on when this strikes, whatsoever.

  • Unpredictable latencies (you are reading some data from disk, but first, the disk has to wait until the data arrives below the reading head). This may follow patterns when you are repeating the exact same actions over and over again, but once you get an unrelated hardware interrupt, this may cause an unexpected delay of 1/7200 rpm * 60 s/min = 8.3 ms.

  • Garbage collection (you are asking about Java, so you have a GC running in the background). Even the best, most modern garbage collectors cannot fully avoid stopping the world from time to time. And even when they don't stop the world, they still run in the background, introducing runtime noise via the cache, memory placement, and software interrupts.

These are probably the most important sources, and there may be others. The point is, your process is never alone on the machine. Unless you run without an OS and disable all hardware interrupts, you just have to live with the fact that your run-times will vary from execution to execution, and there is simply no way to fix that.

Farzad Karimi
  • 770
  • 1
  • 12
  • 31
cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106
  • An RTOS can give you some control over execution time scheduling. – JAB Nov 09 '17 at 15:21
  • 1
    @JAB True, but it cannot guarantee some execution speed (my first two points, cache and NUMA effects, these are *hardware* effects), so there is still some execution time variance. You get guarantees on when your threads are started, and on how much processor time they will actually get. This allows the processes to request enough time so that they can be confident to finish their respective work within the allocated time frame. But that is something very different to finishing at a deterministic time. – cmaster - reinstate monica Nov 09 '17 at 19:39
  • 2
    @cmaster: There's a big one you didn't mention: _CPU speed_. For a tight loop like the OP has, CPU speed is a critical factor. And this, itself, is affected by _temperature_, which is inherently unpredictable. – Mooing Duck Nov 10 '17 at 01:08
  • @MooingDuck Excellent point. I've added it as "Thermal throttling" to the list. Thanks. – cmaster - reinstate monica Nov 10 '17 at 09:23
16

It's simply not possible. First of all, measuring time in nanoseconds is not exact. I feel like this post explains that well.

Secondly you have no control on how the CPU schedules execution. There might be other tasks hogging CPU time, which delays the execution of your program.

Jerome Reinländer
  • 1,227
  • 1
  • 10
  • 26
  • @JeromeReinlancer You are right regarding nanoseconds, but how about seconds? – Asad Ganiev Nov 09 '17 at 08:09
  • 3
    @EroriCube It doesn't matter how you measure it, in the end you need a hard real time capable operating system to achieve this. You could measure in seconds and it often will be right, but at some point your system starts to e.g. defragmentate the drive and you miss your deadline by >1 sec. – rtur Nov 09 '17 at 08:43
9

The precise execution time of arbitrary code is non-deterministic, because is depends on other things that the physical machine is concurrently doing.

Even if you planned to make execution time "constant" by keeping track of the startup timestamp and a planned end timestamp and sleeping the main thread for the duration between then exiting the program, it wold still vary, a reasonably large amount.

When, and for how long, threads execute or wait is out of the programmer's control.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
6

[TL;DR] It is very difficult/impossible.

Longer answer see Planarity Testing by Path Addition PhD thesis - Benchmarking Methodology Chapter for some of the issues including:

  1. Other applications having resources. I.e. not having enough memory and the operating system has to page applications; or code running slower as another application is sharing the CPU.
  2. Clock resolution - your code is only going to run as fast as your CPU is capable. Port it to another computer and your benchmarks might give you wildly different results so do not optimise it just for your system.
  3. Class loading - when the JVM first runs the code it has to load the classes into memory (typically from disk) and parse the byte code so the first time it runs will be significantly slower than subsequent times.
  4. Just-In-Time compilation - when the JVM first loads the byte code it will run it in a purely interpreted mode. Once it has run a block of byte code (i.e. one function within your code) multiple times (say 10,000) it could compile that function to native code. The compilation will slow that execution down but then subsequent invocations will be faster as it is running native, rather than interpreted, code. However, this is not a one-time compilation and if the JVM spots that certain execution paths within the the block are being favoured then it may recompile the byte code to try to optimise those paths and this can result in multiple native versions of the byte code until the JVM stabilises the code against its statistics.
  5. Garbage collection - sometimes your code will be interrupted while Java invokes the garbage collector.

So if you want to benchmark your application to see how it would run optimally then:

  • Stop as many other applications as you can;
  • Run the code many tens of thousands of times;
  • Ignore the first 10,000 - 20,000 executions (to mitigate for Class loading and JIT compilation); and
  • Ignore the iterations when garbage collection occurs (this is more difficult to determine than it sounds).

It will give you an idea of optimal performance but optimal and real-world are two very different things.

MT0
  • 143,790
  • 11
  • 59
  • 117
5

The only way to come close to this would be to use real time Java on an operating system specifically designed to support real-time execution.

Community
  • 1
  • 1
Matt McHenry
  • 20,009
  • 8
  • 65
  • 64
  • ...and even then your execution time will be impacted by noise in the current supplied by your PSU, the ambient temperature of the room, butterflies in China, etc. (Which I assume is why Matt was careful to say "come close") – A C Nov 09 '17 at 23:19
3

As others have said, it is impossible to know the exact time remaining due to other factors influencing the speed of your program. You could however put milestones in and reference past runs to get a semi-accurate time calculated from the variance in actual time so far this run compared to previous runs, as is done when copying large directories of files on Windows for instance or when downloading large files in Chrome.

So you don't specify your exact problem, but let's say it's something like processing 100,000 operations that require contacting a 3rd party system on the internet and it normally takes ~15 minutes to complete. You could keep track of 1) Start Time, 2) Expected End Time, and 3) Portion completed. So say when you're 1/2 done, you could take the elapsed time and say that is how long is remaining. Basically get the rate in operations per second and divide the remaining operations by that to get the number of seconds remaining.

double speed = completedOperations / elapsedSeconds;
double remainingSeconds = remainingOperations / speed;

This can change however. Say you start the process and after getting 1/4 the way through in 5 minutes that offsite backups start, not only thrashing the computer's disks, but your internet connection. Now things are processing at 1/10th the speed. Your estimated completion time will start out being 20 min, then at 5 minutes in it will be 15 min. However it slows at that point so you are only 1/2 done after 30 minutes, and your remaining time at that point will be 30 minutes. Now say the backups complete, you will actually be done in 10 minutes but it says there is 30 minutes remaining.

There is no way around an issue like this that is out of your control. You could do a couple of things to mitigate it. You might want to take the speed over just the last 30 seconds of processing. That will be the most accurate if things continue at the current speed. You could record the average speed at times of the day historically if that is an issue. You could average the total run speed and the last minute speed if the speed fluctuates.

Another thing that might throw it off is variance in the data. For example if you are looking at customers and processing them based on the date they became customers, your first 10,000 operations might be on loyal customers that have been with you for years and have tons of data to process while the last 10,000 might be new customers with little data that process faster. You could then use the underlying amount of data instead of the customer count...


However, if you want to be exact for some reason (most of the time), you could fake it at the cost of time. Take the largest normal run time and just use the amount of time taken since the start to provide the progress and time left. Then when all the actual work is done, put in a sleep() command to wait out the remaining time. There will always be a chance that system load or something makes it take exceptionally long though, but you could then change your maximum time to that new value.

The times of your runs are probably on some kind of curve, the longer you make the time, the more likely any single run will complete in that time, but then more of the runs will be waiting around for nothing:

         #            ^
         #            |
        ###           |
        ###           |
       #####          R
      #######         U
    ###########       N
###################   S

Time-------------->

Granted this seems silly, but your application will run at different speeds due to variables you cannot control, and if a near constant run time is important to you this is the only way.

Jason Goemaat
  • 28,692
  • 15
  • 86
  • 113
1

It is not going to work your way. It depends on the system state, like how much system resources are working on your program.

As I can see, you want to display the time left to open the application. In that case, suppose two users are running your program on different machines, which have different core structure and clocked frequency ...

But I can give a suggestion, you can just read the data of your program and adjust the time on that basis, like other application do, which shows ..% loaded or same as download manager function which shows ..% downloaded.

isanae
  • 3,253
  • 1
  • 22
  • 47