How to use -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print option with JVM HotSpot - java

I 'm trying to use -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*MyClass.myMethod command lines as described in this post.
It seems thats it's available with open-jdk (https://wikis.oracle.com/display/HotSpotInternals/PrintAssembly).
How can I use those options (or similar equivalents) with oracle JDK7 and the JVM HotSpot?

These instructions apply to Linux (Ubuntu 10.04.4 LTS), but should be applicable for your OS. After downloading Oracle JDK 7u3 and appropriately setting your JAVA_HOME and PATH environment variables, execute the following to check available options:
java -XX:+AggressiveOpts -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+PrintFlagsFinal -version
You should see the UnlockDiagnosticVMOptions, CompileCommand and PrintAssembly options are available. Using the CompileCommand option will also enable the PrintAssembly option. However, you will need the HotSpot disassembler plugin for PrintAssembly to work; without it, you might see something like the following:
$ java -version
java version "1.7.0_03"
Java(TM) SE Runtime Environment (build 1.7.0_03-b04)
Java HotSpot(TM) Server VM (build 22.1-b02, mixed mode)
$ java -server -XX:+UnlockDiagnosticVMOptions '-XX:CompileCommand=print,*Main.main' Main
CompilerOracle: print *Main.main
Java HotSpot(TM) Server VM warning: printing of assembly code is enabled; turning on DebugNonSafepoints to gain additional output
Compiled method (c2) 68 1 % Main::main # 4 (49 bytes)
total in heap [0xb3a97548,0xb3a979ec] = 1188
relocation [0xb3a97610,0xb3a97624] = 20
main code [0xb3a97640,0xb3a97840] = 512
stub code [0xb3a97840,0xb3a97850] = 16
oops [0xb3a97850,0xb3a97858] = 8
scopes data [0xb3a97858,0xb3a97898] = 64
scopes pcs [0xb3a97898,0xb3a979e8] = 336
dependencies [0xb3a979e8,0xb3a979ec] = 4
Could not load hsdis-i386.so; library not loadable; PrintAssembly is disabled
OopMapSet contains 1 OopMaps
To get the HotSpot disassembler plugin, you will need to build it. Looking at the OpenJDK 7u2 source, the hsdis plugin readme says:
To use the plugin with a JVM, you need a new version that can load it.
If the product mode of your JVM does not accept -XX:+PrintAssembly,
you do not have a version that is new enough.
To build this project you [need] a copy of GNU binutils to build against.
In theory this should be buildable on Windows but getting a working
GNU build environment on Windows has proven difficult.
We have confirmed above that Oracle JDK 7u3 supports PrintAssembly. I followed the hsdis plugin readme instructions, downloaded GNU binutils 2.22, placed it in the hsdis build/binutils directory and ran make. This eventually produced the following error:
hsdis.c:32:20: error: sysdep.h: No such file or directory
To correct this, I changed hsdis.c using the following patch:
diff -r 6259c6d3bbb7 src/share/tools/hsdis/hsdis.c
--- a/src/share/tools/hsdis/hsdis.c Mon Dec 12 23:08:01 2011 -0800
+++ b/src/share/tools/hsdis/hsdis.c Thu Feb 23 09:26:37 2012 -0500
## -29,7 +29,7 ##
#include "hsdis.h"
-#include <sysdep.h>
+#include <errno.h>
#include <libiberty.h>
#include <bfd.h>
#include <dis-asm.h>
Running make was then successful. Now just copy the hsdis-i386.so plugin in the hsdis build directory to the Oracle JDK 7u3 jre/lib/i386 directory.
Now you can see the disassembled compiled code:
$ java -server -XX:+UnlockDiagnosticVMOptions '-XX:CompileCommand=print,*Main.main' Main
CompilerOracle: print *Main.main
Java HotSpot(TM) Server VM warning: printing of assembly code is enabled; turning on DebugNonSafepoints to gain additional output
Compiled method (c2) 68 1 % Main::main # 4 (49 bytes)
total in heap [0xb3999548,0xb39999ec] = 1188
relocation [0xb3999610,0xb3999624] = 20
main code [0xb3999640,0xb3999840] = 512
stub code [0xb3999840,0xb3999850] = 16
oops [0xb3999850,0xb3999858] = 8
scopes data [0xb3999858,0xb3999898] = 64
scopes pcs [0xb3999898,0xb39999e8] = 336
dependencies [0xb39999e8,0xb39999ec] = 4
Loaded disassembler from [snip]/jdk1.7.0_03/jre/lib/i386/hsdis-i386.so
Decoding compiled method 0xb3999548:
Code:
[Disassembling for mach='i386']
[Entry Point]
[Verified Entry Point]
[Constants]
# {method} 'main' '([Ljava/lang/String;)V' in 'Main'
0xb3999640: call 0xb6ff8510 ; {runtime_call}
0xb3999645: data32 xchg %ax,%ax
0xb3999648: mov %eax,-0x3000(%esp)
0xb399964f: push %ebp
0xb3999650: sub $0x38,%esp
0xb3999656: mov %ecx,%esi
0xb3999658: mov 0x4(%esi),%ebp
0xb399965b: mov 0x8(%esi),%edi
0xb399965e: mov (%ecx),%esi
0xb3999660: mov %ecx,(%esp)
0xb3999663: call 0xb7078cf0 ;*iload_3
[snip]
0xb399983e: hlt
0xb399983f: hlt
[Exception Handler]
[Stub Code]
0xb3999840: jmp 0xb39981e0 ; {no_reloc}
[Deopt Handler Code]
0xb3999845: push $0xb3999845 ; {section_word}
0xb399984a: jmp 0xb397e220 ; {runtime_call}
0xb399984f: .byte 0x0
OopMapSet contains 1 OopMaps
#0
OopMap{off=468}
The test class I've used is:
public class Main {
public static void main(final String[] args) {
long x = 0;
for (int i = 0; i < 1000000; i++) {
x += calculate(i);
}
System.out.println("x=" + x);
}
private static long calculate(final int i) {
return (long)i * (long)i;
}
}

