1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.slf4j.profiler;
25
26 import java.util.ArrayList;
27 import java.util.List;
28
29 import org.slf4j.Logger;
30 import org.slf4j.Marker;
31 import org.slf4j.MarkerFactory;
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 public class Profiler implements TimeInstrument {
50
51 final static String PROFILER_MARKER_NAME = "PROFILER";
52
53 final static int MIN_SW_NAME_LENGTH = 24;
54 final static int MIN_SW_ELAPSED_TIME_NUMBER_LENGTH = 9;
55
56 final String name;
57 final StopWatch globalStopWatch;
58
59
60 List<TimeInstrument> childTimeInstrumentList = new ArrayList<TimeInstrument>();
61
62
63 ProfilerRegistry profilerRegistry;
64
65 Logger logger;
66
67 public Profiler(String name) {
68 this.name = name;
69 this.globalStopWatch = new StopWatch(name);
70 }
71
72 public String getName() {
73 return name;
74 }
75
76 public ProfilerRegistry getProfilerRegistry() {
77 return profilerRegistry;
78 }
79
80 public void registerWith(ProfilerRegistry profilerRegistry) {
81 if (profilerRegistry == null) {
82 return;
83 }
84 this.profilerRegistry = profilerRegistry;
85 profilerRegistry.put(this);
86 }
87
88 public Logger getLogger() {
89 return logger;
90 }
91
92 public void setLogger(Logger logger) {
93 this.logger = logger;
94 }
95
96
97
98
99 public void start(String name) {
100 stopLastTimeInstrument();
101 StopWatch childSW = new StopWatch(name);
102 childTimeInstrumentList.add(childSW);
103 }
104
105 public Profiler startNested(String name) {
106 stopLastTimeInstrument();
107 Profiler nestedProfiler = new Profiler(name);
108 nestedProfiler.registerWith(profilerRegistry);
109 nestedProfiler.setLogger(logger);
110 childTimeInstrumentList.add(nestedProfiler);
111 return nestedProfiler;
112 }
113
114 TimeInstrument getLastTimeInstrument() {
115 if (childTimeInstrumentList.size() > 0) {
116 return childTimeInstrumentList.get(childTimeInstrumentList.size() - 1);
117 } else {
118 return null;
119 }
120 }
121
122 void stopLastTimeInstrument() {
123 TimeInstrument last = getLastTimeInstrument();
124 if (last != null) {
125 last.stop();
126 }
127 }
128
129
130
131
132
133
134
135
136 public long elapsedTime() {
137 return globalStopWatch.elapsedTime();
138 }
139
140 public TimeInstrument stop() {
141 stopLastTimeInstrument();
142 globalStopWatch.stop();
143 return this;
144 }
145
146 public TimeInstrumentStatus getStatus() {
147 return globalStopWatch.status;
148 }
149
150
151
152
153 void sanityCheck() throws IllegalStateException {
154 if(getStatus() != TimeInstrumentStatus.STOPPED) {
155 throw new IllegalStateException("time instrument ["+getName()+" is not stopped");
156 }
157
158 long totalElapsed = globalStopWatch.elapsedTime();
159 long childTotal = 0;
160
161 for(TimeInstrument ti: childTimeInstrumentList) {
162 childTotal += ti.elapsedTime();
163 if(ti.getStatus() != TimeInstrumentStatus.STOPPED) {
164 throw new IllegalStateException("time instrument ["+ti.getName()+" is not stopped");
165 }
166 if(ti instanceof Profiler) {
167 Profiler nestedProfiler = (Profiler) ti;
168 nestedProfiler.sanityCheck();
169 }
170 }
171 if(totalElapsed < childTotal) {
172 throw new IllegalStateException("children have a higher accumulated elapsed time");
173 }
174 }
175
176 static String TOP_PROFILER_FIRST_PREFIX = "+";
177 static String NESTED_PROFILER_FIRST_PREFIX = "|---+";
178 static String TOTAL_ELAPSED = " Total ";
179 static String SUBTOTAL_ELAPSED = " Subtotal ";
180 static String ELAPSED_TIME = " elapsed time ";
181
182
183 public void print() {
184 System.out.println(toString());
185 }
186
187 @Override
188 public String toString() {
189 DurationUnit du = Util.selectDurationUnitForDisplay(globalStopWatch);
190 return buildProfilerString(du, TOP_PROFILER_FIRST_PREFIX, TOTAL_ELAPSED, "");
191 }
192
193 public void log() {
194 Marker profilerMarker = MarkerFactory.getMarker(PROFILER_MARKER_NAME);
195 if(logger == null) {
196 throw new NullPointerException("If you invoke the log() method, then you must associate a logger with this profiler.");
197 }
198 if (logger.isDebugEnabled(profilerMarker)) {
199 DurationUnit du = Util.selectDurationUnitForDisplay(globalStopWatch);
200 String r = buildProfilerString(du, TOP_PROFILER_FIRST_PREFIX, TOTAL_ELAPSED, "");
201 logger.debug(profilerMarker, SpacePadder.LINE_SEP+r);
202 }
203 }
204
205 private String buildProfilerString(DurationUnit du, String firstPrefix, String label, String indentation) {
206 StringBuffer buf = new StringBuffer();
207
208 buf.append(firstPrefix);
209 buf.append(" Profiler [");
210 buf.append(name);
211 buf.append("]");
212 buf.append(SpacePadder.LINE_SEP);
213 for (TimeInstrument child : childTimeInstrumentList) {
214 if (child instanceof StopWatch) {
215 buildStopWatchString(buf, du, ELAPSED_TIME, indentation, (StopWatch) child);
216 } else if (child instanceof Profiler) {
217 Profiler profiler = (Profiler) child;
218 String subString = profiler
219 .buildProfilerString(du, NESTED_PROFILER_FIRST_PREFIX, SUBTOTAL_ELAPSED, indentation + " ");
220 buf.append(subString);
221 buildStopWatchString(buf, du, ELAPSED_TIME, indentation, profiler.globalStopWatch);
222 }
223 }
224 buildStopWatchString(buf, du, label, indentation, globalStopWatch);
225 return buf.toString();
226 }
227
228 private static void buildStopWatchString(StringBuffer buf, DurationUnit du,
229 String prefix, String indentation, StopWatch sw) {
230
231 buf.append(indentation);
232 buf.append("|--");
233 buf.append(prefix);
234 SpacePadder.leftPad(buf, "[" + sw.getName() + "]", MIN_SW_NAME_LENGTH);
235 buf.append(" ");
236 String timeStr = Util.durationInDunrationUnitsAsStr(sw.elapsedTime(),
237 du);
238 SpacePadder.leftPad(buf, timeStr, MIN_SW_ELAPSED_TIME_NUMBER_LENGTH);
239 buf.append(" ");
240 Util.appendDurationUnitAsStr(buf, du);
241 buf.append(SpacePadder.LINE_SEP);
242 }
243
244 }