Skip to content

Commit

Permalink
Speed up date_trunc function (#8122)
Browse files Browse the repository at this point in the history
Summary:
`date_trunc` function is not very efficient now, when timezone is not considered, the length of a day/hour/minute is fixed. So we can speed up the `date_trunc` function for day/hour/minute unit by some simple arithmetic. This resulted in a 25x speed up in the benchmark.

```
➜ ./_build/release/velox/functions/prestosql/benchmarks/velox_functions_prestosql_benchmarks_date_time
WARNING: Benchmark running in DEBUG mode
============================================================================
[...]osql/benchmarks/DateTimeBenchmark.cpp     relative  time/iter   iters/s
============================================================================
truncYear                                                 108.28ms      9.23
truncMonth                                                110.60ms      9.04
truncDay                                                    4.26ms    234.80
truncHour                                                   4.14ms    241.70
truncMinute                                                 4.48ms    223.19
truncSecond                                                 3.62ms    276.45
year                                                       32.24ms     31.01
month                                                      31.89ms     31.36
day                                                        31.39ms     31.86
hour                                                       34.26ms     29.19
hour_vector                                      67.25%    50.95ms     19.63
minute                                                     34.81ms     28.73
second                                                     31.35ms     31.90
```

Pull Request resolved: #8122

Reviewed By: bikramSingh91

Differential Revision: D58370105

Pulled By: kevinwilfong

fbshipit-source-id: 72697cc62b88564c8beae848dc0ae17fe67d0609
  • Loading branch information
ViggoC authored and facebook-github-bot committed Jun 10, 2024
1 parent c4054d9 commit 20069f9
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 7 deletions.
38 changes: 31 additions & 7 deletions velox/functions/prestosql/DateTimeFunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -915,15 +915,25 @@ struct DateTruncFunction : public TimestampWithTimezoneSupport<T> {
unit = getTimestampUnit(unitString).value();
}

if (unit == DateTimeUnit::kSecond) {
result = Timestamp(timestamp.getSeconds(), 0);
return;
switch (unit) {
case DateTimeUnit::kSecond:
result = Timestamp(timestamp.getSeconds(), 0);
return;
case DateTimeUnit::kMinute:
result = adjustEpoch(getSeconds(timestamp, timeZone_), 60);
break;
case DateTimeUnit::kHour:
result = adjustEpoch(getSeconds(timestamp, timeZone_), 60 * 60);
break;
case DateTimeUnit::kDay:
result = adjustEpoch(getSeconds(timestamp, timeZone_), 24 * 60 * 60);
break;
default:
auto dateTime = getDateTime(timestamp, timeZone_);
adjustDateTime(dateTime, unit);
result = Timestamp(timegm(&dateTime), 0);
}

auto dateTime = getDateTime(timestamp, timeZone_);
adjustDateTime(dateTime, unit);

result = Timestamp(timegm(&dateTime), 0);
if (timeZone_ != nullptr) {
result.toGMT(*timeZone_);
}
Expand Down Expand Up @@ -975,6 +985,20 @@ struct DateTruncFunction : public TimestampWithTimezoneSupport<T> {

result = pack(timestamp.toMillis(), unpackZoneKeyId(timestampWithTimezone));
}

private:
/// For fixed interval like second, minute, hour, day and week
/// we can truncate date by a simple arithmetic expression:
/// floor(seconds / intervalSeconds) * intervalSeconds.
FOLLY_ALWAYS_INLINE Timestamp
adjustEpoch(int64_t seconds, int64_t intervalSeconds) {
int64_t s = seconds / intervalSeconds;
if (seconds < 0 && seconds % intervalSeconds) {
s = s - 1;
}
int64_t truncedSeconds = s * intervalSeconds;
return Timestamp(truncedSeconds, 0);
}
};

template <typename T>
Expand Down
41 changes: 41 additions & 0 deletions velox/functions/prestosql/tests/DateTimeFunctionsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1513,11 +1513,45 @@ TEST_F(DateTimeFunctionsTest, dateTrunc) {
fmt::format("date_trunc('{}', c0)", unit), timestamp);
};

disableAdjustTimestampToTimezone();

