How do I stop a Top Terminal Code after executing it once? - java

I want to see the CPU and RAM utilisation of a machine , until my java code is running. So I used top command, but I don't know how and when to stop it??
I don't know, how waitFor() can work for me?
I might run my code in a thread, but how do I tell it to wait for this thread to finish execution and stop?
MyCode
import...*;
public class MyCode {
ThreadSubclass thread1 = new ThreadSubclass();
thread1.start();
/*
I want Mycode to Run in parallel while top command stores output of RAM and CPU usage.
Can I write my code here??
When myCode is complete, stop Top command.
*/
System.out.println("0");
Process cmdProc = Runtime.getRuntime().exec("top");
System.out.println("1");
BufferedReader stdoutReader = new BufferedReader(
new InputStreamReader(cmdProc.getInputStream()));
String line;
while ((line = stdoutReader.readLine()) != null) {
// process procs standard output here
System.out.println(line);
}
System.out.println("2");
BufferedReader stderrReader = new BufferedReader(
new InputStreamReader(cmdProc.getErrorStream()));
while ((line = stderrReader.readLine()) != null) {
// process procs standard error here
System.out.println(line);
}
cmdProc = Runtime.getRuntime().exec("Ctrl+C");
}
in another fileā€¦ ThreadSubclass.java
public class ThreadSubclass extends Thread {
#Override
public void run() {
//Should I write all my code here? I had used fork earlier and it gave me pid, so It was easier for me to run my code inside that if condition of fork pid.
System.out.println("ThreadSubclass is running");
}
}
Current Output:
0
ThreadSubclass is running
1
2
TERM environment variable not set.
Expected OutPut:
0
ThreadSubclass is running
1
2
Top command output
Issues:
If I started "top" command first it didn't goes down to execute other commands.
As shown in this code, when I started Thread first, it shows "TERM environment variable not set."
if possible store it in a text file directly, rather than reading and storing it inside java code.
Process cmdProc = Runtime.getRuntime().exec("top -b > Top.csv");
error =>
top: unknown option '>'
Usage:
top -hv | -bcHiOSs -d secs -n max -u|U user -p pid(s) -o field -w [cols]

Related

Having trouble getting CPU usage in java using a batch file

I am trying to create a CPU usage meter by executing a batch file and returning the result. Here is the method that gets the CPU usage. When the batch file is ran it returns the results in a wierd format so I sort through it looking for the only number which is the CPU usage percentage. The problem I am running into is that I cant return the number after I convert it from a string and try to store it in a variable. Here is the code:
public int getCPUload (){
String s = "";
int r = 0;
try {
Process ps = Runtime.getRuntime().exec("Pc.bat");
BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream()));
while((s = br.readLine()) != null) {
if(s.matches(".*\\d+.*")){
r = Integer.parseInt(s);
}
}
}
catch( Exception ex ) {
System.out.println("ERR: "+ex.toString());
}
return r;
}
and here is the batch file "PC.bat":
wmic cpu get loadpercentage
Ultimately I would like to be able to loop this code to constantly update the value but im not sure how that can be done yet(on a seperate thread maybe?). Help and andvice would be appreciated
use for to parse the Output of a command:
for /f "tokens=2 delims==" %%i in ('wmic cpu get loadpercentage /value') do set /a cpu=%%i
echo %cpu%
set /a gets rid of the "strange" line ending of wmic (obviously works only for numbers - perfect for this case)

Slow System Commands From Java