in my case to see the disassembled compiled code:
$ java -XX:CompileThreshold=1 -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:CompileCommand="compileonly pac/kage/MyClass myMethod" MyClass
in example above has is cycle: for (int i = 0; i < 1 000 000; i++) {...},
that is why in our case without 1 000 000 iterations we need -XX:CompileThreshold=1 option (by default 10 000 for -server) to see our disassembled compiled code.

Related

Java auto vectorization example

I'm trying to find a concise example which shows auto vectorization in java on a x86-64 system.
I've implemented the below code using y[i] = y[i] + x[i] in a for loop. This code can benefit from auto vectorization, so I think java should compile it at runtime using SSE or AVX instructions to speed it up.
However, I couldn't find the vectorized instructions in the resulting native machine code.
VecOpMicroBenchmark.java should benefit from auto vectorization:
/**
* Run with this command to show native assembly:<br/>
* java -XX:+UnlockDiagnosticVMOptions
* -XX:CompileCommand=print,VecOpMicroBenchmark.profile VecOpMicroBenchmark
*/
public class VecOpMicroBenchmark {
private static final int LENGTH = 1024;
private static long profile(float[] x, float[] y) {
long t = System.nanoTime();
for (int i = 0; i < LENGTH; i++) {
y[i] = y[i] + x[i]; // line 14
}
t = System.nanoTime() - t;
return t;
}
public static void main(String[] args) throws Exception {
float[] x = new float[LENGTH];
float[] y = new float[LENGTH];
// to let the JIT compiler do its work, repeatedly invoke
// the method under test and then do a little nap
long minDuration = Long.MAX_VALUE;
for (int i = 0; i < 1000; i++) {
long duration = profile(x, y);
minDuration = Math.min(minDuration, duration);
}
Thread.sleep(10);
System.out.println("\n\nduration: " + minDuration + "ns");
}
}
To find out if it gets vectorized, I did the following:
open eclipse and create the above file
right-click the file and from the dropdown menu, choose Run > Java Application (ignore the output for now)
in the eclipse menu, click Run > Run Configurations...
in the opened window, find VecOpMicroBenchmark, click it and choose the Arguments tab
in the Arguments tab, under VM arguments: put in this: -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,VecOpMicroBenchmark.profile
get libhsdis and copy (possibly rename) the file hsdis-amd64.so (.dll for windows) to java/lib directory. In my case, this was /usr/lib/jvm/java-11-openjdk-amd64/lib .
run VecOpMicroBenchmark again
It should now print lots of information to the console, part of it being the disassembled native machine code, which was produced by the JIT compiler. If you see lots of messages, but no assembly instructions like mov, push, add, etc, then maybe you can somewhere find the following message:
Could not load hsdis-amd64.so; library not loadable; PrintAssembly is disabled
This means that java couldn't find the file hsdis-amd64.so - it's not in the right directory or it doesn't have the right name.
hsdis-amd64.so is the disassembler which is required for showing the resulting native machine code. After the JIT compiler compiles the java bytecode to native machine code, hsdis-amd64.so is used to disassemble the native machine code to make it human readable. You can find more infos on how to get/install it at How to see JIT-compiled code in JVM? .
After finding assembly instructions in the output, I skimmed through it (too much to post all of it here) and looked for line 14. I found this:
0x00007fac90ee9859: nopl 0x0(%rax)
0x00007fac90ee9860: cmp 0xc(%rdx),%esi ; implicit exception: dispatches to 0x00007fac90ee997f
0x00007fac90ee9863: jnb 0x7fac90ee9989
0x00007fac90ee9869: movsxd %esi,%rbx
0x00007fac90ee986c: vmovss 0x10(%rdx,%rbx,4),%xmm0 ;*faload {reexecute=0 rethrow=0 return_oop=0}
; - VecOpMicroBenchmark::profile#16 (line 14)
0x00007fac90ee9872: cmp 0xc(%rdi),%esi ; implicit exception: dispatches to 0x00007fac90ee9997
0x00007fac90ee9875: jnb 0x7fac90ee99a1
0x00007fac90ee987b: movsxd %esi,%rbx
0x00007fac90ee987e: vmovss 0x10(%rdi,%rbx,4),%xmm1 ;*faload {reexecute=0 rethrow=0 return_oop=0}
; - VecOpMicroBenchmark::profile#20 (line 14)
0x00007fac90ee9884: vaddss %xmm1,%xmm0,%xmm0
0x00007fac90ee9888: movsxd %esi,%rbx
0x00007fac90ee988b: vmovss %xmm0,0x10(%rdx,%rbx,4) ;*fastore {reexecute=0 rethrow=0 return_oop=0}
; - VecOpMicroBenchmark::profile#22 (line 14)
So it's using the AVX instruction vaddss. But, if I'm correct here, vaddss means
add scalar single-precision floating-point values and this only adds one float value to another one (here, scalar means just one, whereas here single means 32 bit, i.e. float and not double).
What I expect here is vaddps, which means add packed single-precision floating-point values and which is a true SIMD instruction (SIMD = single instruction, multiple data = vectorized instruction). Here, packed means multiple floats packed together in one register.
About the ..ss and ..ps, see http://www.songho.ca/misc/sse/sse.html :
SSE defines two types of operations; scalar and packed. Scalar operation only operates on the least-significant data element (bit 0~31), and packed operation computes all four elements in parallel. SSE instructions have a suffix -ss for scalar operations (Single Scalar) and -ps for packed operations (Parallel Scalar).
Queston:
Is my java example incorrect, or why is there no SIMD instruction in the output?
In the main() method, put in i < 1000000 instead of just i < 1000. Then the JIT also produces AVX vector instructions like below, and the code runs faster:
0x00007f20c83da588: vmovdqu 0x10(%rbx,%r11,4),%ymm0
0x00007f20c83da58f: vaddps 0x10(%r13,%r11,4),%ymm0,%ymm0
0x00007f20c83da596: vmovdqu %ymm0,0x10(%rbx,%r11,4) ;*fastore {reexecute=0 rethrow=0 return_oop=0}
; - VecOpMicroBenchmark::profile#22 (line 14)
The code from the question is actually optimizable by the JIT compiler using auto-vectorization. However, as Peter Cordes pointed out in a comment, the JIT needs quite some processing, thus it is rather reluctant to decide that it should fully optimize some code.
The solution is simply to execute the code more often during one execution of the program, not just 1000 times, but 100000 times or a million times.
When executing the profile() method this many times, the JIT compiler is convinced that the code is very important and the overall runtime will benefit from full optimization, thus it optimizes the code again and then it also uses true vector instructions like vaddps.
More details in Auto Vectorization in Java

