I was curious how much overhead there was in calling functions via JEP 389: Foreign Linker API. I have searched around but I can't seem to find that kind of info. I was taking a look to see if it is realistic to wrap a c++ 3d math library that uses SIMD stuff with it. For this case the overhead must be very low since the operations themselves take little time.
By my estimations on my machine it takes 10 nanoseconds to call. This is certainly very impressive but that does not work out when the target only takes nanoseconds to run!
I don't have a ton of Java experience so I was wondering if I am missing out on some configuration things or just something obvious. I'm just trying to wrap something up for Clojure.
This is (roughly) how I got my numbers:
rtm.cpp
extern "C" {
float inc_float(float f) {
return f + 1.0f;
}
}
Compiled with
clang -std=c++17 -O0 -shared -undefined dynamic_lookup -o librtm.so rtm.cpp
(also tested with -Ofast)
WrapperTest.java
import static jdk.incubator.foreign.CLinker.C_FLOAT;
import jdk.incubator.foreign.*;
import java.lang.invoke.*;
import java.nio.file.Path;
#Test public void testTonsOfSimpleCallsAlt() throws Throwable {
var path = Path.of("/path/to/librtm.so");
var libraryLookup = LibraryLookup.ofPath(path);
var incFloatHandle = CLinker.getInstance().downcallHandle(
libraryLookup.lookup("inc_float").get(),
MethodType.methodType(float.class, float.class),
FunctionDescriptor.of(C_FLOAT, C_FLOAT)
);
// warmup
for (var i = 0; i < 1024; ++i) {
float dummy = (float)incFloatHandle.invokeExact(1.0f);
}
long startTime = System.nanoTime();
float total = 1.0f;
int loops = 1024 * 1024 * 100;
int ops = 10;
for (var i = 0; i < loops; ++i) {
// The actual important call!
total = (float)incFloatHandle.invokeExact(total);
// nine more of the above line...
total = total - 10.0f;
}
long endTime = System.nanoTime();
float nanos = (float)(endTime - startTime);
System.out.println("Time taken is ms: " + (nanos / 1000000.0f));
System.out.println("Time taken per op in ns:" + (nanos / (float)loops / (float)ops));
}
JVM arguments
--add-modules jdk.incubator.foreign -Dforeign.restricted=permit
Java version
> java --version
openjdk 16 2021-03-16
OpenJDK Runtime Environment AdoptOpenJDK (build 16+36)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 16+36, mixed mode, sharing)
Looking in a profiler I am getting these sorts of call stacks around the call to the c++ function:
- WrapperTest.java:131 java.lang.invoke.LambdaForm$MH.0x0000000800227000.invokeExact_MT(Object, float, Object) 991 1
- LambdaForm$MH java.lang.invoke.LambdaForm$MH.0x0000000800229c00.invoke(Object, float) 991 1
- LambdaForm$MH java.lang.invoke.LambdaForm$MH.0x000000080021d800.invoke(Object, float, long) 991 1
I have just run this via the IntelliJ test runner.
So is the overhead 10ns per call (machine dependent blah blah) or is there a way to get this running faster?
I was really curious about this as well, so I wrote a quick benchmark to see how it compares to JNA as well as shared memory.
The results and code are here :
https://github.com/TwoClocks/benchmark_java_foreign_functions
I got around 25ns on this particular machine, which to me seems pretty good. Calling a C++ virtual function in C++ is 5-10ns-ish? Pretty good calling native code from the JVM (at least I think so). JNA comes in around 700ns. JNI might be a bit faster, but still far slower than the new foreign function stuff.
We have [GetServerTimeZoneInformation] used defined function in MS SQL Server which returns DaylightName or StandardName, ActiveTimeBias, Bias, DaylightBias, IsDST It uses Windows registry key to get these information but I have to write the code where linux(CentOs) operating system is being used and I have to get these information using Java. What is the Java API available which can give these values?
The TimeZone class gives you access to all or most of these data, for example:
TimeZone tz = TimeZone.getDefault();
String daylightName = tz.getDisplayName(true, TimeZone.LONG);
String standardName = tz.getDisplayName(false, TimeZone.LONG);
int rawOffset = tz.getRawOffset();
int daylightOffset = tz.getDSTSavings();
boolean isInDSTNow = tz.inDaylightTime(new Date());
Note however, that Java uses its own version of tzdb, and not the system-wide installed tzdb, so there may be differences between what Java reports and what you would get from native operating system tools, especially for time zones that have been changed recently.
In order to test java-code with date / time set into the past or future I want to try libfaketime (currently we just adjust the system clock, but it causes much trouble like non working kerberos, etc).
I try with this small test program:
$ cat time.java
import java.util.*;
class TimeTest {
public static void main(String[] s) {
long timeInMillis = System.currentTimeMillis();
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(timeInMillis);
java.util.Date date = cal.getTime();
System.out.println("Date: " + date);
}
}
And executes this:
LD_ASSUME_KERNEL=2.6.18 LD_PRELOAD=/usr/lib64/libfaketime.so.1 FAKETIME="-15d" /opt/IBM/WebSphere/AppServer/java_1.7_64/bin/java TimeTest
Invalid clock_id for clock_gettime: -172402[root#myhost ~]#
But as you can see I just get an error message.
The test is performed on a RHEL 6.5 server, kernel 2.6.32-431 and
libfaketime 0.9.6
Do you have any suggestions how I can solve this? I'm also interested in hearing your experiences with libfaketime and java on RHEL.
I have also reported this issue at: https://github.com/wolfcw/libfaketime/issues
Best reagards,
Erling
I've observed this incorrect behaviour as well in IBM JVM 1.7.0 while in Oracle JVM 1.6.0 this works as expected.
The explanation is that IBM JVM apparatently has an internal bug which manifests by calling clock_gettime system call with incorrect clock_id parameter (random negative value).
The workaround (not a fix) is to modify libfaketime.c to reset the clock_id to valid value in fake_clock_gettime function.
case FT_START_AT: /* User-specified offset */
if (user_per_tick_inc_set)
{
/* increment time with every time() call*/
next_time(tp, &user_per_tick_inc);
}
else
{
if (clk_id < 0) { // jvm calls clock_gettime() with invalid random negative clock_id value
clk_id = CLOCK_REALTIME;
}
switch (clk_id)
// the rest is the same
This will prevent the libfaketime.so.1 library from existing on error you are observing
printf("\nInvalid clock_id for clock_gettime: %d", clk_id);
exit(EXIT_FAILURE);
Please note this workaround has a drawback that in case JVM is incorrectly asking system for invalid clockid, we will assume valid clockid which may be not what application expects.
I'm currently using the Robot classes in Java to record the screen. However, it does not achieve the minimum of 30 frames per second. I'm not re-creating objects, and am being as efficient as I can, but I only average around 15 frames per second. Robot is simply not cutting it.
What can I use to capture the screen? I've tried Xuggle, but I can't seem to get that to capture fast enough either.
For operating systems following the X11 standard (Linux, FreeBSD, Solaris, etc.), we can do it this way via JavaCV and FFmpeg:
import com.googlecode.javacv.*;
public class ScreenGrabber {
public static void main(String[] args) throws Exception {
int x = 0, y = 0, w = 1024, h = 768; // specify the region of screen to grab
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(":0.0+" + x + "," + y);
grabber.setFormat("x11grab");
grabber.setImageWidth(w);
grabber.setImageHeight(h);
grabber.start();
CanvasFrame frame = new CanvasFrame("Screen Capture");
while (frame.isVisible()) {
frame.showImage(grabber.grab());
}
frame.dispose();
grabber.stop();
}
}
I don't know about Windows or Mac OS X, but I suspect we would need to access native APIs directly. Nevertheless, JavaCPP could help with that.
Build on #Samuel's answer, according to the official ffmpeg documentation you should be able to keep it pretty cross platform if you make the file parameter passed to the FFmpegFrameGrabber (which is really an input parameter that gets passed down as the -i option to ffmpeg) adhere to the different formats each device expects.
ie:
for Windows: dshow expects -i video="screen-capture-recorder"
for OSX: avfoundation expects -i "<screen device index>:"
and for Linux: x11grab expects -i :<display id>+<x>,<y>.
So just passing those values (arguments to -i) to the constructor and setting the format (via setFormat) accordingly should do the trick:
Examples:
for Windows:
new FFmpegFrameGrabber("video=\"screen-capture-recorder\"")
.setFormat("dshow");
for OSX:
new FFmpegFrameGrabber("\"<screen device index>:\"")
.setFormat("avfoundation");
for Linux:
new FFmpegFrameGrabber(":<display id>+<x>,<y>")
.setFormat("x11grab");
PS: Haven't tested this fully so not sure if the quotes are actually necessary.
What is the best way to find the user's home directory in Java?
The difficulty is that the solution should be cross-platform; it should work on Windows 2000, XP, Vista, OS X, Linux, and other Unix variants. I am looking for a snippet of code that can accomplish this for all platforms, and a way to detect the platform.
Per Java bug 4787931, system property user.home does not work correctly on Windows XP, so using this system property is not an acceptable solution as it is not cross-platform.
The bug you reference (bug 4787391) has been fixed in Java 8. Even if you are using an older version of Java, the System.getProperty("user.home") approach is probably still the best. The user.home approach seems to work in a very large number of cases. A 100% bulletproof solution on Windows is hard, because Windows has a shifting concept of what the home directory means.
If user.home isn't good enough for you I would suggest choosing a definition of home directory for windows and using it, getting the appropriate environment variable with System.getenv(String).
Actually with Java 8 the right way is to use:
System.getProperty("user.home");
The bug JDK-6519127 has been fixed and the "Incompatibilities between JDK 8 and JDK 7" section of the release notes states:
Area: Core Libs / java.lang
Synopsis
The steps used to determine the user's home directory on Windows have changed to follow the Microsoft recommended approach. This change
might be observable on older editions of Windows or where registry
settings or environment variables are set to other directories. Nature
of Incompatibility
behavioral RFE
6519127
Despite the question being old I leave this for future reference.
System.getProperty("user.home");
See the JavaDoc.
The concept of a HOME directory seems to be a bit vague when it comes to Windows. If the environment variables (HOMEDRIVE/HOMEPATH/USERPROFILE) aren't enough, you may have to resort to using native functions via JNI or JNA. SHGetFolderPath allows you to retrieve special folders, like My Documents (CSIDL_PERSONAL) or Local Settings\Application Data (CSIDL_LOCAL_APPDATA).
Sample JNA code:
public class PrintAppDataDir {
public static void main(String[] args) {
if (com.sun.jna.Platform.isWindows()) {
HWND hwndOwner = null;
int nFolder = Shell32.CSIDL_LOCAL_APPDATA;
HANDLE hToken = null;
int dwFlags = Shell32.SHGFP_TYPE_CURRENT;
char[] pszPath = new char[Shell32.MAX_PATH];
int hResult = Shell32.INSTANCE.SHGetFolderPath(hwndOwner, nFolder,
hToken, dwFlags, pszPath);
if (Shell32.S_OK == hResult) {
String path = new String(pszPath);
int len = path.indexOf('\0');
path = path.substring(0, len);
System.out.println(path);
} else {
System.err.println("Error: " + hResult);
}
}
}
private static Map<String, Object> OPTIONS = new HashMap<String, Object>();
static {
OPTIONS.put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
OPTIONS.put(Library.OPTION_FUNCTION_MAPPER,
W32APIFunctionMapper.UNICODE);
}
static class HANDLE extends PointerType implements NativeMapped {
}
static class HWND extends HANDLE {
}
static interface Shell32 extends Library {
public static final int MAX_PATH = 260;
public static final int CSIDL_LOCAL_APPDATA = 0x001c;
public static final int SHGFP_TYPE_CURRENT = 0;
public static final int SHGFP_TYPE_DEFAULT = 1;
public static final int S_OK = 0;
static Shell32 INSTANCE = (Shell32) Native.loadLibrary("shell32",
Shell32.class, OPTIONS);
/**
* see http://msdn.microsoft.com/en-us/library/bb762181(VS.85).aspx
*
* HRESULT SHGetFolderPath( HWND hwndOwner, int nFolder, HANDLE hToken,
* DWORD dwFlags, LPTSTR pszPath);
*/
public int SHGetFolderPath(HWND hwndOwner, int nFolder, HANDLE hToken,
int dwFlags, char[] pszPath);
}
}
Others have answered the question before me but a useful program to print out all available properties is:
for (Map.Entry<?,?> e : System.getProperties().entrySet()) {
System.out.println(String.format("%s = %s", e.getKey(), e.getValue()));
}
Alternative would be to use Apache CommonsIO FileUtils.getUserDirectory() instead of System.getProperty("user.home"). It will get you the same result and there is no chance to introduce a typo when specifying system property.
There is a big chance you already have Apache CommonsIO library in your project. Don't introduce it if you plan to use it only for getting user home directory.
As I was searching for Scala version, all I could find was McDowell's JNA code above. I include my Scala port here, as there currently isn't anywhere more appropriate.
import com.sun.jna.platform.win32._
object jna {
def getHome: java.io.File = {
if (!com.sun.jna.Platform.isWindows()) {
new java.io.File(System.getProperty("user.home"))
}
else {
val pszPath: Array[Char] = new Array[Char](WinDef.MAX_PATH)
new java.io.File(Shell32.INSTANCE.SHGetSpecialFolderPath(null, pszPath, ShlObj.CSIDL_MYDOCUMENTS, false) match {
case true => new String(pszPath.takeWhile(c => c != '\0'))
case _ => System.getProperty("user.home")
})
}
}
}
As with the Java version, you will need to add Java Native Access, including both jar files, to your referenced libraries.
It's nice to see that JNA now makes this much easier than when the original code was posted.
I would use the algorithm detailed in the bug report using System.getenv(String), and fallback to using the user.dir property if none of the environment variables indicated a valid existing directory. This should work cross-platform.
I think, under Windows, what you are really after is the user's notional "documents" directory.
If you want something that works well on windows there is a package called WinFoldersJava which wraps the native call to get the 'special' directories on Windows. We use it frequently and it works well.