What's wrong with System.nanoTime? - java

I have a very long string with the pattern </value> at the very end, I am trying to test the performance of some function calls, so I made the following test to try to find out the answer... but I think I might be using nanoTime incorrectly? Because the result doesn't make sense no matter how I swap the order around...
long start, end;
start = System.nanoTime();
StringUtils.indexOf(s, "</value>");
end = System.nanoTime();
System.out.println(end - start);
start = System.nanoTime();
s.indexOf("</value>");
end = System.nanoTime();
System.out.println(end - start);
start = System.nanoTime();
sb.indexOf("</value>");
end = System.nanoTime();
System.out.println(end - start);
I get the following:
163566 // StringUtils
395227 // String
30797 // StringBuilder
165619 // StringBuilder
359639 // String
32850 // StringUtils
No matter which order I swap them around, the numbers will always be somewhat the same... What's the deal here?
From java.sun.com website's FAQ:
Using System.nanoTime() between various points in the code to perform elapsed time measurements should always be accurate.
Also:
http://download.oracle.com/javase/1.5.0/docs/api/java/lang/System.html#nanoTime()

The differences between the two runs is in the order of microseconds and that is expected. There are many things going on on your machine which make the execution environment never the same between two runs of your application. That is why you get that difference.
EDIT: Java API says:
This method provides nanosecond precision, but not necessarily
nanosecond accuracy.

Most likely there's memory initialization issues or other things that happen at the JVM's startup that is skewing your numbers. You should get a bigger sample to get more accurate numbers. Play around with the order, run it multiple times, etc.

It is more than likely that the methods you check use some common code behind the scenes. But the JIT will do its work only after about 10.000 invocations. Hence, this could be the cause why your first two example seem to be always slower.
Quick fix: just do the 3 method calls before the first measuring on a long enoug string.

Related

Java : Issue with capturing execution time per iteration in a Map