JNI code crash with core dump when throw is called under 64 bit

I'm working with java + c++ ( using JNI ) and i must load own native libraries but application failed with core dump when throw is called lthough the code is surrounded by an exception handler (see code below). It's the same code working without problem on linux 64bit, sparc 64bit and i386 32bit.
The problem occurred when trying to run an application under java 8 on intel SunOs.
The flag -m64 has been added to the Makefile and library was added to the LD_PRELOAD_64 and LD_LIBRARY_PATH_64 has been set correctly.
The java starting, successfully load library and run the native code (Java_com_jnetx_usw_chp_CHPMain_start) and crash on the throw:
INF:17:59:33.20:CHP main(27): CHPMain.run: ok load chp library. Start it...
NOT:17:59:33.22:CHP main(27): CHPMain.run: -> chp.start
Wed Nov 8 17:59:34 CHP::startTest : cycle = 1
Wed Nov 8 17:59:35 CHP::startTest : cycle = 2
Wed Nov 8 17:59:35 Try cause Exception...
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x0000000000012ab5, pid=10081, tid=0x0000000000000026
#
# JRE version: Java(TM) SE Runtime Environment (8.0_121-b13) (build 1.8.0_121-b13)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.121-b13 mixed mode solaris-amd64 compressed oops)
# Problematic frame:
# C 0x0000000000012ab5
#
# Core dump written. Default location: /home/kcc_64/x2001/bin/core or core.10081
#
# An error report file with more information is saved as:
# /home/kcc_64/x2001/bin/hs_err_pid10081.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
#
The native code
JNIEXPORT void JNICALL Java_com_jnetx_usw_chp_CHPMain_start
(JNIEnv *env, jobject jobj, jint trc_level,jobjectArray j_argv,jobject chp_main,jobject chp_smp)
{
chp = new CHP();
chp->startTest();
}
void CHP::startTest() {
int t = 1;
while (true) {
try {
poll(NULL, 0, 1000);
fprintf(stderr, "%s CHP::startTest : cycle = %d\n", getTime(), t++);
if ( 3 == t ) {
fprintf(stderr, "%s : Try generate Exception... \n", getTime());
throw 20;
}
}
catch (const int & e) {
fprintf(stderr, "%s : Catch, e = %d\n", getTime(), e);
break;
}
catch (...) {
fprintf(stderr, "%s : Catch unknown exception...\n", getTime());
break;
}
}
fprintf(stderr, "%s : CHP::startTest : End thread, exit\n", getTime());
}
Why the catch block is ignored and immediately we go to the system signal handler which ends with core dump (see pstack below)?
-bash-3.00$ uname -a
SunOS x2001 5.10 Generic_142910-17 i86pc i386 i86pc
-bash-3.00$ pstack core
-bash-3.00$ gcc --version
gcc (GCC) 4.4.2
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
pflags core
/38: flags = DETACH
sigmask = 0xfffffeff,0x0000ffff cursig = SIGABRT
pstack core
fffffd7fff291aea _lwp_kill () + a
fffffd7fff236c39 raise () + 19
fffffd7fff215bb0 abort () + 90
...
fffffd7ffe9d0343 JVM_handle_solaris_signal () + 8d7
fffffd7ffe9c8617 signalHandler () + 2f
fffffd7fff28c2e6 __sighndlr () + 6
fffffd7fff280bc2 call_user_handler () + 252
fffffd7fff280dee sigacthandler (b, fffffd7f7e2f5208, fffffd7f7e2f4ea0) + ee
--- called from signal handler with signal 11 (SIGSEGV) ---
0000000000013dd5 ???????? () + 28000d930d5
fffffd7fff2904d9 _SUNW_Unwind_RaiseException () + 46
fffffd7f7dea2c53 __cxa_throw () + 9b !!!!!!!!!
fffffd7f7f213310 _ZN3CHP9startTestEv () + 190
fffffd7fee215a14 * com/jnetx/usw/chp/CHPMain.start(I[Ljava/lang/String;Lcom/jnetx/usw/chp/CHPMain;Lcom/jnetx/usw/chp/CHPSmp;)V+0
fffffd7fee2083b6 * com/jnetx/usw/chp/CHPMain.run([Ljava/lang/String;Lcom/jnetx/usw/chp/CHPUpdateListener;)V+563 (line 377)
fffffd7fee2083b6 * com/jnetx/usw/chp/CHPProvider$1.run()V+20 (line 374)
fffffd7fee2007a7 * com/jnetx/usw/chp/CHPProvider$1.run()V+17760
fffffd7ffe4c10ff __1cJJavaCallsLcall_helper6FpnJJavaValue_pnMmethodHandle_pnRJavaCallArguments_pnGThread__v_ () + 8d7
fffffd7ffe4bcd3c __1cJJavaCallsMcall_virtual6FpnJJavaValue_nLKlassHandle_pnGSymbol_5pnRJavaCallArguments_pnGThread__v_ () + 424
fffffd7ffe4bd124 __1cJJavaCallsMcall_virtual6FpnJJavaValue_nGHandle_nLKlassHandle_pnGSymbol_6pnGThread__v_ () + 60
fffffd7ffe64030c __1cMthread_entry6FpnKJavaThread_pnGThread__v_ () + b8
fffffd7ffebd9679 __1cKJavaThreadDrun6M_v_ () + 5e1
fffffd7ffe9bdc85 java_start () + 175
fffffd7fff28bfbb _thr_setup () + 5b
fffffd7fff28c1e0 _lwp_start ()
The issue has been resolved:
There is a known issue with a slight mismatch in the ABI between these two (libgcc_s.so: _Unwind_RaiseException and Solaris libc.so: _Unwind_RaiseException). Binding symbols to the GCC runtime first causes it to be loaded before the Solaris runtime, and everything works out well. But, simply adding this explicitly to our shared library link line did not help anything.
so my simple workaround helped me:
LD_PRELOAD=/usr/sfw/lib/amd64/libgcc_s.so
The main reason has been in the version of gcc, i used 4.4, but fix has been made in 4.9 -
Mixing libc and libgcc_s unwinders on 64-bit Solaris 10+/x86 breaks EH
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788

Launching JRE in Linux from a FAT32 USB

I have a Java application installed on a USB which the user should be able to run from any OS.
For this,
I'm packaging a JRE instance on the USB along with my application.
I'm having a FAT32 file-system on the USB.
However, the problem is, FAT32 has no concept of execute ("+x") permissions. While I can launch a shell script, like so:
$ sh /path/to/fat32-usb/helloWorld.sh
, and while I can launch a simple ELF binary, like so:
$ /lib64/ld-linux-x86-64.so.2 /path/to/fat32-usb/helloWorld
, I can't seem to be able to launch the Java ELF program. I get these errors:
Error: could not find libjava.so
Error: Could not find Java SE Runtime Environment.
Before launching java, I've tried setting these environment variables as follows:
export JAVA_HOME=/path/to/fat32-usb/jre
export LD_LIBRARY_PATH="$JAVA_HOME/lib/amd64:.:$LD_LIBRARY_PATH"
export PATH="$JAVA_HOME/bin:.:$PATH"
I have also tried launching java from inside the $JAVA_HOME/bin directory. Finally, I've also tried copying all the libXXX.so's from $JAVA_HOME/lib/amd64/ to $JAVA_HOME/bin, hoping that they would get picked up from the current directory, ., somehow.
But nothing has worked.
EDIT
Here are the last few lines of strace output:
$ strace -vfo /tmp/java.strace /lib64/ld-linux-x86-64.so.2 /path/to/fat32-usb/jre ...
...
readlink("/proc/self/exe", "/lib/x86_64-linux-gnu/ld-2.17.so", 4096) = 32
write(2, "Error: could not find libjava.so", 32) = 32
write(2, "\n", 1) = 1
write(2, "Error: Could not find Java SE Ru"..., 50) = 50
write(2, "\n", 1) = 1
exit_group(2) = ?
EDIT2
And here is the output of ltrace (just a single line!):
$ ltrace -s 120 -e '*' -ifo /tmp/java.ltrace /lib64/ld-linux-x86-64.so.2 /path/to/fat32-usb/jre ...
30913 [0xffffffffffffffff] +++ exited (status 2) +++
EDIT 3
This is ltrace excerpt around loading of libjava.so by a Java on an ext4 partition (and not the problem FAT32 partition), which I can load fine:
5525 [0x7f7627600763] <... snprintf resumed> "/home/aaa/bbb/jdk1.7.0_40/lib/amd64/libjava.so", 4096, "%s/lib/%s/libjava.so", "/home/aaa/bbb/jdk1.7.0_40", "amd64") = 46
5525 [0x7f762760076d] libjli.so->access("/home/aaa/bbb/jdk1.7.0_40/lib/amd64/libjava.so", 0) = -1
5525 [0x7f762760078d] libjli.so->snprintf( <unfinished ...>
5525 [0x3085246bdb] libc.so.6->(0, 0x7fffffd8, 0x7f7627607363, 39) = 0
5525 [0x3085246be3] libc.so.6->(0, 0x7fffffd8, 0x7f7627607363, 39) = 0
5525 [0x7f762760078d] <... snprintf resumed> "/home/aaa/bbb/jdk1.7.0_40/jre/lib/amd64/libjava.so", 4096, "%s/jre/lib/%s/libjava.so", "/home/aaa/bbb/jdk1.7.0_40", "amd64") = 50
5525 [0x7f7627600797] libjli.so->access("/home/aaa/bbb/jdk1.7.0_40/jre/lib/amd64/libjava.so", 0) = 0
And this is the strace output of, again, the healthy/loading java.
5952 readlink("/proc/self/exe", "/home/aaa/bbb/jdk1.7.0_40/bin/ja"..., 4096) = 34
5952 access("/home/aaa/bbb/jdk1.7.0_40/lib/amd64/libjava.so", F_OK) = -1 ENOENT (No such file or directory)
5952 access("/home/aaa/bbb/jdk1.7.0_40/jre/lib/amd64/libjava.so", F_OK) = 0
5952 open("/home/aaa/bbb/jdk1.7.0_40/jre/lib/amd64/jvm.cfg", O_RDONLY) = 3

Java check latest version programmatically

Goal: check java's version on a machine (I can get this from java -version). Compare it with latest available from java website
I would like to know if there is any way I can check for latest Java releases assuming that I have JRE/JDK installed on a machine.
If I can do this through Java itself, my solution would become platform independent. I could use java.net.URL class to send a request to Java website and get the HTML, however the response would be dynamic as Oracle can change their website and styles and possibly will have maintenance issues in long run.
I have looked at javatester.org, but I would not want it through an applet but through command line (which I can add to a script).
Through javacpl.exe, I can schedule periodic checks, but I would like to do it on demand.
The answer is actually quite simple. http://java.com/en/download/testjava.jsp issues a request to http://java.com/applet/JreCurrentVersion2.txt. That file currently contains a single version number: '1.7.0_11'...which is the latest and greatest, indeed.
Java code example
try (BufferedReader br = new BufferedReader(new InputStreamReader(new URL(
"http://java.com/applet/JreCurrentVersion2.txt").openStream()))) {
String fullVersion = br.readLine();
String version = fullVersion.split("_")[0];
String revision = fullVersion.split("_")[1];
System.out.println("Version " + version + " revision " + revision);
} catch (IOException e) {
// handle properly
}
Update 2014-03-20
Eventhough Java 8 was recently released http://java.com/applet/JreCurrentVersion2.txt currently still returns 1.7.0_51.
Update 2016-07-13
Looks like we need to come back to this every few months... Currently you need to scan http://java.com/en/download/installed8.jsp for a JavaScript variable latest8Version. So, you could run curl -s https://java.com/en/download/installed8.jsp | grep latest8Version.
Update 2018-08-19
http://javadl-esd-secure.oracle.com/update/baseline.version is another hot spot as mentioned in some other answer.
An URL very similar to the now defunct "JreCurrentVersion2.txt":
http://javadl-esd-secure.oracle.com/update/baseline.version
The contents of the link look like this:
1.8.0_111
1.7.0_121
1.6.0_131
1.5.0_99
1.4.2_43
You can easily parse the contents to find the latest JRE versions.
UPDATE: I don't recommend this method because this JRE is the one that has the Ask.com toolbar. You're better off downloading it yourself and distributing it yourself.
The jusched.exe program accesses the following URL to find out what versions are available. I think it's less likely to change because jusched is installed on millions of computers.
https://javadl-esd-secure.oracle.com/update/1.7.0/map-m-1.7.0.xml
Here is a snippet of what it returns for me:
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?>
<java-update-map version="1.0">
<mapping>
<version>1.7.0_17</version>
<url>https://javadl-esd-secure.oracle.com/update/1.7.0/au-descriptor-1.7.0_25-b17.xml</url>
</mapping>
<mapping>
<version>1.7.0_21</version>
<url>https://javadl-esd-secure.oracle.com/update/1.7.0/au-descriptor-1.7.0_25-b17.xml</url>
</mapping>
</java-update-map>
To get the actual version that it is pointing to you have to fetch the above URL. Here is another snippet of what this XML looks like:
xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- XML file to be staged anywhere, and pointed to by map.xml file -->
<java-update>
<information version="1.0" xml:lang="en">
<caption>Java Update - Update Available</caption>
<title>Java Update Available</title>
<description>Java 7 Update 25 is ready to install. Installing Java 7 Update 25 might uninstall the latest Java 6 from your system. Click the Install button to update Java now. If you wish to update Java later, click the Later button.</description>
<moreinfo>http://java.com/moreinfolink</moreinfo>
<AlertTitle>Java Update Available</AlertTitle>
<AlertText>A new version of Java is ready to be installed.</AlertText>
<moreinfotxt>More information...</moreinfotxt>
<url>http://javadl.sun.com/webapps/download/GetFile/1.7.0_25-b17/windows-i586/jre-7u25-windows-i586-iftw.exe</url>
<version>1.7.0_25-b17</version>
<post-status>https://nometrics.java.com</post-status>
<cntry-lookup>http://rps-svcs.sun.com/services/countrylookup</cntry-lookup>
<predownload></predownload>
<options>/installmethod=jau FAMILYUPGRADE=1 SPWEB=http://javadl-esd.sun.com/update/1.7.0/sp-1.7.0_25-b17</options>
<urlinfo>24595ec7f861bc67e572f1e4ad3992441335e1a7</urlinfo>
</information>
</java-update>
The version tag contains the full version number.
You could parse the Java SE Downloads page to extract the Java versions.
That way, you get the version of both JDK6 and JDK7, which allows you to test your particular JDK (6 or 7) against the latest Oracle one.
(As opposed to the Free Java Download page, which only lists the JDK7)
Her is a crude script in Go, which you can compile on Windows, Unix, MacOs into a single independent executable, and use within a command line or a script:
package main
import (
"bytes"
"encoding/xml"
"fmt"
"io/ioutil"
"net/http"
"os/exec"
"regexp"
)
type Jdk struct {
Url string
Ver string
update string
}
func main() {
resp, err := http.Get("http://www.oracle.com/technetwork/java/javase/downloads/index.html")
if err != nil {
fmt.Printf("Error on http Get: %v\n", err)
return
}
bodyb, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("QueriesForOwner: error in ReadAll: %v\n", err)
return
}
br := bytes.NewBuffer(bodyb)
jdkre, err := regexp.Compile(`h3[^\r\n]+(/technetwork/java/javase/downloads/(jdk(?:6|7)(?:u(\d+))?)-downloads-\d+\.html)`)
if err != nil {
fmt.Printf("extract: error in regexp compilation: %v\n", err)
return
}
jdks := jdkre.FindAllSubmatch(br.Bytes(), -1)
jdk7 := Jdk{string(jdks[0][4]), string(jdks[0][5]), string(jdks[0][6])}
jdk6 := Jdk{string(jdks[1][7]), string(jdks[1][8]), string(jdks[1][9])}
fmt.Printf("Jdk7: %v\nJdk6: %v\n", jdk7, jdk6)
jver, err := exec.Command("java", "-version").CombinedOutput()
if err != nil {
fmt.Printf("*ExitError from java -version:", err)
return
}
fmt.Println("JVer: '", string(jver), "'")
jverre, err := regexp.Compile(`1.(\d).\d(?:_(\d+))"`)
jvers := jverre.FindSubmatch(jver)
jj := string(jvers[0])
jv := string(jvers[1])
ju := string(jvers[2])
jdk := jdk6
if jv == "7" {
jdk = jdk7
}
if jdk.update != ju {
fmt.Println("Local JDK *NOT* up-to-date: you have ", jj, ", Oracle has ", jdk.Ver)
} else {
fmt.Println("Local JDK *up-to-date*: you have ", jj, ", equals to Oracle, which has", jdk.Ver)
}
}
Again, this is a crude script, oriented toward JDK, and you would need to adapt it to your specific need, making its output and exit status match what you need for your script.
On my (PC) workstation, it returns:
Jdk7: {/technetwork/java/javase/downloads/jdk7u9-downloads-1859576.html jdk7u9 9}
Jdk6: {/technetwork/java/javase/downloads/jdk6u37-downloads-1859587.html jdk6u37 37}
JVer: ' java version "1.6.0_31"
Java(TM) SE Runtime Environment (build 1.6.0_31-b05)
Java HotSpot(TM) Client VM (build 20.6-b01, mixed mode, sharing)
'
Local JDK *NOT* up-to-date: you have 1.6.0_31" , Oracle has jdk6u37
I don't know what information you are exactly looking for, but you can get some version information using
System.getProperty("java.version");
If this is not what you're looking for, check the other available properties here:
http://docs.oracle.com/javase/6/docs/api/java/lang/System.html#getProperties()
As for the latest available version, I guess you'd have to parse this site manually:
http://java.com/en/download/index.jsp
The latest version is on there, currently it's
Version 7 Update 9
You write that this is not what you want because "Oracle can change their website and styles". However, you want to find out the latest version of Java by accessing their service (website in this case). As long as you're not paying for this, they have no obligation to you, and can change the service whenever they want without your consent. And even when you're a paying customer, the best you can hope for is that they will inform you of upcoming changes, and your maintenance issues will remain.
Remember, it's THEIR service you want to use.
I have solved a similar issue some time ago with this groovy script (disclaimer: is somehow a "toy" script):
#Grapes([
#Grab(group='org.ccil.cowan.tagsoup', module='tagsoup', version='1.2.1')
])
def slurper = new XmlSlurper(new org.ccil.cowan.tagsoup.Parser())
def url = new URL("http://www.java.com/download/manual.jsp")
def html
url.withReader { reader ->
html = slurper.parse(reader)
}
def lastJava = html.body.div.div.div.strong.text()
println "Last available java version: ${lastJava}"
println "Currently installed java version: ${System.properties["java.version"]}"
It yields something like:
Last available java version:
Version 7 Update 9
Currently installed java version: 1.7.0_07
If you want to avoid maintenance issues due to changes to the page structure, maybe a better option is to search for a line containing "Version x Update y".
To get all system variables
Properties properties = System.getProperties();
System.out.println(properties);
Sample output, this might be different in your system depending on your OS and Java JDK/JRE version.
{
java.runtime.name = Java(TM) SE Runtime Environment,
sun.boot.library.path = C:\Program Files\Java\jdk1.8.0_31\jre\bin,
java.vm.version = 25.31-b07,
java.vm.vendor = Oracle Corporation,
java.vendor.url = http://java.oracle.com/,
path.separator = ;,
idea.launcher.port = 7534,
java.vm.name = Java HotSpot(TM) 64-Bit Server VM,
file.encoding.pkg = sun.io,
user.country = NP,
user.script = ,
sun.java.launcher = SUN_STANDARD,
sun.os.patch.level = ,
java.vm.specification.name = Java Virtual Machine Specification,
user.dir = C:\Users\...\roid,
java.runtime.version = 1.8.0_31-b13,
java.awt.graphicsenv = sun.awt.Win32GraphicsEnvironment,
java.endorsed.dirs = C:\Program Files\Java\jdk1.8.0_31\jre\lib\endorsed,
os.arch = amd64,
java.io.tmpdir = C:\Windows\TEMP\,
line.separator = ,
java.vm.specification.vendor = Oracle Corporation,
user.variant = ,
os.name = Windows 8.1,
sun.jnu.encoding = Cp1252,
java.library.path = C:\Program...roid,
java.specification.name = Java Platform API Specification,
java.class.version = 52.0,
sun.management.compiler = HotSpot 64-Bit Tiered Compilers,
os.version = 6.3,
user.home = C:\Users\Xxx,
user.timezone = Asia/Kathmandu,
java.awt.printerjob = sun.awt.windows.WPrinterJob,
file.encoding = UTF-8,
idea.launcher.bin.path = C:\Program Files (x86)\xxx\bin,
java.specification.version = 1.8,
java.class.path = C:\Program Files\Java\jdk1.8.0_31\jre\lib\charsets.jar;...,
user.name = Xxx,
java.vm.specification.version = 1.8,
sun.java.command = com.xxxx.ameras,
java.home = C:\Program Files\Java\jdk1.8.0_31\jre,
sun.arch.data.model = 64,
user.language = en,
java.specification.vendor = Oracle Corporation,
awt.toolkit = sun.awt.windows.WToolkit,
java.vm.info = mixed mode,
java.version = 1.8.0_31,
java.ext.dirs = C:\Program Files\Java\jdk1.8.0_31\jre\lib\ext;...,
java.vendor = Oracle Corporation,
file.separator = \,
java.vendor.url.bug = http://bugreport.sun.com/bugreport/,
sun.io.unicode.encoding = UnicodeLittle,
sun.cpu.endian = little,
sun.desktop = windows,
sun.cpu.isalist = amd64
}
Retrive only specific variable
String javaVersion = System.getProperty("java.version");
System.out.println(javaVersion);
Output
1.8.0_31
#MarcelStör's solution no longer works - the version in the file is 1.8.0_51, while the actual latest version is 1.8.0_91/92. If you go to the Java test page in Firefox or Chrome and open the development console you can get the variable latest8Version which currently is 1.8.0_91. This could be wrapped in a Selenium/Firefox solution, but is an incredibly hacky way of getting this information.
System.getProperty("java.vm.specification.version");
System.getProperty("java.version");

