at.tuwien.minimee.util.TopParser.java Source code

Java tutorial

Introduction

Here is the source code for at.tuwien.minimee.util.TopParser.java

Source

/*******************************************************************************
 * Copyright (c) 2006-2010 Vienna University of Technology, 
 * Department of Software Technology and Interactive Systems
 *
 * All rights reserved. This program and the accompanying
 * materials are made available under the terms of the
 * Apache License, Version 2.0 which accompanies
 * this distribution, and is available at
 * http://www.apache.org/licenses/LICENSE-2.0 
 *******************************************************************************/
package at.tuwien.minimee.util;

import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * This class can parse a file written by the Linux program 'top' and fit 
 * the information into the data structure {@link ExecutionFootprintList}.
 * 
 * 'top' writes a log file with entries as can be seen below every x seconds.
 * 
 * top - 15:45:06 up 2 days, 23:43,  2 users,  load average: 0.19, 0.31, 0.26
 * Tasks:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
 * Cpu(s):  0.8%us,  0.2%sy,  0.0%ni, 98.8%id,  0.1%wa,  0.0%hi,  0.0%si,  0.0%st
 * Mem:   2036960k total,  1853784k used,   183176k free,    74072k buffers
 * Swap:  4192956k total,     5396k used,  4187560k free,   813216k cached
 *
 * PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND            
 * 3758 kulovits  20   0 32400  20m 3452 R   93  1.0   0:00.46 gs                 
 * 
 * @author kulovits
 */
public class TopParser {
    private Log log = LogFactory.getLog(this.getClass());

    private String file;

    private ExecutionFootprint currentExecutionFootprint = null;

    private ExecutionFootprintList list = new ExecutionFootprintList();

    private Integer monitoredPid = null;

    private RandomAccessFile input = null;

    public TopParser(String file) {

        this.file = file;
    }

    public static void main(String[] args) {

        TopParser p = new TopParser("/tmp/profile_1234906043659516000/top.log");
        p.parse();

        System.out.println(p.getList().toString());

    }

    public void parse() {

        try {

            input = new RandomAccessFile(file, "r");

            try {

                monitoredPid = findPid();

                // couldn't determine PID
                if (monitoredPid == null) {
                    return;
                }

                String line = null;
                while ((line = input.readLine()) != null) {
                    parseLine(line);
                }

            } finally {
                input.close();
            }

            // list.debugToConsole();

        } catch (Exception e) {
            log.error(e);
        }
    }

    /**
     * The process ID is in the last line of the file and looks like follows:
     * monitored_pid= 6738 
     * 
     * @param input
     * @return
     * @throws Exception
     */
    private Integer findPid() throws Exception {

        Integer pid = new Integer(0);

        // we open the file
        RandomAccessFile f = new RandomAccessFile(file, "r");

        try {

            long size = f.length();

            f.seek(size - 2);

            // we search the file reverse for '='
            byte[] b = new byte[1];
            for (long i = size - 2; i >= 0; i--) {
                f.seek(i);
                f.read(b);
                if (b[0] == '=') {
                    break;
                }
            }

            String line = f.readLine().trim();

            pid = new Integer(line);

        } finally {
            // this is important, RandomAccessFile doesn't close the file handle by default!
            // if close isn't called, you'll get very soon 'too many open files'
            f.close();
        }

        return pid;
    }

    private void parseLine(String line) {

        StringTokenizer tokenizer = new StringTokenizer(line, " :");

        if (!tokenizer.hasMoreTokens()) {
            return;
        }

        String start = tokenizer.nextToken();

        if (start.compareTo("top") == 0) {

            if (currentExecutionFootprint != null) {
                cleanUp(currentExecutionFootprint);
                list.add(currentExecutionFootprint);
            }
            currentExecutionFootprint = new ExecutionFootprint();

            parseTopLine(tokenizer);

        } else if (start.compareTo("Tasks") == 0) {

            parseTasksLine(tokenizer);
        } else if (start.compareTo("Cpu(s)") == 0) {

            parseCpusLine(line);
        } else if (start.compareTo("Mem") == 0) {

            parseMemLine(tokenizer);
        } else if (start.compareTo("Swap") == 0) {

            parseSwapLine(tokenizer);
        } else if (start.compareTo("PID") == 0) { // Header line

            parseHeaderLine(tokenizer); // we read the header line

            // ExecutionFootprintList fp = tempReadPerformanceData();
        } else if (start.startsWith("monitored_pid=")) {
            // do nothing
        } else {
            try {
                Integer pid = new Integer(start.trim());

                // if (pid.equals(monitoredPid)) {
                // currentExecutionFootprint.setPid(pid);
                ProcessExecutionFootprint pfp = parseProcessLine(tokenizer);

                pfp.setPid(pid);

                currentExecutionFootprint.getProcesses().add(pfp);
                // }

            } catch (NumberFormatException e) {
                log.error(e);
            }
        }
    }