I've a requirement to capture the execution time of some code in iterations. I've decided to use a Map<Integer,Long> for capturing this data where Integer(key) is the iteration number and Long(value) is the time consumed by that iteration in milliseconds.
I've written the below java code to compute the time taken for each iteration. I want to ensure that the time taken by all iterations is zero before invoking actual code. Surprisingly, the below code behaves differently for every execution.
Sometimes, I get the desired output(zero millisecond for all iterations), but at times I do get positive and even negative values for some random iterations.
I've tried replacing System.currentTimeMillis(); with below code:
new java.util.Date().getTime();
System.nanoTime();
org.apache.commons.lang.time.StopWatch
but still no luck.
Any suggestions as why some iterations take additional time and how to eliminate it?
package com.stackoverflow.programmer;
import java.util.HashMap;
import java.util.Map;
public class TestTimeConsumption {
public static void main(String[] args) {
Integer totalIterations = 100000;
Integer nonZeroMilliSecondsCounter = 0;
Map<Integer, Long> timeTakenMap = new HashMap<>();
for (Integer iteration = 1; iteration <= totalIterations; iteration++) {
timeTakenMap.put(iteration, getTimeConsumed(iteration));
if (timeTakenMap.get(iteration) != 0) {
nonZeroMilliSecondsCounter++;
System.out.format("Iteration %6d has taken %d millisecond(s).\n", iteration,
timeTakenMap.get(iteration));
}
}
System.out.format("Total non zero entries : %d", nonZeroMilliSecondsCounter);
}
private static Long getTimeConsumed(Integer iteration) {
long startTime = System.currentTimeMillis();
// Execute code for which execution time needs to be captured
long endTime = System.currentTimeMillis();
return (endTime - startTime);
}
}
Here's the sample output from 5 different executions of the same code:
Execution #1 (NOT OK)
Iteration 42970 has taken 1 millisecond(s).
Total non zero entries : 1
Execution #2 (OK)
Total non zero entries : 0
Execution #3 (OK)
Total non zero entries : 0
Execution #4 (NOT OK)
Iteration 65769 has taken -1 millisecond(s).
Total non zero entries : 1
Execution #5 (NOT OK)
Iteration 424 has taken 1 millisecond(s).
Iteration 33053 has taken 1 millisecond(s).
Iteration 76755 has taken -1 millisecond(s).
Total non zero entries : 3
I am looking for a Java based solution that ensures that all
iterations consume zero milliseconds consistently. I prefer to
accomplish this using pure Java code without using a profiler.
Note: I was also able to accomplish this through C code.
Your HashMap performance may be dropping if it is resizing. The default capacity is 16 which you are exceeding. If you know the expected capacity up front, create the HashMap with the appropriate size taking into account the default load factor of 0.75
If you rerun iterations without defining a new map and the Integer key does not start again from zero, you will need to resize the map taking into account the total of all possible iterations.
int capacity = (int) ((100000/0.75)+1);
Map<Integer, Long> timeTakenMap = new HashMap<>(capacity);
As you are starting to learn here, writing microbenchmarks in Java is not as easy as one would first assume. Everybody gets bitten at some point, even the hardened performance experts who have been doing it for years.
A lot is going on within the JVM and the OS that skews the results, such as GC, hotspot on the fly optimisations, recompilations, clock corrections, thread contention/scheduling, memory contention and cache misses. To name just a few. And sadly these skews are not consistent, and they can very easily dominate a microbenchmark.
To answer your immediate question of why the timings can some times go negative, it is because currentTimeMillis is designed to capture wall clock time and not elapsed time. No wall clock is accurate on a computer and there are times when the clock will be adjusted.. very possibly backwards. More detail on Java's clocks can be read on the following Oracle Blog Inside the Oracle Hotspot VM clocks.
Further details and support of nanoTime verses currentTimeMillis can be read here.
Before continuing with your own benchmark, I strongly recommend that you read how do I write a currect micro benchmark in java. The quick synopses is to 1) warm up the JVM before taking results, 2) jump through hoops to avoid dead code elimination, 3) ensure that nothing else is running on the same machine but accept that there will be thread scheduling going on.. you may even want to pin threads to cores, depends on how far you want to take this, 4) use a framework specifically designed for microbenchmarking such as JMH or for quick light weight spikes JUnitMosaic gives good results.
I'm not sure if I understand your question.
You're trying to execute a certain set of statements S, and expect the execution time to be zero. You then test this premise by executing it a number of times and verifying the result.
That is a strange expectation to have: anything consumes some time, and possibly even more. Hence, although it would be possible to test successfully, that does not prove that no time has been used, since your program is save_time();execute(S);compare_time(). Even if execute(S) is nothing, your timing is discrete, and as such, it is possible that the 'tick' of your wallclock just happens to happen just between save_time and compare_time, leading to some time having been visibly past.
As such, I'd expect your C program to behave exactly the same. Have you run that multiple times? What happens when you increase the iterations to over millions? If it still does not occur, then apparently your C compiler has optimized the code in such a way that no time is measured, and apparently, Java doesn't.
Or am I understanding you wrong?
You hint it right... System.currentTimeMillis(); is the way to go in this case.
There is no warranty that increasing the value of the integer object i represent either a millisecond or a Cycle-Time in no system...
you should take the System.currentTimeMillis() and calculated the elapsed time
Example:
public static void main(String[] args) {
long lapsedTime = System.currentTimeMillis();
doFoo();
lapsedTime -= System.currentTimeMillis();
System.out.println("Time:" + -lapsedTime);
}
I am also not sure exactly, You're trying to execute a certain code, and try to get the execution for each iteration of execution.
I hope I understand correct, if that so than i would suggest please use
System.nanoTime() instead of System.currentTimeMillis(); because if your statement of block has very small enough you always get Zero in Millisecond.
Simple Ex could be:
public static void main(String[] args) {
long lapsedTime = System.nanoTime();
//do your stuff here.
lapsedTime -= System.nanoTime();
System.out.println("Time Taken" + -lapsedTime);
}
If System.nanoTime() and System.currentTimeMillis(); are nothing much difference. But its just how much accurate result you need and some time difference in millisecond you may get Zero in case if you your set of statement are not more in each iteration.

What is the current state of affairs in the world of Java timers?

