Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin doesn't work on Windows with IntelliJ 2016.1.1? #19

Closed
Jire opened this issue Apr 30, 2016 · 16 comments · Fixed by knittl/idea-jmh-plugin#1
Closed

Plugin doesn't work on Windows with IntelliJ 2016.1.1? #19

Jire opened this issue Apr 30, 2016 · 16 comments · Fixed by knittl/idea-jmh-plugin#1

Comments

@Jire
Copy link

Jire commented Apr 30, 2016

When running it seems like it tries to access an invalid path for its lock.

ERROR: org.openjdk.jmh.runner.RunnerException: ERROR: Exception while trying to acquire the JMH lock (C:\Windows\/jmh.lock): Access is denied, exiting. Use -Djmh.ignoreLock=true to forcefully continue.
    at org.openjdk.jmh.runner.Runner.run(Runner.java:213)
    at org.openjdk.jmh.Main.main(Main.java:71)
@artyushov
Copy link
Owner

Hi.

Can you run your benchmarks without plugin?

@Jire
Copy link
Author

Jire commented Apr 30, 2016

Yes, completely.

@geld0r
Copy link

geld0r commented May 1, 2016

I also see this error. I am running the same version under Windows.

I can run benchmarks via gradle successfully (via jmh-gradle-plugin) - is it possible that they conflict?

@artyushov
Copy link
Owner

There is nothing really I can do about it, it's not a plugin issue. The exception is thrown by the JMH runner itself which tries to acquire a lock jmh.lock which is located inside java.io.tmpdir. Try changing this property to point to a directory where your process has required permissions.

@kiril-dayradzhiev
Copy link

Hi all,
I met the same issue.
@artyushov you proposed to change java.io.tmpdir, but how? By using jvmArgs?

Best Regards,
Kiril

@Jire
Copy link
Author

Jire commented Jul 3, 2016

@artyushov We cannot do this trivially through the plugin since there is nowhere to state arguments.

@KarolS
Copy link

KarolS commented Sep 6, 2016

@Jire You can add the TMP environment variable in the plugin configuration and point it to any writeable directory.

@JavaOPs
Copy link

JavaOPs commented Sep 18, 2016

One more solution: run idea64.exe as Administrator

@kiril-dayradzhiev
Copy link

kiril-dayradzhiev commented Oct 5, 2016

Here is the only solution that works for me ->http://stackoverflow.com/questions/37720692/exception-while-trying-to-acquire-a-jmh-lock
I tried to set java.io.tmpdir environment variable in the plugin configuration, but it didn't worked and I don't know why(code snippet from the org.openjdk.jmh.runner.Runner class "private static final String JMH_LOCK_FILE = System.getProperty("java.io.tmpdir") + "/jmh.lock";")

@KarolS
Copy link

KarolS commented Oct 5, 2016

@kiril-dayradzhiev java.io.tmpdir is not an environment variable, it's a Java system property, which on Windows is by default set to the TMP environment variable. The plugin doesn't let you set Java properties, but lets you set environment variables.

@viliam-durina
Copy link

java.io.tmpdir on windows is normally c:\Users\userName\AppData\Local\Temp, so the JMH does not use this one. If it did, this directory is writable.

@mjeffrey
Copy link

mjeffrey commented Nov 26, 2019

In the "Run/Debug Configuration" dialog set the "Environment variables:" field to a writable directory
e.g.

TEMP=c:\tmp
image

This works on intellij ultimate 2019.2.4 and Windows 10.

@knittl
Copy link
Contributor

knittl commented Feb 25, 2020

Or, alternatively, check the checkbox to include system defined environment variables in the environment variables dialog (opened via the "page icon" on the right side of the text box).

Not sure if this could have a negative impact on the benchmarks though …

@joserobjr
Copy link
Contributor

One more solution: run idea64.exe as Administrator

And let a broken plugin make a mess in C:\Windows? No way.

@stokito
Copy link
Collaborator

stokito commented Oct 20, 2020

When JMH starts it checks that there no any other JMH process running on the machine.
To check it tries to create the jmh.lock file in systems temporary folder. Another process may check if the file is exists and wait while it will be removed. Instead of a lock file programs may use socket or even see processes list ps | prep to determine that there is no any running process in the system. Unfortunately JVM doesn't have a built-in single instance checker API and IMHO it would be really nice to have.

