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

com.orientechnologies.common.profiler.OProfiler Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 1999-2005 Luca Garulli (l.garulli--at-orientechnologies.com)
 *
 * 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 com.orientechnologies.common.profiler;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.TimerTask;
import java.util.WeakHashMap;

/**
 * Profiling utility class. Handles chronos (times), statistics and counters. By default it's used as Singleton but you can create
 * any instances you want for separate profiling contexts.
 * 
 * To start the recording use call startRecording(). By default record is turned off to avoid a run-time execution cost.
 * 
 * @author Luca Garulli
 * @copyrights Orient Technologies.com
 */
public class OProfiler implements OProfilerMBean {
  private long                            recording = -1;
  private Map               counters;
  private Map     chronos;
  private Map     stats;
  private Map hooks;                      // REVERSE MAP TO USE THE WEAK HASH MAP
  private Date                            lastReset;

  private volatile Timer                  timer;
  private volatile boolean                autoDumpReset;

  protected static final OProfiler        instance  = new OProfiler();

  public interface OProfilerHookValue {
    public Object getValue();
  }

  public class OProfilerEntry {
    public String name    = null;
    public long   items   = 0;
    public long   last    = 0;
    public long   min     = 999999999;
    public long   max     = 0;
    public long   average = 0;
    public long   total   = 0;

    @Override
    public String toString() {
      return "Chrono [average=" + average + ", items=" + items + ", last=" + last + ", max=" + max + ", min=" + min + ", name="
          + name + ", total=" + total + "]";
    }
  }

  public OProfiler() {
    init();
  }

  public OProfiler(String iRecording) {
    if (iRecording.equalsIgnoreCase("true"))
      startRecording();

    init();
  }

  // ----------------------------------------------------------------------------
  /*
   * (non-Javadoc)
   */
  public void updateCounter(final String iStatName, final long iPlus) {
    if (iStatName == null)
      return;

    // CHECK IF STATISTICS ARE ACTIVED
    if (recording < 0)
      return;

    synchronized (counters) {
      Long stat = counters.get(iStatName);

      long oldValue = stat == null ? 0 : stat.longValue();

      stat = new Long(oldValue + iPlus);

      counters.put(iStatName, stat);
    }
  }

  // ----------------------------------------------------------------------------
  /*
   * (non-Javadoc)
   * 
   * @see com.orientechnologies.common.profiler.ProfileMBean#getStatistic(java.lang.String)
   */
  public long getCounter(final String iStatName) {
    if (iStatName == null)
      return -1;

    // CHECK IF STATISTICS ARE ACTIVED
    if (recording < 0)
      return -1;

    synchronized (counters) {
      Long stat = counters.get(iStatName);

      if (stat == null)
        return -1;

      return stat.longValue();
    }
  }

  /*
   * (non-Javadoc)
   * 
   * @see com.orientechnologies.common.profiler.ProfileMBean#dump()
   */
  public String dump() {
    final float maxMem = Runtime.getRuntime().maxMemory() / 1000000f;
    final float totMem = Runtime.getRuntime().totalMemory() / 1000000f;
    final float freeMem = maxMem - totMem;

    final long now = System.currentTimeMillis();

    final StringBuilder buffer = new StringBuilder();
    buffer.append("\nOrientDB profiler dump of ");
    buffer.append(new Date(now));
    buffer.append(" after ");
    buffer.append((now - recording) / 1000);
    buffer.append(" secs of profiling");
    buffer.append(String.format("\nFree memory: %2.2fMb (%2.2f%%) - Total memory: %2.2fMb - Max memory: %2.2fMb - CPUs: %d",
        freeMem, (freeMem * 100 / (float) maxMem), totMem, maxMem, Runtime.getRuntime().availableProcessors()));
    buffer.append("\n");
    buffer.append(dumpHookValues());
    buffer.append("\n");
    buffer.append(dumpCounters());
    buffer.append("\n\n");
    buffer.append(dumpStats());
    buffer.append("\n\n");
    buffer.append(dumpChronos());
    return buffer.toString();
  }

  /*
   * (non-Javadoc)
   * 
   * @see com.orientechnologies.common.profiler.ProfileMBean#reset()
   */
  public void reset() {
    lastReset = new Date();

    if (counters != null) {
      synchronized (counters) {
        counters.clear();
      }
    }

    if (chronos != null) {
      synchronized (chronos) {
        chronos.clear();
      }
    }

    if (stats != null) {
      synchronized (stats) {
        stats.clear();
      }
    }
  }

