-
Notifications
You must be signed in to change notification settings - Fork 24.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement rounding optimization for fixed offset timezones #46670
Conversation
|
||
TimeUnitRounding(DateTimeUnit unit, ZoneId timeZone) { | ||
this.unit = unit; | ||
this.timeZone = timeZone; | ||
this.unitRoundsToMidnight = this.unit.field.getBaseUnit().getDuration().toMillis() > 3600000L; | ||
this.isUtcTimeZone = timeZone.normalized().equals(ZoneOffset.UTC); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I remember adding this because of performance problems with timeZone.getRules().getOffset(Instant.EPOCH)
in the UTC case. did you benchmark that this is not the case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would the performance differ ? UTC is a fixed timezone so this change just englobes more cases, we're just changing the way we check if we can apply a fixed offset ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I misunderstood your comment sorry, there is a TODO in the java code saying that getRules
should be optimized so +1 to resolve the offset once in the ctr and use it to determine whether the fast rounding should be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the previous implementation did not call timeZone.getRules().getOffset(Instant.EPOCH).getTotalSeconds()
in the UTC case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to resolve the fixeed offset here and call timeZone.getRules().getOffset(Instant.EPOCH)
only once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep agreed, this should be changed
// This works as long as the tz offset doesn't change. It is worth getting this case out of the way first, | ||
// as the calculations for fixing things near to offset changes are a little expensive and unnecessary | ||
// in the common case of working with fixed offset timezones (such as UTC). | ||
if (timeZone.getRules().isFixedOffset() == true) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see above. can you benchmark this against the UTC case and see if the performance differs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are the results of the esrally benchmark used for reproducing the bug.
Dataset is the timestamps-gaussian-sameday
Query is:
"aggs": {
"2": {
"date_histogram": {
"field": "@timestamp",
"fixed_interval": "24h",
"min_doc_count": 1
}
}
},
"query": {
"match_all": {}
}
baseline: master branch (8.x)
contender: branch with fix
| Metric | Task | Baseline | Contender | Diff | Unit |
|-------------------------------+--------------------------+-------------+-------------+----------+--------|
| Median Throughput | query-agg-date_histogram | 0.0896863 | 0.202938 | 0.11325 | ops/s |
| Max Throughput | query-agg-date_histogram | 0.0903743 | 0.207398 | 0.11702 | ops/s |
| 50th percentile latency | query-agg-date_histogram | 161809 | 3268.02 | -158541 | ms |
| 90th percentile latency | query-agg-date_histogram | 230431 | 3435.84 | -226995 | ms |
| 100th percentile latency | query-agg-date_histogram | 247591 | 3502.15 | -244089 | ms |
| 50th percentile service time | query-agg-date_histogram | 10808.3 | 3263.49 | -7544.81 | ms |
| 90th percentile service time | query-agg-date_histogram | 11114.6 | 3431.34 | -7683.28 | ms |
| 100th percentile service time | query-agg-date_histogram | 11688.9 | 3499.13 | -8189.74 | ms |
I am going to work on the micro benchmarks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you also compare the patch with the check for the UTC timezone in the ctor and without?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really a regression and we're just copying what we used to do with Joda. Let's setup a quick micro benchmarks for this if you want but the most important part here is correctness ;).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here, we should resolve the fixed offset once in the ctr
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved this to constructor as discussed. Benchmark results improved by ~12%.
See results below (contender is the newer revision):
|-------------------------------+--------------------------+-------------+-------------+----------+--------|
| Metric | Task | Baseline | Contender | Diff | Unit |
|-------------------------------+--------------------------+-------------+-------------+----------+--------|
| 50th percentile latency | query-agg-date_histogram | 2892.92 | 2539.31 | -353.609 | ms |
| 90th percentile latency | query-agg-date_histogram | 3086.98 | 2762.28 | -324.694 | ms |
| 100th percentile latency | query-agg-date_histogram | 3182.51 | 2865.38 | -317.137 | ms |
| 50th percentile service time | query-agg-date_histogram | 2885.19 | 2532.11 | -353.078 | ms |
| 90th percentile service time | query-agg-date_histogram | 3078.69 | 2755.39 | -323.297 | ms |
| 100th percentile service time | query-agg-date_histogram | 3174.46 | 2857.74 | -316.713 | ms |
|-------------------------------+--------------------------+-------------+-------------+----------+--------|
Pinging @elastic/es-analytics-geo |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I am unsure about the performance implications, maybe resurrecting the RoundingBenchmark
for testing from the 7.x branch makes sense here (or just test on the 7.x branch then port)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @csoulios , the changes look good, I left some comments
|
||
TimeUnitRounding(DateTimeUnit unit, ZoneId timeZone) { | ||
this.unit = unit; | ||
this.timeZone = timeZone; | ||
this.unitRoundsToMidnight = this.unit.field.getBaseUnit().getDuration().toMillis() > 3600000L; | ||
this.isUtcTimeZone = timeZone.normalized().equals(ZoneOffset.UTC); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to resolve the fixeed offset here and call timeZone.getRules().getOffset(Instant.EPOCH)
only once.
|
||
TimeUnitRounding(DateTimeUnit unit, ZoneId timeZone) { | ||
this.unit = unit; | ||
this.timeZone = timeZone; | ||
this.unitRoundsToMidnight = this.unit.field.getBaseUnit().getDuration().toMillis() > 3600000L; | ||
this.isUtcTimeZone = timeZone.normalized().equals(ZoneOffset.UTC); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep agreed, this should be changed
// This works as long as the tz offset doesn't change. It is worth getting this case out of the way first, | ||
// as the calculations for fixing things near to offset changes are a little expensive and unnecessary | ||
// in the common case of working with fixed offset timezones (such as UTC). | ||
if (timeZone.getRules().isFixedOffset() == true) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here, we should resolve the fixed offset once in the ctr
I ran ES Rally benchmark (https://github.com/csoulios/date_histogram-benchmark) for the following scenarios (on my laptop):
All produced similar results:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks @csoulios
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
left a few minor nits, feel free to ignore them
LGTM otherwise, thanks for fixing!
|
||
private final DateTimeUnit unit; | ||
private final ZoneId timeZone; | ||
private final boolean unitRoundsToMidnight; | ||
private final boolean isUtcTimeZone; | ||
/** For fixed offset timezones, this is the offset in milliseconds, otherwise TZ_OFFSET_NON_FIXED */ | ||
private final long fixedOffset; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ignoreable nit: maybe name this fixedOffsetMs or something to indicate its contents
@@ -218,17 +218,20 @@ public Rounding build() { | |||
static class TimeUnitRounding extends Rounding { | |||
|
|||
static final byte ID = 1; | |||
static final long TZ_OFFSET_NON_FIXED = -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment nit: maybe include a small comment what -1
indicates, and why this can never be -1 in a regular offset
@@ -432,20 +436,25 @@ public String toString() { | |||
} | |||
|
|||
static final byte ID = 2; | |||
static final long TZ_OFFSET_NON_FIXED = -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor nit: would one instance of this be enough?
@@ -218,17 +218,20 @@ public Rounding build() { | |||
static class TimeUnitRounding extends Rounding { | |||
|
|||
static final byte ID = 1; | |||
static final long TZ_OFFSET_NON_FIXED = -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor nit: can be private?
@elasticmachine run elasticsearch-ci/bwc |
…6670) Fixes elastic#45702 with date_histogram aggregation when using fixed_interval. Optimization has been implemented for both fixed and calendar intervals
…6670) Fixes elastic#45702 with date_histogram aggregation when using fixed_interval. Optimization has been implemented for both fixed and calendar intervals
Fixes #45702 with date_histogram aggregation when using
fixed_interval
.Implement code change discussed at:
#45702 (comment)
Optimization has been implemented for both fixed and calendar intervals