I am calling a bash scrip script from Java.
The script does the following:
cat /home/user/Downloads/bigtextfile.txt | grep 'hello'
This particular command when run command line takes about 1 second to complete on the text file which is 150MB.
When calling the bash script via Java using the following call:
command = "sh /home/user/bashfiletocall"
p = Runtime.getRuntime().exec(command);
The time to complete takes so long I don't wait.
Am I doing something very wrong and if not can you explain the reason for the huge lack in performance?
NOTE: I was running it in Netbeans and this seems to be the problem .. when I ran the file command line it was quick. The performance between execution in netbeans and command line is huge.
Many thanks.
private String executeCommand(String command) {
StringBuilder output = new StringBuilder();
BufferedReader reader = null;
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
After starting your process you need start reading from the input stream. Otherwise the buffers are running full and p.waitFor() waits forever.
Javadoc of the Process class:
Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, or even deadlock.

Receiving values every second from Linux utilities in a Java program

I want to receive in Java the output from a Linux command line program. I need to read the values line by line, because the utilities are reporting their values once per second and the Java program should not need to wait until the end of execution. It should receive the values every second.
The following small program works fine in the case of the ping command, but not for the perf stat command.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class Main {
Process p;
BufferedReader reader;
public Main(int number) throws IOException {
if (number == 1) {
// does NOT work, blocks on readLine()
p = Runtime.getRuntime().exec("sudo perf stat -e cycles -I 1000 -p 9264"); // change PID to the one to be monitored
}
else if (number == 2) {
// WORKS!
p = Runtime.getRuntime().exec("ping www.google.com");
}
else {
System.out.println("Either 1 or 2...");
System.exit(0);
}
reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
}
public void process() throws IOException {
String res = "";
res = reader.readLine();
System.out.println(res);
}
public static void main (String[] args) throws IOException, InterruptedException {
Main myMain = new Main(Integer.parseInt(args[0]));
while (true) {
myMain.process();
Thread.sleep(1000);
}
}
}
So when running java Main 2 it works correctly, but when invoking java Main 1 it will block on the reader.readLine() call.
What's the difference between the two commands? Also with the command 'ls -l' it works correctly and I receive the values line by line.
EDIT:
The command itself works fine, when I run it directly from the command line. The -I option was introduced in newer kernel versions, it did not exist before (I am using kernel 3.11, Ubuntu).
When using 2>$1 to get also the stderr, it will indeed read a value every second, but it will always read null.
The problem seems to be that perf stat does not use stdout by default, but stderr. See the log-fd option.
So you can either redirect stderr to stdout in the command you use,
Or you capture the input Stream from stderr of the Process

How to run command line within java using thread async

I am new to java. I am tasked to write java program to run the command lines. I tested the command line under the DOS prompt since i do not have have access to Linux box yet. it worked fine. See the PROGRAM below for full command line syntax. the job will take 6 input files and generate some output files. Next i tried to create a class to and using getruntime and process to process this job. Even it compiled without error but when i run it just show the cursor blinking... i thought i need to use Thread async technique. please provide some advices since i do not have enough time for the projects. I also would like to implement a call back or return values when the job is done. an example would be greatly appreciated. Thanks
import java.io.*;
public class RunJob {
// public static final String PROGRAM = "c:\\wrk\\java.exe Hello";
//one command line below
public static final String PROGRAM = "c:/java.exe -cp \"wrk/jmp.jar;wrk/colt.jar\" gov.lanl.yadas.reliability.UltimateMissileReliabilityModel 10000 \"wrk/\" x1.dat x2c.dat x3.dat x4.dat x5.dat x6.dat true";
// Set to true to end the loop
static boolean done = false;
public static void main(String argv[]) throws IOException {
BufferedReader is;
String line;
String returnMsg = "Start ";
final Process p = Runtime.getRuntime().exec(PROGRAM);
System.out.println("start");
Thread waiter = new Thread() {
public void run() {
try {
p.waitFor();
} catch (InterruptedException ex) {
System.out.println("InterruptedException");
return;
}
System.out.println("Program terminated!");
done = true;
}
};
waiter.start();
is = new BufferedReader(new InputStreamReader(p.getInputStream()));
while (!done && ((line = is.readLine()) != null))
{
System.out.println(line);
returnMsg = returnMsg + line;
}
System.out.println(returnMsg);
System.out.println("End");
return;
}// main
}
I assume that there is a good reason why you want to run a java program from another java program and not just from a shell script, or by invoking an API - but if not - please reconsider.
As to your problem - if your application produces a lot of output (the one you are running as a process) - your application will hang. The p.waitFor() will halt until the process ends. But if you don't read the information from the InputStream - it will overflow and hang!
Advice #1: put the p.waitFor() at the end.
Advice #2: read this article. If I remember correctly it is the one I read when I had a similar problem. You can also google for "StreamGobbler" - it is a common name for a separate thread that "gobbles" your streams.
Advice #3: Don't forget the ErrorStream - if your application will produce too many errors - that stream will cause the process to hang as well.

Problem ProcessBuilder running script sh

trying to execute an script, using this piece of code:
String command = "./myScript.sh";
pb = new ProcessBuilder(command, param1, param2);
pb.directory(directory);
pb.start();
I am not getting any kind of error, but neither the supposed results. Anyway, I tryed to run the same command, direclty in the terminal, and everything working correctly.
Am I missing something??
Thanks in advance
When you start a process (pb.start()) you get back a Process instance. If your script reads input or writes output to stdout or stderr you need to handle this on separate threads using Process.getInputStream(), ...getOutputStream() and getErrorStream(). If you don't do this the process can hang. You also should call Process.waitFor() and then Process.exitValue() to get the return status of the process. If it's a negative number then the system was unable to launch your script.
EDIT: Here is a short simplified example. This is a toy only and will work reliably ONLY under the following conditions:
The script does not require any input
The script does not produce a large amount of output on both stdout and stderr. If it does, then since the program reads all of stdout before stderr, the stderr buffer may fill up and block the process from completing. In a 'real' implementation you would read stdout and stderr in separate threads (hint, wrap the loadStream() method in a class that implements Runnable).
public class PBTest
{
public static void main(String[] args) throws Exception
{
ProcessBuilder pb = new ProcessBuilder("sc","query","wuauserv");
Process p = pb.start();
String output = loadStream(p.getInputStream());
String error = loadStream(p.getErrorStream());
int rc = p.waitFor();
System.out.println("Process ended with rc=" + rc);
System.out.println("\nStandard Output:\n");
System.out.println(output);
System.out.println("\nStandard Error:\n");
System.out.println(error);
}
private static String loadStream(InputStream s) throws Exception
{
BufferedReader br = new BufferedReader(new InputStreamReader(s));
StringBuilder sb = new StringBuilder();
String line;
while((line=br.readLine()) != null)
sb.append(line).append("\n");
return sb.toString();
}
}
The problem was not on the way I called the script, which was right.
But it was inside the script. At first it was:
#!/bin/bash
inputFolder=$1
outputFolder=$2
cd $inputFolder
for file in `ls ` ; do
ffmpeg -i $inputFolder/$file -ar 22050 $outputFolder/$file.mp4
done
But I got ffmpeg command not found, so I changed it to:
#!/bin/bash
inputFolder=$1
outputFolder=$2
cd $inputFolder
for file in `ls ` ; do
/usr/local/bin/ffmpeg -i $inputFolder/$file -ar 22050 $outputFolder/$file.mp4
done
with the hole path. But I have still doubts, why this is necessary, if I have ffmpeg in my path and I cand execute in console direclty form any directory??
If someone can give me an answer, it will be welcome :)

Categories