001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.utils;
014
015import java.lang.reflect.*;
016import java.util.*;
017import java.util.concurrent.atomic.*;
018
019import org.apache.juneau.annotation.*;
020import org.apache.juneau.marshall.*;
021
022/**
023 * Basic timing information.
024 *
025 * Keeps track of number of starts/finishes on tasks and keeps an average run time.
026 */
027@Bean(bpi="method,runs,running,errors,minTime,maxTime,avgTime,totalTime,exceptions")
028public class MethodExecStats implements Comparable<MethodExecStats> {
029
030   private String method;
031   private WeightedAverage avgTime = new WeightedAverage();
032   private volatile int minTime = -1, maxTime;
033
034   private AtomicInteger
035      starts = new AtomicInteger(),
036      finishes = new AtomicInteger(),
037      errors = new AtomicInteger();
038
039   private AtomicLong
040      totalTime = new AtomicLong();
041
042   private StackTraceDatabase stackTraceDb;
043
044   /**
045    * Constructor.
046    *
047    * @param method Arbitrary label.  Should be kept to less than 50 characters.
048    * @param stackTraceStopClass Don't calculate stack traces when this class is encountered.
049    */
050   public MethodExecStats(Method method, Class<?> stackTraceStopClass) {
051      this.method = method.getDeclaringClass().getSimpleName() + "." + method.getName();
052      this.stackTraceDb = new StackTraceDatabase(-1, stackTraceStopClass);
053   }
054
055   /**
056    * Constructor.
057    *
058    * @param method Arbitrary label.  Should be kept to less than 50 characters.
059    */
060   public MethodExecStats(Method method) {
061      this(method, MethodInvoker.class);
062   }
063
064   /**
065    * Call when task is started.
066    */
067   public void started() {
068      starts.incrementAndGet();
069   }
070
071   /**
072    * Call when task is finished.
073    * @param nanoTime The execution time of the task in nanoseconds.
074    */
075   public void finished(long nanoTime) {
076      finishes.incrementAndGet();
077      int milliTime = (int)(nanoTime/1_000_000);
078      totalTime.addAndGet(nanoTime);
079      avgTime.add(1, nanoTime);
080      minTime = minTime == -1 ? milliTime : Math.min(minTime, milliTime);
081      maxTime = Math.max(maxTime, milliTime);
082   }
083
084   /**
085    * Call when an error occurs.
086    * @param e The exception thrown.  Can be <jk>null</jk>.
087    */
088   public void error(Throwable e) {
089      errors.incrementAndGet();
090      stackTraceDb.add(e);
091   }
092
093   /**
094    * Returns the method name of these stats.
095    *
096    * @return The method name of these stats.
097    */
098   public String getMethod() {
099      return method;
100   }
101
102   /**
103    * Returns the number of times the {@link #started()} method was called.
104    *
105    * @return The number of times the {@link #started()} method was called.
106    */
107   public int getRuns() {
108      return starts.get();
109   }
110
111   /**
112    * Returns the number currently running method invocations.
113    *
114    * @return The number of currently running method invocations.
115    */
116   public int getRunning() {
117      return starts.get() - finishes.get();
118   }
119
120   /**
121    * Returns the number of times the {@link #error(Throwable)} method was called.
122    *
123    * @return The number of times the {@link #error(Throwable)} method was called.
124    */
125   public int getErrors() {
126      return errors.get();
127   }
128
129   /**
130    * Returns the max execution time.
131    *
132    * @return The average execution time in milliseconds.
133    */
134   public int getMinTime() {
135      return minTime == -1 ? 0 : minTime;
136   }
137
138   /**
139    * Returns the max execution time.
140    *
141    * @return The average execution time in milliseconds.
142    */
143   public int getMaxTime() {
144      return maxTime;
145   }
146
147   /**
148    * Returns the average execution time.
149    *
150    * @return The average execution time in milliseconds.
151    */
152   public int getAvgTime() {
153      return (int)avgTime.getValue() / 1_000_000;
154   }
155
156   /**
157    * Returns the total execution time.
158    *
159    * @return The total execution time in milliseconds.
160    */
161   public long getTotalTime() {
162      return totalTime.get() / 1_000_000;
163   }
164
165   /**
166    * Returns information on all stack traces of all exceptions encountered.
167    *
168    * @return Information on all stack traces of all exceptions encountered.
169    */
170   public List<StackTraceInfo> getExceptions() {
171      return stackTraceDb.getClonedStackTraceInfos();
172   }
173
174   @Override /* Object */
175   public String toString() {
176      return SimpleJson.DEFAULT.toString(this);
177   }
178
179   @Override /* Comparable */
180   public int compareTo(MethodExecStats o) {
181      return Long.compare(o.getTotalTime(), getTotalTime());
182   }
183}