This way is faster, saving about 8% on the microbenchmark that rounds to the nearest month. That is in the hot path for `date_histogram` which is a very popular aggregation so it seems worth it to at least try and speed it up a little. Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
66b3e89482
commit
dfd502f9ca
|
@ -63,3 +63,29 @@ To get realistic results, you should exercise care when running benchmarks. Here
|
|||
* Blindly believe the numbers that your microbenchmark produces but verify them by measuring e.g. with `-prof perfasm`.
|
||||
* Run more threads than your number of CPU cores (in case you run multi-threaded microbenchmarks).
|
||||
* Look only at the `Score` column and ignore `Error`. Instead take countermeasures to keep `Error` low / variance explainable.
|
||||
|
||||
## Disassembling
|
||||
|
||||
Disassembling is fun! Maybe not always useful, but always fun! Generally, you'll want to install `perf` and FCML's `hsdis`.
|
||||
`perf` is generally available via `apg-get install perf` or `pacman -S perf`. FCML is a little more involved. This worked
|
||||
on 2020-08-01:
|
||||
|
||||
```
|
||||
wget https://github.com/swojtasiak/fcml-lib/releases/download/v1.2.2/fcml-1.2.2.tar.gz
|
||||
tar xf fcml*
|
||||
cd fcml*
|
||||
./configure
|
||||
make
|
||||
cd example/hsdis
|
||||
make
|
||||
cp .libs/libhsdis.so.0.0.0
|
||||
sudo cp .libs/libhsdis.so.0.0.0 /usr/lib/jvm/java-14-adoptopenjdk/lib/hsdis-amd64.so
|
||||
```
|
||||
|
||||
If you want to disassemble a single method do something like this:
|
||||
|
||||
```
|
||||
gradlew -p benchmarks run --args ' MemoryStatsBenchmark -jvmArgs "-XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*.yourMethodName -XX:PrintAssemblyOptions=intel"
|
||||
```
|
||||
|
||||
If you want `perf` to find the hot methods for you then do add `-prof:perfasm`.
|
||||
|
|
|
@ -92,8 +92,27 @@ class DateUtilsRounding {
|
|||
return (year * 365L + (leapYears - DAYS_0000_TO_1970)) * MILLIS_PER_DAY; // millis per day
|
||||
}
|
||||
|
||||
private static boolean isLeapYear(final int year) {
|
||||
return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0);
|
||||
static boolean isLeapYear(final int year) {
|
||||
// Joda had
|
||||
// return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0);
|
||||
// But we've replaced that with this:
|
||||
if ((year & 3) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (year % 100 != 0) {
|
||||
return true;
|
||||
}
|
||||
return ((year / 100) & 3) == 0;
|
||||
/*
|
||||
* It is a little faster because it saves a division. We don't have good
|
||||
* measurements for this method on its own, but this change speeds up
|
||||
* rounding the nearest month by about 8%.
|
||||
*
|
||||
* Note: If you decompile this method to x86 assembly you won't see the
|
||||
* division you'd expect from % 100 and / 100. Instead you'll see a funny
|
||||
* sequence of bit twiddling operations which the jvm thinks is faster.
|
||||
* Division is slow so it almost certainly is.
|
||||
*/
|
||||
}
|
||||
|
||||
private static final long AVERAGE_MILLIS_PER_YEAR_DIVIDED_BY_TWO = MILLIS_PER_YEAR / 2;
|
||||
|
|
|
@ -46,4 +46,14 @@ public class DateUtilsRoundingTests extends ESTestCase {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testIsLeapYear() {
|
||||
assertTrue(DateUtilsRounding.isLeapYear(2004));
|
||||
assertTrue(DateUtilsRounding.isLeapYear(2000));
|
||||
assertTrue(DateUtilsRounding.isLeapYear(1996));
|
||||
assertFalse(DateUtilsRounding.isLeapYear(2001));
|
||||
assertFalse(DateUtilsRounding.isLeapYear(1900));
|
||||
assertFalse(DateUtilsRounding.isLeapYear(-1000));
|
||||
assertTrue(DateUtilsRounding.isLeapYear(-996));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue