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