  public long startChrono() {
    // CHECK IF CHRONOS ARE ACTIVED
    if (recording < 0)
      return -1;

    return System.currentTimeMillis();
  }

  public long stopChrono(final String iName, final long iStartTime) {
    return updateEntry(chronos, iName, System.currentTimeMillis() - iStartTime);
  }

  public long updateStat(final String iName, final long iValue) {
    return updateEntry(stats, iName, iValue);
  }

  /*
   * (non-Javadoc)
   * 
   * @see com.orientechnologies.common.profiler.ProfileMBean#dumpStatistics()
   */
  public String dumpCounters() {
    // CHECK IF STATISTICS ARE ACTIVED
    if (recording < 0)
      return "Counters: ";

    final StringBuilder buffer = new StringBuilder();

    synchronized (counters) {
      buffer.append("DUMPING COUNTERS (last reset on: " + lastReset.toString() + ")...");

      buffer.append(String.format("\n%50s +-------------------------------------------------------------------+", ""));
      buffer.append(String.format("\n%50s | Value                                                             |", "Name"));
      buffer.append(String.format("\n%50s +-------------------------------------------------------------------+", ""));

      final List keys = new ArrayList(counters.keySet());
      Collections.sort(keys);

      for (String k : keys) {
        final Long stat = counters.get(k);
        buffer.append(String.format("\n%-50s | %-65d |", k, stat));
      }
    }

    buffer.append(String.format("\n%50s +-------------------------------------------------------------------+", ""));
    return buffer.toString();
  }

  public String dumpChronos() {
    return dumpEntries(chronos, new StringBuilder("DUMPING CHRONOS (last reset on: " + lastReset.toString() + "). Times in ms..."));
  }

  public String dumpStats() {
    return dumpEntries(stats, new StringBuilder("DUMPING STATISTICS (last reset on: " + lastReset.toString() + "). Times in ms..."));
  }

  public String dumpHookValues() {
    if (recording < 0)
      return "HookValues: ";

    final StringBuilder buffer = new StringBuilder();

    synchronized (hooks) {
      if (hooks.size() == 0)
        return "";

      buffer.append("HOOK VALUES:");

      buffer.append(String.format("\n%50s +-------------------------------------------------------------------+", ""));
      buffer.append(String.format("\n%50s | Value                                                             |", "Name"));
      buffer.append(String.format("\n%50s +-------------------------------------------------------------------+", ""));

      final List names = new ArrayList(hooks.values());
      Collections.sort(names);

      for (String k : names) {
        for (Map.Entry v : hooks.entrySet()) {
          if (v.getValue().equals(k)) {
            final OProfilerHookValue hook = v.getKey();
            if (hook != null) {
              final Object hookValue = hook.getValue();
              buffer.append(String.format("\n%-50s | %-65s |", k, hookValue != null ? hookValue.toString() : "null"));
            }
            break;
          }
        }
      }
    }

    buffer.append(String.format("\n%50s +-------------------------------------------------------------------+", ""));
    return buffer.toString();
  }

  public Object getHookValue(final String iName) {
    for (Map.Entry v : hooks.entrySet()) {
      if (v.getValue().equals(iName)) {
        final OProfilerHookValue h = v.getKey();
        if (h != null)
          return h.getValue();
      }
    }
    return null;
  }

  /*
   * (non-Javadoc)
   * 
   * @see com.orientechnologies.common.profiler.ProfileMBean#getStatistics()
   */
  public String[] getCountersAsString() {
    synchronized (counters) {
      final String[] output = new String[counters.size()];
      int i = 0;
      for (Entry entry : counters.entrySet()) {
        output[i++] = entry.getKey() + ": " + entry.getValue().toString();
      }
      return output;
    }
  }

  public String[] getChronosAsString() {
    synchronized (chronos) {
      final String[] output = new String[chronos.size()];
      int i = 0;
      for (Entry entry : chronos.entrySet()) {
        output[i++] = entry.getKey() + ": " + entry.getValue().toString();
      }
      return output;
    }
  }

  public String[] getStatsAsString() {
    synchronized (stats) {
      final String[] output = new String[stats.size()];
      int i = 0;
      for (Entry entry : stats.entrySet()) {
        output[i++] = entry.getKey() + ": " + entry.getValue().toString();
      }
      return output;
    }
  }

