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