The standard Java API has a File.createTempFile(prefix, suffix) but it always creates a file with random name so other processes can't find the same file. Instead JMH gets the system property java.io.tmpdir and creates the jmh.lock file inside.

In Linux/UNIX the java.io.tmpdir is always /tmp/ folder. Note that all users have an access to folder.
On Windows when you call System.getProperty("java.io.tmpdir") Java calls the Win32 API's function GetTempPath.
According to the MSDN:

The GetTempPath function checks for the existence of environment
variables in the following order and uses the first path found:

  1. The path specified by the TMP environment variable.
  2. The path specified by the TEMP environment variable. The historical reasons on why TMP and TEMP coexist.
  3. The path specified by the USERPROFILE environment variable.
  4. The Windows directory C:\WINDOWS\.

So what really happens is that when we are starting JMH benchmark from IntelliJ the environment variables are really empty and the java.io.tmpdir returns C:\WINDOWS\. But access to the folder is denied. System variables looks like:

"java.io.tmpdir" -> "C:\WINDOWS\"
"java.library.path" -> "C:\Program Files\Zulu\zulu-8\bin;
    C:\WINDOWS\Sun\Java\bin;
    C:\WINDOWS\system32;
    C:\WINDOWS;."

But if in run configuration check Include system environment variables then will be copied the TMP, TEMP, USERPROFILE variables which are probably already configured system wide. So the resulted java.io.tmpdir will return C:\Users\Admin\AppData\Local\Temp\ i.e. user specific temp folder. Interesting, that other users in system still can run JMH simultaneously.

So the workaround was committed in 7b98e73 to create by default JMH configuration with already checked Include system environment variables. But actually this still not guaranties that TMP, TEMP, USERPROFILE variables are set in system.
Also this may have some side effects: when you inherit system envs then java.library.path system variable is also affected:

"java.io.tmpdir" -> "C:\Users\Admin\AppData\Local\Temp\"
"java.library.path" -> "C:\Program Files\Zulu\zulu-8\bin;
    C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;
    C:\WINDOWS;
    C:\WINDOWS\system32;

I.e. the property is affected by PATH env. The java.library.path is used by JNI to find DLL with native code.
So technically speaking it may have some unexpected side effects.
That means that for safety users should manually add the TEMP variable only instead of inherit.

JMH also have a VM option -Djmh.ignoreLock=true but it will anyway try to create the lock file but in case of access denial it will show error message but continue. We can add the VM option but then users will be confused by the error message.
And anyway latter they'll get java.lang.IllegalStateException: Error creating compiler hints file error in another place.

I don't know exactly how to fix it properly. But I think the best solution would be:

  1. IntelliJ must assign the TEMP env itself for all new Run configurations because now that means that temp files are just not working out of the box. I just tried to call File.createTempFile() and got IOException: Access is denied at java.io.WinNTFileSystem.createFileExclusively. I guess a lot of users are confused by this.
  2. JMH's jmh.ignoreLock option must not even try to create the lock file and not confuse users by error message. Then we may use it because we anyway have double execution protection implemented in Prevent multiple JMH runs in the same IDE #6. This also will speed up a little bit running. I created the PR to JMH

We also have three workarounds:

  1. We may just create a temporary directory ourselves and pass it into JMH by java.io.tmpdir VM option. But where to create it?
  2. Similar to previous, we may add the TEMP env ourselves if it not exists i.e. do 1. IntelliJ must assign the TEMP env ourselves.
  3. Just inherit parent envs and hope that everything will be fine. This workaround we currently use.

I would like to hear your thought or opinions and if no any objections I'll create a corresponding issue tickets in IntelliJ and create a PR to JMH.

JFYI: The similar issues exists for JMH gradle plugin:

knittl added a commit to knittl/idea-jmh-plugin that referenced this issue Oct 24, 2020
Limit the impact of inherited environment variables to Windows systems.
This was/is a workaround for artyushov#19: non-Windows systems already properly
provide the path to the tmp directory.
@knittl
Copy link
Contributor

knittl commented Oct 24, 2020

@stokito I have created a follow-up MR to limit the impact of inheriting environment variables to Windows systems only: #40

See related, original MR knittl#1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet