View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software 
12   * distributed under the License is distributed on an "AS IS" BASIS, 
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
14   * See the License for the specific language governing permissions and 
15   * limitations under the License.
16   */
17  
18  
19  package org.apache.jdo.impl.enhancer.util;
20  
21  import java.util.HashMap;
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.Comparator;
25  
26  import java.text.DecimalFormat;
27  
28  import java.io.PrintWriter;
29  
30  
31  /***
32   * Utility class for simple performance analysis.
33   */
34  public final class Timer
35  {
36      // a method's timing descriptor
37      static private class MethodDescriptor
38      {
39          final String name;
40          int instantiations;
41          int calls;
42          long self;
43          long total;
44  
45          MethodDescriptor(String name)
46          {
47              this.name = name;
48          }
49      }
50  
51      // a method call's timing descriptor
52      static private class MethodCall
53      {
54          final MethodDescriptor method;
55          final String message;
56          long self;
57          long total;
58  
59          MethodCall(MethodDescriptor method,
60                     String message,
61                     long self,
62                     long total)
63          {
64              this.method = method;
65              this.message = message;
66              this.self = self;
67              this.total = total;
68          }
69      }
70  
71      // output device
72      PrintWriter out = new PrintWriter(System.out, true);
73  
74      // methods
75      HashMap methods = new HashMap();
76  
77      // method call stack
78      private final ArrayList calls = new ArrayList(16);
79      
80      public Timer()
81      {
82          this.out = out;
83      }
84  
85      public Timer(PrintWriter out)
86      {
87          this.out = out;
88      }
89  
90      public final synchronized void push(String name)
91      {
92          push(name, name);
93      }
94      
95      public final synchronized void push(String name, String message)
96      {
97          // get time
98          final long now = System.currentTimeMillis();
99  
100         // get a method descriptor
101         MethodDescriptor current = (MethodDescriptor)methods.get(name);
102         if (current == null) {
103             current = new MethodDescriptor(name);
104             methods.put(name, current);
105         }
106 
107         // update method descriptor
108         current.calls++;
109         current.instantiations++;
110 
111         // update method call stack
112         calls.add(new MethodCall(current, message, now, now));
113     }
114 
115     public final synchronized void pop()
116     {
117         // get time
118         final long now = System.currentTimeMillis();
119 
120         // update method call stack
121         final MethodCall call = (MethodCall)calls.remove(calls.size()-1);
122 
123         // get current call's time
124         final long currentSelf = now - call.self;
125         final long currentTotal = now - call.total;
126 
127         // update previous call's self time
128         if (calls.size() > 0) {
129             final MethodCall previous = (MethodCall)calls.get(calls.size()-1);
130             previous.self += currentTotal;
131         }
132 
133         // update method descriptor
134         final MethodDescriptor current = call.method;
135         current.self += currentSelf;
136         if (--current.instantiations == 0) {
137             current.total += currentTotal;
138         }
139 
140         if (false) {
141             out.println("Timer (n,g): " + call.message + " : ("
142                         + currentSelf + ", " + currentTotal + ")");
143         }
144     }
145 
146     static private final String pad(String s, int i)
147     {
148         StringBuffer b = new StringBuffer();
149         for (i -= s.length(); i > 0; i--)
150             b.append((char)' ');
151         b.append(s);
152         return b.toString();
153     }
154     
155     public final synchronized void print()
156     {
157         out.println("Timer : printing accumulated times ...");
158         final Object[] calls = methods.values().toArray();
159 
160         Arrays.sort(calls,
161                     new Comparator() {
162                             public int compare(Object o1,
163                                                Object o2) {
164                                 return (int)(((MethodDescriptor)o2).total
165                                              - ((MethodDescriptor)o1).total);
166                             }
167                             public boolean equals(Object obj) {
168                                 return (compare(this, obj) == 0);
169                             }
170                         });
171         
172         out.println("Timer :  total s    self s  #calls  name");
173         DecimalFormat nf = new DecimalFormat();
174         nf.setMaximumFractionDigits(2);
175         nf.setMinimumFractionDigits(2);
176         //nf.applyPattern("#,##0.00");
177         //out.println("Timer : pattern = " + nf.toPattern());
178         for (int i = 0; i < calls.length; i++) {
179             final MethodDescriptor current = (MethodDescriptor)calls[i];
180 
181             out.println("Timer : "
182                         + pad(nf.format(current.total / 1000.0), 8) + "  "
183                         + pad(nf.format(current.self / 1000.0), 8) + "  "
184                         + pad(String.valueOf(current.calls), 6) + "  "
185                         + current.name);
186         }
187     }
188 }