From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id E41BC6EC40; Thu, 19 Aug 2021 13:20:05 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org E41BC6EC40 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1629368406; bh=oL+k1BJFqQXw/cH2BrWkSe/O+JMnxiAfhsIf3z05GMI=; h=To:References:Date:In-Reply-To:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=KEmkIm/NYVkHdML8MKhS6NuzsNFRbWJlStTq1RIBdGJZU4GWmJ9XygH5E2jeK+e6o 4cJPFeDcDnofZOLPsa5D45Cwbw0pc4Bu7yVPq1EMMT9ORc1j0unP5hLFWbc7DwgM0b KLasGbFCoPLXhowVebaxS9xo8Kqiqzu6RPAQA/u4= Received: from smtp3.mail.ru (smtp3.mail.ru [94.100.179.58]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id A95756EC40 for ; Thu, 19 Aug 2021 13:20:01 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org A95756EC40 Received: by smtp3.mail.ru with esmtpa (envelope-from ) id 1mGf9T-0005hA-MM; Thu, 19 Aug 2021 13:20:00 +0300 To: Timur Safin , vdavydov@tarantool.org, tarantool-patches@dev.tarantool.org References: Message-ID: <82319534-df35-ceb6-ee22-cb4cbaff5e41@tarantool.org> Date: Thu, 19 Aug 2021 13:19:59 +0300 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:78.0) Gecko/20100101 Thunderbird/78.13.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit Content-Language: en-GB X-4EC0790: 10 X-7564579A: B8F34718100C35BD X-77F55803: 4F1203BC0FB41BD92087353F0EC44DD9D5AC6413C25DCF08CC98B8FCC5CD86F3182A05F538085040E820A5F865C309CE640DAA08485CAFA321837BFFF507A0A9F5026BBB6AF2F146 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE711269A7C2F827F16EA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F79006378629C75C8EFA8C148638F802B75D45FF36EB9D2243A4F8B5A6FCA7DBDB1FC311F39EFFDF887939037866D6147AF826D8AC490D9C0C1E65192D4BE6A60EF2C583117882F4460429724CE54428C33FAD305F5C1EE8F4F765FCAA867293B0326636D2E47CDBA5A96583BD4B6F7A4D31EC0BC014FD901B82EE079FA2833FD35BB23D27C277FBC8AE2E8BAA867293B0326636D2E47CDBA5A96583BA9C0B312567BB231DD303D21008E29813377AFFFEAFD269A417C69337E82CC2E827F84554CEF50127C277FBC8AE2E8BA83251EDC214901ED5E8D9A59859A8B60A9A04DE7321024275ECD9A6C639B01B4E70A05D1297E1BBCB5012B2E24CD356 X-C1DE0DAB: 0D63561A33F958A58F70B615FDD201D6B2A37EAFCAF45311D92FFD42EA589D24D59269BC5F550898D99A6476B3ADF6B47008B74DF8BB9EF7333BD3B22AA88B938A852937E12ACA758B25CD4253D1D611410CA545F18667F91A7EA1CDA0B5A7A0 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D3483E1FCD56FEA62E6F260A90B58EFFC9F1DFBBA8AD9CBC4589D79752B159B028319483ED66786DD011D7E09C32AA3244C21FFE2476F840C91C229A43CD5EE23D4853296C06374E602DCA3B3C10BC03908 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2biojGSxK+6r6oBGuxJWasb3r7Q== X-Mailru-Sender: 3B9A0136629DC9125D61937A2360A446A1DAC65E55A1E00BEFCAEF6E8831FF6A6967BCE13AB6E3CC424AE0EB1F3D1D21E2978F233C3FAE6EE63DB1732555E4A8EE80603BA4A5B0BC112434F685709FCF0DA7A0AF5A3A8387 X-Mras: Ok Subject: Re: [Tarantool-patches] [PATCH v6 4/5] datetime: perf test for datetime parser X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Serge Petrenko via Tarantool-patches Reply-To: Serge Petrenko Cc: v.shpilevoy@tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" 19.08.2021 05:56, Timur Safin пишет: > 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 > --- I agree with Vladimir here. Looks like this perf test doesn't belong to Tarantool repository. Would you mind dropping it? > 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 > +#include > +#include > +#include > + > +#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..5096eb987 > --- /dev/null > +++ b/perf/datetime-compare.cc > @@ -0,0 +1,213 @@ > +#include "dt.h" > +#include > +#include > +#include > + > +#include "datetime-common.h" > + > +template > +struct datetime_bench > +{ > + T secs; > + uint32_t nsec; > + uint32_t offset; > + > +static struct datetime_bench date_array[]; > +}; > +template > +struct datetime_bench datetime_bench::date_array[DIM(tests)]; > + > +/// Parse 70 datetime literals of various lengths > +template > +static void > +Assign70() > +{ > + size_t index; > + int64_t secs_expected; > + int nanosecs; > + int ofs; > + using dt_bench = datetime_bench; > + > + 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 > +static void > +DateTime_Assign70(benchmark::State &state) > +{ > + for (auto _ : state) > + Assign70(); > +} > +BENCHMARK_TEMPLATE1(DateTime_Assign70, uint64_t); > +BENCHMARK_TEMPLATE1(DateTime_Assign70, double); > + > +#define COMPARE_RESULT_BENCH(a, b) (a < b ? -1 : a > b) > + > +template > +int datetime_compare(const struct datetime_bench *lhs, > + const struct datetime_bench *rhs) > +{ > + int result = COMPARE_RESULT_BENCH(lhs->secs, rhs->secs); > + if (result != 0) > + return result; > + > + return COMPARE_RESULT_BENCH(lhs->nsec, rhs->nsec); > +} > + > +template > +static void > +AssignCompare70() > +{ > + size_t index; > + int nanosecs; > + int ofs; > + using dt_bench = datetime_bench; > + > + 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(&dt_bench::date_array[index], > + &dt_bench::date_array[index + 1]); > + assert(rc == 0 || rc == -1 || rc == 1); > + } > +} > + > +template > +static void > +DateTime_AssignCompare70(benchmark::State &state) > +{ > + for (auto _ : state) > + AssignCompare70(); > +} > +BENCHMARK_TEMPLATE1(DateTime_AssignCompare70, uint64_t); > +BENCHMARK_TEMPLATE1(DateTime_AssignCompare70, double); > + > +template > +static void > +Compare20() > +{ > + size_t index; > + int nanosecs; > + int ofs; > + using dt_bench = datetime_bench; > + > + for (size_t i = 0; i < 10; i++) { > + volatile int rc = datetime_compare(&dt_bench::date_array[i], > + &dt_bench::date_array[32 + i]); > + assert(rc == 0 || rc == -1 || rc == 1); > + } > +} > + > +template > +static void > +DateTime_Compare20(benchmark::State &state) > +{ > + for (auto _ : state) > + Compare20(); > +} > +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 > +int > +datetime_to_string(const struct datetime_bench *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 > +static void > +ToString1() > +{ > + char buf[48]; > + struct datetime_bench dateval = datetime_bench::date_array[13]; > + > + volatile auto len = datetime_to_string(&dateval, buf, sizeof(buf)); > +} > + > +template > +static void > +DateTime_ToString1(benchmark::State &state) > +{ > + for (auto _ : state) > + ToString1(); > +} > +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 > +#include > + > +#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(); -- Serge Petrenko