001package org.cpsolver.ifs.util;
002
003import java.lang.management.ManagementFactory;
004import java.lang.management.ThreadMXBean;
005
006import org.apache.log4j.Logger;
007
008/**
009 * CPU time measurement. <b>JAVA profiling extension is used. Java needs to be
010 * executed with -Xrunjprof. When the java is executed outside this profiler,
011 * {@link System#currentTimeMillis()} is used.</b> Using {@link ThreadMXBean}
012 * to get the current thread CPU time, if supported. Using {@link System#nanoTime()} 
013 * otherwise.
014 * 
015 * @version IFS 1.3 (Iterative Forward Search)<br>
016 *          Copyright (C) 2006 - 2014 Tomáš Müller<br>
017 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
018 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
019 * <br>
020 *          This library is free software; you can redistribute it and/or modify
021 *          it under the terms of the GNU Lesser General Public License as
022 *          published by the Free Software Foundation; either version 3 of the
023 *          License, or (at your option) any later version. <br>
024 * <br>
025 *          This library is distributed in the hope that it will be useful, but
026 *          WITHOUT ANY WARRANTY; without even the implied warranty of
027 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
028 *          Lesser General Public License for more details. <br>
029 * <br>
030 *          You should have received a copy of the GNU Lesser General Public
031 *          License along with this library; if not see
032 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
033 */
034public class JProf {
035    private static Mode sMode = Mode.wall;
036    private static enum Mode {
037        cpu, wall, user
038    }
039    private static boolean sInitialized = false;
040    
041    /** Enable / disable the thread CPU timing, if needed */
042    private synchronized static void init() {
043        if (sInitialized) return;
044        sMode = Mode.valueOf(System.getProperty("jprof", sMode.name()));
045        if (sMode != Mode.wall) {
046            try {
047                ThreadMXBean bean = ManagementFactory.getThreadMXBean();
048                if (!bean.isCurrentThreadCpuTimeSupported()) {
049                    Logger.getLogger(JProf.class).warn("Measuring " + sMode.name() + " time is not supported, falling back to wall time.");
050                    sMode = Mode.wall;
051                }
052                if (!bean.isThreadCpuTimeEnabled())
053                    bean.setThreadCpuTimeEnabled(true);
054            } catch (UnsupportedOperationException e) {
055                Logger.getLogger(JProf.class).error("Unable to measure " + sMode.name() + " time, falling back to wall time: " + e.getMessage());
056                sMode = Mode.wall;
057                sMode = Mode.wall;
058            }
059        }
060        Logger.getLogger(JProf.class).info("Using " + sMode.name() + " time.");
061        sInitialized = true;
062    }
063    
064    /** Current CPU time of this thread in seconds
065     * @return CPU time in seconds
066     **/
067    public static double currentTimeSec() {
068        init();
069        try {
070            switch (sMode) {
071                case cpu :
072                    return ManagementFactory.getThreadMXBean().getCurrentThreadCpuTime() / 1e9;
073                case user :
074                    return ManagementFactory.getThreadMXBean().getCurrentThreadUserTime() / 1e9;
075                case wall :
076                default:
077                    return System.nanoTime() / 1e9;
078            }
079        } catch (UnsupportedOperationException e) {
080            Logger.getLogger(JProf.class).error("Unable to measure " + sMode.name() + " time, falling back to wall time: " + e.getMessage());
081            sMode = Mode.wall;
082            return System.nanoTime() / 1e9;
083        }
084    }
085    
086    /** Current CPU time of this thread in milliseconds 
087     * @return CPU time in milliseconds
088     **/
089    public static long currentTimeMillis() {
090        init();
091        try {
092            switch (sMode) {
093                case cpu :
094                    return ManagementFactory.getThreadMXBean().getCurrentThreadCpuTime() / 1000000;
095                case user :
096                    return ManagementFactory.getThreadMXBean().getCurrentThreadUserTime() / 1000000;
097                case wall :
098                default:
099                    return System.currentTimeMillis();
100            }
101        } catch (UnsupportedOperationException e) {
102            Logger.getLogger(JProf.class).error("Unable to measure " + sMode.name() + " time, falling back to wall time: " + e.getMessage());
103            sMode = Mode.wall;
104            return System.currentTimeMillis();
105        }
106    }
107}