1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.logging.log4j.perf.jmh;
19
20 import java.nio.ByteBuffer;
21 import java.text.SimpleDateFormat;
22 import java.util.Calendar;
23 import java.util.Date;
24 import java.util.concurrent.TimeUnit;
25
26 import org.apache.logging.log4j.core.util.Charsets;
27 import org.openjdk.jmh.annotations.BenchmarkMode;
28 import org.openjdk.jmh.annotations.GenerateMicroBenchmark;
29 import org.openjdk.jmh.annotations.Mode;
30 import org.openjdk.jmh.annotations.OutputTimeUnit;
31 import org.openjdk.jmh.annotations.Scope;
32 import org.openjdk.jmh.annotations.State;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 @State(Scope.Thread)
49 public class TimeFormatBenchmark {
50
51 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
52 long midnightToday = 0;
53 long midnightTomorrow = 0;
54
55 @State(Scope.Thread)
56 public static class BufferState {
57 ByteBuffer buffer = ByteBuffer.allocate(12);
58 }
59
60 private long millisSinceMidnight(long now) {
61 if (now >= midnightTomorrow) {
62 midnightToday = calcMidnightMillis(0);
63 midnightTomorrow = calcMidnightMillis(1);
64 }
65 return now - midnightToday;
66 }
67
68 private long calcMidnightMillis(int addDays) {
69
70 Calendar cal = Calendar.getInstance();
71 cal.set(Calendar.HOUR_OF_DAY, 0);
72 cal.set(Calendar.MINUTE, 0);
73 cal.set(Calendar.SECOND, 0);
74 cal.set(Calendar.MILLISECOND, 0);
75 cal.add(Calendar.DATE, addDays);
76 return cal.getTimeInMillis();
77 }
78
79 public static void main(String[] args) {
80 System.out.println(new TimeFormatBenchmark().customFastFormatString(new BufferState()));
81 System.out.println(new TimeFormatBenchmark().customFormatString(new BufferState()));
82 }
83
84 @GenerateMicroBenchmark
85 @BenchmarkMode(Mode.SampleTime)
86 @OutputTimeUnit(TimeUnit.NANOSECONDS)
87 public void baseline() {
88 }
89
90 @GenerateMicroBenchmark
91 @BenchmarkMode(Mode.SampleTime)
92 @OutputTimeUnit(TimeUnit.NANOSECONDS)
93 public String simpleDateFormatString() {
94 return simpleDateFormat.format(new Date());
95 }
96
97 @GenerateMicroBenchmark
98 @BenchmarkMode(Mode.SampleTime)
99 @OutputTimeUnit(TimeUnit.NANOSECONDS)
100 public int simpleDateFormatBytes(BufferState state) {
101 String str = simpleDateFormat.format(new Date());
102 byte[] bytes = str.getBytes(Charsets.UTF_8);
103 state.buffer.clear();
104 state.buffer.put(bytes);
105 return state.buffer.position();
106 }
107
108 @GenerateMicroBenchmark
109 @BenchmarkMode(Mode.SampleTime)
110 @OutputTimeUnit(TimeUnit.NANOSECONDS)
111 public String customFastFormatString(BufferState state) {
112 state.buffer.clear();
113 fastFormat(System.currentTimeMillis(), state.buffer);
114 return new String(state.buffer.array(), 0, state.buffer.position(), Charsets.UTF_8);
115 }
116
117 @GenerateMicroBenchmark
118 @BenchmarkMode(Mode.SampleTime)
119 @OutputTimeUnit(TimeUnit.NANOSECONDS)
120 public int customFastFormatBytes(BufferState state) {
121 state.buffer.clear();
122 fastFormat(System.currentTimeMillis(), state.buffer);
123 return state.buffer.position();
124 }
125
126 @GenerateMicroBenchmark
127 @BenchmarkMode(Mode.SampleTime)
128 @OutputTimeUnit(TimeUnit.NANOSECONDS)
129 public String customFormatString(BufferState state) {
130 state.buffer.clear();
131 format(System.currentTimeMillis(), state.buffer);
132 return new String(state.buffer.array(), 0, state.buffer.position(), Charsets.UTF_8);
133 }
134
135 @GenerateMicroBenchmark
136 @BenchmarkMode(Mode.SampleTime)
137 @OutputTimeUnit(TimeUnit.NANOSECONDS)
138 public int customFormatBytes(BufferState state) {
139 state.buffer.clear();
140 format(System.currentTimeMillis(), state.buffer);
141 return state.buffer.position();
142 }
143
144 public ByteBuffer fastFormat(long time, ByteBuffer buffer) {
145
146
147
148
149
150
151 int ms = (int) (millisSinceMidnight(time));
152
153
154 int hour = (int) (((ms >> 7) * 9773437L) >> 38);
155 ms -= 3600000 * hour;
156
157 int minute = (int) (((ms >> 5) * 2290650L) >> 32);
158 ms -= 60000 * minute;
159
160 int second = ((ms >> 3) * 67109) >> 23;
161 ms -= 1000 * second;
162
163
164
165 int temp = (hour * 13) >> 7;
166 buffer.put((byte) (temp + '0'));
167
168
169 buffer.put((byte) (hour - 10 * temp + '0'));
170 buffer.put((byte) ':');
171
172
173
174 temp = (minute * 13) >> 7;
175 buffer.put((byte) (temp + '0'));
176
177
178 buffer.put((byte) (minute - 10 * temp + '0'));
179 buffer.put((byte) ':');
180
181
182
183 temp = (second * 13) >> 7;
184 buffer.put((byte) (temp + '0'));
185 buffer.put((byte) (second - 10 * temp + '0'));
186 buffer.put((byte) '.');
187
188
189
190 temp = (ms * 41) >> 12;
191 buffer.put((byte) (temp + '0'));
192
193 ms -= 100 * temp;
194 temp = (ms * 205) >> 11;
195 buffer.put((byte) (temp + '0'));
196
197 ms -= 10 * temp;
198 buffer.put((byte) (ms + '0'));
199 return buffer;
200 }
201
202 public ByteBuffer format(long time, ByteBuffer buffer) {
203
204
205
206
207
208 int ms = (int) (millisSinceMidnight(time));
209
210 int hours = ms / 3600000;
211 ms -= 3600000 * hours;
212
213 int minutes = ms / 60000;
214 ms -= 60000 * minutes;
215
216 int seconds = ms / 1000;
217 ms -= 1000 * seconds;
218
219
220 int temp = hours / 10;
221 buffer.put((byte) (temp + '0'));
222
223
224 buffer.put((byte) (hours - 10 * temp + '0'));
225 buffer.put((byte) ':');
226
227
228 temp = minutes / 10;
229 buffer.put((byte) (temp + '0'));
230
231
232 buffer.put((byte) (minutes - 10 * temp + '0'));
233 buffer.put((byte) ':');
234
235
236 temp = seconds / 10;
237 buffer.put((byte) (temp + '0'));
238 buffer.put((byte) (seconds - 10 * temp + '0'));
239 buffer.put((byte) '.');
240
241
242 temp = ms / 100;
243 buffer.put((byte) (temp + '0'));
244
245 ms -= 100 * temp;
246 temp = ms / 10;
247 buffer.put((byte) (temp + '0'));
248
249 ms -= 10 * temp;
250 buffer.put((byte) (ms + '0'));
251 return buffer;
252 }
253 }