EXPECT_EQ(std::nullopt, dateTrunc("second", std::nullopt));
EXPECT_EQ(Timestamp(0, 0), dateTrunc("second", Timestamp(0, 0)));
EXPECT_EQ(Timestamp(0, 0), dateTrunc("second", Timestamp(0, 123)));
EXPECT_EQ(Timestamp(-1, 0), dateTrunc("second", Timestamp(-1, 0)));
EXPECT_EQ(Timestamp(-1, 0), dateTrunc("second", Timestamp(-1, 123)));
EXPECT_EQ(Timestamp(0, 0), dateTrunc("day", Timestamp(0, 123)));
EXPECT_EQ(
Timestamp(998474645, 0),
dateTrunc("second", Timestamp(998'474'645, 321'001'234)));
EXPECT_EQ(
Timestamp(998474640, 0),
dateTrunc("minute", Timestamp(998'474'645, 321'001'234)));
EXPECT_EQ(
Timestamp(998474400, 0),
dateTrunc("hour", Timestamp(998'474'645, 321'001'234)));
EXPECT_EQ(
Timestamp(998438400, 0),
dateTrunc("day", Timestamp(998'474'645, 321'001'234)));
EXPECT_EQ(
Timestamp(998265600, 0),
dateTrunc("week", Timestamp(998'474'645, 321'001'234)));
EXPECT_EQ(
Timestamp(996624000, 0),
dateTrunc("month", Timestamp(998'474'645, 321'001'234)));
EXPECT_EQ(
Timestamp(993945600, 0),
dateTrunc("quarter", Timestamp(998'474'645, 321'001'234)));
EXPECT_EQ(
Timestamp(978307200, 0),
dateTrunc("year", Timestamp(998'474'645, 321'001'234)));

setQueryTimeZone("America/Los_Angeles");

EXPECT_EQ(std::nullopt, dateTrunc("second", std::nullopt));
EXPECT_EQ(Timestamp(0, 0), dateTrunc("second", Timestamp(0, 0)));
EXPECT_EQ(Timestamp(0, 0), dateTrunc("second", Timestamp(0, 123)));
EXPECT_EQ(Timestamp(-57600, 0), dateTrunc("day", Timestamp(0, 0)));
EXPECT_EQ(
Timestamp(998474645, 0),
dateTrunc("second", Timestamp(998'474'645, 321'001'234)));
Expand All @@ -1530,6 +1564,9 @@ TEST_F(DateTimeFunctionsTest, dateTrunc) {
EXPECT_EQ(
Timestamp(998463600, 0),
dateTrunc("day", Timestamp(998'474'645, 321'001'234)));
EXPECT_EQ(
Timestamp(998290800, 0),
dateTrunc("week", Timestamp(998'474'645, 321'001'234)));
EXPECT_EQ(
Timestamp(996649200, 0),
dateTrunc("month", Timestamp(998'474'645, 321'001'234)));
Expand All @@ -1545,6 +1582,7 @@ TEST_F(DateTimeFunctionsTest, dateTrunc) {
EXPECT_EQ(std::nullopt, dateTrunc("second", std::nullopt));
EXPECT_EQ(Timestamp(0, 0), dateTrunc("second", Timestamp(0, 0)));
EXPECT_EQ(Timestamp(0, 0), dateTrunc("second", Timestamp(0, 123)));
EXPECT_EQ(Timestamp(-19800, 0), dateTrunc("day", Timestamp(0, 0)));
EXPECT_EQ(
Timestamp(998474645, 0),
dateTrunc("second", Timestamp(998'474'645, 321'001'234)));
Expand All @@ -1557,6 +1595,9 @@ TEST_F(DateTimeFunctionsTest, dateTrunc) {
EXPECT_EQ(
Timestamp(998418600, 0),
dateTrunc("day", Timestamp(998'474'645, 321'001'234)));
EXPECT_EQ(
Timestamp(998245800, 0),
dateTrunc("week", Timestamp(998'474'645, 321'001'234)));
EXPECT_EQ(
Timestamp(996604200, 0),
dateTrunc("month", Timestamp(998'474'645, 321'001'234)));
Expand Down

0 comments on commit 20069f9

Please sign in to comment.