001package net.sf.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. <s>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.</s> Using {@link ThreadMXBean}
012 * to get the current thread CPU time, if supported. Using {@link System#nanoTime()} 
013 * otherwise.
014 * 
015 * @version IFS 1.2 (Iterative Forward Search)<br>
016 *          Copyright (C) 2006 - 2010 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    public static double currentTimeSec() {
066        init();
067        try {
068            switch (sMode) {
069                case cpu :
070                    return ManagementFactory.getThreadMXBean().getCurrentThreadCpuTime() / 1e9;
071                case user :
072                    return ManagementFactory.getThreadMXBean().getCurrentThreadUserTime() / 1e9;
073                case wall :
074                default:
075                    return System.nanoTime() / 1e9;
076            }
077        } catch (UnsupportedOperationException e) {
078            Logger.getLogger(JProf.class).error("Unable to measure " + sMode.name() + " time, falling back to wall time: " + e.getMessage());
079            sMode = Mode.wall;
080            return System.nanoTime() / 1e9;
081        }
082    }
083    
084    /** Current CPU time of this thread in milliseconds */
085    public static long currentTimeMillis() {
086        init();
087        try {
088            switch (sMode) {
089                case cpu :
090                    return ManagementFactory.getThreadMXBean().getCurrentThreadCpuTime() / 1000000;
091                case user :
092                    return ManagementFactory.getThreadMXBean().getCurrentThreadUserTime() / 1000000;
093                case wall :
094                default:
095                    return System.currentTimeMillis();
096            }
097        } catch (UnsupportedOperationException e) {
098            Logger.getLogger(JProf.class).error("Unable to measure " + sMode.name() + " time, falling back to wall time: " + e.getMessage());
099            sMode = Mode.wall;
100            return System.currentTimeMillis();
101        }
102    }
103}