    private void cleanUp(ExecutionFootprint fp) {

        List<ProcessExecutionFootprint> processes = new ArrayList<ProcessExecutionFootprint>();

        ProcessExecutionFootprint root = null;

        for (ProcessExecutionFootprint pfp : fp.getProcesses()) {
            if (pfp.getPid() == monitoredPid.intValue()) {
                root = pfp;
                break;
            }
        }

        // we didn't find any process with PID 'monitoredPid'
        if (root == null) {
            // we remove all processes from list
            fp.getProcesses().clear();
            return;
        }

        processes.add(root);

        ProcessExecutionFootprint pfp = root;

        while (pfp.getPpid() != 1) {

            ProcessExecutionFootprint prev = pfp;
            for (ProcessExecutionFootprint iter : fp.getProcesses()) {
                if (iter.getPpid() == pfp.getPid()) {
                    pfp = iter;
                    break;
                }
            }

            // we didn't find a child
            if (prev == pfp) {
                break;
            }

            if (pfp.getPid() != 1) {
                processes.add(pfp);
            }
        }

        fp.setProcesses(processes);
    }

    private void parseTopLine(StringTokenizer tokenizer) {

    }

    private void parseTasksLine(StringTokenizer tokenizer) {

    }

    private void parseCpusLine(String line) {

        int index;

        index = line.indexOf("%us");
        if (index != -1) {
            int lastIndex = line.lastIndexOf(' ', index);
            // this is the case when 'Cpu(s):100.0%us,'
            if (lastIndex == -1) {
                lastIndex = line.lastIndexOf(':', index) + 1;
            }
            String s = line.substring(lastIndex, index);
            currentExecutionFootprint.getSystemFootprint().setTotalCpusUser(new Double(s));
        }

        index = line.indexOf("%sy");
        if (index != -1) {
            String s = line.substring(line.lastIndexOf(',', index) + 1, index);
            currentExecutionFootprint.getSystemFootprint().setTotalCpusSystem(new Double(s));
        }

        index = line.indexOf("%id");
        if (index != -1) {
            String s = line.substring(line.lastIndexOf(',', index) + 1, index);
            currentExecutionFootprint.getSystemFootprint().setTotalCpusIdle(new Double(s));
        }

    }

    private void parseMemLine(StringTokenizer tokenizer) {

        int column = 1;
        Double d = null;

        for (column = 1; tokenizer.hasMoreTokens() && column < 4; column++) {

            String strColumn = tokenizer.nextToken().trim();

            switch (column) {
            case 1: // total mem available (e.g. 2036960k)

                d = parseSizeColumn(strColumn);
                currentExecutionFootprint.getSystemFootprint().setTotalMemoryAvailable(d);

                break;

            case 2: // this is just the text: 'total,'
                break;

            case 3:
                d = parseSizeColumn(strColumn);
                currentExecutionFootprint.getSystemFootprint().setTotalMemoryAvailable(d);

                break;
            }

        }
    }

    private void parseSwapLine(StringTokenizer tokenizer) {

    }

    /**
     * Doesn't do anything right now, maybe do some validation
     * @param tokenizer
     */
    private void parseHeaderLine(StringTokenizer tokenizer) {

    }

    private ProcessExecutionFootprint parseProcessLine(StringTokenizer tokenizer) {

        ProcessExecutionFootprint pfp = new ProcessExecutionFootprint();

        int column = 1;
        for (column = 1; tokenizer.hasMoreTokens(); column++) {

            String strColumn = tokenizer.nextToken(" ");

            switch (column) {

            case 1: // USER
                break;

            case 2: // PR
                break;

            case 3: // NI
                break;

            case 4: // VIRT

                Double virt = parseSizeColumn(strColumn);
                pfp.setVirtualMemory(virt);

                break;

            case 5: // RES

                Double res = parseSizeColumn(strColumn);
                pfp.setResidentSize(res);

                break;

            case 6: // SHR

                Double shr = parseSizeColumn(strColumn);
                pfp.setSharedMemory(shr);

                break;

            case 7: // S
                break;

            case 8: // %CPU

                Double pCPU = new Double(strColumn);
                pfp.setCpu(pCPU);

                break;

            case 9: // %MEM

                Double pMem = new Double(strColumn);
                pfp.setPMem(pMem);

                break;

            case 10: // TIME+

                // mm:ss.hh

                String[] tokens = strColumn.split("[:|.]");

                if (tokens.length == 3) {
                    long cpuTimeUsed = (new Long(tokens[0])) * 60 * 1000;
                    cpuTimeUsed += (new Long(tokens[1])) * 1000;
                    cpuTimeUsed += (new Long(tokens[2])) * 10;
                    pfp.setCpuTimeUsed(cpuTimeUsed);
                }

                break;

            case 11: // PPID

                pfp.setPpid(new Integer(strColumn));

                break;

            case 12:

                pfp.setCommand(strColumn);
                break;

            default:
                continue;
            }
        }

        return pfp;
    }

    private Double parseSizeColumn(String strColumn) {
        strColumn = strColumn.trim();

        Double virt = null;

        if (strColumn.charAt(strColumn.length() - 1) == 'g') { // we have giga byte
            virt = new Double(strColumn.substring(0, strColumn.length() - 1));
            virt *= (1024 * 1024);
        } else if (strColumn.charAt(strColumn.length() - 1) == 'm') { // we have mega byte
            virt = new Double(strColumn.substring(0, strColumn.length() - 1));
            virt *= 1024;
        } else if (strColumn.charAt(strColumn.length() - 1) == 'k') { // we have kilo bytes
            virt = new Double(strColumn.substring(0, strColumn.length() - 1));
        } else {
            virt = new Double(strColumn);
        }
        return virt;
    }

    public ExecutionFootprintList getList() {
        return list;
    }
}