Scala perf: Why is this Scala app 30x slower than the equivalent Java app?

I am a very proficient C# developer, but need to start writing code that works on the JVM. The Java language is feature poor compared to C# these days, so I was interested in the features that Scala offers.
However, when hearing that in Scala, all operators are simply methods, I became suspicious of the performance impact that would have on math-heavy computations (which is important for the types of applications my team writes)
So I ran some simple int based tests, and find that Scala is about 30x slower than the equivalent Java code. Not good! Can anyone tell me what I'm doing wrong? or how to improve the computational performance of the scala example to be on par with Java?
UPDATE1: as pointed out by the first two answers, I was being a super-noob and running this in the IntelliJ IDE. I don't know how to run the scala app via the java command line, which may be an IntelliJ issue. Thanks for the help guys, I'll need to investigate simple commandline execution of scala before I continue with perf testing, as the IDE given results are obviously too inaccurate.
UPDATE2: Luigi in the comments says in IntelliJ he gets equal times, so it seems that my wild difference isn't due to IntelliJ? Any other ideas on what this could be? I'll try getting this running via command line and post an update with my results.
UPDATE3:
after running this via commandline, I get the same 30x perf difference.
My computer is a 3core AMD x64 3.4Ghz, running J2SE 6 jdk 64bit 1.6.0_31, Window7.
Here are my runtimes:
Java: 210ms.
Scala: between 2000 and 7400ms (generally the 7000 range)
so, i suppose the question is still open. why is scala running so slow on my platform? something with the java 64bit runtime, or with Java 6?
runtime versions:
C:\Users\jason>java -showversion
java version "1.6.0_31"
Java(TM) SE Runtime Environment (build 1.6.0_31-b05)
Java HotSpot(TM) 64-Bit Server VM (build 20.6-b01, mixed mode)
C:\Users\jason>scala
Welcome to Scala version 2.9.1-1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_31).
UPDATE 4 while my original test has a 30x difference, increasing the iterations to 100000000 causes the difference to shrink to about 33%, so it seems scala was still being dominated by some unknown initialization cost on my machine. i'll close this with the highest rated answer as i don't think we'll find out the performance problem, due to no one except me seeing the issue :(
*UPDATE 5, SOLUTION: based on the help from the 2 answers i got, i figured out the problem, see my answer below for more details (summary: the first call to System.nanoTime() takes a long time) *
Here are my sample apps:
//scala
object HelloWorld {
//extends Application {
def main(args: Array[String]) {
println("hello scala")
var total: Long = 0
var i: Long = 0
var x: Long=0;
//warm up of the JVM to avoid timing of runtime initialization
while (i < 100000)
{
x=i;
x += x - 1;
x -= x + 1;
x += 1;
x -= 1;
total += x;
i+=1;
}
//reset variables
total = 0
i = 0;
//start timing
var start: Long = System.nanoTime
//run test
while (i < 100000) {
x=i;
x += x - 1;
x -= x + 1;
x += 1;
x -= 1;
total += x;
i+=1;
}
var end: Long = System.nanoTime
System.out.println("ms, checksum = ")
System.out.println((end - start) / 1000)
System.out.println(total)
}
}
and here is the java equivalent, 30x faster
//java
public class app {
public static void main(String[] args)
{
String message = "hello, java";
System.out.println(message);
long total = 0;
//warm up of the JVM to avoid timing of runtime initialization
for(long i=0;i< 100000;i++)
{
long x=i;
x+=x-1;
x-=x+1;
x++;
x--;
total+=x;
}
//reset variables
total = 0;
//start timing and run test
long start = System.nanoTime();
for(long i=0;i< 100000;i++)
{
long x=i;
x+=x-1;
x-=x+1;
x++;
x--;
total+=x;
}
long end = System.nanoTime();
System.out.println("ms, checksum = ");
System.out.println((end-start)/1000);
System.out.println(total);
}
}
So, I guess I figured out the answer myself.
The problem is in the call to System.nanoTime. Doing this has some initialization cost (loading up the Java base libraries, etc) which is much less expensive to load when called from the Java runtime than from the Scala runtime.
I prove this by changing the initial value of total, instead setting it to
var total: Long = System.nanoTime()
This is added before the first "warm up" loop, and doing so now makes both versions of the app (Java and Scala) run at the same time: about 2100 for 1000000 iterations.
Thanks for your guys' help on this, I wouldn't have figured this out without your assistance.
ps: I'll leave the "accepted answer" as-is because I wouldn't have tracked this down without his help.
I've re-run your code (and increased number of cycles x1000, so to get some meaning into benchmark).
Results:
Scala: 92 ms
Java: 59 ms
You can see that Java is 30% faster.
Looking at the bytecode, I can say that two versions are almost identical - so the difference is really strange (the bytecode listing is quite long, so I won't post it here).
Increasing the count x10000 gives this:
Scala: 884 ms
Java: 588 ms
Since the results are fairly stable, there should be some constant factor lurking somewhere. Maybe in some parameters that "scala" runner passes to JVM?
EDIT:
My configuration:
$ java -version
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02, mixed mode)
$ scala -version
Scala code runner version 2.9.0.1 -- Copyright 2002-2011, LAMP/EPFL
$ inxi -SCD
System: Host the-big-maker Kernel 2.6.35-22-generic x86_64 (64 bit) Distro Linux Mint 10 Julia
CPU: Quad core AMD Phenom II X4 965 (-MCP-) cache 2048 KB flags (lm nx sse sse2 sse3 sse4a svm)
Clock Speeds: (1) 800.00 MHz (2) 800.00 MHz (3) 800.00 MHz (4) 800.00 MHz
Disks: HDD Total Size: 750.2GB (5.8% used) 1: /dev/sda OCZ 90.0GB
2: /dev/sdb ST3500413AS 500.1GB 3: /dev/sdc ST3802110A 80.0GB
4: /dev/sdd Maxtor_6Y080M0 80.0GB
$ javac app.java
$ scalac app.scala
$ scala HelloWorld
hello scala
ms, checksum =
1051
-100000
$ java app
hello, java
ms, checksum =
1044
-100000
What I'm doing wrong?

Categories

Resources