001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *        http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 */
019
020package org.apache.isis.core.runtime.profiler;
021
022import java.text.NumberFormat;
023import java.util.HashMap;
024import java.util.Locale;
025import java.util.Map;
026
027public class Profiler {
028
029    private final static String DELIMITER = "\t";
030    private static NumberFormat FLOAT_FORMAT = NumberFormat.getNumberInstance(Locale.UK);
031    private static NumberFormat INTEGER_FORMAT = NumberFormat.getNumberInstance(Locale.UK);
032
033    private final static Map<Thread, String> threads = new HashMap<Thread, String>();
034
035    private static int nextId = 0;
036    private static int nextThread = 0;
037
038    protected static ProfilerSystem profilerSystem = new ProfilerSystem();
039
040    /**
041     * Primarily for testing.
042     * 
043     * @param profilerSystem
044     */
045    public static void setProfilerSystem(final ProfilerSystem profilerSystem) {
046        Profiler.profilerSystem = profilerSystem;
047    }
048
049    public static String memoryLog() {
050        final long free = memory();
051        return INTEGER_FORMAT.format(free) + " bytes";
052    }
053
054    private static long time() {
055        return profilerSystem.time();
056    }
057
058    private static long memory() {
059        return profilerSystem.memory();
060    }
061
062    // ////////////////////////////////////////////////////////////
063    // Profiler instance, constructor
064    // ////////////////////////////////////////////////////////////
065
066    private final String thread;
067
068    private final int id;
069    private final String name;
070
071    private long elapsedTime = 0;
072    private long memory;
073    private long start = 0;
074    private boolean timing = false;
075
076    public Profiler(final String name) {
077        this.name = name;
078        synchronized (Profiler.class) {
079            this.id = nextId++;
080        }
081        final Thread t = Thread.currentThread();
082        final String thread = threads.get(t);
083        if (thread != null) {
084            this.thread = thread;
085        } else {
086            this.thread = "t" + nextThread++;
087            threads.put(t, this.thread);
088        }
089        memory = memory();
090    }
091
092    public String getName() {
093        return name;
094    }
095
096    // ////////////////////////////////////////////////////////////
097    // start, stop, reset
098    // ////////////////////////////////////////////////////////////
099
100    public void reset() {
101        elapsedTime = 0;
102        start = time();
103        memory = memory();
104    }
105
106    public void start() {
107        start = time();
108        timing = true;
109    }
110
111    public void stop() {
112        timing = false;
113        final long end = time();
114        elapsedTime += end - start;
115    }
116
117    // ////////////////////////////////////////////////////////////
118    // MemoryUsage, ElapsedTime
119    // ////////////////////////////////////////////////////////////
120
121    public long getElapsedTime() {
122        return timing ? time() - start : elapsedTime;
123    }
124
125    public long getMemoryUsage() {
126        return memory() - memory;
127    }
128
129    // ////////////////////////////////////////////////////////////
130    // logging
131    // ////////////////////////////////////////////////////////////
132
133    public String memoryUsageLog() {
134        return INTEGER_FORMAT.format(getMemoryUsage()) + " bytes";
135    }
136
137    public String timeLog() {
138        return FLOAT_FORMAT.format(getElapsedTime() / 1000.0) + " secs";
139    }
140
141    public String log() {
142        return id + DELIMITER + thread + DELIMITER + getName() + DELIMITER + getMemoryUsage() + DELIMITER + getElapsedTime();
143    }
144
145    @Override
146    public String toString() {
147        return getElapsedTime() + "ms - " + name;
148    }
149
150}