From time to time I encounter mentions of System.nanoTime() being a lot slower (the call could cost up to microseconds) than System.currentTimeMillis(), but prooflinks are often outdated, or lead to some fairly opinionated blog posts that can't be really trusted, or contain information pertaining to specific platform, or this, or that and so on.
I didn't run benchmarks since I'm being realistic about my ability to conduct an experiment concerning such a sensitive matter, but my conditions are really well-defined, so I'm expecting quite a simple answer.
So, on an average 64-bit Linux (implying 64-bit JRE), Java 8 and a modern hardware, will switching to nanoTime() cost me that microseconds to call? Should I stay with currentTimeMillis()?
As always, it depends on what you're using it for. Since others are bashing nanoTime, I'll put a plug in for it. I exclusively use nanoTime to measure elapsed time in production code.
I shy away from currentTimeMillis in production because I typically need a clock that doesn't jump backwards and forwards around like the wall clock can (and does). This is critical in my systems which use important timer-based decisions. nanoTime should be monotonically increasing at the rate you'd expect.
In fact, one of my co-workers says "currentTimeMillis is only useful for human entertainment," (such as the time in debug logs, or displayed on a website) because it cannot be trusted to measure elapsed time.
But really, we try not to use time as much as possible, and attempt to keep time out of our protocols; then we try to use logical clocks; and finally if absolutely necessary, we use durations based on nanoTime.
Update: There is one place where we use currentTimeMillis as a sanity check when connecting two hosts, but we're checking if the hosts' clocks are more than 5 minutes apart.
If you are currently using currentTimeMillis() and are happy with the resolution, then you definitely shouldn't change.
According the javadoc:
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 {#link #currentTimeMillis()}.
So depending on the OS implementation, there is no guarantee that the nano time returned is even correct! It's just the 9 digits long and has the same number of millis as currentTimeMillis().
A perfectly valid implementation could be currentTimeMillis() * 1000000
Therefore, I don't think you really gain a benefit from nano seconds even if there wasn't a performance issue.
I want to stress that even if the calls would be very cheap, you will not get the nanosecond resolution of your measurements.
Let me give you an example (code from http://docs.oracle.com/javase/8/docs/api/java/lang/System.html#nanoTime--):
long startTime = System.nanoTime();
// ... the code being measured ...
long estimatedTime = System.nanoTime() - startTime;
So while both long values will be resolved to a nanosecond, JVM is not giving you a guarantee that every call you make to nanoTime(), JVM will give you a new value.
To illustrate this, I wrote a simple program and ran it on Win7x64 (feel free to run it and report the results as well):
package testNano;
public class Main {
public static void main(String[] args) {
long attempts = 10_000_000L;
long stale = 0;
long prevTime;
for (int i = 0; i < attempts; i++) {
prevTime = System.nanoTime();
long nanoTime = System.nanoTime();
if (prevTime == nanoTime) stale++;
}
System.out.format("nanoTime() returned stale value in %d out of %d tests%n", stale, attempts);
}
}
It prints out nanoTime() returned stale value in 9117171 out of 10000000 tests.
EDIT
I also recommend to read the Oracle article on this: https://blogs.oracle.com/dholmes/entry/inside_the_hotspot_vm_clocks. The conclusions of the article are:
If you are interested in measuring absolute time then always use System.currentTimeMillis(). Be aware that its resolution may be quite coarse (though this is rarely an issue for absolute times.)
If you are interested in measuring/calculating elapsed time, then always use System.nanoTime(). On most systems it will give a resolution on the order of microseconds. Be aware though, this call can also take microseconds to execute on some platforms.
Also you might find this discussion interesting: Why is System.nanoTime() way slower (in performance) than System.currentTimeMillis()?.
Running this very simple test:
public static void main(String[] args) {
// Warmup loops
long l;
for (int i=0;i<1000000;i++) {
l = System.currentTimeMillis();
}
for (int i=0;i<1000000;i++) {
l = System.nanoTime();
}
// Full loops
long start = System.nanoTime();
for (int i=0;i<10000000;i++) {
l = System.currentTimeMillis();
}
start = System.nanoTime()-start;
System.err.println("System.currentTimeMillis() "+start/1000);
start = System.nanoTime();
for (int i=0;i<10000000;i++) {
l = System.nanoTime();
}
start = System.nanoTime()-start;
System.err.println("System.nanoTime() "+start/1000);
}
On Windows 7 this shows millis to be just over 2 times as fast:
System.currentTimeMillis() 138615
System.nanoTime() 299575
On other platforms, the difference isn't as large, with nanoTime() actually being slightly (~10%) faster:
On OS X:
System.currentTimeMillis() 463065
System.nanoTime() 432896
On Linux with OpenJDK:
System.currentTimeMillis() 352722
System.nanoTime() 312960
Well the best thing to do in such situations is always to benchmark it. And since the timing depends solely on your platform and OS there's really nothing we can do for you here, particularly since you nowhere explain what you actually use the timer for.
Neither nanoTime nor currentTimeMillis generally guarantee monotonicity (nanoTime does on HotSpot for Solaris only and otherwise relies on an existing monotone time source of the OS - so for most people it will be monotonic even if currentTimeMillis is not).
Luckily for you writing benchmarks in Java is relatively easy these days thanks to jmh (java measuring harness) and even luckier for you Aleksey Shipilёv actually investigated nanoTime a while ago: See here - including source code to do the interesting benchmarking yourself (it's also a nice primer to jmh itself, if you want to write accurate benchmarks with only relatively little knowledge - that's the one to pick.. just amazing how far the engineers behind that project went to make benchmarking as straight-forward as possible to the general populace! Although you certainly can still fuck up if you're not careful ;-))
To summarize the results for a modern linux distribution or Solaris and a x86 CPU:
Precision: 30ns
Latency: 30ns best case
Windows:
Precision: Hugely variable, 370ns to 15 µs
Latency: Hugely variable, 15ns to 15 µs
But note Windows is also known to give you a precision of up to 100ms for currentTimeMillis in some rare situations soo.. pick your poison.
Mac OS X:
Precision: 1µs
Latency: 50ns
Be vary these results will differ greatly depending on your used platform (CPU/MB - there are some interesting older hardware combinations around, although they're luckily getting older) and OS. Heck obviously just running this on a 800 MHz CPU your results will be rather different when compared to a 3.6GHz server.

java - system.nanoTime() runs too slow

I am using system.nanoTime in my app and I calculate time relative to a starttime.
My app ran very well until I copied it to a new computer and on it the nano time gives me slower values.
I wrote a simple app just to make sure.
the nano time is compared to the system time.
It shows the same values in other computers except my new one . any suggestions?
Here is my code:
First I have
private long initNanoTime = System.nanoTime();
private long initTime = System.currentTimeMillis();
than I loop a thread that runs every second:
long timeUsingNanoTime = initTime + (System.nanoTime() - initNanoTime) / 1000000;
long timeUsingMilis = System.currentTimeMillis();
long nanotimeOffset = Math.abs(timeUsingNanoTime - timeUsingMilis);
if (nanotimeOffset < 100l) ? print("close") : print(far);
Edit : I am using nano because I need to handle even ts that occur in nano time and print to a log the nano time which it was received in
It's like the Java API docs say about System.nanoTime():
This method can only be used to measure elapsed time and is not
related to any other notion of system or wall-clock time. The value
returned represents nanoseconds since some fixed but arbitrary origin
time (perhaps in the future, so values may be negative). The same
origin is used by all invocations of this method in an instance of a
Java virtual machine; other virtual machine instances are likely to
use a different origin.
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().
It does not provide any coupling with the timestamp (currentTimeMillis) and does not provide a fixed resolution.
In your case it seems that Java now has a higher resolution timer available than before, and so does not need to use the system time.

Time taken to execute a java method is zero?

I am reading the system time just before the method is invoked and immediately after method returns and taking the time difference, which will give the time taken by a method for execution.
Code snippet
long start = System.currentTimeMillis ();
method ();
long end = System.currentTimeMillis ();
System.out.println ("Time taken for execution is " + (end - start));
The strange thing is the output is 0..how is this possible..?
Chances are it's taking a shorter time than the fairly coarse-grained system clock. (For example, you may find that System.currentTimeMillis() only changes every 10 or 15 milliseconds.)
System.currentTimeMillis is good for finding out the current time, but it's not fine-grained enough for measuring short durations. Instead, you should use System.nanoTime() which uses a high-resolution timer. nanoTime() is not suitable for finding the current time - but it's designed for measuring durations.
Think of it as being the difference between a wall clock and a stopwatch.
use nanoTime()
Because it took less than 1 millisecond?
If you want to get a more meaningful metric, I would suggest calling your method in a loop 1000000 times, timing that, and then dividing by 1000000.
Of course, even then, that might not be representative; the effects on the cache will be different, etc.

System.nanotime running slow?

One of my friends showed me something he had done, and I was at a serious loss to explain how this could have happened: he was using a System.nanotime to time something, and it gave the user an update every second to tell how much time had elapsed (it Thread.sleep(1000) for that part), and it took seemingly forever (something that was waiting for 10 seconds took roughly 3 minutes to finish). We tried using millitime in order to see how much time had elapsed: it printed how much nanotime had elapsed every second, and we saw that for every second, the nanotime was moving by roughly 40-50 milliseconds every second.
I checked for bugs relating to System.nanotime and Java, but it seemed the only things I could find involved the nanotime suddenly greatly increasing and then stopping. I also browsed this blog entry based on something I read in a different question, but that didn't have anything that may cause it.
Obviously this could be worked around for this situation by just using the millitime instead; there are lots of workarounds to this, but what I'm curious about is if there's anything other than a hardware issue with the system clock or at least whatever the most accurate clock the CPU has (since that's what System.nanotime seems to use) that could cause it to run consistently slow like this?
long initialNano = System.nanoTime();
long initialMili = System.currentTimeMillis();
//Obviously the code isn't actually doing a while(true),
//but it illustrates the point
while(true) {
Thread.sleep(1000);
long currentNano = System.nanoTime();
long currentMili = System.currentTimeMillis();
double secondsNano = ((double) (currentNano - initialNano))/1000000000D;
double secondsMili = ((double) (currentMili - initialMili))/1000D;
System.out.println(secondsNano);
System.out.println(secondsMili);
}
secondsNano will print something along the lines of 0.04, whereas secondsMili will print something very close to 1.
It looks like a bug along this line has been reported at Sun's bug database, but they closed it as a duplicate, but their link doesn't go to an existing bug. It seems to be very system-specific, so I'm getting more and more sure this is a hardware issue.
... he was using a System.nanotime to cause the program to wait before doing something, and ...
Can you show us some code that demonstrates exactly what he was doing? Was it some strange kind of busy loop, like this:
long t = System.nanoTime() + 1000000000L;
while (System.nanoTime() < t) { /* do nothing */ }
If yes, then that's not the right way to make your program pause for a while. Use Thread.sleep(...) instead to make the program wait for a specified number of milliseconds.
You do realise that the loop you are using doesn't take exactly 1 second to run? Firstly Thread.sleep() isn't guaranteed to be accurate, and the rest of the code in the loop does take some time to execute (Both nanoTime() and currentTimeMillis() actually can be quite slow depending on the underlying implementation). Secondly, System.currentTimeMillis() is not guaranteed to be accurate either (it only updates every 50ms on some operating system and hardware combinations). You also mention it being inaccurate to 40-50ms above and then go on to say 0.004s which is actually only 4ms.
I would recommend you change your System.out.println() to be:
System.out.println(secondsNano - secondsMili);
This way, you'll be able to see how much the two clocks differ on a second-by-second basis. I left it running for about 12 hours on my laptop and it was out by 1.46 seconds (fast, not slow). This shows that there is some drift in the two clocks.
I would think that the currentTimeMillis() method provides a more accurate time over a large period of time, yet nanoTime() has a greater resolution and is good for timing code or providing sub-millisecond timing over short time periods.
I've experienced the same problem. Except in my case, it is more pronounced.
With this simple program:
public class test {
public static void main(String[] args) {
while (true) {
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
}
OStream.out("\t" + System.currentTimeMillis() + "\t" + nanoTimeMillis());
}
}
static long nanoTimeMillis() {
return Math.round(System.nanoTime() / 1000000.0);
}
}
I get the following results:
13:05:16:380 main: 1288199116375 61530042
13:05:16:764 main: 1288199117375 61530438
13:05:17:134 main: 1288199118375 61530808
13:05:17:510 main: 1288199119375 61531183
13:05:17:886 main: 1288199120375 61531559
The nanoTime is showing only ~400ms elapsed for each second.

Categories

Resources