What happens inside the JVM so that a method invocation in Java becomes slower when you call it somewhere else in your code? -
the short code below isolates problem. i'm timing method addtostorage. start executing 1 million times , i'm able time down around 723 nanoseconds. short pause (using busy spinning method not release cpu core) , time method again n times, on different code location. surprise find the smaller n bigger addtostorage latency.
for example:
if n = 1 3.6 micros if n = 2 3.1 , 2.5 micros if n = 5 3.7, 1.8, 1.7, 1.5 , 1.5 micros does know why happening , how fix it? method consistently perform @ fastest time possible, no matter call it.
note: not think thread related since i'm not using thread.sleep. i've tested using taskset pin thread cpu core same results.
import java.util.arraylist; import java.util.list; public class jvmodd { private final stringbuilder sbuilder = new stringbuilder(1024); private final list<string> storage = new arraylist<string>(1024 * 1024); public void addtostorage() { sbuilder.setlength(0); sbuilder.append("blah1: ").append(system.nanotime()).append('\n'); sbuilder.append("blah2: ").append(system.nanotime()).append('\n'); sbuilder.append("blah3: ").append(system.nanotime()).append('\n'); sbuilder.append("blah4: ").append(system.nanotime()).append('\n'); sbuilder.append("blah5: ").append(system.nanotime()).append('\n'); sbuilder.append("blah6: ").append(system.nanotime()).append('\n'); sbuilder.append("blah7: ").append(system.nanotime()).append('\n'); sbuilder.append("blah8: ").append(system.nanotime()).append('\n'); sbuilder.append("blah9: ").append(system.nanotime()).append('\n'); sbuilder.append("blah10: ").append(system.nanotime()).append('\n'); storage.add(sbuilder.tostring()); } public static long mysleep(long t) { long x = 0; for(int = 0; < t * 10000; i++) { x += system.currenttimemillis() / system.nanotime(); } return x; } public static void main(string[] args) throws exception { int warmup = integer.parseint(args[0]); int mod = integer.parseint(args[1]); int passes = integer.parseint(args[2]); int sleep = integer.parseint(args[3]); jvmodd jo = new jvmodd(); // first warm for(int = 0; < warmup; i++) { long time = system.nanotime(); jo.addtostorage(); time = system.nanotime() - time; if (i % mod == 0) system.out.println(time); } // see how fast method is: while(true) { system.out.println(); // thread.sleep(sleep); mysleep(sleep); long mintime = long.max_value; for(int = 0; < passes; i++) { long time = system.nanotime(); jo.addtostorage(); time = system.nanotime() - time; if (i > 0) system.out.print(','); system.out.print(time); mintime = math.min(time, mintime); } system.out.println("\nmintime: " + mintime); } } } executing:
$ java -server -cp . jvmodd 1000000 100000 1 5000 59103 820 727 772 734 767 730 726 840 736 3404 mintime: 3404
there going on in here don't know start. lets start here....
long time = system.nanotime(); jo.addtostorage(); time = system.nanotime() - time; the latency of addtostoarge() cannot measured using technique. runs meaning you're below resolution of clock. without running this, guess measures dominated clock edge counts. you'll need bulk unit of work measure lower levels of noise in it.
as happening? there number of call site optimizations important being inlining. inlining totally eliminate call site it's path specific optimization. if call method different place, follow slow path of performing virtual method lookup followed jump code. see benefits of inlining different path, path have "warmed up".
i recommend @ both jmh (delivered jdk). there facilities in there such blackhole effects of cpu clocks winding down. might want evaluate quality of bench of tools jitwatch (adopt openjdk project) take logs produced jit , interrupt them.
Comments
Post a Comment