/******************************************************************************* * Copyright (c) 2008-2009 Cambridge Semantics Incorporated. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package org.openanzo.analysis; import java.util.EmptyStackException; import java.util.HashMap; import java.util.Map; import java.util.Stack; import org.openanzo.exceptions.LogUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Profiler uses a logger to write profile information to the log */ public class Profiler { /** Default Profiler Logger */ public static final String DEFAULT_PROFILER_LOGGER = "org.openanzo.analysis.profiling.DefaultProfilerLogger"; Map<Long, TimerData> timers = new HashMap<Long, TimerData>(); long count = 0; Logger log = null; Stack<Long> list = new Stack<Long>(); /** * Create a profiler that uses the default logger */ public Profiler() { this.log = LoggerFactory.getLogger(DEFAULT_PROFILER_LOGGER); } /** * Create a profiler that uses a specific logger * * @param log * logger to use */ public Profiler(Logger log) { this.log = log; } /** * Start timing with a specific title * * @param title * title for starting a timer * @return id for timer */ public long start(String title) { if (!log.isDebugEnabled()) { return -1; } return start(title, null); } /** * Start a timer with a title and an object that is passed to the title as a parameter * * @param title * title for starting a timer * @param titleObj * object that is passed to the logger as a param to the title * @return the id of the timer */ public synchronized long start(String title, Object titleObj) { if (!log.isDebugEnabled()) { return -1; } long id = count++; TimerData timer = new TimerData(title, titleObj); timers.put(id, timer); timer.start(); list.push(id); return id; } /** * Pop the last timer of the stack and stop it */ public void stop() { if (!log.isDebugEnabled()) { return; } try { long id = list.pop(); stop(id); } catch (EmptyStackException e) { log.warn(LogUtils.INTERNAL_MARKER, "stop called too many times. Profiler measurements may be incorrect!", e); } } /** * Stop a specific timer * * @param id * id of timer to stop */ public synchronized void stop(long id) { if (!log.isDebugEnabled()) { return; } TimerData timer = timers.get(id); if (timer == null) { return; } else { timer.stop(); timers.remove(id); } } class TimerData { String title = null; Object titleObj = null; long start = -1; long stop = -1; TimerData(String title) { this.title = title; } TimerData(String title, Object titleObj) { this.title = title; this.titleObj = titleObj; } void start() { if (titleObj == null) { log.debug(LogUtils.INTERNAL_MARKER, START, title); } else { log.debug(LogUtils.INTERNAL_MARKER, START2, title, titleObj); } start = System.currentTimeMillis(); } void stop() { stop = System.currentTimeMillis(); if (titleObj == null) { log.debug(LogUtils.INTERNAL_MARKER, STOP, Long.toString(stop - start), title); } else { log.debug(LogUtils.INTERNAL_MARKER, STOP2, new Object[] { Long.toString(stop - start), title, titleObj }); } } static final String START = "START:{}"; static final String START2 = "START:{}"; static final String STOP = "STOP: [{}] {}"; static final String STOP2 = "STOP: [{}] {} {}"; } }