brettwooldridge / NuProcess

Low-overhead, non-blocking I/O, external Process implementation for Java
Apache License 2.0
712 stars 84 forks source link

Insane CPU usage compared to running same executable from terminal (Mac OS) #97

Open mrlimbic opened 5 years ago

mrlimbic commented 5 years ago

I was trying to use remote control mode with Jadeo (MTC sync video player app) on Mac OS. In this mode Jadeo runs like an interpreter, so need to use I/O to send it commands and receive responses.

What is very strange is that CPU usage is 20x higher when using NuProcess vs running Jadeo in remote control mode from the Mac terminal.

What could be causing this? I tried to switch to using NuProcess because I had same issue when using ProcessBuilder and piped streams and thought it was blocking I/O with PipedStreams causing it. But NuProcess also does same. Why only from Java?

brettwooldridge commented 5 years ago

@mrlimbic Very strange. Is Jadeo outputting something constantly to stderr or stdout? Have you tried attaching a profiler to see where the time is being spent? I would be very interested to see the profile.

mrlimbic commented 5 years ago

The protocol is simple and short. You type a simple one line text command which receives a simple text confirmation (usually also one line). If you start the app with arg --remote it will work in remote mode.

Example remote control commands.. http://xjadeo.sourceforge.net/remote.html

It's Jadeo itself that uses lots of CPU (but only when started from java), not the java app talking to it. I'm not sure how to profile Jadeo. I could profile the java app if that would help?

brettwooldridge commented 5 years ago

@mrlimbic Profiling the Java-side could still (possibly) be interesting. Is this on Mac, Linux, or Windows?

mrlimbic commented 5 years ago

I don't know if this happens on other platforms. I am working in Mac OS so it may be specific.

brettwooldridge commented 5 years ago

@mrlimbic Thanks. The code paths are different for each platform, so knowing the platform helps narrow down the code to be considered. The fact that the same issue occurs with ProcessBuilder and PipedXXXStreams is an interesting datapoint.

It is pretty complex, but you can investigate running dtrace on the Jadeo process. It would give a good idea of where Jadeo is spending its time. If you do run a dtrace, please attach the trace log here.

Though it would still be interesting to see the Java-side profile.

mrlimbic commented 5 years ago

How do I run dtrace on Jadeo when starting it from java? If I start Jadeo via dtrace in the terminal then the problem isn't replicated so that information won't be so useful.

Which classes should I profile on the java side? Is there a way to profile native calls?

brettwooldridge commented 5 years ago

@mrlimbic It looks like you can "attach" to a running process. Search for the word "attach" on the linked dtrace page. You're going to need to dig a little deep here, and google/research on your own about dtrace on OS X...

mrlimbic commented 5 years ago

Does this help? I used the dtrace script called syscallbypid.d

The numbers for Jadeo were way bigger when run from java than any other process on the machine.

   571 Jadeo-bin                ulock_wait                  20594
   571 Jadeo-bin                ulock_wake                  20594
   571 Jadeo-bin                read                      1496393
   571 Jadeo-bin                select                    1496393
   571 Jadeo-bin                psynch_mutexdrop          3279947
   571 Jadeo-bin                psynch_mutexwait          3279947

When run from terminal the numbers way lower and similar ranges to other process. These two were were the highest.

   643 Jadeo-bin                psynch_cvbroad              13855
   643 Jadeo-bin                psynch_cvwait               16704
bturner commented 5 years ago

I don't know whether it's true with Jadeo (never heard of this application), but some applications I've seen (Git, for example) attempt to detect whether there's a PTY attached to the process and they run differently if there is. Perhaps the difference here is that when you run the process via NuProcess there's no PTY, but when you run it via the terminal there is? You might experiment with using nohup/& and stream redirection to move the process to the background, or something, and see if that reproduces the high CPU load without NuProcess. (Just a thought. As I said, I don't know anything about Jadeo.)

mrlimbic commented 5 years ago

Thanks @bturner. I gave up on this for a while due to no progress but will try your suggestion tomorrow. It's still something important that I'd like to be possible without setting fire to the laptop.

mrlimbic commented 4 years ago

When attempting to repoduce the problem from another language instead of Java I came across this difference in Python. I think you are right @bturner. The question is how can I do this from Java now.

100+% CPU usage like this.. cp = subprocess.run(["/Applications/Jadeo.app/Contents/MacOS/Jadeo", "--remote", "--ontop", "--no-splash"], shell=False)

But only 1% CPU usage like this.. cp = subprocess.run(["/Applications/Jadeo.app/Contents/MacOS/Jadeo", "--remote", "--ontop", "--no-splash"], shell=True)

mrlimbic commented 4 years ago

Running process through bash reduces CPU from 100% to 15%. However still nowehere near as good as Python using shell=True.

ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.directory(new File(JADEO_MAC_DIR));
processBuilder.command("bash", "-c", JADEO_MAC_BIN + " --remote --no-splash --ontop");