From 2e114db5c96d27fbf5b4689e19baae1e5ba0d29b Mon Sep 17 00:00:00 2001 From: Dmitry Date: Fri, 15 Oct 2021 14:53:20 +0300 Subject: [PATCH] + bench_converter --- tests/bench_converter.py | 105 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 tests/bench_converter.py diff --git a/tests/bench_converter.py b/tests/bench_converter.py new file mode 100644 index 0000000..ae4bdd4 --- /dev/null +++ b/tests/bench_converter.py @@ -0,0 +1,105 @@ + +from typing import Iterable, List, Tuple, Union, Optional +from uuid import uuid4 +import datetime +from itertools import islice +from dataclasses import dataclass +import time +import statistics +import functools + +from sync_ics2gcal import CalendarConverter + + +@dataclass +class IcsTestEvent: + uid: str + start_date: Union[datetime.datetime, datetime.date] + end_date: Union[datetime.datetime, datetime.date, None] = None + duration: Optional[datetime.timedelta] = None + created: Union[datetime.datetime, datetime.date, None] = None + updated: Union[datetime.datetime, datetime.date, None] = None + + @staticmethod + def _format_datetime(value: Union[datetime.datetime, datetime.date]): + result: str = '' + if isinstance(value, datetime.datetime): + result += f'DATE-TIME:{value.strftime("%Y%m%dT%H%M%SZ")}' + else: + result += f'DATE:{value.strftime("%Y%m%d")}' + return result + + def render(self) -> str: + result: str = '' + result += 'BEGIN:VEVENT\r\n' + result += f'UID:{self.uid}\r\n' + result += f'DTSTART;VALUE={IcsTestEvent._format_datetime(self.start_date)}\r\n' + if self.end_date is not None: + result += f'DTEND;VALUE={IcsTestEvent._format_datetime(self.end_date)}\r\n' + else: + result += f'DURATION:P{self.duration.days}D\r\n' + if self.created is not None: + result += f'CREATED:{self.created.strftime("%Y%m%dT%H%M%SZ")}\r\n' + if self.updated is not None: + result += f'LAST-MODIFIED:{self.updated.strftime("%Y%m%dT%H%M%SZ")}\r\n' + result += 'END:VEVENT\r\n' + return result + + +@dataclass +class IcsTestCalendar: + events: List[IcsTestEvent] + + def render(self) -> str: + result: str = '' + result += 'BEGIN:VCALENDAR\r\n' + for event in self.events: + result += event.render() + result += 'END:VCALENDAR\r\n' + return result + + +def gen_test_calendar(events_count: int) -> IcsTestCalendar: + def gen_events() -> Iterable[IcsTestEvent]: + for i in range(10000000): + uid = f'{uuid4()}@test.com' + start_date = datetime.datetime.now() + datetime.timedelta(hours=i) + end_date = start_date + datetime.timedelta(hours=1) + event: IcsTestEvent = IcsTestEvent( + uid=uid, start_date=start_date, end_date=end_date, created=start_date, updated=start_date) + yield event + + events: List[IcsTestEvent] = list(islice(gen_events(), events_count)) + result: IcsTestCalendar = IcsTestCalendar(events) + return result + + +test_calendar: IcsTestCalendar = gen_test_calendar(1000) +ics_test_calendar: str = test_calendar.render() +converter = CalendarConverter() +converter.loads(ics_test_calendar) + + +def bench(num_iters=1000): + def make_wrapper(func): + @functools.wraps(func) + def wrapper(*args, **kw): + times = [] + for _ in range(num_iters): + t0 = time.perf_counter_ns() + result = func(*args, **kw) + t1 = time.perf_counter_ns() + times.append(t1 - t0) + best = min(times) + avg = round(sum(times) / num_iters, 2) + median = statistics.median(times) + print( + f'{func.__name__} x {num_iters} => best: {best} ns, \tavg: {avg} ns, \tmedian: {median} ns') + return result + return wrapper() + return make_wrapper + + +@bench(num_iters=500) +def events_to_gcal(): + converter.events_to_gcal()