  public Date getLastReset() {
    return lastReset;
  }

  public List getCounters() {
    synchronized (counters) {
      final List list = new ArrayList(counters.keySet());
      Collections.sort(list);
      return list;
    }
  }

  public List getHooks() {
    synchronized (hooks) {
      final List list = new ArrayList(hooks.values());
      Collections.sort(list);
      return list;
    }
  }

  public List getChronos() {
    synchronized (chronos) {
      final List list = new ArrayList(chronos.keySet());
      Collections.sort(list);
      return list;
    }
  }

  public List getStats() {
    synchronized (stats) {
      final List list = new ArrayList(stats.keySet());
      Collections.sort(list);
      return list;
    }
  }

  public OProfilerEntry getStat(final String iStatName) {
    synchronized (stats) {
      return stats.get(iStatName);
    }
  }

  public OProfilerEntry getChrono(final String iChronoName) {
    synchronized (chronos) {
      return chronos.get(iChronoName);
    }
  }

  public boolean isRecording() {
    return recording > -1;
  }

  public OProfilerMBean startRecording() {
    recording = System.currentTimeMillis();
    return this;
  }

  public OProfilerMBean stopRecording() {
    recording = -1;
    return this;
  }

  public static OProfiler getInstance() {
    return instance;
  }

  public void registerHookValue(final String iName, final OProfilerHookValue iHookValue) {
    if (recording < 0)
      return;

    synchronized (hooks) {
      for (Map.Entry entry : hooks.entrySet()) {
        if (entry.getValue().equals(iName)) {
          hooks.remove(entry.getKey());
          break;
        }
      }

      hooks.put(iHookValue, iName);
    }
  }

  public void unregisterHookValue(final String iName) {
    if (recording < 0)
      return;

    synchronized (hooks) {
      for (Map.Entry entry : hooks.entrySet()) {
        if (entry.getValue().equals(iName)) {
          hooks.remove(entry.getKey());
          break;
        }
      }
    }
  }

  private void init() {
    counters = new HashMap();
    chronos = new HashMap();
    stats = new HashMap();
    hooks = new WeakHashMap();

    lastReset = new Date();
  }

  private synchronized long updateEntry(final Map iValues, final String iName, final long iValue) {
    if (recording < 0)
      return iValue;

    synchronized (iValues) {
      OProfilerEntry c = iValues.get(iName);

      if (c == null) {
        // CREATE NEW CHRONO
        c = new OProfilerEntry();
        iValues.put(iName, c);
      }

      c.name = iName;
      c.items++;
      c.last = iValue;
      c.total += c.last;
      c.average = c.total / c.items;

      if (c.last < c.min)
        c.min = c.last;

      if (c.last > c.max)
        c.max = c.last;

      return c.last;
    }
  }

  private synchronized String dumpEntries(final Map iValues, final StringBuilder iBuffer) {
    // CHECK IF CHRONOS ARE ACTIVED
    if (recording < 0)
      return "";

    synchronized (iValues) {
      if (iValues.size() == 0)
        return "";

      OProfilerEntry c;

      iBuffer.append(String.format("\n%50s +-------------------------------------------------------------------+", ""));
      iBuffer.append(String.format("\n%50s | %10s %10s %10s %10s %10s %10s |", "Name", "last", "total", "min", "max", "average",
          "items"));
      iBuffer.append(String.format("\n%50s +-------------------------------------------------------------------+", ""));

      final List keys = new ArrayList(iValues.keySet());
      Collections.sort(keys);

      for (String k : keys) {
        c = iValues.get(k);
        iBuffer.append(String.format("\n%-50s | %10d %10d %10d %10d %10d %10d |", k, c.last, c.total, c.min, c.max, c.average,
            c.items));
      }
      iBuffer.append(String.format("\n%50s +-------------------------------------------------------------------+", ""));
      return iBuffer.toString();
    }
  }

  public void setAutoDump(final int iSeconds) {
    if (timer != null) {
      timer.cancel();
      timer = null;
    }

    if (iSeconds > 0) {
      final int ms = iSeconds * 1000;

      timer = new Timer(true);
      timer.scheduleAtFixedRate(new TimerTask() {

        @Override
        public void run() {
          System.out.println(OProfiler.getInstance().dump());
          if (autoDumpReset)
            reset();
        }
      }, ms, ms);
    }
  }

  public void setAutoDumpReset(final boolean iNewValue) {
    autoDumpReset = iNewValue;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy