From: Timur Safin via Tarantool-patches <tarantool-patches@dev.tarantool.org> To: v.shpilevoy@tarantool.org, imun@tarantool.org, imeevma@tarantool.org, tarantool-patches@dev.tarantool.org Subject: [Tarantool-patches] [PATCH v5 7/8] datetime: perf test for datetime parser Date: Mon, 16 Aug 2021 02:59:41 +0300 [thread overview] Message-ID: <a03695bdf38099ce1a5e5269d3f7b0ae72c1e4c9.1629071531.git.tsafin@tarantool.org> (raw) In-Reply-To: <cover.1629071531.git.tsafin@tarantool.org> It was told that if field `datetime.secs` would be `double` we should get better performance in LuaJIT instead of `uint64_t` type, which is used at the moment. So we have created benchmark, which was comparing implementations of functions from `datetime.c` if we would use `double` or `int64_t` for `datetime.secs` field. Despite expectations, based on prior experience with floaing-point on x86 processors, comparison shows that `double` provides similar or sometimes better timings. And picture stays consistent be it SSE2, AVX1 or AVX2 code. Part of #5941 --- perf/CMakeLists.txt | 3 + perf/datetime-common.h | 105 +++++++++++++++++++ perf/datetime-compare.cc | 213 +++++++++++++++++++++++++++++++++++++++ perf/datetime-parser.cc | 105 +++++++++++++++++++ 4 files changed, 426 insertions(+) create mode 100644 perf/datetime-common.h create mode 100644 perf/datetime-compare.cc create mode 100644 perf/datetime-parser.cc diff --git a/perf/CMakeLists.txt b/perf/CMakeLists.txt index 3651de5b4..b5d7caf81 100644 --- a/perf/CMakeLists.txt +++ b/perf/CMakeLists.txt @@ -12,3 +12,6 @@ include_directories(${CMAKE_SOURCE_DIR}/third_party) add_executable(tuple.perftest tuple.cc) target_link_libraries(tuple.perftest core box tuple benchmark::benchmark) + +add_executable(datetime.perftest datetime-parser.cc datetime-compare.cc) +target_link_libraries(datetime.perftest cdt core benchmark::benchmark) diff --git a/perf/datetime-common.h b/perf/datetime-common.h new file mode 100644 index 000000000..6fd4e1e3b --- /dev/null +++ b/perf/datetime-common.h @@ -0,0 +1,105 @@ +#include <assert.h> +#include <stdint.h> +#include <string.h> +#include <benchmark/benchmark.h> + +#include "dt.h" +#include "datetime.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static const char sample[] = "2012-12-24T15:30Z"; + +#define S(s) \ + { s, sizeof(s) - 1 } + +static struct +{ + const char *sz; + size_t len; +} tests[] = { + S("2012-12-24 15:30Z"), + S("2012-12-24 15:30z"), + S("2012-12-24 15:30"), + S("2012-12-24 16:30+01:00"), + S("2012-12-24 16:30+0100"), + S("2012-12-24 16:30+01"), + S("2012-12-24 14:30-01:00"), + S("2012-12-24 14:30-0100"), + S("2012-12-24 14:30-01"), + S("2012-12-24 15:30:00Z"), + S("2012-12-24 15:30:00z"), + S("2012-12-24 15:30:00"), + S("2012-12-24 16:30:00+01:00"), + S("2012-12-24 16:30:00+0100"), + S("2012-12-24 14:30:00-01:00"), + S("2012-12-24 14:30:00-0100"), + S("2012-12-24 15:30:00.123456Z"), + S("2012-12-24 15:30:00.123456z"), + S("2012-12-24 15:30:00.123456"), + S("2012-12-24 16:30:00.123456+01:00"), + S("2012-12-24 16:30:00.123456+01"), + S("2012-12-24 14:30:00.123456-01:00"), + S("2012-12-24 14:30:00.123456-01"), + S("2012-12-24t15:30Z"), + S("2012-12-24t15:30z"), + S("2012-12-24t15:30"), + S("2012-12-24t16:30+01:00"), + S("2012-12-24t16:30+0100"), + S("2012-12-24t14:30-01:00"), + S("2012-12-24t14:30-0100"), + S("2012-12-24t15:30:00Z"), + S("2012-12-24t15:30:00z"), + S("2012-12-24t15:30:00"), + S("2012-12-24t16:30:00+01:00"), + S("2012-12-24t16:30:00+0100"), + S("2012-12-24t14:30:00-01:00"), + S("2012-12-24t14:30:00-0100"), + S("2012-12-24t15:30:00.123456Z"), + S("2012-12-24t15:30:00.123456z"), + S("2012-12-24t16:30:00.123456+01:00"), + S("2012-12-24t14:30:00.123456-01:00"), + S("2012-12-24 16:30 +01:00"), + S("2012-12-24 14:30 -01:00"), + S("2012-12-24 15:30 UTC"), + S("2012-12-24 16:30 UTC+1"), + S("2012-12-24 16:30 UTC+01"), + S("2012-12-24 16:30 UTC+0100"), + S("2012-12-24 16:30 UTC+01:00"), + S("2012-12-24 14:30 UTC-1"), + S("2012-12-24 14:30 UTC-01"), + S("2012-12-24 14:30 UTC-01:00"), + S("2012-12-24 14:30 UTC-0100"), + S("2012-12-24 15:30 GMT"), + S("2012-12-24 16:30 GMT+1"), + S("2012-12-24 16:30 GMT+01"), + S("2012-12-24 16:30 GMT+0100"), + S("2012-12-24 16:30 GMT+01:00"), + S("2012-12-24 14:30 GMT-1"), + S("2012-12-24 14:30 GMT-01"), + S("2012-12-24 14:30 GMT-01:00"), + S("2012-12-24 14:30 GMT-0100"), + S("2012-12-24 14:30 -01:00"), + S("2012-12-24 16:30:00 +01:00"), + S("2012-12-24 14:30:00 -01:00"), + S("2012-12-24 16:30:00.123456 +01:00"), + S("2012-12-24 14:30:00.123456 -01:00"), + S("2012-12-24 15:30:00.123456 -00:00"), + S("20121224T1630+01:00"), + S("2012-12-24T1630+01:00"), + S("20121224T16:30+01"), + S("20121224T16:30 +01"), +}; +#undef S + +#define DIM(a) (sizeof(a) / sizeof(a[0])) + +int +parse_datetime(const char *str, size_t len, int64_t *sp, int32_t *np, + int32_t *op); + +#ifdef __cplusplus +} +#endif diff --git a/perf/datetime-compare.cc b/perf/datetime-compare.cc new file mode 100644 index 000000000..6e561a5eb --- /dev/null +++ b/perf/datetime-compare.cc @@ -0,0 +1,213 @@ +#include "dt.h" +#include <string.h> +#include <assert.h> +#include <limits.h> + +#include "datetime-common.h" + +template <typename T> +struct datetime_bench +{ + T secs; + uint32_t nsec; + uint32_t offset; + +static struct datetime_bench date_array[]; +}; +template<typename T> +struct datetime_bench<T> datetime_bench<T>::date_array[DIM(tests)]; + +/// Parse 70 datetime literals of various lengths +template <typename T> +static void +Assign70() +{ + size_t index; + int64_t secs_expected; + int nanosecs; + int ofs; + using dt_bench = datetime_bench<T>; + + for (index = 0; index < DIM(tests); index++) { + int64_t secs; + int rc = parse_datetime(tests[index].sz, tests[index].len, + &secs, &nanosecs, &ofs); + assert(rc == 0); + dt_bench::date_array[index].secs = (T)secs; + dt_bench::date_array[index].nsec = nanosecs; + dt_bench::date_array[index].offset = ofs; + } +} + +template <typename T> +static void +DateTime_Assign70(benchmark::State &state) +{ + for (auto _ : state) + Assign70<T>(); +} +BENCHMARK_TEMPLATE1(DateTime_Assign70, uint64_t); +BENCHMARK_TEMPLATE1(DateTime_Assign70, double); + +#define COMPARE_RESULT_BENCH(a, b) (a < b ? -1 : a > b) + +template <typename T> +int datetime_compare(const struct datetime_bench<T> *lhs, + const struct datetime_bench<T> *rhs) +{ + int result = COMPARE_RESULT_BENCH(lhs->secs, rhs->secs); + if (result != 0) + return result; + + return COMPARE_RESULT_BENCH(lhs->nsec, rhs->nsec); +} + +template <typename T> +static void +AssignCompare70() +{ + size_t index; + int nanosecs; + int ofs; + using dt_bench = datetime_bench<T>; + + size_t arrays_sz = DIM(tests); + for (index = 0; index < arrays_sz; index++) { + int64_t secs; + int rc = parse_datetime(tests[index].sz, tests[index].len, + &secs, &nanosecs, &ofs); + assert(rc == 0); + dt_bench::date_array[index].secs = (T)secs; + dt_bench::date_array[index].nsec = nanosecs; + dt_bench::date_array[index].offset = ofs; + } + + for (index = 0; index < (arrays_sz - 1); index++) { + volatile int rc = datetime_compare<T>(&dt_bench::date_array[index], + &dt_bench::date_array[index + 1]); + assert(rc == 0 || rc == -1 || rc == 1); + } +} + +template <typename T> +static void +DateTime_AssignCompare70(benchmark::State &state) +{ + for (auto _ : state) + AssignCompare70<T>(); +} +BENCHMARK_TEMPLATE1(DateTime_AssignCompare70, uint64_t); +BENCHMARK_TEMPLATE1(DateTime_AssignCompare70, double); + +template <typename T> +static void +Compare20() +{ + size_t index; + int nanosecs; + int ofs; + using dt_bench = datetime_bench<T>; + + for (size_t i = 0; i < 10; i++) { + volatile int rc = datetime_compare<T>(&dt_bench::date_array[i], + &dt_bench::date_array[32 + i]); + assert(rc == 0 || rc == -1 || rc == 1); + } +} + +template <typename T> +static void +DateTime_Compare20(benchmark::State &state) +{ + for (auto _ : state) + Compare20<T>(); +} +BENCHMARK_TEMPLATE1(DateTime_Compare20, uint64_t); +BENCHMARK_TEMPLATE1(DateTime_Compare20, double); + + +#define SECS_EPOCH_1970_OFFSET ((int64_t)DT_EPOCH_1970_OFFSET * SECS_PER_DAY) + +template<typename T> +int +datetime_to_string(const struct datetime_bench<T> *date, char *buf, uint32_t len) +{ +#define ADVANCE(sz) \ + if (buf != NULL) { \ + buf += sz; \ + len -= sz; \ + } \ + ret += sz; + + int offset = date->offset; + /* for negative offsets around Epoch date we could get + * negative secs value, which should be attributed to + * 1969-12-31, not 1970-01-01, thus we first shift + * epoch to Rata Die then divide by seconds per day, + * not in reverse + */ + int64_t secs = (int64_t)date->secs + offset * 60 + SECS_EPOCH_1970_OFFSET; + assert((secs / SECS_PER_DAY) <= INT_MAX); + dt_t dt = dt_from_rdn(secs / SECS_PER_DAY); + + int year, month, day, sec, ns, sign; + dt_to_ymd(dt, &year, &month, &day); + + int hour = (secs / 3600) % 24, + minute = (secs / 60) % 60; + sec = secs % 60; + ns = date->nsec; + + int ret = 0; + uint32_t sz = snprintf(buf, len, "%04d-%02d-%02dT%02d:%02d", + year, month, day, hour, minute); + ADVANCE(sz); + if (sec || ns) { + sz = snprintf(buf, len, ":%02d", sec); + ADVANCE(sz); + if (ns) { + if ((ns % 1000000) == 0) + sz = snprintf(buf, len, ".%03d", ns / 1000000); + else if ((ns % 1000) == 0) + sz = snprintf(buf, len, ".%06d", ns / 1000); + else + sz = snprintf(buf, len, ".%09d", ns); + ADVANCE(sz); + } + } + if (offset == 0) { + sz = snprintf(buf, len, "Z"); + ADVANCE(sz); + } + else { + if (offset < 0) + sign = '-', offset = -offset; + else + sign = '+'; + + sz = snprintf(buf, len, "%c%02d:%02d", sign, offset / 60, offset % 60); + ADVANCE(sz); + } + return ret; +} +#undef ADVANCE + +template <typename T> +static void +ToString1() +{ + char buf[48]; + struct datetime_bench<T> dateval = datetime_bench<T>::date_array[13]; + + volatile auto len = datetime_to_string<T>(&dateval, buf, sizeof buf); +} + +template <typename T> +static void +DateTime_ToString1(benchmark::State &state) +{ + for (auto _ : state) + ToString1<T>(); +} +BENCHMARK_TEMPLATE1(DateTime_ToString1, uint64_t); +BENCHMARK_TEMPLATE1(DateTime_ToString1, double); diff --git a/perf/datetime-parser.cc b/perf/datetime-parser.cc new file mode 100644 index 000000000..61557fe8f --- /dev/null +++ b/perf/datetime-parser.cc @@ -0,0 +1,105 @@ +#include "dt.h" +#include <string.h> +#include <assert.h> + +#include "datetime-common.h" + +/* p5-time-moment/src/moment_parse.c: parse_string_lenient() */ +int +parse_datetime(const char *str, size_t len, int64_t *sp, int32_t *np, + int32_t *op) +{ + size_t n; + dt_t dt; + char c; + int sod = 0, nanosecond = 0, offset = 0; + + n = dt_parse_iso_date(str, len, &dt); + if (!n) + return 1; + if (n == len) + goto exit; + + c = str[n++]; + if (!(c == 'T' || c == 't' || c == ' ')) + return 1; + + str += n; + len -= n; + + n = dt_parse_iso_time(str, len, &sod, &nanosecond); + if (!n) + return 1; + if (n == len) + goto exit; + + if (str[n] == ' ') + n++; + + str += n; + len -= n; + + n = dt_parse_iso_zone_lenient(str, len, &offset); + if (!n || n != len) + return 1; + +exit: + *sp = ((int64_t)dt_rdn(dt) - 719163) * 86400 + sod - offset * 60; + *np = nanosecond; + *op = offset; + + return 0; +} + +/// Parse 70 datetime literals of various lengths +static void +ParseTimeStamps() +{ + size_t index; + int64_t secs_expected; + int nanosecs; + int ofs; + parse_datetime(sample, sizeof(sample) - 1, &secs_expected, + &nanosecs, &ofs); + + for (index = 0; index < DIM(tests); index++) + { + int64_t secs; + int rc = parse_datetime(tests[index].sz, tests[index].len, + &secs, &nanosecs, &ofs); + assert(rc == 0); + assert(secs == secs_expected); + } +} + +static void +CDT_Parse70(benchmark::State &state) +{ + for (auto _ : state) + ParseTimeStamps(); +} +BENCHMARK(CDT_Parse70); + +/// Parse single datetime literal of longest length +static void +Parse1() +{ + const char civil_string[] = "2015-02-18T10:50:31.521345123+10:00"; + int64_t secs; + int nanosecs; + int ofs; + int rc = parse_datetime(civil_string, sizeof(civil_string) - 1, + &secs, &nanosecs, &ofs); + assert(rc == 0); + assert(nanosecs == 521345123); +} + +static void +CDT_Parse1(benchmark::State &state) +{ + for (auto _ : state) + Parse1(); +} +BENCHMARK(CDT_Parse1); + +BENCHMARK_MAIN(); -- 2.29.2
next prev parent reply other threads:[~2021-08-16 0:03 UTC|newest] Thread overview: 50+ messages / expand[flat|nested] mbox.gz Atom feed top 2021-08-15 23:59 [Tarantool-patches] [PATCH v5 0/8] Initial datetime implementation Timur Safin via Tarantool-patches 2021-08-15 23:59 ` [Tarantool-patches] [PATCH v5 1/8] build: add Christian Hansen c-dt to the build Timur Safin via Tarantool-patches 2021-08-17 12:15 ` Serge Petrenko via Tarantool-patches 2021-08-17 23:24 ` Safin Timur via Tarantool-patches 2021-08-18 8:56 ` Serge Petrenko via Tarantool-patches 2021-08-17 15:50 ` Vladimir Davydov via Tarantool-patches 2021-08-18 10:04 ` Safin Timur via Tarantool-patches 2021-08-15 23:59 ` [Tarantool-patches] [PATCH v5 2/8] lua: built-in module datetime Timur Safin via Tarantool-patches 2021-08-17 12:15 ` Serge Petrenko via Tarantool-patches 2021-08-17 23:30 ` Safin Timur via Tarantool-patches 2021-08-18 8:56 ` Serge Petrenko via Tarantool-patches 2021-08-17 16:52 ` Vladimir Davydov via Tarantool-patches 2021-08-17 19:16 ` Vladimir Davydov via Tarantool-patches 2021-08-18 13:38 ` Safin Timur via Tarantool-patches 2021-08-18 10:03 ` Safin Timur via Tarantool-patches 2021-08-18 10:06 ` Safin Timur via Tarantool-patches 2021-08-18 11:45 ` Vladimir Davydov via Tarantool-patches 2021-08-15 23:59 ` [Tarantool-patches] [PATCH v5 3/8] lua, datetime: display datetime Timur Safin via Tarantool-patches 2021-08-17 12:15 ` Serge Petrenko via Tarantool-patches 2021-08-17 23:32 ` Safin Timur via Tarantool-patches 2021-08-17 17:06 ` Vladimir Davydov via Tarantool-patches 2021-08-18 14:10 ` Safin Timur via Tarantool-patches 2021-08-15 23:59 ` [Tarantool-patches] [PATCH v5 4/8] box, datetime: messagepack support for datetime Timur Safin via Tarantool-patches 2021-08-16 0:20 ` Safin Timur via Tarantool-patches 2021-08-17 12:15 ` Serge Petrenko via Tarantool-patches 2021-08-17 12:16 ` Serge Petrenko via Tarantool-patches 2021-08-17 23:42 ` Safin Timur via Tarantool-patches 2021-08-18 9:01 ` Serge Petrenko via Tarantool-patches 2021-08-17 18:36 ` Vladimir Davydov via Tarantool-patches 2021-08-18 14:27 ` Safin Timur via Tarantool-patches 2021-08-15 23:59 ` [Tarantool-patches] [PATCH v5 5/8] box, datetime: datetime comparison for indices Timur Safin via Tarantool-patches 2021-08-17 12:16 ` Serge Petrenko via Tarantool-patches 2021-08-17 23:43 ` Safin Timur via Tarantool-patches 2021-08-18 9:03 ` Serge Petrenko via Tarantool-patches 2021-08-17 19:05 ` Vladimir Davydov via Tarantool-patches 2021-08-18 17:18 ` Safin Timur via Tarantool-patches 2021-08-15 23:59 ` [Tarantool-patches] [PATCH v5 6/8] lua, datetime: time intervals support Timur Safin via Tarantool-patches 2021-08-17 12:16 ` Serge Petrenko via Tarantool-patches 2021-08-17 23:44 ` Safin Timur via Tarantool-patches 2021-08-17 18:52 ` Vladimir Davydov via Tarantool-patches 2021-08-15 23:59 ` Timur Safin via Tarantool-patches [this message] 2021-08-17 19:13 ` [Tarantool-patches] [PATCH v5 7/8] datetime: perf test for datetime parser Vladimir Davydov via Tarantool-patches 2021-08-15 23:59 ` [Tarantool-patches] [PATCH v5 8/8] datetime: changelog for datetime module Timur Safin via Tarantool-patches 2021-08-17 12:16 ` Serge Petrenko via Tarantool-patches 2021-08-17 23:44 ` Safin Timur via Tarantool-patches 2021-08-18 9:04 ` Serge Petrenko via Tarantool-patches 2021-08-17 12:15 ` [Tarantool-patches] [PATCH v5 0/8] Initial datetime implementation Serge Petrenko via Tarantool-patches [not found] ` <20210818082222.mofgheciutpipelz@esperanza> 2021-08-18 8:25 ` Vladimir Davydov via Tarantool-patches 2021-08-18 13:24 ` Safin Timur via Tarantool-patches 2021-08-18 14:22 ` Vladimir Davydov via Tarantool-patches
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=a03695bdf38099ce1a5e5269d3f7b0ae72c1e4c9.1629071531.git.tsafin@tarantool.org \ --to=tarantool-patches@dev.tarantool.org \ --cc=imeevma@tarantool.org \ --cc=imun@tarantool.org \ --cc=tsafin@tarantool.org \ --cc=v.shpilevoy@tarantool.org \ --subject='Re: [Tarantool-patches] [PATCH v5 7/8] datetime: perf test for datetime parser' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox