CPU Usage Chart Part 2

July 21st, 2015

In the previous blog post I went over how the front end displays a chart mapping the % CPU usage of the server running this website. Now I’ll continue by explaining the hidden side of things on the back end. The purpose of the back end is to generate this text file containing the time and % CPU. There are 4 main pieces that make this work starting with the Linux command mpstat.

You can type in mpstat into your linux command line and hit enter and the image below will be your result. This actually breaks down into what type of processes are keeping your processor busy. Without any arguments on your mpstat command it outputs the average since your computer last restarted.

The next image is the result of issuing the command mpstat 2 5. This means the server takes the average CPU usage over each 2 second period and prints it. Then it averages all the periods and prints that last. More information on the mpstat command can be found here.

Since we have the ability to tell the current CPU usage we need to now store it repeatedly. The java program calls the command mpstat 5 1 and then adds its result the current text file. Read through the program’s comments if you’d like more details on how this is accomplished.

                import java.io.*;
                import java.util.Date;

                public class cpuTracker {
                    public static void main(String[] args) throws IOException, InterruptedException
                        // Create process to execute mpstat 5 1 and then wait for it to execute and collect
                        // the result in BufferReader reader. 
                        Process p = Runtime.getRuntime().exec("mpstat 5 1");
                        BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));

                        // The while loop reads through each line created by the command mpstat 5 1
                        // for which the second to last line is the one that we are interested in.
                        String line = "";
                        String previousLine = "";
                        while ((line = reader.readLine())!= null) {
                            previousLine = line;

                        // Split the line containing our data by any whitespace. The 12th string is
                        // the %idle that we are looking for. We then convert it to a decimal and then
                        // manipulate it so that it has just 2 decimal points.

                        String[] fromTerminal = previousLine.split("\\s+");
                        double percentCPU = Double.parseDouble(fromTerminal[11]);
                        percentCPU = 100 - percentCPU;
                        percentCPU = Math.round(percentCPU * 100);
                        percentCPU = percentCPU/100;

                        // We now read the current text file stored on the Apache web server portion of
                        // the linux server. We ignore the first line containing only a [ and then ignore 
                        // the second line containing the oldest CPU data.
                        // We store all 119 needed lines in String array keepData

                        String fileName = "/var/www/html/farristate.com/Site/WebsiteChart/myTutorials.txt";
                        String inLine = "";
                        FileReader fileReader = new FileReader(fileName);
                        BufferedReader txtReader = new BufferedReader(fileReader);

                        //ignore first tow lines of file
                        inLine = txtReader.readLine();
                        inLine = txtReader.readLine();
                        //array storing 119 lines
                        String[] keepData = new String[119];
                        int count = 0;

                        while(((inLine = txtReader.readLine()) != null) && (count < 119)) {
                            keepData[count] = inLine;

                        // The original text file is now overwritten with our new version. The [ bracket is added
                        // to the first line and then each of the stored lines is written to the text file.

                        File outFile = new File("/var/www/html/farristate.com/Site/WebsiteChart/myTutorials.txt");
                        FileWriter writer = new FileWriter(outFile);
                        writer.write("[ ");
                        count = 0;
                        while((count != 119) && (keepData[count] != null)) {
                            writer.write(" \n");
                        writer.write(", \n");
                        // Finally we add the new data to the text file. A Date object is created and then
                        // we get milliseconds since January 1st, 1970. The last line added is the closing bracket
                        // of the text file.

                        Date now = new Date();
                        Long longTime = new Long(now.getTime());
                        writer.write("    {\"time\":" + longTime + ", \"percent\":" + percentCPU + "} \n");

There’s one last hurdle that has to be crossed for the CPU usage text file to be continuously updated. We needed to add our Java program to the Linux cron scheduler but the built in scheduler will only run a command every minute. We want our CPU usage updated every 5 seconds but cron is not built for such frequent calls. Instead of changing the Java program to loop 12 times in a minute, which could lead to uneven updates to the CPU text file, I let cron run a short bash script every minute. This script guarantees that the java program will run every 5 seconds in the background. The & symbol at the end of the called command means that the command will be run in the background and not take time before the script sleeps for 5 seconds.

                while [ $i –lt 12 ]; do
                    java -cp /path/to/java/src/cpuTracker cpuTracker &
                    sleep 5
                    i=$(( I + 1 ))

Thank you for following along and check back soon for more updates. I've reached a stopping point on this project for now but there are many spots that could be improved.