This repository has been archived by the owner on Mar 20, 2018. It is now read-only.
/
LocalDateBenchmark.java
312 lines (289 loc) · 10.9 KB
/
LocalDateBenchmark.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
/*
* Copyright 2015 Stephen Colebourne
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.threeten;
import java.time.LocalDate;
import java.time.Month;
import java.time.chrono.IsoChronology;
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.annotations.Warmup;
@Measurement(batchSize = 2000, iterations = 8, time = 2, timeUnit = TimeUnit.SECONDS)
@Warmup(iterations = 5)
@Threads(value = 1)
@Fork(value = 1)
@State(Scope.Benchmark)
public class LocalDateBenchmark {
private static final LocalDate DATE = LocalDate.of(2014, 6, 1);
@Param({"1", "27", "30", "90", "-1"})
public int arg;
@Benchmark
public LocalDate bmkPlusDays1() {
return DATE.plusDays(arg);
}
@Benchmark
public LocalDate bmkPlusDaysInline() {
return plusDaysInline(DATE, arg);
}
@Benchmark
public LocalDate bmkPlusDays1Better1() {
return plusDaysBetter1(DATE, arg);
}
@Benchmark
public LocalDate bmkPlusDays1Better2() {
return plusDaysBetter2(DATE, arg);
}
@Benchmark
public LocalDate bmkPlusDays1Better3a() {
return plusDaysBetter3a(DATE, arg);
}
@Benchmark
public LocalDate bmkPlusDays1Better3b() {
return plusDaysBetter3b(DATE, arg);
}
@Benchmark
public LocalDate bmkPlusDays1Better3c() {
return plusDaysBetter3c(DATE, arg);
}
@Benchmark
public LocalDate bmkPlusDays1Better4() {
return plusDaysBetter4(DATE, arg);
}
@Benchmark
public LocalDate bmkPlusDays1Better5() {
return plusDaysBetter5(DATE, arg);
}
//-------------------------------------------------------------------------
public LocalDate plusDaysInline(LocalDate input, long daysToAdd) {
if (daysToAdd == 0) {
return input;
}
long epDay = Math.addExact(input.toEpochDay(), daysToAdd);
return LocalDate.ofEpochDay(epDay);
}
// 4.1x speedup (463 vs 113) for same month
// little change non-optimized path (114 vs 113)
public LocalDate plusDaysBetter1(LocalDate input, long daysToAdd) {
if (daysToAdd == 0) {
return input;
}
long dom = input.getDayOfMonth() + daysToAdd;
if (dom > 0 && dom <= 28) {
return LocalDate.of(input.getYear(), input.getMonthValue(), (int) dom);
}
long epDay = Math.addExact(input.toEpochDay(), daysToAdd);
return LocalDate.ofEpochDay(epDay);
}
// 3.7x speedup (415 vs 113) for same month
// little change non-optimized path (111 vs 113)
public LocalDate plusDaysBetter2(LocalDate input, long daysToAdd) {
if (daysToAdd == 0) {
return input;
}
long dom = input.getDayOfMonth() + daysToAdd;
if (dom > 0 && dom <= input.lengthOfMonth()) {
return LocalDate.of(input.getYear(), input.getMonthValue(), (int) dom);
}
long epDay = Math.addExact(input.toEpochDay(), daysToAdd);
return LocalDate.ofEpochDay(epDay);
}
// 3.7x speedup (422 vs 113) for same month
// 3.7x speedup (417 vs 113) for next month
// little change non-optimized path (113 vs 113)
public LocalDate plusDaysBetter3a(LocalDate input, long daysToAdd) {
if (daysToAdd == 0) {
return input;
}
long dom = input.getDayOfMonth() + daysToAdd;
if (dom > 0 && dom <= 59) { // 59th Jan is 28th Feb
int monthLen = input.lengthOfMonth();
int month = input.getMonthValue();
int year = input.getYear();
if (dom <= monthLen) {
return LocalDate.of(year, month, (int) dom);
} else if (month < 12) {
return LocalDate.of(year, month + 1, (int) (dom - monthLen));
} else {
return LocalDate.of(year + 1, 1, (int) (dom - monthLen));
}
}
long epDay = Math.addExact(input.toEpochDay(), daysToAdd);
return LocalDate.ofEpochDay(epDay);
}
// faster than 3a for same month, little change otherwise
public LocalDate plusDaysBetter3b(LocalDate input, long daysToAdd) {
if (daysToAdd == 0) {
return input;
}
long dom = input.getDayOfMonth() + daysToAdd;
if (dom > 0 && dom <= 28) { // same month
return input.withDayOfMonth((int) dom);
}
if (dom > 0 && dom <= 59) { // 59th Jan is 28th Feb
int monthLen = input.lengthOfMonth();
int month = input.getMonthValue();
int year = input.getYear();
if (dom <= monthLen) {
return LocalDate.of(year, month, (int) dom);
} else if (month < 12) {
return LocalDate.of(year, month + 1, (int) (dom - monthLen));
} else {
return LocalDate.of(year + 1, 1, (int) (dom - monthLen));
}
}
long epDay = Math.addExact(input.toEpochDay(), daysToAdd);
return LocalDate.ofEpochDay(epDay);
}
// marginally faster than 3b for same month, little change otherwise
public LocalDate plusDaysBetter3c(LocalDate input, long daysToAdd) {
if (daysToAdd == 0) {
return input;
}
long dom = input.getDayOfMonth() + daysToAdd;
if (dom > 0) {
if (dom <= 28) { // same month
return input.withDayOfMonth((int) dom);
}
if (dom <= 59) { // 59th Jan is 28th Feb
int monthLen = input.lengthOfMonth();
int month = input.getMonthValue();
int year = input.getYear();
if (dom <= monthLen) {
return LocalDate.of(year, month, (int) dom);
} else if (month < 12) {
return LocalDate.of(year, month + 1, (int) (dom - monthLen));
} else {
return LocalDate.of(year + 1, 1, (int) (dom - monthLen));
}
}
}
long epDay = Math.addExact(input.toEpochDay(), daysToAdd);
return LocalDate.ofEpochDay(epDay);
}
// 3.9x speedup (444 vs 113) for same month
// 2.9x speedup (344 vs 113) for next/previous month
// marginally slower for non-optimized path (109 vs 113)
public LocalDate plusDaysBetter4(LocalDate input, long daysToAdd) {
if (daysToAdd == 0) {
return input;
}
long dom = input.getDayOfMonth() + daysToAdd;
if (dom > 0) {
int monthLen = input.lengthOfMonth();
int month = input.getMonthValue();
int year = input.getYear();
if (dom <= monthLen) {
// same month
return LocalDate.of(year, month, (int) dom);
} else if (dom <= monthLen + 28) {
// next month (28 guarantees only one month later)
dom -= monthLen;
if (month == 12) {
return LocalDate.of(year + 1, 1, (int) dom);
} else {
return LocalDate.of(year, month + 1, (int) dom);
}
}
} else if (dom > -28) {
// previous month (28 guarantees only one month earlier)
int month = input.getMonthValue();
int year = input.getYear();
if (month == 1) {
return LocalDate.of(year - 1, 12, (int) dom + 31);
} else {
int monthLen = Month.of(month - 1).length(input.isLeapYear());
return LocalDate.of(year, month - 1, (int) dom + monthLen);
}
}
long epDay = Math.addExact(input.toEpochDay(), daysToAdd);
return LocalDate.ofEpochDay(epDay);
}
// 3.6x speedup (406 vs 113) for same month
// 2.7x speedup (305 vs 113) for next month
// 2.4x speedup (271 vs 113) for 90 days
// little change non-optimized path (118 vs 113)
public LocalDate plusDaysBetter5(LocalDate input, long daysToAdd) {
if (daysToAdd == 0) {
return input;
}
long dom = input.getDayOfMonth() + daysToAdd;
if (dom > 0 && dom <= 180) {
int month = input.getMonthValue();
int year = input.getYear();
while (true) {
switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10: {
if (dom <= 31) {
return LocalDate.of(year, month, (int) dom);
} else {
month++;
dom -= 31;
}
}
case 4:
case 6:
case 9:
case 11: {
if (dom <= 30) {
return LocalDate.of(year, month, (int) dom);
} else {
month++;
dom -= 30;
}
}
case 2: {
if (IsoChronology.INSTANCE.isLeapYear(year)) {
if (dom <= 29) {
return LocalDate.of(year, month, (int) dom);
} else {
month++;
dom -= 29;
}
} else {
if (dom <= 28) {
return LocalDate.of(year, month, (int) dom);
} else {
month++;
dom -= 29;
}
}
}
case 12: {
if (dom <= 31) {
return LocalDate.of(year, month, (int) dom);
} else {
year++;
month = 1;
dom -= 31;
}
}
}
}
}
long epDay = Math.addExact(input.toEpochDay(), daysToAdd);
return LocalDate.ofEpochDay(epDay);
}
}