All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ml.shifu.guagua.util.JMap Maven / Gradle / Ivy

The newest version!
/*
 * Copyright [2013-2014] PayPal Software Foundation
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ml.shifu.guagua.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.lang.management.ManagementFactory;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import ml.shifu.guagua.util.FileUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Helper to run jmap and print the output. Copy from Apache Giraph.
 */
public class JMap {

    private static final Logger LOG = LoggerFactory.getLogger(JMap.class);

    /** The command to run */
    public static final String CMD = "jmap";
    /** Arguments to pass in to command */
    public static final String ARGS = "-histo";

    private static int staticProcessId = -1;

    private static final String USER_DIR = "user.dir";

    /** Do not construct */
    protected JMap() {
    }

    /**
     * Get the process ID of the current running process
     * 
     * @return Integer process ID
     */
    public synchronized static int getProcessId() {
        if(staticProcessId == -1) {
            String processId = ManagementFactory.getRuntimeMXBean().getName();
            if(processId.contains("@")) {
                processId = processId.substring(0, processId.indexOf("@"));
            }
            staticProcessId = Integer.parseInt(processId);
        }
        return staticProcessId;
    }

    /**
     * Run jmap, print numLines of output from it to stderr.
     * 
     * @param numLines
     *            Number of lines to print
     */
    public static void heapHistogramDump(int numLines) {
        heapHistogramDump(numLines, System.err);
    }

    /**
     * Run jmap, print numLines of output from it to stream passed in.
     * 
     * @param numLines
     *            Number of lines to print
     * @param printStream
     *            Stream to print to
     */
    public static void heapHistogramDump(int numLines, PrintStream printStream) {
        BufferedReader in = null;
        try {
            String JAVA_HOME = System.getProperty("java.home");
            if(JAVA_HOME == null) {
                throw new IllegalArgumentException("java.home is not set!");
            }

            List commandList = new ArrayList();
            commandList.add(JAVA_HOME + File.separator + ".." + File.separator + "bin" + File.separator + CMD);
            commandList.add(ARGS);
            commandList.add(getProcessId() + "");

            String workingDir = System.getProperty(USER_DIR, ".");

            ProcessBuilder pb = new ProcessBuilder();

            File execDir = new File(workingDir);
            pb.command(commandList);
            pb.directory(execDir);
            pb.redirectErrorStream(true);

            Process jmapProcess = null;
            StreamCollector jmapStreamCollector;
            synchronized(StreamCollector.class) {
                jmapProcess = pb.start();
                jmapStreamCollector = new StreamCollector(jmapProcess.getInputStream(), numLines);
                jmapStreamCollector.start();
            }

            Runtime.getRuntime()
                    .addShutdownHook(new Thread(new JMapShutdownHook(jmapProcess, jmapStreamCollector, workingDir)));
        } catch (IOException e) {
            LOG.error("IOException in dump heap", e);
        } finally {
            if(in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    LOG.error("Error in closing input stream", e);
                }
            }
        }
    }

    private static class JMapShutdownHook implements Runnable {

        private Process process;

        private StreamCollector collector;

        private String exeDir;

        public JMapShutdownHook(Process process, StreamCollector collector, String exeDir) {
            this.process = process;
            this.collector = collector;
            this.exeDir = exeDir;
        }

        @Override
        public void run() {
            try {
                LOG.info("start run shutdown hook");
                synchronized(this) {
                    if(process != null) {
                        LOG.warn("foeced a shutdown hook to kill process");
                        process.destroy();
                        int returnCode = -1;
                        try {
                            returnCode = process.waitFor();
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                        LOG.info("Current process exited with {} (note that 143 typically means killed).", returnCode);
                    }
                }
            } finally {
                if(this.collector != null) {
                    this.collector.close();
                }
            }
            FileUtils.deleteQuietly(new File(exeDir));
        }

    }

    private static class StreamCollector extends Thread {
        /** Number of last lines to keep */
        private static final int LAST_LINES_COUNT = 100;
        /** Class logger */
        private static final Logger LOG = LoggerFactory.getLogger(StreamCollector.class);
        /** Buffered reader of input stream */
        private final BufferedReader bufferedReader;
        /** Last lines (help to debug failures) */
        private final LinkedList lastLines = new LinkedList();
        private final int maxLines;

        /**
         * Constructor.
         * 
         * @param is
         *            InputStream to dump to LOG.info
         */
        public StreamCollector(final InputStream is, int maxLines) {
            super(StreamCollector.class.getName());
            this.maxLines = maxLines;
            setDaemon(true);
            InputStreamReader streamReader = new InputStreamReader(is, Charset.defaultCharset());
            bufferedReader = new BufferedReader(streamReader);
        }

        @Override
        public void run() {
            readLines();
        }

        /**
         * Read all the lines from the bufferedReader.
         */
        private synchronized void readLines() {
            String line;
            try {
                int lineIndex = 0;
                while((line = bufferedReader.readLine()) != null && lineIndex < this.maxLines) {
                    if(lastLines.size() > LAST_LINES_COUNT) {
                        lastLines.removeFirst();
                    }
                    lastLines.add(line);
                    lineIndex += 1;
                    LOG.info("readLines: {}.", line);
                }
            } catch (IOException e) {
                LOG.error("readLines: Ignoring IOException", e);
            }
        }

        /**
         * Dump the last n lines of the collector. Likely used in the case of failure.
         * 
         * @param level
         *            Log level to dump with
         */
        @SuppressWarnings("unused")
        public synchronized void dumpLastLines() {
            // Get any remaining lines
            readLines();
            // Dump the lines to the screen
            for(String line: lastLines) {
                LOG.info(line);
            }
        }

        public void close() {
            try {
                this.bufferedReader.close();
            } catch (IOException ignore) {
            }
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy