From aae284943ea66be3c9a6a2b5f87dad11dec363ce Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Thu, 27 Feb 2025 17:46:42 -0800 Subject: [PATCH 1/4] Use benchmarks from pyperformance as PGO task. --- Lib/test/pgo_task/__init__.py | 25 + Lib/test/pgo_task/__main__.py | 29 + Lib/test/pgo_task/bm_argparse.py | 119 ++++ Lib/test/pgo_task/bm_async_generators.py | 42 ++ Lib/test/pgo_task/bm_bpe_tokeniser.py | 150 ++++ Lib/test/pgo_task/bm_chaos.py | 290 ++++++++ Lib/test/pgo_task/bm_comprehensions.py | 89 +++ Lib/test/pgo_task/bm_coroutines.py | 26 + Lib/test/pgo_task/bm_decimal_factorial.py | 43 ++ Lib/test/pgo_task/bm_decimal_pi.py | 44 ++ Lib/test/pgo_task/bm_deepcopy.py | 74 ++ Lib/test/pgo_task/bm_deltablue.py | 631 +++++++++++++++++ Lib/test/pgo_task/bm_fannkuch.py | 51 ++ Lib/test/pgo_task/bm_float.py | 56 ++ Lib/test/pgo_task/bm_gc_collect.py | 59 ++ Lib/test/pgo_task/bm_gc_traversal.py | 30 + Lib/test/pgo_task/bm_generators.py | 43 ++ Lib/test/pgo_task/bm_go.py | 453 ++++++++++++ Lib/test/pgo_task/bm_hexiom.py | 643 ++++++++++++++++++ Lib/test/pgo_task/bm_json_dumps.py | 31 + Lib/test/pgo_task/bm_json_loads.py | 101 +++ Lib/test/pgo_task/bm_logging.py | 129 ++++ Lib/test/pgo_task/bm_mdp.py | 259 +++++++ Lib/test/pgo_task/bm_meteor_contest.py | 212 ++++++ Lib/test/pgo_task/bm_nbody.py | 135 ++++ Lib/test/pgo_task/bm_nqueens.py | 57 ++ Lib/test/pgo_task/bm_pathlib.py | 68 ++ Lib/test/pgo_task/bm_pickle.py | 244 +++++++ Lib/test/pgo_task/bm_pidigits.py | 53 ++ Lib/test/pgo_task/bm_pprint.py | 18 + Lib/test/pgo_task/bm_raytrace.py | 379 +++++++++++ Lib/test/pgo_task/bm_regex_effbot.py | 159 +++++ Lib/test/pgo_task/bm_richards.py | 418 ++++++++++++ Lib/test/pgo_task/bm_richards_super.py | 424 ++++++++++++ Lib/test/pgo_task/bm_scimark.py | 395 +++++++++++ Lib/test/pgo_task/bm_spectral_norm.py | 68 ++ Lib/test/pgo_task/bm_sqlite_synth.py | 49 ++ Lib/test/pgo_task/bm_telco.py | 116 ++++ .../pgo_task/bm_typing_runtime_protocols.py | 168 +++++ Lib/test/pgo_task/bm_unpack_sequence.py | 132 ++++ Lib/test/pgo_task/bm_var_access.py | 284 ++++++++ Lib/test/pgo_task/data/frankenstein_intro.txt | 25 + configure | 2 +- configure.ac | 2 +- 44 files changed, 6823 insertions(+), 2 deletions(-) create mode 100644 Lib/test/pgo_task/__init__.py create mode 100644 Lib/test/pgo_task/__main__.py create mode 100644 Lib/test/pgo_task/bm_argparse.py create mode 100644 Lib/test/pgo_task/bm_async_generators.py create mode 100644 Lib/test/pgo_task/bm_bpe_tokeniser.py create mode 100644 Lib/test/pgo_task/bm_chaos.py create mode 100644 Lib/test/pgo_task/bm_comprehensions.py create mode 100644 Lib/test/pgo_task/bm_coroutines.py create mode 100644 Lib/test/pgo_task/bm_decimal_factorial.py create mode 100644 Lib/test/pgo_task/bm_decimal_pi.py create mode 100644 Lib/test/pgo_task/bm_deepcopy.py create mode 100644 Lib/test/pgo_task/bm_deltablue.py create mode 100644 Lib/test/pgo_task/bm_fannkuch.py create mode 100644 Lib/test/pgo_task/bm_float.py create mode 100644 Lib/test/pgo_task/bm_gc_collect.py create mode 100644 Lib/test/pgo_task/bm_gc_traversal.py create mode 100644 Lib/test/pgo_task/bm_generators.py create mode 100644 Lib/test/pgo_task/bm_go.py create mode 100644 Lib/test/pgo_task/bm_hexiom.py create mode 100644 Lib/test/pgo_task/bm_json_dumps.py create mode 100644 Lib/test/pgo_task/bm_json_loads.py create mode 100644 Lib/test/pgo_task/bm_logging.py create mode 100644 Lib/test/pgo_task/bm_mdp.py create mode 100644 Lib/test/pgo_task/bm_meteor_contest.py create mode 100644 Lib/test/pgo_task/bm_nbody.py create mode 100644 Lib/test/pgo_task/bm_nqueens.py create mode 100644 Lib/test/pgo_task/bm_pathlib.py create mode 100644 Lib/test/pgo_task/bm_pickle.py create mode 100644 Lib/test/pgo_task/bm_pidigits.py create mode 100644 Lib/test/pgo_task/bm_pprint.py create mode 100644 Lib/test/pgo_task/bm_raytrace.py create mode 100644 Lib/test/pgo_task/bm_regex_effbot.py create mode 100644 Lib/test/pgo_task/bm_richards.py create mode 100644 Lib/test/pgo_task/bm_richards_super.py create mode 100644 Lib/test/pgo_task/bm_scimark.py create mode 100644 Lib/test/pgo_task/bm_spectral_norm.py create mode 100644 Lib/test/pgo_task/bm_sqlite_synth.py create mode 100644 Lib/test/pgo_task/bm_telco.py create mode 100644 Lib/test/pgo_task/bm_typing_runtime_protocols.py create mode 100644 Lib/test/pgo_task/bm_unpack_sequence.py create mode 100644 Lib/test/pgo_task/bm_var_access.py create mode 100644 Lib/test/pgo_task/data/frankenstein_intro.txt diff --git a/Lib/test/pgo_task/__init__.py b/Lib/test/pgo_task/__init__.py new file mode 100644 index 00000000000000..f52caad9034f6b --- /dev/null +++ b/Lib/test/pgo_task/__init__.py @@ -0,0 +1,25 @@ +# Most of the bm_*.py files are based on the corresponding benchmark from the +# "pyperformance" project. They have been slightly modified to be better +# suited as a PGO task. The pyperformance code is licensed under the terms +# stated below. +# +# The MIT License +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. diff --git a/Lib/test/pgo_task/__main__.py b/Lib/test/pgo_task/__main__.py new file mode 100644 index 00000000000000..475adf746de89b --- /dev/null +++ b/Lib/test/pgo_task/__main__.py @@ -0,0 +1,29 @@ +import glob +import importlib +import os +import time + + +def main(): + tasks = [] + package_dir = os.path.dirname(__file__) + for fn in glob.glob(os.path.join(package_dir, 'bm_*.py')): + tasks.append(fn) + total_time = 0 + for fn in sorted(tasks): + name, ext = os.path.splitext(os.path.basename(fn)) + module = importlib.import_module(f'test.pgo_task.{name}') + if not hasattr(module, 'run_pgo'): + print('missing run_pgo', fn) + continue + t0 = time.perf_counter() + print('Running task', name, end='...') + module.run_pgo() + tm = time.perf_counter() - t0 + total_time += tm + print(f' {tm:.3f} seconds.') + print(f'Total time for tasks {total_time:.3f} seconds') + + +if __name__ == '__main__': + main() diff --git a/Lib/test/pgo_task/bm_argparse.py b/Lib/test/pgo_task/bm_argparse.py new file mode 100644 index 00000000000000..bdb8b66c2d2ccb --- /dev/null +++ b/Lib/test/pgo_task/bm_argparse.py @@ -0,0 +1,119 @@ +""" +Benchmark argparse programs with: +1) multiple subparsers, each with their own subcommands, and then parse a series of command-line arguments. +2) a large number of optional arguments, and then parse a series of command-line arguments. + +Author: Savannah Ostrowski +""" + +import argparse + + +def generate_arguments(i: int) -> list: + arguments = ["input.txt", "output.txt"] + for i in range(i): + arguments.extend([f"--option{i}", f"value{i}"]) + return arguments + + +def bm_many_optionals() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description="A version control system CLI") + + parser.add_argument("--version", action="version", version="1.0") + + subparsers = parser.add_subparsers(dest="command", required=True) + + add_parser = subparsers.add_parser("add", help="Add a file to the repository") + add_parser.add_argument("files", nargs="+", help="List of files to add to staging") + + commit_parser = subparsers.add_parser( + "commit", help="Commit changes to the repository" + ) + commit_parser.add_argument("-m", "--message", required=True, help="Commit message") + + commit_group = commit_parser.add_mutually_exclusive_group(required=False) + commit_group.add_argument( + "--amend", action="store_true", help="Amend the last commit" + ) + commit_group.add_argument( + "--no-edit", action="store_true", help="Reuse the last commit message" + ) + + push_parser = subparsers.add_parser( + "push", help="Push changes to remote repository" + ) + + network_group = push_parser.add_argument_group("Network options") + network_group.add_argument("--dryrun", action="store_true", help="Simulate changes") + network_group.add_argument( + "--timeout", type=int, default=30, help="Timeout in seconds" + ) + + auth_group = push_parser.add_argument_group("Authentication options") + auth_group.add_argument( + "--username", required=True, help="Username for authentication" + ) + auth_group.add_argument( + "--password", required=True, help="Password for authentication" + ) + + global_group = parser.add_mutually_exclusive_group() + global_group.add_argument("--verbose", action="store_true", help="Verbose output") + global_group.add_argument("--quiet", action="store_true", help="Quiet output") + + argument_lists = [ + ["--verbose", "add", "file1.txt", "file2.txt"], + ["add", "file1.txt", "file2.txt"], + ["commit", "-m", "Initial commit"], + ["commit", "-m", "Add new feature", "--amend"], + [ + "push", + "--dryrun", + "--timeout", + "60", + "--username", + "user", + "--password", + "pass", + ], + ] + + for arguments in argument_lists: + parser.parse_args(arguments) + + +def bm_subparsers() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser() + + parser.add_argument("input_file", type=str, help="The input file") + parser.add_argument("output_file", type=str, help="The output file") + + for i in range(1000): + parser.add_argument(f"--option{i}", type=str, help=f"Optional argument {i}") + + argument_lists = [ + generate_arguments(500), + generate_arguments(1000), + ] + + for args in argument_lists: + parser.parse_args(args) + + +BENCHMARKS = { + "many_optionals": bm_many_optionals, + "subparsers": bm_subparsers, +} + + +def add_cmdline_args(cmd, args): + cmd.append(args.benchmark) + + +def add_parser_args(parser): + parser.add_argument("benchmark", choices=BENCHMARKS, help="Which benchmark to run.") + + +def run_pgo(): + for bm, func in BENCHMARKS.items(): + func() diff --git a/Lib/test/pgo_task/bm_async_generators.py b/Lib/test/pgo_task/bm_async_generators.py new file mode 100644 index 00000000000000..9e229cb5fe4496 --- /dev/null +++ b/Lib/test/pgo_task/bm_async_generators.py @@ -0,0 +1,42 @@ +""" +Benchmark recursive async generators implemented in python +by traversing a binary tree. + +Author: Kumar Aditya +""" + +from __future__ import annotations + +from collections.abc import AsyncIterator + + +class Tree: + def __init__(self, left: Tree | None, value: int, right: Tree | None) -> None: + self.left = left + self.value = value + self.right = right + + async def __aiter__(self) -> AsyncIterator[int]: + if self.left: + async for i in self.left: + yield i + yield self.value + if self.right: + async for i in self.right: + yield i + + +def tree(input: range) -> Tree | None: + n = len(input) + if n == 0: + return None + i = n // 2 + return Tree(tree(input[:i]), input[i], tree(input[i + 1:])) + +async def bench_async_generators(loops=100000) -> None: + async for _ in tree(range(loops)): + pass + +def run_pgo(): + import asyncio + asyncio.run(bench_async_generators(1000)) diff --git a/Lib/test/pgo_task/bm_bpe_tokeniser.py b/Lib/test/pgo_task/bm_bpe_tokeniser.py new file mode 100644 index 00000000000000..65f52da2c42d39 --- /dev/null +++ b/Lib/test/pgo_task/bm_bpe_tokeniser.py @@ -0,0 +1,150 @@ +""" +Benchmark a BPE tokeniser. + +Author: Shantanu Jain + +Based on code from tiktoken. +https://github.com/openai/tiktoken +""" +from __future__ import annotations + +import collections +import re +from pathlib import Path + + +class SimpleBytePairEncoding: + def __init__(self, *, pat_str: str, mergeable_ranks: dict[bytes, int]) -> None: + self.pat_str = pat_str + self.mergeable_ranks = mergeable_ranks + + self._decoder = {token: token_bytes for token_bytes, token in mergeable_ranks.items()} + self._pat = re.compile(pat_str) + + def encode(self, text: str) -> list[int]: + # Use the regex to split the text into (approximately) words + words = self._pat.findall(text) + tokens = [] + for word in words: + # Turn each word into tokens, using the byte pair encoding algorithm + word_bytes = word.encode("utf-8") + word_tokens = bpe_encode(self.mergeable_ranks, word_bytes) + tokens.extend(word_tokens) + return tokens + + def decode_bytes(self, tokens: list[int]) -> bytes: + return b"".join(self._decoder[token] for token in tokens) + + def decode(self, tokens: list[int]) -> str: + return self.decode_bytes(tokens).decode("utf-8", errors="replace") + + @staticmethod + def train(training_data: str, vocab_size: int, pat_str: str): + mergeable_ranks = bpe_train(data=training_data, vocab_size=vocab_size, pat_str=pat_str) + return SimpleBytePairEncoding(pat_str=pat_str, mergeable_ranks=mergeable_ranks) + + +def bpe_encode(mergeable_ranks: dict[bytes, int], input: bytes) -> list[int]: + # A simple, uncached, quadratic BPE + parts = [bytes([b]) for b in input] + while True: + # Iterate over all pairs and find the pair we want to merge the most + min_idx = None + min_rank = None + for i, pair in enumerate(zip(parts[:-1], parts[1:])): + rank = mergeable_ranks.get(pair[0] + pair[1]) + if rank is not None and (min_rank is None or rank < min_rank): + min_idx = i + min_rank = rank + + # If there were no pairs we could merge, we're done! + if min_rank is None: + break + assert min_idx is not None + + # Otherwise, merge that pair and leave the rest unchanged. Then repeat. + parts = parts[:min_idx] + [parts[min_idx] + parts[min_idx + 1]] + parts[min_idx + 2 :] + + tokens = [mergeable_ranks[part] for part in parts] + return tokens + + +def bpe_train(data: str, vocab_size: int, pat_str: str) -> dict[bytes, int]: + # First, add tokens for each individual byte value + if vocab_size < 2**8: + raise ValueError("vocab_size must be at least 256, so we can encode all bytes") + ranks = {} + for i in range(2**8): + ranks[bytes([i])] = i + + # Splinter up our data into lists of bytes + # data = "Hello world" + # words = [ + # [b'H', b'e', b'l', b'l', b'o'], + # [b' ', b'w', b'o', b'r', b'l', b'd'] + # ] + words: list[list[bytes]] = [ + [bytes([b]) for b in word.encode("utf-8")] for word in re.findall(pat_str, data) + ] + + # Now, use our data to figure out which merges we should make + while len(ranks) < vocab_size: + # Find the most common pair. This will become our next token + stats = collections.Counter() + for piece in words: + for pair in zip(piece[:-1], piece[1:]): + stats[pair] += 1 + + most_common_pair = max(stats, key=lambda x: stats[x]) + token_bytes = most_common_pair[0] + most_common_pair[1] + token = len(ranks) + # Add the new token! + ranks[token_bytes] = token + + # Now merge that most common pair in all the words. That is, update our training data + # to reflect our decision to make that pair into a new token. + new_words = [] + for word in words: + new_word = [] + i = 0 + while i < len(word) - 1: + if (word[i], word[i + 1]) == most_common_pair: + # We found our pair! Merge it + new_word.append(token_bytes) + i += 2 + else: + new_word.append(word[i]) + i += 1 + if i == len(word) - 1: + new_word.append(word[i]) + new_words.append(new_word) + words = new_words + + return ranks + + +def train(data: str): + pattern = ( + r"""'s|'t|'re|'ve|'m|'ll|'d| ?[a-zA-Z]+| ?\d+| ?[^\sa-zA-Z\d]+|\s+(?!\S)|\s+""" + ) + enc = SimpleBytePairEncoding.train(data, vocab_size=1024, pat_str=pattern) + + tokens = enc.encode("hello world") + assert enc.decode(tokens) == "hello world" + + enc.encode(data) + + +def bench_bpe_tokeniser(loops: int) -> float: + DATA = Path(__file__).parent / "data" / "frankenstein_intro.txt" + with open(DATA, "r", encoding="utf8") as f: + data = f.read() + + range_it = range(loops) + + for _ in range_it: + train(data) + + +def run_pgo(): + bench_bpe_tokeniser(1) diff --git a/Lib/test/pgo_task/bm_chaos.py b/Lib/test/pgo_task/bm_chaos.py new file mode 100644 index 00000000000000..635c9379e53904 --- /dev/null +++ b/Lib/test/pgo_task/bm_chaos.py @@ -0,0 +1,290 @@ +"""create chaosgame-like fractals + +Copyright (C) 2005 Carl Friedrich Bolz +""" + +import math +import random + + +DEFAULT_THICKNESS = 0.25 +DEFAULT_WIDTH = 256 +DEFAULT_HEIGHT = 256 +DEFAULT_ITERATIONS = 5000 +DEFAULT_RNG_SEED = 1234 + + +class GVector(object): + + def __init__(self, x=0, y=0, z=0): + self.x = x + self.y = y + self.z = z + + def Mag(self): + return math.sqrt(self.x ** 2 + self.y ** 2 + self.z ** 2) + + def dist(self, other): + return math.sqrt((self.x - other.x) ** 2 + + (self.y - other.y) ** 2 + + (self.z - other.z) ** 2) + + def __add__(self, other): + if not isinstance(other, GVector): + raise ValueError("Can't add GVector to " + str(type(other))) + v = GVector(self.x + other.x, self.y + other.y, self.z + other.z) + return v + + def __sub__(self, other): + return self + other * -1 + + def __mul__(self, other): + v = GVector(self.x * other, self.y * other, self.z * other) + return v + __rmul__ = __mul__ + + def linear_combination(self, other, l1, l2=None): + if l2 is None: + l2 = 1 - l1 + v = GVector(self.x * l1 + other.x * l2, + self.y * l1 + other.y * l2, + self.z * l1 + other.z * l2) + return v + + def __str__(self): + return "<%f, %f, %f>" % (self.x, self.y, self.z) + + def __repr__(self): + return "GVector(%f, %f, %f)" % (self.x, self.y, self.z) + + +class Spline(object): + """Class for representing B-Splines and NURBS of arbitrary degree""" + + def __init__(self, points, degree, knots): + """Creates a Spline. + + points is a list of GVector, degree is the degree of the Spline. + """ + if len(points) > len(knots) - degree + 1: + raise ValueError("too many control points") + elif len(points) < len(knots) - degree + 1: + raise ValueError("not enough control points") + last = knots[0] + for cur in knots[1:]: + if cur < last: + raise ValueError("knots not strictly increasing") + last = cur + self.knots = knots + self.points = points + self.degree = degree + + def GetDomain(self): + """Returns the domain of the B-Spline""" + return (self.knots[self.degree - 1], + self.knots[len(self.knots) - self.degree]) + + def __call__(self, u): + """Calculates a point of the B-Spline using de Boors Algorithm""" + dom = self.GetDomain() + if u < dom[0] or u > dom[1]: + raise ValueError("Function value not in domain") + if u == dom[0]: + return self.points[0] + if u == dom[1]: + return self.points[-1] + I = self.GetIndex(u) + d = [self.points[I - self.degree + 1 + ii] + for ii in range(self.degree + 1)] + U = self.knots + for ik in range(1, self.degree + 1): + for ii in range(I - self.degree + ik + 1, I + 2): + ua = U[ii + self.degree - ik] + ub = U[ii - 1] + co1 = (ua - u) / (ua - ub) + co2 = (u - ub) / (ua - ub) + index = ii - I + self.degree - ik - 1 + d[index] = d[index].linear_combination(d[index + 1], co1, co2) + return d[0] + + def GetIndex(self, u): + dom = self.GetDomain() + for ii in range(self.degree - 1, len(self.knots) - self.degree): + if u >= self.knots[ii] and u < self.knots[ii + 1]: + I = ii + break + else: + I = dom[1] - 1 + return I + + def __len__(self): + return len(self.points) + + def __repr__(self): + return "Spline(%r, %r, %r)" % (self.points, self.degree, self.knots) + + +def write_ppm(im, filename): + magic = 'P6\n' + maxval = 255 + w = len(im) + h = len(im[0]) + + with open(filename, "w", encoding="latin1", newline='') as fp: + fp.write(magic) + fp.write('%i %i\n%i\n' % (w, h, maxval)) + for j in range(h): + for i in range(w): + val = im[i][j] + c = val * 255 + fp.write('%c%c%c' % (c, c, c)) + + +class Chaosgame(object): + + def __init__(self, splines, thickness=0.1): + self.splines = splines + self.thickness = thickness + self.minx = min([p.x for spl in splines for p in spl.points]) + self.miny = min([p.y for spl in splines for p in spl.points]) + self.maxx = max([p.x for spl in splines for p in spl.points]) + self.maxy = max([p.y for spl in splines for p in spl.points]) + self.height = self.maxy - self.miny + self.width = self.maxx - self.minx + self.num_trafos = [] + maxlength = thickness * self.width / self.height + for spl in splines: + length = 0 + curr = spl(0) + for i in range(1, 1000): + last = curr + t = 1 / 999 * i + curr = spl(t) + length += curr.dist(last) + self.num_trafos.append(max(1, int(length / maxlength * 1.5))) + self.num_total = sum(self.num_trafos) + + def get_random_trafo(self): + r = random.randrange(int(self.num_total) + 1) + l = 0 + for i in range(len(self.num_trafos)): + if r >= l and r < l + self.num_trafos[i]: + return i, random.randrange(self.num_trafos[i]) + l += self.num_trafos[i] + return len(self.num_trafos) - 1, random.randrange(self.num_trafos[-1]) + + def transform_point(self, point, trafo=None): + x = (point.x - self.minx) / self.width + y = (point.y - self.miny) / self.height + if trafo is None: + trafo = self.get_random_trafo() + start, end = self.splines[trafo[0]].GetDomain() + length = end - start + seg_length = length / self.num_trafos[trafo[0]] + t = start + seg_length * trafo[1] + seg_length * x + basepoint = self.splines[trafo[0]](t) + if t + 1 / 50000 > end: + neighbour = self.splines[trafo[0]](t - 1 / 50000) + derivative = neighbour - basepoint + else: + neighbour = self.splines[trafo[0]](t + 1 / 50000) + derivative = basepoint - neighbour + if derivative.Mag() != 0: + basepoint.x += derivative.y / derivative.Mag() * (y - 0.5) * \ + self.thickness + basepoint.y += -derivative.x / derivative.Mag() * (y - 0.5) * \ + self.thickness + else: + print("r", end='') + self.truncate(basepoint) + return basepoint + + def truncate(self, point): + if point.x >= self.maxx: + point.x = self.maxx + if point.y >= self.maxy: + point.y = self.maxy + if point.x < self.minx: + point.x = self.minx + if point.y < self.miny: + point.y = self.miny + + def create_image_chaos(self, w, h, iterations, filename, rng_seed): + # Always use the same sequence of random numbers + # to get reproductible benchmark + random.seed(rng_seed) + + im = [[1] * h for i in range(w)] + point = GVector((self.maxx + self.minx) / 2, + (self.maxy + self.miny) / 2, 0) + for _ in range(iterations): + point = self.transform_point(point) + x = (point.x - self.minx) / self.width * w + y = (point.y - self.miny) / self.height * h + x = int(x) + y = int(y) + if x == w: + x -= 1 + if y == h: + y -= 1 + im[x][h - y - 1] = 0 + + if filename: + write_ppm(im, filename) + + +def main(args): + splines = [ + Spline([ + GVector(1.597350, 3.304460, 0.000000), + GVector(1.575810, 4.123260, 0.000000), + GVector(1.313210, 5.288350, 0.000000), + GVector(1.618900, 5.329910, 0.000000), + GVector(2.889940, 5.502700, 0.000000), + GVector(2.373060, 4.381830, 0.000000), + GVector(1.662000, 4.360280, 0.000000)], + 3, [0, 0, 0, 1, 1, 1, 2, 2, 2]), + Spline([ + GVector(2.804500, 4.017350, 0.000000), + GVector(2.550500, 3.525230, 0.000000), + GVector(1.979010, 2.620360, 0.000000), + GVector(1.979010, 2.620360, 0.000000)], + 3, [0, 0, 0, 1, 1, 1]), + Spline([ + GVector(2.001670, 4.011320, 0.000000), + GVector(2.335040, 3.312830, 0.000000), + GVector(2.366800, 3.233460, 0.000000), + GVector(2.366800, 3.233460, 0.000000)], + 3, [0, 0, 0, 1, 1, 1]) + ] + + chaos = Chaosgame(splines, args.thickness) + chaos.create_image_chaos( + args.width, args.height, args.iterations, args.filename, args.rng_seed + ) + + +def run_pgo(): + import argparse + cmd = argparse.ArgumentParser() + cmd.add_argument("--thickness", + type=float, default=DEFAULT_THICKNESS, + help="Thickness (default: %s)" % DEFAULT_THICKNESS) + cmd.add_argument("--width", + type=int, default=DEFAULT_WIDTH, + help="Image width (default: %s)" % DEFAULT_WIDTH) + cmd.add_argument("--height", + type=int, default=DEFAULT_HEIGHT, + help="Image height (default: %s)" % DEFAULT_HEIGHT) + cmd.add_argument("--iterations", + type=int, default=DEFAULT_ITERATIONS, + help="Number of iterations (default: %s)" + % DEFAULT_ITERATIONS) + cmd.add_argument("--filename", metavar="FILENAME.PPM", + help="Output filename of the PPM picture") + cmd.add_argument("--rng-seed", + type=int, default=DEFAULT_RNG_SEED, + help="Random number generator seed (default: %s)" + % DEFAULT_RNG_SEED) + args = cmd.parse_args() + main(args) diff --git a/Lib/test/pgo_task/bm_comprehensions.py b/Lib/test/pgo_task/bm_comprehensions.py new file mode 100644 index 00000000000000..2aac8ced269e3e --- /dev/null +++ b/Lib/test/pgo_task/bm_comprehensions.py @@ -0,0 +1,89 @@ +""" +Benchmark comprehensions. + +Author: Carl Meyer +""" + +from dataclasses import dataclass +from enum import Enum +from typing import Iterable, List, Optional + + +class WidgetKind(Enum): + BIG = 1 + SMALL = 2 + + +@dataclass +class Widget: + widget_id: int + creator_id: int + derived_widget_ids: List[int] + kind: WidgetKind + has_knob: bool + has_spinner: bool + + +class WidgetTray: + def __init__(self, owner_id: int, widgets: List[Widget]) -> None: + self.owner_id = owner_id + self.sorted_widgets: List[Widget] = [] + self._add_widgets(widgets) + + def _any_knobby(self, widgets: Iterable[Optional[Widget]]) -> bool: + return any(w.has_knob for w in widgets if w) + + def _is_big_spinny(self, widget: Widget) -> bool: + return widget.kind == WidgetKind.BIG and widget.has_spinner + + def _add_widgets(self, widgets: List[Widget]) -> None: + # sort order: mine first, then any widgets with derived knobby widgets in order of + # number derived, then other widgets in order of number derived, and we exclude + # big spinny widgets entirely + widgets = [w for w in widgets if not self._is_big_spinny(w)] + id_to_widget = {w.widget_id: w for w in widgets} + id_to_derived = { + w.widget_id: [id_to_widget.get(dwid) for dwid in w.derived_widget_ids] + for w in widgets + } + sortable_widgets = [ + ( + w.creator_id == self.owner_id, + self._any_knobby(id_to_derived[w.widget_id]), + len(id_to_derived[w.widget_id]), + w.widget_id, + ) + for w in widgets + ] + sortable_widgets.sort() + self.sorted_widgets = [id_to_widget[sw[-1]] for sw in sortable_widgets] + + +def make_some_widgets() -> List[Widget]: + widget_id = 0 + widgets = [] + for creator_id in range(3): + for kind in WidgetKind: + for has_knob in [True, False]: + for has_spinner in [True, False]: + derived = [w.widget_id for w in widgets[::creator_id + 1]] + widgets.append( + Widget( + widget_id, creator_id, derived, kind, has_knob, has_spinner + ) + ) + widget_id += 1 + assert len(widgets) == 24 + return widgets + + +def bench_comprehensions(loops: int) -> float: + range_it = range(loops) + widgets = make_some_widgets() + for _ in range_it: + tray = WidgetTray(1, widgets) + assert len(tray.sorted_widgets) == 18 + + +def run_pgo(): + bench_comprehensions(10_000) diff --git a/Lib/test/pgo_task/bm_coroutines.py b/Lib/test/pgo_task/bm_coroutines.py new file mode 100644 index 00000000000000..6ba750b80994f5 --- /dev/null +++ b/Lib/test/pgo_task/bm_coroutines.py @@ -0,0 +1,26 @@ +""" +Benchmark for recursive coroutines. + +Author: Kumar Aditya +""" + + +async def fibonacci(n: int) -> int: + if n <= 1: + return n + return await fibonacci(n - 1) + await fibonacci(n - 2) + + +def bench_coroutines(loops: int) -> float: + range_it = range(loops) + for _ in range_it: + coro = fibonacci(25) + try: + while True: + coro.send(None) + except StopIteration: + pass + + +def run_pgo(): + bench_coroutines(1) diff --git a/Lib/test/pgo_task/bm_decimal_factorial.py b/Lib/test/pgo_task/bm_decimal_factorial.py new file mode 100644 index 00000000000000..ce91d063b2d450 --- /dev/null +++ b/Lib/test/pgo_task/bm_decimal_factorial.py @@ -0,0 +1,43 @@ +""" +Calculate `factorial` using the decimal module. + +- 2024-06-14: Michael Droettboom copied this from + Modules/_decimal/tests/bench.py in the CPython source and adapted to use + pyperf. +""" + +# Original copyright notice in CPython source: + +# +# Copyright (C) 2001-2012 Python Software Foundation. All Rights Reserved. +# Modified and extended by Stefan Krah. +# + + +import decimal + + +def factorial(n, m): + if n > m: + return factorial(m, n) + elif m == 0: + return 1 + elif n == m: + return n + else: + return factorial(n, (n + m) // 2) * factorial((n + m) // 2 + 1, m) + + +def bench_decimal_factorial(): + c = decimal.getcontext() + c.prec = decimal.MAX_PREC + c.Emax = decimal.MAX_EMAX + c.Emin = decimal.MIN_EMIN + + for n in [10000, 100000]: + # C version of decimal + _ = factorial(decimal.Decimal(n), 0) + + +def run_pgo(): + bench_decimal_factorial() diff --git a/Lib/test/pgo_task/bm_decimal_pi.py b/Lib/test/pgo_task/bm_decimal_pi.py new file mode 100644 index 00000000000000..9afef0bcf9d4cb --- /dev/null +++ b/Lib/test/pgo_task/bm_decimal_pi.py @@ -0,0 +1,44 @@ +""" +Calculate `pi` using the decimal module. + +The `pidigits` benchmark does a similar thing using regular (long) ints. + +- 2024-06-14: Michael Droettboom copied this from + Modules/_decimal/tests/bench.py in the CPython source and adapted to use + pyperf. +""" + +# Original copyright notice in CPython source: + +# +# Copyright (C) 2001-2012 Python Software Foundation. All Rights Reserved. +# Modified and extended by Stefan Krah. +# + + +import decimal + + + +def pi_decimal(): + """decimal""" + D = decimal.Decimal + lasts, t, s, n, na, d, da = D(0), D(3), D(3), D(1), D(0), D(0), D(24) + while s != lasts: + lasts = s + n, na = n + na, na + 8 + d, da = d + da, da + 32 + t = (t * n) / d + s += t + return s + + +def bench_decimal_pi(): + for prec in [9, 19]: + decimal.getcontext().prec = prec + for _ in range(10000): + _ = pi_decimal() + + +def run_pgo(): + bench_decimal_pi() diff --git a/Lib/test/pgo_task/bm_deepcopy.py b/Lib/test/pgo_task/bm_deepcopy.py new file mode 100644 index 00000000000000..f200250aec642e --- /dev/null +++ b/Lib/test/pgo_task/bm_deepcopy.py @@ -0,0 +1,74 @@ +""" +Benchmark to measure performance of the python builtin method copy.deepcopy + +Performance is tested on a nested dictionary and a dataclass + +Author: Pieter Eendebak + +""" +import copy +from dataclasses import dataclass + + +@dataclass +class A: + string: str + lst: list + boolean: bool + + +def benchmark_reduce(n): + """ Benchmark where the __reduce__ functionality is used """ + class C(object): + def __init__(self): + self.a = 1 + self.b = 2 + + def __reduce__(self): + return (C, (), self.__dict__) + + def __setstate__(self, state): + self.__dict__.update(state) + c = C() + + for ii in range(n): + _ = copy.deepcopy(c) + + +def benchmark_memo(n): + """ Benchmark where the memo functionality is used """ + A = [1] * 100 + data = {'a': (A, A, A), 'b': [A] * 100} + + for ii in range(n): + _ = copy.deepcopy(data) + + +def benchmark(n): + """ Benchmark on some standard data types """ + a = { + 'list': [1, 2, 3, 43], + 't': (1 ,2, 3), + 'str': 'hello', + 'subdict': {'a': True} + } + dc = A('hello', [1, 2, 3], True) + + dt = 0 + for ii in range(n): + for jj in range(30): + _ = copy.deepcopy(a) + for s in ['red', 'blue', 'green']: + dc.string = s + for kk in range(5): + dc.lst[0] = kk + for b in [True, False]: + dc.boolean = b + _ = copy.deepcopy(dc) + + +def run_pgo(): + loops = 100 + benchmark(loops) + benchmark_reduce(loops) + benchmark_memo(loops) diff --git a/Lib/test/pgo_task/bm_deltablue.py b/Lib/test/pgo_task/bm_deltablue.py new file mode 100644 index 00000000000000..0ddaab0e7a55c8 --- /dev/null +++ b/Lib/test/pgo_task/bm_deltablue.py @@ -0,0 +1,631 @@ +""" +deltablue.py +============ + +Ported for the PyPy project. +Contributed by Daniel Lindsley + +This implementation of the DeltaBlue benchmark was directly ported +from the `V8's source code`_, which was in turn derived +from the Smalltalk implementation by John Maloney and Mario +Wolczko. The original Javascript implementation was licensed under the GPL. + +It's been updated in places to be more idiomatic to Python (for loops over +collections, a couple magic methods, ``OrderedCollection`` being a list & things +altering those collections changed to the builtin methods) but largely retains +the layout & logic from the original. (Ugh.) + +.. _`V8's source code`: (https://github.com/v8/v8/blob/master/benchmarks/deltablue.js) +""" + + +# The JS variant implements "OrderedCollection", which basically completely +# overlaps with ``list``. So we'll cheat. :D +class OrderedCollection(list): + pass + + +class Strength(object): + REQUIRED = None + STRONG_PREFERRED = None + PREFERRED = None + STRONG_DEFAULT = None + NORMAL = None + WEAK_DEFAULT = None + WEAKEST = None + + def __init__(self, strength, name): + super(Strength, self).__init__() + self.strength = strength + self.name = name + + @classmethod + def stronger(cls, s1, s2): + return s1.strength < s2.strength + + @classmethod + def weaker(cls, s1, s2): + return s1.strength > s2.strength + + @classmethod + def weakest_of(cls, s1, s2): + if cls.weaker(s1, s2): + return s1 + + return s2 + + @classmethod + def strongest(cls, s1, s2): + if cls.stronger(s1, s2): + return s1 + + return s2 + + def next_weaker(self): + strengths = { + 0: self.__class__.WEAKEST, + 1: self.__class__.WEAK_DEFAULT, + 2: self.__class__.NORMAL, + 3: self.__class__.STRONG_DEFAULT, + 4: self.__class__.PREFERRED, + # TODO: This looks like a bug in the original code. Shouldn't this be + # ``STRONG_PREFERRED? Keeping for porting sake... + 5: self.__class__.REQUIRED, + } + return strengths[self.strength] + + +# This is a terrible pattern IMO, but true to the original JS implementation. +Strength.REQUIRED = Strength(0, "required") +Strength.STRONG_PREFERRED = Strength(1, "strongPreferred") +Strength.PREFERRED = Strength(2, "preferred") +Strength.STRONG_DEFAULT = Strength(3, "strongDefault") +Strength.NORMAL = Strength(4, "normal") +Strength.WEAK_DEFAULT = Strength(5, "weakDefault") +Strength.WEAKEST = Strength(6, "weakest") + + +class Constraint(object): + + def __init__(self, strength): + super(Constraint, self).__init__() + self.strength = strength + + def add_constraint(self): + global planner + self.add_to_graph() + planner.incremental_add(self) + + def satisfy(self, mark): + global planner + self.choose_method(mark) + + if not self.is_satisfied(): + if self.strength == Strength.REQUIRED: + print('Could not satisfy a required constraint!') + + return None + + self.mark_inputs(mark) + out = self.output() + overridden = out.determined_by + + if overridden is not None: + overridden.mark_unsatisfied() + + out.determined_by = self + + if not planner.add_propagate(self, mark): + print('Cycle encountered') + + out.mark = mark + return overridden + + def destroy_constraint(self): + global planner + if self.is_satisfied(): + planner.incremental_remove(self) + else: + self.remove_from_graph() + + def is_input(self): + return False + + +class UrnaryConstraint(Constraint): + + def __init__(self, v, strength): + super(UrnaryConstraint, self).__init__(strength) + self.my_output = v + self.satisfied = False + self.add_constraint() + + def add_to_graph(self): + self.my_output.add_constraint(self) + self.satisfied = False + + def choose_method(self, mark): + if self.my_output.mark != mark and \ + Strength.stronger(self.strength, self.my_output.walk_strength): + self.satisfied = True + else: + self.satisfied = False + + def is_satisfied(self): + return self.satisfied + + def mark_inputs(self, mark): + # No-ops. + pass + + def output(self): + # Ugh. Keeping it for consistency with the original. So much for + # "we're all adults here"... + return self.my_output + + def recalculate(self): + self.my_output.walk_strength = self.strength + self.my_output.stay = not self.is_input() + + if self.my_output.stay: + self.execute() + + def mark_unsatisfied(self): + self.satisfied = False + + def inputs_known(self, mark): + return True + + def remove_from_graph(self): + if self.my_output is not None: + self.my_output.remove_constraint(self) + self.satisfied = False + + +class StayConstraint(UrnaryConstraint): + + def __init__(self, v, string): + super(StayConstraint, self).__init__(v, string) + + def execute(self): + # The methods, THEY DO NOTHING. + pass + + +class EditConstraint(UrnaryConstraint): + + def __init__(self, v, string): + super(EditConstraint, self).__init__(v, string) + + def is_input(self): + return True + + def execute(self): + # This constraint also does nothing. + pass + + +class Direction(object): + # Hooray for things that ought to be structs! + NONE = 0 + FORWARD = 1 + BACKWARD = -1 + + +class BinaryConstraint(Constraint): + + def __init__(self, v1, v2, strength): + super(BinaryConstraint, self).__init__(strength) + self.v1 = v1 + self.v2 = v2 + self.direction = Direction.NONE + self.add_constraint() + + def choose_method(self, mark): + if self.v1.mark == mark: + if self.v2.mark != mark and Strength.stronger(self.strength, self.v2.walk_strength): + self.direction = Direction.FORWARD + else: + self.direction = Direction.BACKWARD + + if self.v2.mark == mark: + if self.v1.mark != mark and Strength.stronger(self.strength, self.v1.walk_strength): + self.direction = Direction.BACKWARD + else: + self.direction = Direction.NONE + + if Strength.weaker(self.v1.walk_strength, self.v2.walk_strength): + if Strength.stronger(self.strength, self.v1.walk_strength): + self.direction = Direction.BACKWARD + else: + self.direction = Direction.NONE + else: + if Strength.stronger(self.strength, self.v2.walk_strength): + self.direction = Direction.FORWARD + else: + self.direction = Direction.BACKWARD + + def add_to_graph(self): + self.v1.add_constraint(self) + self.v2.add_constraint(self) + self.direction = Direction.NONE + + def is_satisfied(self): + return self.direction != Direction.NONE + + def mark_inputs(self, mark): + self.input().mark = mark + + def input(self): + if self.direction == Direction.FORWARD: + return self.v1 + + return self.v2 + + def output(self): + if self.direction == Direction.FORWARD: + return self.v2 + + return self.v1 + + def recalculate(self): + ihn = self.input() + out = self.output() + out.walk_strength = Strength.weakest_of( + self.strength, ihn.walk_strength) + out.stay = ihn.stay + + if out.stay: + self.execute() + + def mark_unsatisfied(self): + self.direction = Direction.NONE + + def inputs_known(self, mark): + i = self.input() + return i.mark == mark or i.stay or i.determined_by is None + + def remove_from_graph(self): + if self.v1 is not None: + self.v1.remove_constraint(self) + + if self.v2 is not None: + self.v2.remove_constraint(self) + + self.direction = Direction.NONE + + +class ScaleConstraint(BinaryConstraint): + + def __init__(self, src, scale, offset, dest, strength): + self.direction = Direction.NONE + self.scale = scale + self.offset = offset + super(ScaleConstraint, self).__init__(src, dest, strength) + + def add_to_graph(self): + super(ScaleConstraint, self).add_to_graph() + self.scale.add_constraint(self) + self.offset.add_constraint(self) + + def remove_from_graph(self): + super(ScaleConstraint, self).remove_from_graph() + + if self.scale is not None: + self.scale.remove_constraint(self) + + if self.offset is not None: + self.offset.remove_constraint(self) + + def mark_inputs(self, mark): + super(ScaleConstraint, self).mark_inputs(mark) + self.scale.mark = mark + self.offset.mark = mark + + def execute(self): + if self.direction == Direction.FORWARD: + self.v2.value = self.v1.value * self.scale.value + self.offset.value + else: + self.v1.value = ( + self.v2.value - self.offset.value) / self.scale.value + + def recalculate(self): + ihn = self.input() + out = self.output() + out.walk_strength = Strength.weakest_of( + self.strength, ihn.walk_strength) + out.stay = ihn.stay and self.scale.stay and self.offset.stay + + if out.stay: + self.execute() + + +class EqualityConstraint(BinaryConstraint): + + def execute(self): + self.output().value = self.input().value + + +class Variable(object): + + def __init__(self, name, initial_value=0): + super(Variable, self).__init__() + self.name = name + self.value = initial_value + self.constraints = OrderedCollection() + self.determined_by = None + self.mark = 0 + self.walk_strength = Strength.WEAKEST + self.stay = True + + def __repr__(self): + # To make debugging this beast from pdb easier... + return '' % ( + self.name, + self.value + ) + + def add_constraint(self, constraint): + self.constraints.append(constraint) + + def remove_constraint(self, constraint): + self.constraints.remove(constraint) + + if self.determined_by == constraint: + self.determined_by = None + + +class Planner(object): + + def __init__(self): + super(Planner, self).__init__() + self.current_mark = 0 + + def incremental_add(self, constraint): + mark = self.new_mark() + overridden = constraint.satisfy(mark) + + while overridden is not None: + overridden = overridden.satisfy(mark) + + def incremental_remove(self, constraint): + out = constraint.output() + constraint.mark_unsatisfied() + constraint.remove_from_graph() + unsatisfied = self.remove_propagate_from(out) + strength = Strength.REQUIRED + # Do-while, the Python way. + repeat = True + + while repeat: + for u in unsatisfied: + if u.strength == strength: + self.incremental_add(u) + + strength = strength.next_weaker() + + repeat = strength != Strength.WEAKEST + + def new_mark(self): + self.current_mark += 1 + return self.current_mark + + def make_plan(self, sources): + mark = self.new_mark() + plan = Plan() + todo = sources + + while len(todo): + c = todo.pop(0) + + if c.output().mark != mark and c.inputs_known(mark): + plan.add_constraint(c) + c.output().mark = mark + self.add_constraints_consuming_to(c.output(), todo) + + return plan + + def extract_plan_from_constraints(self, constraints): + sources = OrderedCollection() + + for c in constraints: + if c.is_input() and c.is_satisfied(): + sources.append(c) + + return self.make_plan(sources) + + def add_propagate(self, c, mark): + todo = OrderedCollection() + todo.append(c) + + while len(todo): + d = todo.pop(0) + + if d.output().mark == mark: + self.incremental_remove(c) + return False + + d.recalculate() + self.add_constraints_consuming_to(d.output(), todo) + + return True + + def remove_propagate_from(self, out): + out.determined_by = None + out.walk_strength = Strength.WEAKEST + out.stay = True + unsatisfied = OrderedCollection() + todo = OrderedCollection() + todo.append(out) + + while len(todo): + v = todo.pop(0) + + for c in v.constraints: + if not c.is_satisfied(): + unsatisfied.append(c) + + determining = v.determined_by + + for c in v.constraints: + if c != determining and c.is_satisfied(): + c.recalculate() + todo.append(c.output()) + + return unsatisfied + + def add_constraints_consuming_to(self, v, coll): + determining = v.determined_by + cc = v.constraints + + for c in cc: + if c != determining and c.is_satisfied(): + # I guess we're just updating a reference (``coll``)? Seems + # inconsistent with the rest of the implementation, where they + # return the lists... + coll.append(c) + + +class Plan(object): + + def __init__(self): + super(Plan, self).__init__() + self.v = OrderedCollection() + + def add_constraint(self, c): + self.v.append(c) + + def __len__(self): + return len(self.v) + + def __getitem__(self, index): + return self.v[index] + + def execute(self): + for c in self.v: + c.execute() + + +# Main + +def chain_test(n): + """ + This is the standard DeltaBlue benchmark. A long chain of equality + constraints is constructed with a stay constraint on one end. An + edit constraint is then added to the opposite end and the time is + measured for adding and removing this constraint, and extracting + and executing a constraint satisfaction plan. There are two cases. + In case 1, the added constraint is stronger than the stay + constraint and values must propagate down the entire length of the + chain. In case 2, the added constraint is weaker than the stay + constraint so it cannot be accomodated. The cost in this case is, + of course, very low. Typical situations lie somewhere between these + two extremes. + """ + global planner + planner = Planner() + prev, first, last = None, None, None + + # We need to go up to n inclusively. + for i in range(n + 1): + name = "v%s" % i + v = Variable(name) + + if prev is not None: + EqualityConstraint(prev, v, Strength.REQUIRED) + + if i == 0: + first = v + + if i == n: + last = v + + prev = v + + StayConstraint(last, Strength.STRONG_DEFAULT) + edit = EditConstraint(first, Strength.PREFERRED) + edits = OrderedCollection() + edits.append(edit) + plan = planner.extract_plan_from_constraints(edits) + + for i in range(100): + first.value = i + plan.execute() + + if last.value != i: + print("Chain test failed.") + + +def projection_test(n): + """ + This test constructs a two sets of variables related to each + other by a simple linear transformation (scale and offset). The + time is measured to change a variable on either side of the + mapping and to change the scale and offset factors. + """ + global planner + planner = Planner() + scale = Variable("scale", 10) + offset = Variable("offset", 1000) + src = None + + dests = OrderedCollection() + + for i in range(n): + src = Variable("src%s" % i, i) + dst = Variable("dst%s" % i, i) + dests.append(dst) + StayConstraint(src, Strength.NORMAL) + ScaleConstraint(src, scale, offset, dst, Strength.REQUIRED) + + change(src, 17) + + if dst.value != 1170: + print("Projection 1 failed") + + change(dst, 1050) + + if src.value != 5: + print("Projection 2 failed") + + change(scale, 5) + + for i in range(n - 1): + if dests[i].value != (i * 5 + 1000): + print("Projection 3 failed") + + change(offset, 2000) + + for i in range(n - 1): + if dests[i].value != (i * 5 + 2000): + print("Projection 4 failed") + + +def change(v, new_value): + global planner + edit = EditConstraint(v, Strength.PREFERRED) + edits = OrderedCollection() + edits.append(edit) + + plan = planner.extract_plan_from_constraints(edits) + + for i in range(10): + v.value = new_value + plan.execute() + + edit.destroy_constraint() + + +# HOORAY FOR GLOBALS... Oh wait. +# In spirit of the original, we'll keep it, but ugh. +planner = None + + +def delta_blue(n): + chain_test(n) + projection_test(n) + + +def run_pgo(): + n = 1000 + delta_blue(n) diff --git a/Lib/test/pgo_task/bm_fannkuch.py b/Lib/test/pgo_task/bm_fannkuch.py new file mode 100644 index 00000000000000..6cb7682bf79b5d --- /dev/null +++ b/Lib/test/pgo_task/bm_fannkuch.py @@ -0,0 +1,51 @@ +""" +The Computer Language Benchmarks Game +http://benchmarksgame.alioth.debian.org/ + +Contributed by Sokolov Yura, modified by Tupteq. +""" + + +DEFAULT_ARG = 9 + + +def fannkuch(n): + count = list(range(1, n + 1)) + max_flips = 0 + m = n - 1 + r = n + perm1 = list(range(n)) + perm = list(range(n)) + perm1_ins = perm1.insert + perm1_pop = perm1.pop + + while 1: + while r != 1: + count[r - 1] = r + r -= 1 + + if perm1[0] != 0 and perm1[m] != m: + perm = perm1[:] + flips_count = 0 + k = perm[0] + while k: + perm[:k + 1] = perm[k::-1] + flips_count += 1 + k = perm[0] + + if flips_count > max_flips: + max_flips = flips_count + + while r != n: + perm1_ins(r, perm1_pop(0)) + count[r] -= 1 + if count[r] > 0: + break + r += 1 + else: + return max_flips + + +def run_pgo(): + arg = DEFAULT_ARG + fannkuch(arg) diff --git a/Lib/test/pgo_task/bm_float.py b/Lib/test/pgo_task/bm_float.py new file mode 100644 index 00000000000000..7314d7aed1e331 --- /dev/null +++ b/Lib/test/pgo_task/bm_float.py @@ -0,0 +1,56 @@ +""" +Artificial, floating point-heavy benchmark originally used by Factor. +""" + +from math import sin, cos, sqrt + + +POINTS = 100000 + + +class Point(object): + __slots__ = ('x', 'y', 'z') + + def __init__(self, i): + self.x = x = sin(i) + self.y = cos(i) * 3 + self.z = (x * x) / 2 + + def __repr__(self): + return "" % (self.x, self.y, self.z) + + def normalize(self): + x = self.x + y = self.y + z = self.z + norm = sqrt(x * x + y * y + z * z) + self.x /= norm + self.y /= norm + self.z /= norm + + def maximize(self, other): + self.x = self.x if self.x > other.x else other.x + self.y = self.y if self.y > other.y else other.y + self.z = self.z if self.z > other.z else other.z + return self + + +def maximize(points): + next = points[0] + for p in points[1:]: + next = next.maximize(p) + return next + + +def benchmark(n): + points = [None] * n + for i in range(n): + points[i] = Point(i) + for p in points: + p.normalize() + return maximize(points) + + +def run_pgo(): + points = POINTS + benchmark(points) diff --git a/Lib/test/pgo_task/bm_gc_collect.py b/Lib/test/pgo_task/bm_gc_collect.py new file mode 100644 index 00000000000000..eac319c3d4c887 --- /dev/null +++ b/Lib/test/pgo_task/bm_gc_collect.py @@ -0,0 +1,59 @@ +import gc + +CYCLES = 100 +LINKS = 20 + + +class Node: + def __init__(self): + self.next = None + self.prev = None + + def link_next(self, next): + self.next = next + self.next.prev = self + + +def create_cycle(node, n_links): + """Create a cycle of n_links nodes, starting with node.""" + + if n_links == 0: + return + + current = node + for i in range(n_links): + next_node = Node() + current.link_next(next_node) + current = next_node + + current.link_next(node) + + +def create_gc_cycles(n_cycles, n_links): + """Create n_cycles cycles n_links+1 nodes each.""" + + cycles = [] + for _ in range(n_cycles): + node = Node() + cycles.append(node) + create_cycle(node, n_links) + return cycles + + +def benchamark_collection(loops, cycles, links): + total_time = 0 + for _ in range(loops): + gc.collect() + all_cycles = create_gc_cycles(cycles, links) + + # Main loop to measure + del all_cycles + collected = gc.collect() + + assert collected is None or collected >= cycles * (links + 1) + + return total_time + + +def run_pgo(): + benchamark_collection(1, CYCLES, LINKS) diff --git a/Lib/test/pgo_task/bm_gc_traversal.py b/Lib/test/pgo_task/bm_gc_traversal.py new file mode 100644 index 00000000000000..2f2be099bb252b --- /dev/null +++ b/Lib/test/pgo_task/bm_gc_traversal.py @@ -0,0 +1,30 @@ +import gc + +N_LEVELS = 1000 + + +def create_recursive_containers(n_levels): + + current_list = [] + for n in range(n_levels): + new_list = [None] * n + for index in range(n): + new_list[index] = current_list + current_list = new_list + + return current_list + + +def benchamark_collection(loops, n_levels): + all_cycles = create_recursive_containers(n_levels) + for _ in range(loops): + gc.collect() + # Main loop to measure + collected = gc.collect() + + assert collected is None or collected == 0 + + + +def run_pgo(): + benchamark_collection(1, N_LEVELS) diff --git a/Lib/test/pgo_task/bm_generators.py b/Lib/test/pgo_task/bm_generators.py new file mode 100644 index 00000000000000..ddd89b367eaab8 --- /dev/null +++ b/Lib/test/pgo_task/bm_generators.py @@ -0,0 +1,43 @@ +""" +Benchmark recursive generators implemented in python +by traversing a binary tree. + +Author: Kumar Aditya +""" + +from __future__ import annotations + +from collections.abc import Iterator + + +class Tree: + def __init__(self, left: Tree | None, value: int, right: Tree | None) -> None: + self.left = left + self.value = value + self.right = right + + def __iter__(self) -> Iterator[int]: + if self.left: + yield from self.left + yield self.value + if self.right: + yield from self.right + + +def tree(input: range) -> Tree | None: + n = len(input) + if n == 0: + return None + i = n // 2 + return Tree(tree(input[:i]), input[i], tree(input[i + 1:])) + +def bench_generators(loops: int) -> float: + assert list(tree(range(10))) == list(range(10)) + range_it = range(loops) + iterable = tree(range(100000)) + for _ in range_it: + for _ in iterable: + pass + +def run_pgo(): + bench_generators(1) diff --git a/Lib/test/pgo_task/bm_go.py b/Lib/test/pgo_task/bm_go.py new file mode 100644 index 00000000000000..c57eaa282c36fd --- /dev/null +++ b/Lib/test/pgo_task/bm_go.py @@ -0,0 +1,453 @@ +""" +Go board game +""" +import math +import random + + +SIZE = 9 +GAMES = 200 +KOMI = 7.5 +EMPTY, WHITE, BLACK = 0, 1, 2 +SHOW = {EMPTY: '.', WHITE: 'o', BLACK: 'x'} +PASS = -1 +MAXMOVES = SIZE * SIZE * 3 +TIMESTAMP = 0 +MOVES = 0 + + +def to_pos(x, y): + return y * SIZE + x + + +def to_xy(pos): + y, x = divmod(pos, SIZE) + return x, y + + +class Square: + + def __init__(self, board, pos): + self.board = board + self.pos = pos + self.timestamp = TIMESTAMP + self.removestamp = TIMESTAMP + self.zobrist_strings = [random.randrange(9223372036854775807) + for i in range(3)] + + def set_neighbours(self): + x, y = self.pos % SIZE, self.pos // SIZE + self.neighbours = [] + for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]: + newx, newy = x + dx, y + dy + if 0 <= newx < SIZE and 0 <= newy < SIZE: + self.neighbours.append(self.board.squares[to_pos(newx, newy)]) + + def move(self, color): + global TIMESTAMP, MOVES + TIMESTAMP += 1 + MOVES += 1 + self.board.zobrist.update(self, color) + self.color = color + self.reference = self + self.ledges = 0 + self.used = True + for neighbour in self.neighbours: + neighcolor = neighbour.color + if neighcolor == EMPTY: + self.ledges += 1 + else: + neighbour_ref = neighbour.find(update=True) + if neighcolor == color: + if neighbour_ref.reference.pos != self.pos: + self.ledges += neighbour_ref.ledges + neighbour_ref.reference = self + self.ledges -= 1 + else: + neighbour_ref.ledges -= 1 + if neighbour_ref.ledges == 0: + neighbour.remove(neighbour_ref) + self.board.zobrist.add() + + def remove(self, reference, update=True): + self.board.zobrist.update(self, EMPTY) + self.removestamp = TIMESTAMP + if update: + self.color = EMPTY + self.board.emptyset.add(self.pos) +# if color == BLACK: +# self.board.black_dead += 1 +# else: +# self.board.white_dead += 1 + for neighbour in self.neighbours: + if neighbour.color != EMPTY and neighbour.removestamp != TIMESTAMP: + neighbour_ref = neighbour.find(update) + if neighbour_ref.pos == reference.pos: + neighbour.remove(reference, update) + else: + if update: + neighbour_ref.ledges += 1 + + def find(self, update=False): + reference = self.reference + if reference.pos != self.pos: + reference = reference.find(update) + if update: + self.reference = reference + return reference + + def __repr__(self): + return repr(to_xy(self.pos)) + + +class EmptySet: + + def __init__(self, board): + self.board = board + self.empties = list(range(SIZE * SIZE)) + self.empty_pos = list(range(SIZE * SIZE)) + + def random_choice(self): + choices = len(self.empties) + while choices: + i = int(random.random() * choices) + pos = self.empties[i] + if self.board.useful(pos): + return pos + choices -= 1 + self.set(i, self.empties[choices]) + self.set(choices, pos) + return PASS + + def add(self, pos): + self.empty_pos[pos] = len(self.empties) + self.empties.append(pos) + + def remove(self, pos): + self.set(self.empty_pos[pos], self.empties[len(self.empties) - 1]) + self.empties.pop() + + def set(self, i, pos): + self.empties[i] = pos + self.empty_pos[pos] = i + + +class ZobristHash: + + def __init__(self, board): + self.board = board + self.hash_set = set() + self.hash = 0 + for square in self.board.squares: + self.hash ^= square.zobrist_strings[EMPTY] + self.hash_set.clear() + self.hash_set.add(self.hash) + + def update(self, square, color): + self.hash ^= square.zobrist_strings[square.color] + self.hash ^= square.zobrist_strings[color] + + def add(self): + self.hash_set.add(self.hash) + + def dupe(self): + return self.hash in self.hash_set + + +class Board: + + def __init__(self): + self.squares = [Square(self, pos) for pos in range(SIZE * SIZE)] + for square in self.squares: + square.set_neighbours() + self.reset() + + def reset(self): + for square in self.squares: + square.color = EMPTY + square.used = False + self.emptyset = EmptySet(self) + self.zobrist = ZobristHash(self) + self.color = BLACK + self.finished = False + self.lastmove = -2 + self.history = [] + self.white_dead = 0 + self.black_dead = 0 + + def move(self, pos): + square = self.squares[pos] + if pos != PASS: + square.move(self.color) + self.emptyset.remove(square.pos) + elif self.lastmove == PASS: + self.finished = True + if self.color == BLACK: + self.color = WHITE + else: + self.color = BLACK + self.lastmove = pos + self.history.append(pos) + + def random_move(self): + return self.emptyset.random_choice() + + def useful_fast(self, square): + if not square.used: + for neighbour in square.neighbours: + if neighbour.color == EMPTY: + return True + return False + + def useful(self, pos): + global TIMESTAMP + TIMESTAMP += 1 + square = self.squares[pos] + if self.useful_fast(square): + return True + old_hash = self.zobrist.hash + self.zobrist.update(square, self.color) + empties = opps = weak_opps = neighs = weak_neighs = 0 + for neighbour in square.neighbours: + neighcolor = neighbour.color + if neighcolor == EMPTY: + empties += 1 + continue + neighbour_ref = neighbour.find() + if neighbour_ref.timestamp != TIMESTAMP: + if neighcolor == self.color: + neighs += 1 + else: + opps += 1 + neighbour_ref.timestamp = TIMESTAMP + neighbour_ref.temp_ledges = neighbour_ref.ledges + neighbour_ref.temp_ledges -= 1 + if neighbour_ref.temp_ledges == 0: + if neighcolor == self.color: + weak_neighs += 1 + else: + weak_opps += 1 + neighbour_ref.remove(neighbour_ref, update=False) + dupe = self.zobrist.dupe() + self.zobrist.hash = old_hash + strong_neighs = neighs - weak_neighs + strong_opps = opps - weak_opps + return not dupe and \ + (empties or weak_opps or (strong_neighs and (strong_opps or weak_neighs))) + + def useful_moves(self): + return [pos for pos in self.emptyset.empties if self.useful(pos)] + + def replay(self, history): + for pos in history: + self.move(pos) + + def score(self, color): + if color == WHITE: + count = KOMI + self.black_dead + else: + count = self.white_dead + for square in self.squares: + squarecolor = square.color + if squarecolor == color: + count += 1 + elif squarecolor == EMPTY: + surround = 0 + for neighbour in square.neighbours: + if neighbour.color == color: + surround += 1 + if surround == len(square.neighbours): + count += 1 + return count + + def check(self): + for square in self.squares: + if square.color == EMPTY: + continue + + members1 = set([square]) + changed = True + while changed: + changed = False + for member in members1.copy(): + for neighbour in member.neighbours: + if neighbour.color == square.color and neighbour not in members1: + changed = True + members1.add(neighbour) + ledges1 = 0 + for member in members1: + for neighbour in member.neighbours: + if neighbour.color == EMPTY: + ledges1 += 1 + + root = square.find() + + # print 'members1', square, root, members1 + # print 'ledges1', square, ledges1 + + members2 = set() + for square2 in self.squares: + if square2.color != EMPTY and square2.find() == root: + members2.add(square2) + + ledges2 = root.ledges + # print 'members2', square, root, members1 + # print 'ledges2', square, ledges2 + + assert members1 == members2 + assert ledges1 == ledges2, ('ledges differ at %r: %d %d' % ( + square, ledges1, ledges2)) + + set(self.emptyset.empties) + + empties2 = set() + for square in self.squares: + if square.color == EMPTY: + empties2.add(square.pos) + + def __repr__(self): + result = [] + for y in range(SIZE): + start = to_pos(0, y) + result.append(''.join( + [SHOW[square.color] + ' ' for square in self.squares[start:start + SIZE]])) + return '\n'.join(result) + + +class UCTNode: + + def __init__(self): + self.bestchild = None + self.pos = -1 + self.wins = 0 + self.losses = 0 + self.pos_child = [None for x in range(SIZE * SIZE)] + self.parent = None + + def play(self, board): + """ uct tree search """ + color = board.color + node = self + path = [node] + while True: + pos = node.select(board) + if pos == PASS: + break + board.move(pos) + child = node.pos_child[pos] + if not child: + child = node.pos_child[pos] = UCTNode() + child.unexplored = board.useful_moves() + child.pos = pos + child.parent = node + path.append(child) + break + path.append(child) + node = child + self.random_playout(board) + self.update_path(board, color, path) + + def select(self, board): + """ select move; unexplored children first, then according to uct value """ + if self.unexplored: + i = random.randrange(len(self.unexplored)) + pos = self.unexplored[i] + self.unexplored[i] = self.unexplored[len(self.unexplored) - 1] + self.unexplored.pop() + return pos + elif self.bestchild: + return self.bestchild.pos + else: + return PASS + + def random_playout(self, board): + """ random play until both players pass """ + for x in range(MAXMOVES): # XXX while not self.finished? + if board.finished: + break + board.move(board.random_move()) + + def update_path(self, board, color, path): + """ update win/loss count along path """ + wins = board.score(BLACK) >= board.score(WHITE) + for node in path: + if color == BLACK: + color = WHITE + else: + color = BLACK + if wins == (color == BLACK): + node.wins += 1 + else: + node.losses += 1 + if node.parent: + node.parent.bestchild = node.parent.best_child() + + def score(self): + winrate = self.wins / float(self.wins + self.losses) + parentvisits = self.parent.wins + self.parent.losses + if not parentvisits: + return winrate + nodevisits = self.wins + self.losses + return winrate + math.sqrt((math.log(parentvisits)) / (5 * nodevisits)) + + def best_child(self): + maxscore = -1 + maxchild = None + for child in self.pos_child: + if child and child.score() > maxscore: + maxchild = child + maxscore = child.score() + return maxchild + + def best_visited(self): + maxvisits = -1 + maxchild = None + for child in self.pos_child: + # if child: + # print to_xy(child.pos), child.wins, child.losses, child.score() + if child and (child.wins + child.losses) > maxvisits: + maxvisits, maxchild = (child.wins + child.losses), child + return maxchild + + +# def user_move(board): +# while True: +# text = input('?').strip() +# if text == 'p': +# return PASS +# if text == 'q': +# raise EOFError +# try: +# x, y = [int(i) for i in text.split()] +# except ValueError: +# continue +# if not (0 <= x < SIZE and 0 <= y < SIZE): +# continue +# pos = to_pos(x, y) +# if board.useful(pos): +# return pos + + +def computer_move(board): + pos = board.random_move() + if pos == PASS: + return PASS + tree = UCTNode() + tree.unexplored = board.useful_moves() + nboard = Board() + for game in range(GAMES): + node = tree + nboard.reset() + nboard.replay(board.history) + node.play(nboard) + return tree.best_visited().pos + + +def versus_cpu(): + random.seed(1) + board = Board() + return computer_move(board) + + +def run_pgo(): + versus_cpu() diff --git a/Lib/test/pgo_task/bm_hexiom.py b/Lib/test/pgo_task/bm_hexiom.py new file mode 100644 index 00000000000000..eb545ec207d769 --- /dev/null +++ b/Lib/test/pgo_task/bm_hexiom.py @@ -0,0 +1,643 @@ +""" +Solver of Hexiom board game. + +Benchmark from Laurent Vaucher. + +Source: https://github.com/slowfrog/hexiom : hexiom2.py, level36.txt + +(Main function tweaked by Armin Rigo.) +""" + +import io + +# 2016-07-07: CPython 3.6 takes ~25 ms to solve the board level 25 +DEFAULT_LEVEL = 25 + + +################################## +class Dir(object): + + def __init__(self, x, y): + self.x = x + self.y = y + + +DIRS = [Dir(1, 0), + Dir(-1, 0), + Dir(0, 1), + Dir(0, -1), + Dir(1, 1), + Dir(-1, -1)] + +EMPTY = 7 + +################################## + + +class Done(object): + MIN_CHOICE_STRATEGY = 0 + MAX_CHOICE_STRATEGY = 1 + HIGHEST_VALUE_STRATEGY = 2 + FIRST_STRATEGY = 3 + MAX_NEIGHBORS_STRATEGY = 4 + MIN_NEIGHBORS_STRATEGY = 5 + + def __init__(self, count, empty=False): + self.count = count + self.cells = None if empty else [ + [0, 1, 2, 3, 4, 5, 6, EMPTY] for i in range(count)] + + def clone(self): + ret = Done(self.count, True) + ret.cells = [self.cells[i][:] for i in range(self.count)] + return ret + + def __getitem__(self, i): + return self.cells[i] + + def set_done(self, i, v): + self.cells[i] = [v] + + def already_done(self, i): + return len(self.cells[i]) == 1 + + def remove(self, i, v): + if v in self.cells[i]: + self.cells[i].remove(v) + return True + else: + return False + + def remove_all(self, v): + for i in range(self.count): + self.remove(i, v) + + def remove_unfixed(self, v): + changed = False + for i in range(self.count): + if not self.already_done(i): + if self.remove(i, v): + changed = True + return changed + + def filter_tiles(self, tiles): + for v in range(8): + if tiles[v] == 0: + self.remove_all(v) + + def next_cell_min_choice(self): + minlen = 10 + mini = -1 + for i in range(self.count): + if 1 < len(self.cells[i]) < minlen: + minlen = len(self.cells[i]) + mini = i + return mini + + def next_cell_max_choice(self): + maxlen = 1 + maxi = -1 + for i in range(self.count): + if maxlen < len(self.cells[i]): + maxlen = len(self.cells[i]) + maxi = i + return maxi + + def next_cell_highest_value(self): + maxval = -1 + maxi = -1 + for i in range(self.count): + if (not self.already_done(i)): + maxvali = max(k for k in self.cells[i] if k != EMPTY) + if maxval < maxvali: + maxval = maxvali + maxi = i + return maxi + + def next_cell_first(self): + for i in range(self.count): + if (not self.already_done(i)): + return i + return -1 + + def next_cell_max_neighbors(self, pos): + maxn = -1 + maxi = -1 + for i in range(self.count): + if not self.already_done(i): + cells_around = pos.hex.get_by_id(i).links + n = sum(1 if (self.already_done(nid) and (self[nid][0] != EMPTY)) else 0 + for nid in cells_around) + if n > maxn: + maxn = n + maxi = i + return maxi + + def next_cell_min_neighbors(self, pos): + minn = 7 + mini = -1 + for i in range(self.count): + if not self.already_done(i): + cells_around = pos.hex.get_by_id(i).links + n = sum(1 if (self.already_done(nid) and (self[nid][0] != EMPTY)) else 0 + for nid in cells_around) + if n < minn: + minn = n + mini = i + return mini + + def next_cell(self, pos, strategy=HIGHEST_VALUE_STRATEGY): + if strategy == Done.HIGHEST_VALUE_STRATEGY: + return self.next_cell_highest_value() + elif strategy == Done.MIN_CHOICE_STRATEGY: + return self.next_cell_min_choice() + elif strategy == Done.MAX_CHOICE_STRATEGY: + return self.next_cell_max_choice() + elif strategy == Done.FIRST_STRATEGY: + return self.next_cell_first() + elif strategy == Done.MAX_NEIGHBORS_STRATEGY: + return self.next_cell_max_neighbors(pos) + elif strategy == Done.MIN_NEIGHBORS_STRATEGY: + return self.next_cell_min_neighbors(pos) + else: + raise Exception("Wrong strategy: %d" % strategy) + +################################## + + +class Node(object): + + def __init__(self, pos, id, links): + self.pos = pos + self.id = id + self.links = links + +################################## + + +class Hex(object): + + def __init__(self, size): + self.size = size + self.count = 3 * size * (size - 1) + 1 + self.nodes_by_id = self.count * [None] + self.nodes_by_pos = {} + id = 0 + for y in range(size): + for x in range(size + y): + pos = (x, y) + node = Node(pos, id, []) + self.nodes_by_pos[pos] = node + self.nodes_by_id[node.id] = node + id += 1 + for y in range(1, size): + for x in range(y, size * 2 - 1): + ry = size + y - 1 + pos = (x, ry) + node = Node(pos, id, []) + self.nodes_by_pos[pos] = node + self.nodes_by_id[node.id] = node + id += 1 + + def link_nodes(self): + for node in self.nodes_by_id: + (x, y) = node.pos + for dir in DIRS: + nx = x + dir.x + ny = y + dir.y + if self.contains_pos((nx, ny)): + node.links.append(self.nodes_by_pos[(nx, ny)].id) + + def contains_pos(self, pos): + return pos in self.nodes_by_pos + + def get_by_pos(self, pos): + return self.nodes_by_pos[pos] + + def get_by_id(self, id): + return self.nodes_by_id[id] + + +################################## +class Pos(object): + + def __init__(self, hex, tiles, done=None): + self.hex = hex + self.tiles = tiles + self.done = Done(hex.count) if done is None else done + + def clone(self): + return Pos(self.hex, self.tiles, self.done.clone()) + +################################## + + +def constraint_pass(pos, last_move=None): + changed = False + left = pos.tiles[:] + done = pos.done + + # Remove impossible values from free cells + free_cells = (range(done.count) if last_move is None + else pos.hex.get_by_id(last_move).links) + for i in free_cells: + if not done.already_done(i): + vmax = 0 + vmin = 0 + cells_around = pos.hex.get_by_id(i).links + for nid in cells_around: + if done.already_done(nid): + if done[nid][0] != EMPTY: + vmin += 1 + vmax += 1 + else: + vmax += 1 + + for num in range(7): + if (num < vmin) or (num > vmax): + if done.remove(i, num): + changed = True + + # Computes how many of each value is still free + for cell in done.cells: + if len(cell) == 1: + left[cell[0]] -= 1 + + for v in range(8): + # If there is none, remove the possibility from all tiles + if (pos.tiles[v] > 0) and (left[v] == 0): + if done.remove_unfixed(v): + changed = True + else: + possible = sum((1 if v in cell else 0) for cell in done.cells) + # If the number of possible cells for a value is exactly the number of available tiles + # put a tile in each cell + if pos.tiles[v] == possible: + for i in range(done.count): + cell = done.cells[i] + if (not done.already_done(i)) and (v in cell): + done.set_done(i, v) + changed = True + + # Force empty or non-empty around filled cells + filled_cells = (range(done.count) if last_move is None + else [last_move]) + for i in filled_cells: + if done.already_done(i): + num = done[i][0] + empties = 0 + filled = 0 + unknown = [] + cells_around = pos.hex.get_by_id(i).links + for nid in cells_around: + if done.already_done(nid): + if done[nid][0] == EMPTY: + empties += 1 + else: + filled += 1 + else: + unknown.append(nid) + if len(unknown) > 0: + if num == filled: + for u in unknown: + if EMPTY in done[u]: + done.set_done(u, EMPTY) + changed = True + # else: + # raise Exception("Houston, we've got a problem") + elif num == filled + len(unknown): + for u in unknown: + if done.remove(u, EMPTY): + changed = True + + return changed + + +ASCENDING = 1 +DESCENDING = -1 + + +def find_moves(pos, strategy, order): + done = pos.done + cell_id = done.next_cell(pos, strategy) + if cell_id < 0: + return [] + + if order == ASCENDING: + return [(cell_id, v) for v in done[cell_id]] + else: + # Try higher values first and EMPTY last + moves = list(reversed([(cell_id, v) + for v in done[cell_id] if v != EMPTY])) + if EMPTY in done[cell_id]: + moves.append((cell_id, EMPTY)) + return moves + + +def play_move(pos, move): + (cell_id, i) = move + pos.done.set_done(cell_id, i) + + +def print_pos(pos, output): + hex = pos.hex + done = pos.done + size = hex.size + for y in range(size): + print(" " * (size - y - 1), end="", file=output) + for x in range(size + y): + pos2 = (x, y) + id = hex.get_by_pos(pos2).id + if done.already_done(id): + c = str(done[id][0]) if done[id][0] != EMPTY else "." + else: + c = "?" + print("%s " % c, end="", file=output) + print(end="\n", file=output) + for y in range(1, size): + print(" " * y, end="", file=output) + for x in range(y, size * 2 - 1): + ry = size + y - 1 + pos2 = (x, ry) + id = hex.get_by_pos(pos2).id + if done.already_done(id): + c = str(done[id][0]) if done[id][0] != EMPTY else "." + else: + c = "?" + print("%s " % c, end="", file=output) + print(end="\n", file=output) + + +OPEN = 0 +SOLVED = 1 +IMPOSSIBLE = -1 + + +def solved(pos, output, verbose=False): + hex = pos.hex + tiles = pos.tiles[:] + done = pos.done + exact = True + all_done = True + for i in range(hex.count): + if len(done[i]) == 0: + return IMPOSSIBLE + elif done.already_done(i): + num = done[i][0] + tiles[num] -= 1 + if (tiles[num] < 0): + return IMPOSSIBLE + vmax = 0 + vmin = 0 + if num != EMPTY: + cells_around = hex.get_by_id(i).links + for nid in cells_around: + if done.already_done(nid): + if done[nid][0] != EMPTY: + vmin += 1 + vmax += 1 + else: + vmax += 1 + + if (num < vmin) or (num > vmax): + return IMPOSSIBLE + if num != vmin: + exact = False + else: + all_done = False + + if (not all_done) or (not exact): + return OPEN + + print_pos(pos, output) + return SOLVED + + +def solve_step(prev, strategy, order, output, first=False): + if first: + pos = prev.clone() + while constraint_pass(pos): + pass + else: + pos = prev + + moves = find_moves(pos, strategy, order) + if len(moves) == 0: + return solved(pos, output) + else: + for move in moves: + # print("Trying (%d, %d)" % (move[0], move[1])) + ret = OPEN + new_pos = pos.clone() + play_move(new_pos, move) + # print_pos(new_pos) + while constraint_pass(new_pos, move[0]): + pass + cur_status = solved(new_pos, output) + if cur_status != OPEN: + ret = cur_status + else: + ret = solve_step(new_pos, strategy, order, output) + if ret == SOLVED: + return SOLVED + return IMPOSSIBLE + + +def check_valid(pos): + hex = pos.hex + tiles = pos.tiles + # fill missing entries in tiles + tot = 0 + for i in range(8): + if tiles[i] > 0: + tot += tiles[i] + else: + tiles[i] = 0 + # check total + if tot != hex.count: + raise Exception( + "Invalid input. Expected %d tiles, got %d." % (hex.count, tot)) + + +def solve(pos, strategy, order, output): + check_valid(pos) + return solve_step(pos, strategy, order, output, first=True) + + +# TODO Write an 'iterator' to go over all x,y positions + +def read_file(file): + lines = [line.strip("\r\n") for line in file.splitlines()] + size = int(lines[0]) + hex = Hex(size) + linei = 1 + tiles = 8 * [0] + done = Done(hex.count) + for y in range(size): + line = lines[linei][size - y - 1:] + p = 0 + for x in range(size + y): + tile = line[p:p + 2] + p += 2 + if tile[1] == ".": + inctile = EMPTY + else: + inctile = int(tile) + tiles[inctile] += 1 + # Look for locked tiles + if tile[0] == "+": + # print("Adding locked tile: %d at pos %d, %d, id=%d" % + # (inctile, x, y, hex.get_by_pos((x, y)).id)) + done.set_done(hex.get_by_pos((x, y)).id, inctile) + + linei += 1 + for y in range(1, size): + ry = size - 1 + y + line = lines[linei][y:] + p = 0 + for x in range(y, size * 2 - 1): + tile = line[p:p + 2] + p += 2 + if tile[1] == ".": + inctile = EMPTY + else: + inctile = int(tile) + tiles[inctile] += 1 + # Look for locked tiles + if tile[0] == "+": + # print("Adding locked tile: %d at pos %d, %d, id=%d" % + # (inctile, x, ry, hex.get_by_pos((x, ry)).id)) + done.set_done(hex.get_by_pos((x, ry)).id, inctile) + linei += 1 + hex.link_nodes() + done.filter_tiles(tiles) + return Pos(hex, tiles, done) + + +def solve_file(file, strategy, order, output): + pos = read_file(file) + solve(pos, strategy, order, output) + + +LEVELS = {} + +LEVELS[2] = (""" +2 + . 1 + . 1 1 + 1 . +""", """\ + 1 1 +. . . + 1 1 +""") + +LEVELS[10] = (""" +3 + +.+. . + +. 0 . 2 + . 1+2 1 . + 2 . 0+. + .+.+. +""", """\ + . . 1 + . 1 . 2 +0 . 2 2 . + . . . . + 0 . . +""") + +LEVELS[20] = (""" +3 + . 5 4 + . 2+.+1 + . 3+2 3 . + +2+. 5 . + . 3 . +""", """\ + 3 3 2 + 4 5 . 1 +3 5 2 . . + 2 . . . + . . . +""") + +LEVELS[25] = (""" +3 + 4 . . + . . 2 . + 4 3 2 . 4 + 2 2 3 . + 4 2 4 +""", """\ + 3 4 2 + 2 4 4 . +. . . 4 2 + . 2 4 3 + . 2 . +""") + +LEVELS[30] = (""" +4 + 5 5 . . + 3 . 2+2 6 + 3 . 2 . 5 . + . 3 3+4 4 . 3 + 4 5 4 . 5 4 + 5+2 . . 3 + 4 . . . +""", """\ + 3 4 3 . + 4 6 5 2 . + 2 5 5 . . 2 +. . 5 4 . 4 3 + . 3 5 4 5 4 + . 2 . 3 3 + . . . . +""") + +LEVELS[36] = (""" +4 + 2 1 1 2 + 3 3 3 . . + 2 3 3 . 4 . + . 2 . 2 4 3 2 + 2 2 . . . 2 + 4 3 4 . . + 3 2 3 3 +""", """\ + 3 4 3 2 + 3 4 4 . 3 + 2 . . 3 4 3 +2 . 1 . 3 . 2 + 3 3 . 2 . 2 + 3 . 2 . 2 + 2 2 . 1 +""") + + +def main(loops, level): + board, solution = LEVELS[level] + order = DESCENDING + strategy = Done.FIRST_STRATEGY + stream = io.StringIO() + + board = board.strip() + expected = solution.rstrip() + + range_it = range(loops) + + for _ in range_it: + stream = io.StringIO() + solve_file(board, strategy, order, stream) + output = stream.getvalue() + stream = None + + output = '\n'.join(line.rstrip() for line in output.splitlines()) + if output != expected: + raise AssertionError("got a wrong answer:\n%s\nexpected: %s" + % (output, expected)) + + +def run_pgo(): + main(10, level=DEFAULT_LEVEL) diff --git a/Lib/test/pgo_task/bm_json_dumps.py b/Lib/test/pgo_task/bm_json_dumps.py new file mode 100644 index 00000000000000..8b0fc656353c3e --- /dev/null +++ b/Lib/test/pgo_task/bm_json_dumps.py @@ -0,0 +1,31 @@ +import json +import sys + + +EMPTY = ({}, 2000) +SIMPLE_DATA = {'key1': 0, 'key2': True, 'key3': 'value', 'key4': 'foo', + 'key5': 'string'} +SIMPLE = (SIMPLE_DATA, 1000) +NESTED_DATA = {'key1': 0, 'key2': SIMPLE[0], 'key3': 'value', 'key4': SIMPLE[0], + 'key5': SIMPLE[0], 'key': '\u0105\u0107\u017c'} +NESTED = (NESTED_DATA, 1000) +HUGE = ([NESTED[0]] * 1000, 1) + +CASES = ['EMPTY', 'SIMPLE', 'NESTED', 'HUGE'] + + +def bench_json_dumps(data): + for obj, count_it in data: + for _ in count_it: + json.dumps(obj) + + +def run_pgo(): + cases = CASES + data = [] + for case in cases: + obj, count = globals()[case] + data.append((obj, range(count))) + + for _ in range(10): + bench_json_dumps(data) diff --git a/Lib/test/pgo_task/bm_json_loads.py b/Lib/test/pgo_task/bm_json_loads.py new file mode 100644 index 00000000000000..857b5fcda24713 --- /dev/null +++ b/Lib/test/pgo_task/bm_json_loads.py @@ -0,0 +1,101 @@ + +"""Script for testing the performance of json parsing and serialization. + +This will dump/load several real world-representative objects a few +thousand times. The methodology below was chosen for was chosen to be similar +to real-world scenarios which operate on single objects at a time. +""" + +# Python imports +import json +import random +import sys + + +DICT = { + 'ads_flags': 0, + 'age': 18, + 'bulletin_count': 0, + 'comment_count': 0, + 'country': 'BR', + 'encrypted_id': 'G9urXXAJwjE', + 'favorite_count': 9, + 'first_name': '', + 'flags': 412317970704, + 'friend_count': 0, + 'gender': 'm', + 'gender_for_display': 'Male', + 'id': 302935349, + 'is_custom_profile_icon': 0, + 'last_name': '', + 'locale_preference': 'pt_BR', + 'member': 0, + 'tags': ['a', 'b', 'c', 'd', 'e', 'f', 'g'], + 'profile_foo_id': 827119638, + 'secure_encrypted_id': 'Z_xxx2dYx3t4YAdnmfgyKw', + 'session_number': 2, + 'signup_id': '201-19225-223', + 'status': 'A', + 'theme': 1, + 'time_created': 1225237014, + 'time_updated': 1233134493, + 'unread_message_count': 0, + 'user_group': '0', + 'username': 'collinwinter', + 'play_count': 9, + 'view_count': 7, + 'zip': ''} + +TUPLE = ( + [265867233, 265868503, 265252341, 265243910, 265879514, + 266219766, 266021701, 265843726, 265592821, 265246784, + 265853180, 45526486, 265463699, 265848143, 265863062, + 265392591, 265877490, 265823665, 265828884, 265753032], 60) + + +def mutate_dict(orig_dict, random_source): + new_dict = dict(orig_dict) + for key, value in new_dict.items(): + rand_val = random_source.random() * sys.maxsize + if isinstance(key, (int, bytes, str)): + new_dict[key] = type(key)(rand_val) + return new_dict + + +random_source = random.Random(5) # Fixed seed. +DICT_GROUP = [mutate_dict(DICT, random_source) for _ in range(3)] + + +def bench_json_loads(objs): + for obj in objs: + # 20 loads + json.loads(obj) + json.loads(obj) + json.loads(obj) + json.loads(obj) + json.loads(obj) + json.loads(obj) + json.loads(obj) + json.loads(obj) + json.loads(obj) + json.loads(obj) + json.loads(obj) + json.loads(obj) + json.loads(obj) + json.loads(obj) + json.loads(obj) + json.loads(obj) + json.loads(obj) + json.loads(obj) + json.loads(obj) + json.loads(obj) + + +def run_pgo(): + json_dict = json.dumps(DICT) + json_tuple = json.dumps(TUPLE) + json_dict_group = json.dumps(DICT_GROUP) + objs = (json_dict, json_tuple, json_dict_group) + + for _ in range(10): + bench_json_loads(objs) diff --git a/Lib/test/pgo_task/bm_logging.py b/Lib/test/pgo_task/bm_logging.py new file mode 100644 index 00000000000000..33654a50edfed1 --- /dev/null +++ b/Lib/test/pgo_task/bm_logging.py @@ -0,0 +1,129 @@ +""" +Script for testing the performance of logging simple messages. + +Rationale for logging_silent by Antoine Pitrou: + +"The performance of silent logging calls is actually important for all +applications which have debug() calls in their critical paths. This is +quite common in network and/or distributed programming where you want to +allow logging many events for diagnosis of unexpected runtime issues +(because many unexpected conditions can appear), but with those logs +disabled by default for performance and readability reasons." + +https://mail.python.org/pipermail/speed/2017-May/000576.html +""" + +# Python imports +import io +import logging + +# A simple format for parametered logging +FORMAT = 'important: %s' +MESSAGE = 'some important information to be logged' + + +def truncate_stream(stream): + stream.seek(0) + stream.truncate() + + +def bench_silent(loops, logger, stream): + truncate_stream(stream) + + # micro-optimization: use fast local variables + m = MESSAGE + range_it = range(loops) + + for _ in range_it: + # repeat 10 times + logger.debug(m) + logger.debug(m) + logger.debug(m) + logger.debug(m) + logger.debug(m) + logger.debug(m) + logger.debug(m) + logger.debug(m) + logger.debug(m) + logger.debug(m) + + if len(stream.getvalue()) != 0: + raise ValueError("stream is expected to be empty") + + +def bench_simple_output(loops, logger, stream): + truncate_stream(stream) + + # micro-optimization: use fast local variables + m = MESSAGE + range_it = range(loops) + + for _ in range_it: + # repeat 10 times + logger.warning(m) + logger.warning(m) + logger.warning(m) + logger.warning(m) + logger.warning(m) + logger.warning(m) + logger.warning(m) + logger.warning(m) + logger.warning(m) + logger.warning(m) + + lines = stream.getvalue().splitlines() + if len(lines) != loops * 10: + raise ValueError("wrong number of lines") + + +def bench_formatted_output(loops, logger, stream): + truncate_stream(stream) + + # micro-optimization: use fast local variables + fmt = FORMAT + msg = MESSAGE + range_it = range(loops) + + for _ in range_it: + # repeat 10 times + logger.warning(fmt, msg) + logger.warning(fmt, msg) + logger.warning(fmt, msg) + logger.warning(fmt, msg) + logger.warning(fmt, msg) + logger.warning(fmt, msg) + logger.warning(fmt, msg) + logger.warning(fmt, msg) + logger.warning(fmt, msg) + logger.warning(fmt, msg) + + lines = stream.getvalue().splitlines() + if len(lines) != loops * 10: + raise ValueError("wrong number of lines") + + +BENCHMARKS = { + "silent": bench_silent, + "simple": bench_simple_output, + "format": bench_formatted_output, +} + + +def run_pgo(): + + # NOTE: StringIO performance will impact the results... + stream = io.StringIO() + + handler = logging.StreamHandler(stream=stream) + logger = logging.getLogger("benchlogger") + logger.propagate = False + logger.addHandler(handler) + logger.setLevel(logging.WARNING) + + benchmarks = sorted(BENCHMARKS) + + for bench in benchmarks: + name = 'logging_%s' % bench + bench_func = BENCHMARKS[bench] + + bench_func(100, logger, stream) diff --git a/Lib/test/pgo_task/bm_mdp.py b/Lib/test/pgo_task/bm_mdp.py new file mode 100644 index 00000000000000..0b6f136e972240 --- /dev/null +++ b/Lib/test/pgo_task/bm_mdp.py @@ -0,0 +1,259 @@ +import collections +from collections import defaultdict +from fractions import Fraction + +def topoSort(roots, getParents): + """Return a topological sorting of nodes in a graph. + + roots - list of root nodes to search from + getParents - function which returns the parents of a given node + """ + + results = [] + visited = set() + + # Use iterative version to avoid stack limits for large datasets + stack = [(node, 0) for node in roots] + while stack: + current, state = stack.pop() + if state == 0: + # before recursing + if current not in visited: + visited.add(current) + stack.append((current, 1)) + stack.extend((parent, 0) for parent in getParents(current)) + else: + # after recursing + assert(current in visited) + results.append(current) + return results + + +def getDamages(L, A, D, B, stab, te): + x = (2 * L) // 5 + x = ((x + 2) * A * B) // (D * 50) + 2 + if stab: + x += x // 2 + x = int(x * te) + return [(x * z) // 255 for z in range(217, 256)] + + +def getCritDist(L, p, A1, A2, D1, D2, B, stab, te): + p = min(p, Fraction(1)) + norm = getDamages(L, A1, D1, B, stab, te) + crit = getDamages(L * 2, A2, D2, B, stab, te) + + dist = defaultdict(Fraction) + for mult, vals in zip([1 - p, p], [norm, crit]): + mult /= len(vals) + for x in vals: + dist[x] += mult + return dist + + +def plus12(x): + return x + x // 8 + + +stats_t = collections.namedtuple('stats_t', ['atk', 'df', 'speed', 'spec']) +NOMODS = stats_t(0, 0, 0, 0) + + +fixeddata_t = collections.namedtuple( + 'fixeddata_t', ['maxhp', 'stats', 'lvl', 'badges', 'basespeed']) +halfstate_t = collections.namedtuple( + 'halfstate_t', ['fixed', 'hp', 'status', 'statmods', 'stats']) + + +def applyHPChange(hstate, change): + hp = min(hstate.fixed.maxhp, max(0, hstate.hp + change)) + return hstate._replace(hp=hp) + + +def applyBadgeBoosts(badges, stats): + return stats_t(*[(plus12(x) if b else x) for x, b in zip(stats, badges)]) + + +attack_stats_t = collections.namedtuple( + 'attack_stats_t', ['power', 'isspec', 'stab', 'te', 'crit']) +attack_data = { + 'Ember': attack_stats_t(40, True, True, 0.5, False), + 'Dig': attack_stats_t(100, False, False, 1, False), + 'Slash': attack_stats_t(70, False, False, 1, True), + 'Water Gun': attack_stats_t(40, True, True, 2, False), + 'Bubblebeam': attack_stats_t(65, True, True, 2, False), +} + + +def _applyActionSide1(state, act): + me, them, extra = state + + if act == 'Super Potion': + me = applyHPChange(me, 50) + return {(me, them, extra): Fraction(1)} + + mdata = attack_data[act] + aind = 3 if mdata.isspec else 0 + dind = 3 if mdata.isspec else 1 + pdiv = 64 if mdata.crit else 512 + dmg_dist = getCritDist(me.fixed.lvl, Fraction(me.fixed.basespeed, pdiv), + me.stats[aind], me.fixed.stats[aind], them.stats[ + dind], them.fixed.stats[dind], + mdata.power, mdata.stab, mdata.te) + + dist = defaultdict(Fraction) + for dmg, p in dmg_dist.items(): + them2 = applyHPChange(them, -dmg) + dist[me, them2, extra] += p + return dist + + +def _applyAction(state, side, act): + if side == 0: + return _applyActionSide1(state, act) + else: + me, them, extra = state + dist = _applyActionSide1((them, me, extra), act) + return {(k[1], k[0], k[2]): v for k, v in dist.items()} + + +class Battle(object): + + def __init__(self): + self.successors = {} + self.min = defaultdict(float) + self.max = defaultdict(lambda: 1.0) + self.frozen = set() + + self.win = 4, True + self.loss = 4, False + self.max[self.loss] = 0.0 + self.min[self.win] = 1.0 + self.frozen.update([self.win, self.loss]) + + def _getSuccessorsA(self, statep): + st, state = statep + for action in ['Dig', 'Super Potion']: + yield (1, state, action) + + def _applyActionPair(self, state, side1, act1, side2, act2, dist, pmult): + for newstate, p in _applyAction(state, side1, act1).items(): + if newstate[0].hp == 0: + newstatep = self.loss + elif newstate[1].hp == 0: + newstatep = self.win + else: + newstatep = 2, newstate, side2, act2 + dist[newstatep] += p * pmult + + def _getSuccessorsB(self, statep): + st, state, action = statep + dist = defaultdict(Fraction) + for eact, p in [('Water Gun', Fraction(64, 130)), + ('Bubblebeam', Fraction(66, 130))]: + priority1 = state[0].stats.speed + \ + 10000 * (action == 'Super Potion') + priority2 = state[1].stats.speed + 10000 * (action == 'X Defend') + + if priority1 > priority2: + self._applyActionPair(state, 0, action, 1, eact, dist, p) + elif priority1 < priority2: + self._applyActionPair(state, 1, eact, 0, action, dist, p) + else: + self._applyActionPair(state, 0, action, 1, eact, dist, p / 2) + self._applyActionPair(state, 1, eact, 0, action, dist, p / 2) + + return {k: float(p) for k, p in dist.items() if p > 0} + + def _getSuccessorsC(self, statep): + st, state, side, action = statep + dist = defaultdict(Fraction) + for newstate, p in _applyAction(state, side, action).items(): + if newstate[0].hp == 0: + newstatep = self.loss + elif newstate[1].hp == 0: + newstatep = self.win + else: + newstatep = 0, newstate + dist[newstatep] += p + return {k: float(p) for k, p in dist.items() if p > 0} + + def getSuccessors(self, statep): + try: + return self.successors[statep] + except KeyError: + st = statep[0] + if st == 0: + result = list(self._getSuccessorsA(statep)) + else: + if st == 1: + dist = self._getSuccessorsB(statep) + elif st == 2: + dist = self._getSuccessorsC(statep) + result = sorted(dist.items(), key=lambda t: (-t[1], t[0])) + self.successors[statep] = result + return result + + def getSuccessorsList(self, statep): + if statep[0] == 4: + return [] + temp = self.getSuccessors(statep) + if statep[0] != 0: + temp = list(zip(*temp))[0] if temp else [] + return temp + + def evaluate(self, tolerance=0.15): + badges = 1, 0, 0, 0 + + starfixed = fixeddata_t(59, stats_t(40, 44, 56, 50), 11, NOMODS, 115) + starhalf = halfstate_t(starfixed, 59, 0, NOMODS, + stats_t(40, 44, 56, 50)) + charfixed = fixeddata_t(63, stats_t(39, 34, 46, 38), 26, badges, 65) + charhalf = halfstate_t(charfixed, 63, 0, NOMODS, applyBadgeBoosts( + badges, stats_t(39, 34, 46, 38))) + initial_state = charhalf, starhalf, 0 + initial_statep = 0, initial_state + + dmin, dmax, frozen = self.min, self.max, self.frozen + stateps = topoSort([initial_statep], self.getSuccessorsList) + + itercount = 0 + while dmax[initial_statep] - dmin[initial_statep] > tolerance: + itercount += 1 + + for sp in stateps: + if sp in frozen: + continue + + if sp[0] == 0: + # choice node + dmin[sp] = max(dmin[sp2] for sp2 in self.getSuccessors(sp)) + dmax[sp] = max(dmax[sp2] for sp2 in self.getSuccessors(sp)) + else: + dmin[sp] = sum(dmin[sp2] * p for sp2, + p in self.getSuccessors(sp)) + dmax[sp] = sum(dmax[sp2] * p for sp2, + p in self.getSuccessors(sp)) + + if dmin[sp] >= dmax[sp]: + dmax[sp] = dmin[sp] = (dmin[sp] + dmax[sp]) / 2 + frozen.add(sp) + return (dmax[initial_statep] + dmin[initial_statep]) / 2 + + +def bench_mdp(loops): + expected = 0.89873589887 + max_diff = 1e-6 + range_it = range(loops) + + for _ in range_it: + result = Battle().evaluate(0.192) + + if abs(result - expected) > max_diff: + raise Exception("invalid result: got %s, expected %s " + "(diff: %s, max diff: %s)" + % (result, expected, result - expected, max_diff)) + + +def run_pgo(): + bench_mdp(1) diff --git a/Lib/test/pgo_task/bm_meteor_contest.py b/Lib/test/pgo_task/bm_meteor_contest.py new file mode 100644 index 00000000000000..046fc53143b460 --- /dev/null +++ b/Lib/test/pgo_task/bm_meteor_contest.py @@ -0,0 +1,212 @@ +""" +Meteor Puzzle board: +http://benchmarksgame.alioth.debian.org/u32/meteor-description.html#meteor + +The Computer Language Benchmarks Game +http://benchmarksgame.alioth.debian.org/ + +contributed by Daniel Nanz, 2008-08-21 +""" + +from bisect import bisect + + +SOLVE_ARG = 60 + +WIDTH, HEIGHT = 5, 10 +DIR_NO = 6 +S, E = WIDTH * HEIGHT, 2 +SE = S + (E / 2) +SW = SE - E +W, NW, NE = -E, -SE, -SW + +SOLUTIONS = [ + '00001222012661126155865558633348893448934747977799', + '00001222012771127148774485464855968596835966399333', + '00001222012771127148774485494855998596835966366333', + '00001222012771127148774485994855948596835966366333', + '00001222012771127166773863384653846538445584959999', + '00001222012771127183778834833348555446554666969999', + '00001222012771127183778834833348555446554966699996', + '00001223012331123166423564455647456775887888979999', + '00001555015541144177484726877268222683336689399993', + '00001555015541144177484728677286222863338669399993', + '00001599015591159148594482224827748276837766366333', + '00001777017871184155845558449984669662932629322333', + '00004222042664426774996879687759811598315583153331', + '00004222042774427384773183331866118615586555969999', + '00004223042334423784523785771855718566186611969999', + '00004227042874428774528735833155831566316691169999', + '00004333045534455384175781777812228116286662969999', + '00004333045934459384559185991866118612286727267772', + '00004333047734427384277182221866118615586555969999', + '00004555045514411224172621768277368736683339899998', + '00004555045514411224172721777299998966836688368333', + '00004555045534413334132221177266172677886888969999', + '00004555045534473334739967792617926192661882211888', + '00004555045564466694699992288828811233317273177731', + '00004555045564466694699997773172731233312881122888', + '00004555045564496664999962288828811233317273177731', + '00004555045564496664999967773172731233312881122888', + '00004555045584411884171187722866792679236992369333', + '00004555045584411884191189999832226333267372677766', + '00004555045584411884191189999866222623336727367773', + '13335138551389511895778697869947762446624022240000', + '13777137271333211882888226999946669446554055540000', + '13777137271333211882888229999649666446554055540000', + '27776272768221681166819958195548395443954033340000', + '33322392623926696648994485554855148117871077710000', + '33366366773867284772842228449584195119551099510000', + '33366366953869584955849958447784172117721022210000', + '33366366953869589955849458447784172117721022210000', + '33386388663866989999277712727142211441554055540000', + '33396329963297629766822778117148811448554055540000', + '33399366953869586955846458447784172117721022210000', + '37776372763332622266899998119148811448554055540000', + '39999396683336822268277682748477144114551055510000', + '39999398663338622286277862748477144114551055510000', + '66777627376233362223899998119148811448554055540000', + '69999666945564455584333843887738172117721022210000', + '88811228816629162971629776993743337443554055540000', + '88822118821333213727137776999946669446554055540000', + '88822118821333213727137779999649666446554055540000', + '89999893338663786377286712627142211441554055540000', + '99777974743984439884333685556855162116621022210000', + '99995948554483564835648336837766172117721022210000', + '99996119661366513855133853782547782447824072240000', + '99996911668166581755817758732548732443324032240000', + '99996926668261182221877718757148355443554033340000', + '99996955568551681166812228177248372443774033340000', + '99996955568551681166813338137748372447724022240000', + '99996966645564455584333843887738172117721022210000', + '99996988868877627166277112223143331443554055540000', + '99997988878857765474655446532466132113321032210000'] + + +def rotate(ido, rd={E: NE, NE: NW, NW: W, W: SW, SW: SE, SE: E}): + return [rd[o] for o in ido] + + +def flip(ido, fd={E: E, NE: SE, NW: SW, W: W, SW: NW, SE: NE}): + return [fd[o] for o in ido] + + +def permute(ido, r_ido, rotate=rotate, flip=flip): + ps = [ido] + for r in range(DIR_NO - 1): + ps.append(rotate(ps[-1])) + if ido == r_ido: # C2-symmetry + ps = ps[0:DIR_NO // 2] + for pp in ps[:]: + ps.append(flip(pp)) + return ps + + +def convert(ido): + '''incremental direction offsets -> "coordinate offsets" ''' + out = [0] + for o in ido: + out.append(out[-1] + o) + return list(set(out)) + + +def get_footprints(board, cti, pieces): + fps = [[[] for p in range(len(pieces))] for ci in range(len(board))] + for c in board: + for pi, p in enumerate(pieces): + for pp in p: + fp = frozenset([cti[c + o] for o in pp if (c + o) in cti]) + if len(fp) == 5: + fps[min(fp)][pi].append(fp) + return fps + + +def get_senh(board, cti): + '''-> south-east neighborhood''' + se_nh = [] + nh = [E, SW, SE] + for c in board: + se_nh.append(frozenset([cti[c + o] for o in nh if (c + o) in cti])) + return se_nh + + +def get_puzzle(width, height): + board = [E * x + S * y + (y % 2) + for y in range(height) + for x in range(width)] + cti = dict((board[i], i) for i in range(len(board))) + + # Incremental direction offsets + idos = [[E, E, E, SE], + [SE, SW, W, SW], + [W, W, SW, SE], + [E, E, SW, SE], + [NW, W, NW, SE, SW], + [E, E, NE, W], + [NW, NE, NE, W], + [NE, SE, E, NE], + [SE, SE, E, SE], + [E, NW, NW, NW]] + + # Restrict piece 4 + perms = (permute(p, idos[3]) for p in idos) + pieces = [[convert(pp) for pp in p] for p in perms] + return (board, cti, pieces) + + +def solve(n, i_min, free, curr_board, pieces_left, solutions, fps, se_nh, + # Hack to use a fast local variable to avoid a global lookup + bisect=bisect): + + fp_i_cands = fps[i_min] + for p in pieces_left: + fp_cands = fp_i_cands[p] + for fp in fp_cands: + if fp <= free: + n_curr_board = curr_board[:] + for ci in fp: + n_curr_board[ci] = p + + if len(pieces_left) > 1: + n_free = free - fp + n_i_min = min(n_free) + if len(n_free & se_nh[n_i_min]) > 0: + n_pieces_left = pieces_left[:] + n_pieces_left.remove(p) + solve(n, n_i_min, n_free, n_curr_board, + n_pieces_left, solutions, fps, se_nh) + else: + s = ''.join(map(str, n_curr_board)) + solutions.insert(bisect(solutions, s), s) + rs = s[::-1] + solutions.insert(bisect(solutions, rs), rs) + if len(solutions) >= n: + return + + if len(solutions) >= n: + return + + +def bench_meteor_contest(loops, board, pieces, solve_arg, fps, se_nh): + range_it = range(loops) + + for _ in range_it: + free = frozenset(range(len(board))) + curr_board = [-1] * len(board) + pieces_left = list(range(len(pieces))) + solutions = [] + solve(solve_arg, 0, free, curr_board, pieces_left, + solutions, fps, se_nh) + + if solutions != SOLUTIONS: + raise ValueError("unexpected solutions") + + +def run_pgo(): + board, cti, pieces = get_puzzle(WIDTH, HEIGHT) + fps = get_footprints(board, cti, pieces) + se_nh = get_senh(board, cti) + + solve_arg = SOLVE_ARG + loops = 1 + bench_meteor_contest(loops, board, pieces, solve_arg, fps, se_nh) diff --git a/Lib/test/pgo_task/bm_nbody.py b/Lib/test/pgo_task/bm_nbody.py new file mode 100644 index 00000000000000..996cb0e3aeea65 --- /dev/null +++ b/Lib/test/pgo_task/bm_nbody.py @@ -0,0 +1,135 @@ +""" +N-body benchmark from the Computer Language Benchmarks Game. + +This is intended to support Unladen Swallow's pyperf.py. Accordingly, it has been +modified from the Shootout version: +- Accept standard Unladen Swallow benchmark options. +- Run report_energy()/advance() in a loop. +- Reimplement itertools.combinations() to work with older Python versions. + +Pulled from: +http://benchmarksgame.alioth.debian.org/u64q/program.php?test=nbody&lang=python3&id=1 + +Contributed by Kevin Carson. +Modified by Tupteq, Fredrik Johansson, and Daniel Nanz. +""" + +__contact__ = "collinwinter@google.com (Collin Winter)" +DEFAULT_ITERATIONS = 20000 +DEFAULT_REFERENCE = 'sun' + + +def combinations(l): + """Pure-Python implementation of itertools.combinations(l, 2).""" + result = [] + for x in range(len(l) - 1): + ls = l[x + 1:] + for y in ls: + result.append((l[x], y)) + return result + + +PI = 3.14159265358979323 +SOLAR_MASS = 4 * PI * PI +DAYS_PER_YEAR = 365.24 + +BODIES = { + 'sun': ([0.0, 0.0, 0.0], [0.0, 0.0, 0.0], SOLAR_MASS), + + 'jupiter': ([4.84143144246472090e+00, + -1.16032004402742839e+00, + -1.03622044471123109e-01], + [1.66007664274403694e-03 * DAYS_PER_YEAR, + 7.69901118419740425e-03 * DAYS_PER_YEAR, + -6.90460016972063023e-05 * DAYS_PER_YEAR], + 9.54791938424326609e-04 * SOLAR_MASS), + + 'saturn': ([8.34336671824457987e+00, + 4.12479856412430479e+00, + -4.03523417114321381e-01], + [-2.76742510726862411e-03 * DAYS_PER_YEAR, + 4.99852801234917238e-03 * DAYS_PER_YEAR, + 2.30417297573763929e-05 * DAYS_PER_YEAR], + 2.85885980666130812e-04 * SOLAR_MASS), + + 'uranus': ([1.28943695621391310e+01, + -1.51111514016986312e+01, + -2.23307578892655734e-01], + [2.96460137564761618e-03 * DAYS_PER_YEAR, + 2.37847173959480950e-03 * DAYS_PER_YEAR, + -2.96589568540237556e-05 * DAYS_PER_YEAR], + 4.36624404335156298e-05 * SOLAR_MASS), + + 'neptune': ([1.53796971148509165e+01, + -2.59193146099879641e+01, + 1.79258772950371181e-01], + [2.68067772490389322e-03 * DAYS_PER_YEAR, + 1.62824170038242295e-03 * DAYS_PER_YEAR, + -9.51592254519715870e-05 * DAYS_PER_YEAR], + 5.15138902046611451e-05 * SOLAR_MASS)} + + +SYSTEM = list(BODIES.values()) +PAIRS = combinations(SYSTEM) + + +def advance(dt, n, bodies=SYSTEM, pairs=PAIRS): + for i in range(n): + for (([x1, y1, z1], v1, m1), + ([x2, y2, z2], v2, m2)) in pairs: + dx = x1 - x2 + dy = y1 - y2 + dz = z1 - z2 + mag = dt * ((dx * dx + dy * dy + dz * dz) ** (-1.5)) + b1m = m1 * mag + b2m = m2 * mag + v1[0] -= dx * b2m + v1[1] -= dy * b2m + v1[2] -= dz * b2m + v2[0] += dx * b1m + v2[1] += dy * b1m + v2[2] += dz * b1m + for (r, [vx, vy, vz], m) in bodies: + r[0] += dt * vx + r[1] += dt * vy + r[2] += dt * vz + + +def report_energy(bodies=SYSTEM, pairs=PAIRS, e=0.0): + for (((x1, y1, z1), v1, m1), + ((x2, y2, z2), v2, m2)) in pairs: + dx = x1 - x2 + dy = y1 - y2 + dz = z1 - z2 + e -= (m1 * m2) / ((dx * dx + dy * dy + dz * dz) ** 0.5) + for (r, [vx, vy, vz], m) in bodies: + e += m * (vx * vx + vy * vy + vz * vz) / 2. + return e + + +def offset_momentum(ref, bodies=SYSTEM, px=0.0, py=0.0, pz=0.0): + for (r, [vx, vy, vz], m) in bodies: + px -= vx * m + py -= vy * m + pz -= vz * m + (r, v, m) = ref + v[0] = px / m + v[1] = py / m + v[2] = pz / m + + +def bench_nbody(loops, reference, iterations): + # Set up global state + offset_momentum(BODIES[reference]) + + range_it = range(loops) + + for _ in range_it: + report_energy() + advance(0.01, iterations) + report_energy() + + +def run_pgo(): + loops = 1 + bench_nbody(loops, DEFAULT_REFERENCE, DEFAULT_ITERATIONS) diff --git a/Lib/test/pgo_task/bm_nqueens.py b/Lib/test/pgo_task/bm_nqueens.py new file mode 100644 index 00000000000000..174197920b5a5b --- /dev/null +++ b/Lib/test/pgo_task/bm_nqueens.py @@ -0,0 +1,57 @@ +"""Simple, brute-force N-Queens solver.""" + +__author__ = "collinwinter@google.com (Collin Winter)" + + +# Pure-Python implementation of itertools.permutations(). +def permutations(iterable, r=None): + """permutations(range(3), 2) --> (0,1) (0,2) (1,0) (1,2) (2,0) (2,1)""" + pool = tuple(iterable) + n = len(pool) + if r is None: + r = n + indices = list(range(n)) + cycles = list(range(n - r + 1, n + 1))[::-1] + yield tuple(pool[i] for i in indices[:r]) + while n: + for i in reversed(range(r)): + cycles[i] -= 1 + if cycles[i] == 0: + indices[i:] = indices[i + 1:] + indices[i:i + 1] + cycles[i] = n - i + else: + j = cycles[i] + indices[i], indices[-j] = indices[-j], indices[i] + yield tuple(pool[i] for i in indices[:r]) + break + else: + return + + +# From http://code.activestate.com/recipes/576647/ +def n_queens(queen_count): + """N-Queens solver. + + Args: + queen_count: the number of queens to solve for. This is also the + board size. + + Yields: + Solutions to the problem. Each yielded value is looks like + (3, 8, 2, 1, 4, ..., 6) where each number is the column position for the + queen, and the index into the tuple indicates the row. + """ + cols = range(queen_count) + for vec in permutations(cols): + if (queen_count == len(set(vec[i] + i for i in cols)) + == len(set(vec[i] - i for i in cols))): + yield vec + + +def bench_n_queens(queen_count): + list(n_queens(queen_count)) + + +def run_pgo(): + queen_count = 8 + bench_n_queens(queen_count) diff --git a/Lib/test/pgo_task/bm_pathlib.py b/Lib/test/pgo_task/bm_pathlib.py new file mode 100644 index 00000000000000..de5443eaa2dcce --- /dev/null +++ b/Lib/test/pgo_task/bm_pathlib.py @@ -0,0 +1,68 @@ +""" +Test the performance of pathlib operations. + +This benchmark stresses the creation of small objects, globbing, and system +calls. +""" + +# Python imports +import os +import pathlib +import shutil +import tempfile + + +NUM_FILES = 2000 + + +def generate_filenames(tmp_path, num_files): + i = 0 + while num_files: + for ext in [".py", ".txt", ".tar.gz", ""]: + i += 1 + yield os.path.join(tmp_path, str(i) + ext) + num_files -= 1 + + +def setup(num_files): + tmp_path = tempfile.mkdtemp() + for fn in generate_filenames(tmp_path, num_files): + with open(fn, "wb") as f: + f.write(b'benchmark') + + return tmp_path + + +def bench_pathlib(loops, tmp_path): + base_path = pathlib.Path(tmp_path) + + # Warm up the filesystem cache and keep some objects in memory. + path_objects = list(base_path.iterdir()) + # FIXME: does this code really cache anything? + for p in path_objects: + p.stat() + assert len(path_objects) == NUM_FILES, len(path_objects) + + range_it = range(loops) + + for _ in range_it: + # Do something simple with each path. + for p in base_path.iterdir(): + p.stat() + for p in base_path.glob("*.py"): + p.stat() + for p in base_path.iterdir(): + p.stat() + for p in base_path.glob("*.py"): + p.stat() + + + +def run_pgo(): + modname = pathlib.__name__ + tmp_path = setup(NUM_FILES) + loops = 1 + try: + bench_pathlib(loops, tmp_path) + finally: + shutil.rmtree(tmp_path) diff --git a/Lib/test/pgo_task/bm_pickle.py b/Lib/test/pgo_task/bm_pickle.py new file mode 100644 index 00000000000000..43053f59ef2b05 --- /dev/null +++ b/Lib/test/pgo_task/bm_pickle.py @@ -0,0 +1,244 @@ + +"""Script for testing the performance of pickling/unpickling. + +This will pickle/unpickle several real world-representative objects a few +thousand times. The methodology below was chosen for was chosen to be similar +to real-world scenarios which operate on single objects at a time. Note that if +we did something like + + pickle.dumps([dict(some_dict) for _ in range(10000)]) + +this isn't equivalent to dumping the dict 10000 times: pickle uses a +highly-efficient encoding for the n-1 following copies. +""" + +import datetime +import random +import sys + +__author__ = "collinwinter@google.com (Collin Winter)" + + +DICT = { + 'ads_flags': 0, + 'age': 18, + 'birthday': datetime.date(1980, 5, 7), + 'bulletin_count': 0, + 'comment_count': 0, + 'country': 'BR', + 'encrypted_id': 'G9urXXAJwjE', + 'favorite_count': 9, + 'first_name': '', + 'flags': 412317970704, + 'friend_count': 0, + 'gender': 'm', + 'gender_for_display': 'Male', + 'id': 302935349, + 'is_custom_profile_icon': 0, + 'last_name': '', + 'locale_preference': 'pt_BR', + 'member': 0, + 'tags': ['a', 'b', 'c', 'd', 'e', 'f', 'g'], + 'profile_foo_id': 827119638, + 'secure_encrypted_id': 'Z_xxx2dYx3t4YAdnmfgyKw', + 'session_number': 2, + 'signup_id': '201-19225-223', + 'status': 'A', + 'theme': 1, + 'time_created': 1225237014, + 'time_updated': 1233134493, + 'unread_message_count': 0, + 'user_group': '0', + 'username': 'collinwinter', + 'play_count': 9, + 'view_count': 7, + 'zip': ''} + +TUPLE = ( + [265867233, 265868503, 265252341, 265243910, 265879514, + 266219766, 266021701, 265843726, 265592821, 265246784, + 265853180, 45526486, 265463699, 265848143, 265863062, + 265392591, 265877490, 265823665, 265828884, 265753032], 60) + + +def mutate_dict(orig_dict, random_source): + new_dict = dict(orig_dict) + for key, value in new_dict.items(): + rand_val = random_source.random() * sys.maxsize + if isinstance(key, (int, bytes, str)): + new_dict[key] = type(key)(rand_val) + return new_dict + + +random_source = random.Random(5) # Fixed seed. +DICT_GROUP = [mutate_dict(DICT, random_source) for _ in range(3)] + + +def bench_pickle(loops, pickle, options): + range_it = range(loops) + + # micro-optimization: use fast local variables + dumps = pickle.dumps + objs = (DICT, TUPLE, DICT_GROUP) + protocol = options.protocol + + for _ in range_it: + for obj in objs: + # 20 dumps + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + + + +def bench_unpickle(loops, pickle, options): + pickled_dict = pickle.dumps(DICT, options.protocol) + pickled_tuple = pickle.dumps(TUPLE, options.protocol) + pickled_dict_group = pickle.dumps(DICT_GROUP, options.protocol) + range_it = range(loops) + + # micro-optimization: use fast local variables + loads = pickle.loads + objs = (pickled_dict, pickled_tuple, pickled_dict_group) + + for _ in range_it: + for obj in objs: + # 20 loads dict + loads(obj) + loads(obj) + loads(obj) + loads(obj) + loads(obj) + loads(obj) + loads(obj) + loads(obj) + loads(obj) + loads(obj) + loads(obj) + loads(obj) + loads(obj) + loads(obj) + loads(obj) + loads(obj) + loads(obj) + loads(obj) + loads(obj) + loads(obj) + + + +LIST = [[list(range(10)), list(range(10))] for _ in range(10)] + + +def bench_pickle_list(loops, pickle, options): + range_it = range(loops) + # micro-optimization: use fast local variables + dumps = pickle.dumps + obj = LIST + protocol = options.protocol + + for _ in range_it: + # 10 dumps list + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + dumps(obj, protocol) + + + +def bench_unpickle_list(loops, pickle, options): + pickled_list = pickle.dumps(LIST, options.protocol) + range_it = range(loops) + + # micro-optimization: use fast local variables + loads = pickle.loads + + for _ in range_it: + # 10 loads list + loads(pickled_list) + loads(pickled_list) + loads(pickled_list) + loads(pickled_list) + loads(pickled_list) + loads(pickled_list) + loads(pickled_list) + loads(pickled_list) + loads(pickled_list) + loads(pickled_list) + + + +MICRO_DICT = dict((key, dict.fromkeys(range(10))) for key in range(100)) + + +def bench_pickle_dict(loops, pickle, options): + range_it = range(loops) + # micro-optimization: use fast local variables + protocol = options.protocol + obj = MICRO_DICT + + for _ in range_it: + # 5 dumps dict + pickle.dumps(obj, protocol) + pickle.dumps(obj, protocol) + pickle.dumps(obj, protocol) + pickle.dumps(obj, protocol) + pickle.dumps(obj, protocol) + + + +BENCHMARKS = { + # 20 inner-loops: don't count the 3 pickled objects + 'pickle': (bench_pickle, 20), + + # 20 inner-loops: don't count the 3 unpickled objects + 'unpickle': (bench_unpickle, 20), + + 'pickle_list': (bench_pickle_list, 10), + 'unpickle_list': (bench_unpickle_list, 10), + 'pickle_dict': (bench_pickle_dict, 5), +} + + +def is_accelerated_module(module): + return getattr(pickle.Pickler, '__module__', '') != 'pickle' + + +def add_cmdline_args(cmd, args): + if args.pure_python: + cmd.append("--pure-python") + cmd.extend(("--protocol", str(args.protocol))) + cmd.append(args.benchmark) + + +def run_pgo(): + import pickle + + class options: + protocol = pickle.HIGHEST_PROTOCOL + + for benchmark, inner_loops in BENCHMARKS.values(): + benchmark(10*inner_loops, pickle, options) diff --git a/Lib/test/pgo_task/bm_pidigits.py b/Lib/test/pgo_task/bm_pidigits.py new file mode 100644 index 00000000000000..a9ad7431fba161 --- /dev/null +++ b/Lib/test/pgo_task/bm_pidigits.py @@ -0,0 +1,53 @@ +# coding: utf-8 +""" +Calculating some of the digits of π. + +This benchmark stresses big integer arithmetic. + +Adapted from code on: +http://benchmarksgame.alioth.debian.org/ +""" + +import itertools + +DEFAULT_DIGITS = 2000 +icount = itertools.count +islice = itertools.islice + + +def gen_x(): + return map(lambda k: (k, 4 * k + 2, 0, 2 * k + 1), icount(1)) + + +def compose(a, b): + aq, ar, as_, at = a + bq, br, bs, bt = b + return (aq * bq, + aq * br + ar * bt, + as_ * bq + at * bs, + as_ * br + at * bt) + + +def extract(z, j): + q, r, s, t = z + return (q * j + r) // (s * j + t) + + +def gen_pi_digits(): + z = (1, 0, 0, 1) + x = gen_x() + while 1: + y = extract(z, 3) + while y != extract(z, 4): + z = compose(z, next(x)) + y = extract(z, 3) + z = compose((10, -10 * y, 0, 1), z) + yield y + + +def calc_ndigits(n): + return list(islice(gen_pi_digits(), n)) + + +def run_pgo(): + calc_ndigits(DEFAULT_DIGITS) diff --git a/Lib/test/pgo_task/bm_pprint.py b/Lib/test/pgo_task/bm_pprint.py new file mode 100644 index 00000000000000..86075a4f97c66a --- /dev/null +++ b/Lib/test/pgo_task/bm_pprint.py @@ -0,0 +1,18 @@ +"""Test the performance of pprint.PrettyPrinter. + +This benchmark was available as `python -m pprint` until Python 3.12. + +Authors: Fred Drake (original), Oleg Iarygin (pyperformance port). +""" + +from pprint import PrettyPrinter + + +printable = [('string', (1, 2), [3, 4], {5: 6, 7: 8})] * 10_000 +p = PrettyPrinter() + + +def run_pgo(): + if hasattr(p, '_safe_repr'): + p._safe_repr(printable, {}, None, 0) + p.pformat(printable) diff --git a/Lib/test/pgo_task/bm_raytrace.py b/Lib/test/pgo_task/bm_raytrace.py new file mode 100644 index 00000000000000..c00eeac39647ad --- /dev/null +++ b/Lib/test/pgo_task/bm_raytrace.py @@ -0,0 +1,379 @@ +""" +This file contains definitions for a simple raytracer. +Copyright Callum and Tony Garnock-Jones, 2008. + +This file may be freely redistributed under the MIT license, +http://www.opensource.org/licenses/mit-license.php + +From http://www.lshift.net/blog/2008/10/29/toy-raytracer-in-python +""" + +import array +import math + + +DEFAULT_WIDTH = 100 +DEFAULT_HEIGHT = 100 +EPSILON = 0.00001 + + +class Vector(object): + + def __init__(self, initx, inity, initz): + self.x = initx + self.y = inity + self.z = initz + + def __str__(self): + return '(%s,%s,%s)' % (self.x, self.y, self.z) + + def __repr__(self): + return 'Vector(%s,%s,%s)' % (self.x, self.y, self.z) + + def magnitude(self): + return math.sqrt(self.dot(self)) + + def __add__(self, other): + if other.isPoint(): + return Point(self.x + other.x, self.y + other.y, self.z + other.z) + else: + return Vector(self.x + other.x, self.y + other.y, self.z + other.z) + + def __sub__(self, other): + other.mustBeVector() + return Vector(self.x - other.x, self.y - other.y, self.z - other.z) + + def scale(self, factor): + return Vector(factor * self.x, factor * self.y, factor * self.z) + + def dot(self, other): + other.mustBeVector() + return (self.x * other.x) + (self.y * other.y) + (self.z * other.z) + + def cross(self, other): + other.mustBeVector() + return Vector(self.y * other.z - self.z * other.y, + self.z * other.x - self.x * other.z, + self.x * other.y - self.y * other.x) + + def normalized(self): + return self.scale(1.0 / self.magnitude()) + + def negated(self): + return self.scale(-1) + + def __eq__(self, other): + return (self.x == other.x) and (self.y == other.y) and (self.z == other.z) + + def isVector(self): + return True + + def isPoint(self): + return False + + def mustBeVector(self): + return self + + def mustBePoint(self): + raise 'Vectors are not points!' + + def reflectThrough(self, normal): + d = normal.scale(self.dot(normal)) + return self - d.scale(2) + + +Vector.ZERO = Vector(0, 0, 0) +Vector.RIGHT = Vector(1, 0, 0) +Vector.UP = Vector(0, 1, 0) +Vector.OUT = Vector(0, 0, 1) + +assert Vector.RIGHT.reflectThrough(Vector.UP) == Vector.RIGHT +assert Vector(-1, -1, 0).reflectThrough(Vector.UP) == Vector(-1, 1, 0) + + +class Point(object): + + def __init__(self, initx, inity, initz): + self.x = initx + self.y = inity + self.z = initz + + def __str__(self): + return '(%s,%s,%s)' % (self.x, self.y, self.z) + + def __repr__(self): + return 'Point(%s,%s,%s)' % (self.x, self.y, self.z) + + def __add__(self, other): + other.mustBeVector() + return Point(self.x + other.x, self.y + other.y, self.z + other.z) + + def __sub__(self, other): + if other.isPoint(): + return Vector(self.x - other.x, self.y - other.y, self.z - other.z) + else: + return Point(self.x - other.x, self.y - other.y, self.z - other.z) + + def isVector(self): + return False + + def isPoint(self): + return True + + def mustBeVector(self): + raise 'Points are not vectors!' + + def mustBePoint(self): + return self + + +class Sphere(object): + + def __init__(self, centre, radius): + centre.mustBePoint() + self.centre = centre + self.radius = radius + + def __repr__(self): + return 'Sphere(%s,%s)' % (repr(self.centre), self.radius) + + def intersectionTime(self, ray): + cp = self.centre - ray.point + v = cp.dot(ray.vector) + discriminant = (self.radius * self.radius) - (cp.dot(cp) - v * v) + if discriminant < 0: + return None + else: + return v - math.sqrt(discriminant) + + def normalAt(self, p): + return (p - self.centre).normalized() + + +class Halfspace(object): + + def __init__(self, point, normal): + self.point = point + self.normal = normal.normalized() + + def __repr__(self): + return 'Halfspace(%s,%s)' % (repr(self.point), repr(self.normal)) + + def intersectionTime(self, ray): + v = ray.vector.dot(self.normal) + if v: + return 1 / -v + else: + return None + + def normalAt(self, p): + return self.normal + + +class Ray(object): + + def __init__(self, point, vector): + self.point = point + self.vector = vector.normalized() + + def __repr__(self): + return 'Ray(%s,%s)' % (repr(self.point), repr(self.vector)) + + def pointAtTime(self, t): + return self.point + self.vector.scale(t) + + +Point.ZERO = Point(0, 0, 0) + + +class Canvas(object): + + def __init__(self, width, height): + self.bytes = array.array('B', [0] * (width * height * 3)) + for i in range(width * height): + self.bytes[i * 3 + 2] = 255 + self.width = width + self.height = height + + def plot(self, x, y, r, g, b): + i = ((self.height - y - 1) * self.width + x) * 3 + self.bytes[i] = max(0, min(255, int(r * 255))) + self.bytes[i + 1] = max(0, min(255, int(g * 255))) + self.bytes[i + 2] = max(0, min(255, int(b * 255))) + + def write_ppm(self, filename): + header = 'P6 %d %d 255\n' % (self.width, self.height) + with open(filename, "wb") as fp: + fp.write(header.encode('ascii')) + fp.write(self.bytes.tobytes()) + + +def firstIntersection(intersections): + result = None + for i in intersections: + candidateT = i[1] + if candidateT is not None and candidateT > -EPSILON: + if result is None or candidateT < result[1]: + result = i + return result + + +class Scene(object): + + def __init__(self): + self.objects = [] + self.lightPoints = [] + self.position = Point(0, 1.8, 10) + self.lookingAt = Point.ZERO + self.fieldOfView = 45 + self.recursionDepth = 0 + + def moveTo(self, p): + self.position = p + + def lookAt(self, p): + self.lookingAt = p + + def addObject(self, object, surface): + self.objects.append((object, surface)) + + def addLight(self, p): + self.lightPoints.append(p) + + def render(self, canvas): + fovRadians = math.pi * (self.fieldOfView / 2.0) / 180.0 + halfWidth = math.tan(fovRadians) + halfHeight = 0.75 * halfWidth + width = halfWidth * 2 + height = halfHeight * 2 + pixelWidth = width / (canvas.width - 1) + pixelHeight = height / (canvas.height - 1) + + eye = Ray(self.position, self.lookingAt - self.position) + vpRight = eye.vector.cross(Vector.UP).normalized() + vpUp = vpRight.cross(eye.vector).normalized() + + for y in range(canvas.height): + for x in range(canvas.width): + xcomp = vpRight.scale(x * pixelWidth - halfWidth) + ycomp = vpUp.scale(y * pixelHeight - halfHeight) + ray = Ray(eye.point, eye.vector + xcomp + ycomp) + colour = self.rayColour(ray) + canvas.plot(x, y, *colour) + + def rayColour(self, ray): + if self.recursionDepth > 3: + return (0, 0, 0) + try: + self.recursionDepth = self.recursionDepth + 1 + intersections = [(o, o.intersectionTime(ray), s) + for (o, s) in self.objects] + i = firstIntersection(intersections) + if i is None: + return (0, 0, 0) # the background colour + else: + (o, t, s) = i + p = ray.pointAtTime(t) + return s.colourAt(self, ray, p, o.normalAt(p)) + finally: + self.recursionDepth = self.recursionDepth - 1 + + def _lightIsVisible(self, l, p): + for (o, s) in self.objects: + t = o.intersectionTime(Ray(p, l - p)) + if t is not None and t > EPSILON: + return False + return True + + def visibleLights(self, p): + result = [] + for l in self.lightPoints: + if self._lightIsVisible(l, p): + result.append(l) + return result + + +def addColours(a, scale, b): + return (a[0] + scale * b[0], + a[1] + scale * b[1], + a[2] + scale * b[2]) + + +class SimpleSurface(object): + + def __init__(self, **kwargs): + self.baseColour = kwargs.get('baseColour', (1, 1, 1)) + self.specularCoefficient = kwargs.get('specularCoefficient', 0.2) + self.lambertCoefficient = kwargs.get('lambertCoefficient', 0.6) + self.ambientCoefficient = 1.0 - self.specularCoefficient - self.lambertCoefficient + + def baseColourAt(self, p): + return self.baseColour + + def colourAt(self, scene, ray, p, normal): + b = self.baseColourAt(p) + + c = (0, 0, 0) + if self.specularCoefficient > 0: + reflectedRay = Ray(p, ray.vector.reflectThrough(normal)) + reflectedColour = scene.rayColour(reflectedRay) + c = addColours(c, self.specularCoefficient, reflectedColour) + + if self.lambertCoefficient > 0: + lambertAmount = 0 + for lightPoint in scene.visibleLights(p): + contribution = (lightPoint - p).normalized().dot(normal) + if contribution > 0: + lambertAmount = lambertAmount + contribution + lambertAmount = min(1, lambertAmount) + c = addColours(c, self.lambertCoefficient * lambertAmount, b) + + if self.ambientCoefficient > 0: + c = addColours(c, self.ambientCoefficient, b) + + return c + + +class CheckerboardSurface(SimpleSurface): + + def __init__(self, **kwargs): + SimpleSurface.__init__(self, **kwargs) + self.otherColour = kwargs.get('otherColour', (0, 0, 0)) + self.checkSize = kwargs.get('checkSize', 1) + + def baseColourAt(self, p): + v = p - Point.ZERO + v.scale(1.0 / self.checkSize) + if ((int(abs(v.x) + 0.5) + + int(abs(v.y) + 0.5) + + int(abs(v.z) + 0.5)) % 2): + return self.otherColour + else: + return self.baseColour + + +def bench_raytrace(loops, width, height, filename): + range_it = range(loops) + + for i in range_it: + canvas = Canvas(width, height) + s = Scene() + s.addLight(Point(30, 30, 10)) + s.addLight(Point(-10, 100, 30)) + s.lookAt(Point(0, 3, 0)) + s.addObject(Sphere(Point(1, 3, -10), 2), + SimpleSurface(baseColour=(1, 1, 0))) + for y in range(6): + s.addObject(Sphere(Point(-3 - y * 0.4, 2.3, -5), 0.4), + SimpleSurface(baseColour=(y / 6.0, 1 - y / 6.0, 0.5))) + s.addObject(Halfspace(Point(0, 0, 0), Vector.UP), + CheckerboardSurface()) + s.render(canvas) + + if filename: + canvas.write_ppm(filename) + + +def run_pgo(): + loops = 1 + bench_raytrace(loops, DEFAULT_WIDTH, DEFAULT_HEIGHT, None) diff --git a/Lib/test/pgo_task/bm_regex_effbot.py b/Lib/test/pgo_task/bm_regex_effbot.py new file mode 100644 index 00000000000000..aa954bf5978fba --- /dev/null +++ b/Lib/test/pgo_task/bm_regex_effbot.py @@ -0,0 +1,159 @@ + +"""Benchmarks for Python's regex engine. + +These are some of the original benchmarks used to tune Python's regex engine +in 2000 written by Fredrik Lundh. Retreived from +http://mail.python.org/pipermail/python-dev/2000-August/007797.html and +integrated into Unladen Swallow's pyperf.py in 2009 by David Laing. + +These benchmarks are of interest since they helped to guide the original +optimization of the sre engine, and we shouldn't necessarily ignore them just +because they're "old". +""" + +# Python imports +import re + +USE_BYTES = False + + +def re_compile(s): + if USE_BYTES: + return re.compile(s.encode('latin1')) + else: + return re.compile(s) + +# These are the regular expressions to be tested. These sync up, +# index-for-index with the list of strings generated by gen_string_table() +# below. + + +def gen_regex_table(): + return [ + re_compile('Python|Perl'), + re_compile('Python|Perl'), + re_compile('(Python|Perl)'), + re_compile('(?:Python|Perl)'), + re_compile('Python'), + re_compile('Python'), + re_compile('.*Python'), + re_compile('.*Python.*'), + re_compile('.*(Python)'), + re_compile('.*(?:Python)'), + re_compile('Python|Perl|Tcl'), + re_compile('Python|Perl|Tcl'), + re_compile('(Python|Perl|Tcl)'), + re_compile('(?:Python|Perl|Tcl)'), + re_compile('(Python)\\1'), + re_compile('(Python)\\1'), + re_compile('([0a-z][a-z0-9]*,)+'), + re_compile('(?:[0a-z][a-z0-9]*,)+'), + re_compile('([a-z][a-z0-9]*,)+'), + re_compile('(?:[a-z][a-z0-9]*,)+'), + re_compile('.*P.*y.*t.*h.*o.*n.*')] + + +def gen_string_table(n): + """Generates the list of strings that will be used in the benchmarks. + + All strings have repeated prefixes and suffices, and n specifies the + number of repetitions. + """ + strings = [] + + def append(s): + if USE_BYTES: + strings.append(s.encode('latin1')) + else: + strings.append(s) + append('-' * n + 'Perl' + '-' * n) + append('P' * n + 'Perl' + 'P' * n) + append('-' * n + 'Perl' + '-' * n) + append('-' * n + 'Perl' + '-' * n) + append('-' * n + 'Python' + '-' * n) + append('P' * n + 'Python' + 'P' * n) + append('-' * n + 'Python' + '-' * n) + append('-' * n + 'Python' + '-' * n) + append('-' * n + 'Python' + '-' * n) + append('-' * n + 'Python' + '-' * n) + append('-' * n + 'Perl' + '-' * n) + append('P' * n + 'Perl' + 'P' * n) + append('-' * n + 'Perl' + '-' * n) + append('-' * n + 'Perl' + '-' * n) + append('-' * n + 'PythonPython' + '-' * n) + append('P' * n + 'PythonPython' + 'P' * n) + append('-' * n + 'a5,b7,c9,' + '-' * n) + append('-' * n + 'a5,b7,c9,' + '-' * n) + append('-' * n + 'a5,b7,c9,' + '-' * n) + append('-' * n + 'a5,b7,c9,' + '-' * n) + append('-' * n + 'Python' + '-' * n) + return strings + + +def init_benchmarks(n_values=None): + """Initialize the strings we'll run the regexes against. + + The strings used in the benchmark are prefixed and suffixed by + strings that are repeated n times. + + The sequence n_values contains the values for n. + If n_values is None the values of n from the original benchmark + are used. + + The generated list of strings is cached in the string_tables + variable, which is indexed by n. + + Returns: + A list of string prefix/suffix lengths. + """ + + if n_values is None: + n_values = (0, 5, 50, 250, 1000, 5000, 10000) + + string_tables = {n: gen_string_table(n) for n in n_values} + regexs = gen_regex_table() + + data = [] + for n in n_values: + for id in range(len(regexs)): + regex = regexs[id] + string = string_tables[n][id] + data.append((regex, string)) + return data + + +def bench_regex_effbot(loops): + if bench_regex_effbot.data is None: + bench_regex_effbot.data = init_benchmarks() + data = bench_regex_effbot.data + + range_it = range(loops) + search = re.search + + for _ in range_it: + # Runs all of the benchmarks for a given value of n. + for regex, string in data: + # search 10 times + search(regex, string) + search(regex, string) + search(regex, string) + search(regex, string) + search(regex, string) + search(regex, string) + search(regex, string) + search(regex, string) + search(regex, string) + search(regex, string) + + + +# cached data, generated at the first call +bench_regex_effbot.data = None + + +def run_pgo(): + global USE_BYTES + + bench_regex_effbot(1) + USE_BYTES = True + bench_regex_effbot(1) diff --git a/Lib/test/pgo_task/bm_richards.py b/Lib/test/pgo_task/bm_richards.py new file mode 100644 index 00000000000000..bb91fef6692e10 --- /dev/null +++ b/Lib/test/pgo_task/bm_richards.py @@ -0,0 +1,418 @@ +""" +based on a Java version: + Based on original version written in BCPL by Dr Martin Richards + in 1981 at Cambridge University Computer Laboratory, England + and a C++ version derived from a Smalltalk version written by + L Peter Deutsch. + Java version: Copyright (C) 1995 Sun Microsystems, Inc. + Translation from C++, Mario Wolczko + Outer loop added by Alex Jacoby +""" + + +# Task IDs +I_IDLE = 1 +I_WORK = 2 +I_HANDLERA = 3 +I_HANDLERB = 4 +I_DEVA = 5 +I_DEVB = 6 + +# Packet types +K_DEV = 1000 +K_WORK = 1001 + +# Packet + +BUFSIZE = 4 + +BUFSIZE_RANGE = range(BUFSIZE) + + +class Packet(object): + + def __init__(self, l, i, k): + self.link = l + self.ident = i + self.kind = k + self.datum = 0 + self.data = [0] * BUFSIZE + + def append_to(self, lst): + self.link = None + if lst is None: + return self + else: + p = lst + next = p.link + while next is not None: + p = next + next = p.link + p.link = self + return lst + +# Task Records + + +class TaskRec(object): + pass + + +class DeviceTaskRec(TaskRec): + + def __init__(self): + self.pending = None + + +class IdleTaskRec(TaskRec): + + def __init__(self): + self.control = 1 + self.count = 10000 + + +class HandlerTaskRec(TaskRec): + + def __init__(self): + self.work_in = None + self.device_in = None + + def workInAdd(self, p): + self.work_in = p.append_to(self.work_in) + return self.work_in + + def deviceInAdd(self, p): + self.device_in = p.append_to(self.device_in) + return self.device_in + + +class WorkerTaskRec(TaskRec): + + def __init__(self): + self.destination = I_HANDLERA + self.count = 0 +# Task + + +class TaskState(object): + + def __init__(self): + self.packet_pending = True + self.task_waiting = False + self.task_holding = False + + def packetPending(self): + self.packet_pending = True + self.task_waiting = False + self.task_holding = False + return self + + def waiting(self): + self.packet_pending = False + self.task_waiting = True + self.task_holding = False + return self + + def running(self): + self.packet_pending = False + self.task_waiting = False + self.task_holding = False + return self + + def waitingWithPacket(self): + self.packet_pending = True + self.task_waiting = True + self.task_holding = False + return self + + def isPacketPending(self): + return self.packet_pending + + def isTaskWaiting(self): + return self.task_waiting + + def isTaskHolding(self): + return self.task_holding + + def isTaskHoldingOrWaiting(self): + return self.task_holding or (not self.packet_pending and self.task_waiting) + + def isWaitingWithPacket(self): + return self.packet_pending and self.task_waiting and not self.task_holding + + +tracing = False +layout = 0 + + +def trace(a): + global layout + layout -= 1 + if layout <= 0: + print() + layout = 50 + print(a, end='') + + +TASKTABSIZE = 10 + + +class TaskWorkArea(object): + + def __init__(self): + self.taskTab = [None] * TASKTABSIZE + + self.taskList = None + + self.holdCount = 0 + self.qpktCount = 0 + + +taskWorkArea = TaskWorkArea() + + +class Task(TaskState): + + def __init__(self, i, p, w, initialState, r): + self.link = taskWorkArea.taskList + self.ident = i + self.priority = p + self.input = w + + self.packet_pending = initialState.isPacketPending() + self.task_waiting = initialState.isTaskWaiting() + self.task_holding = initialState.isTaskHolding() + + self.handle = r + + taskWorkArea.taskList = self + taskWorkArea.taskTab[i] = self + + def fn(self, pkt, r): + raise NotImplementedError + + def addPacket(self, p, old): + if self.input is None: + self.input = p + self.packet_pending = True + if self.priority > old.priority: + return self + else: + p.append_to(self.input) + return old + + def runTask(self): + if self.isWaitingWithPacket(): + msg = self.input + self.input = msg.link + if self.input is None: + self.running() + else: + self.packetPending() + else: + msg = None + + return self.fn(msg, self.handle) + + def waitTask(self): + self.task_waiting = True + return self + + def hold(self): + taskWorkArea.holdCount += 1 + self.task_holding = True + return self.link + + def release(self, i): + t = self.findtcb(i) + t.task_holding = False + if t.priority > self.priority: + return t + else: + return self + + def qpkt(self, pkt): + t = self.findtcb(pkt.ident) + taskWorkArea.qpktCount += 1 + pkt.link = None + pkt.ident = self.ident + return t.addPacket(pkt, self) + + def findtcb(self, id): + t = taskWorkArea.taskTab[id] + if t is None: + raise Exception("Bad task id %d" % id) + return t + + +# DeviceTask + + +class DeviceTask(Task): + + def __init__(self, i, p, w, s, r): + Task.__init__(self, i, p, w, s, r) + + def fn(self, pkt, r): + d = r + assert isinstance(d, DeviceTaskRec) + if pkt is None: + pkt = d.pending + if pkt is None: + return self.waitTask() + else: + d.pending = None + return self.qpkt(pkt) + else: + d.pending = pkt + if tracing: + trace(pkt.datum) + return self.hold() + + +class HandlerTask(Task): + + def __init__(self, i, p, w, s, r): + Task.__init__(self, i, p, w, s, r) + + def fn(self, pkt, r): + h = r + assert isinstance(h, HandlerTaskRec) + if pkt is not None: + if pkt.kind == K_WORK: + h.workInAdd(pkt) + else: + h.deviceInAdd(pkt) + work = h.work_in + if work is None: + return self.waitTask() + count = work.datum + if count >= BUFSIZE: + h.work_in = work.link + return self.qpkt(work) + + dev = h.device_in + if dev is None: + return self.waitTask() + + h.device_in = dev.link + dev.datum = work.data[count] + work.datum = count + 1 + return self.qpkt(dev) + +# IdleTask + + +class IdleTask(Task): + + def __init__(self, i, p, w, s, r): + Task.__init__(self, i, 0, None, s, r) + + def fn(self, pkt, r): + i = r + assert isinstance(i, IdleTaskRec) + i.count -= 1 + if i.count == 0: + return self.hold() + elif i.control & 1 == 0: + i.control //= 2 + return self.release(I_DEVA) + else: + i.control = i.control // 2 ^ 0xd008 + return self.release(I_DEVB) + + +# WorkTask + + +A = ord('A') + + +class WorkTask(Task): + + def __init__(self, i, p, w, s, r): + Task.__init__(self, i, p, w, s, r) + + def fn(self, pkt, r): + w = r + assert isinstance(w, WorkerTaskRec) + if pkt is None: + return self.waitTask() + + if w.destination == I_HANDLERA: + dest = I_HANDLERB + else: + dest = I_HANDLERA + + w.destination = dest + pkt.ident = dest + pkt.datum = 0 + + for i in BUFSIZE_RANGE: # range(BUFSIZE) + w.count += 1 + if w.count > 26: + w.count = 1 + pkt.data[i] = A + w.count - 1 + + return self.qpkt(pkt) + + +def schedule(): + t = taskWorkArea.taskList + while t is not None: + if tracing: + print("tcb =", t.ident) + + if t.isTaskHoldingOrWaiting(): + t = t.link + else: + if tracing: + trace(chr(ord("0") + t.ident)) + t = t.runTask() + + +class Richards(object): + + def run(self, iterations): + for i in range(iterations): + taskWorkArea.holdCount = 0 + taskWorkArea.qpktCount = 0 + + IdleTask(I_IDLE, 1, 10000, TaskState().running(), IdleTaskRec()) + + wkq = Packet(None, 0, K_WORK) + wkq = Packet(wkq, 0, K_WORK) + WorkTask(I_WORK, 1000, wkq, TaskState( + ).waitingWithPacket(), WorkerTaskRec()) + + wkq = Packet(None, I_DEVA, K_DEV) + wkq = Packet(wkq, I_DEVA, K_DEV) + wkq = Packet(wkq, I_DEVA, K_DEV) + HandlerTask(I_HANDLERA, 2000, wkq, TaskState( + ).waitingWithPacket(), HandlerTaskRec()) + + wkq = Packet(None, I_DEVB, K_DEV) + wkq = Packet(wkq, I_DEVB, K_DEV) + wkq = Packet(wkq, I_DEVB, K_DEV) + HandlerTask(I_HANDLERB, 3000, wkq, TaskState( + ).waitingWithPacket(), HandlerTaskRec()) + + wkq = None + DeviceTask(I_DEVA, 4000, wkq, + TaskState().waiting(), DeviceTaskRec()) + DeviceTask(I_DEVB, 5000, wkq, + TaskState().waiting(), DeviceTaskRec()) + + schedule() + + if taskWorkArea.holdCount == 9297 and taskWorkArea.qpktCount == 23246: + pass + else: + return False + + return True + + +def run_pgo(): + richard = Richards() + richard.run(1) diff --git a/Lib/test/pgo_task/bm_richards_super.py b/Lib/test/pgo_task/bm_richards_super.py new file mode 100644 index 00000000000000..acf0a497f84046 --- /dev/null +++ b/Lib/test/pgo_task/bm_richards_super.py @@ -0,0 +1,424 @@ +""" +based on a Java version: + Based on original version written in BCPL by Dr Martin Richards + in 1981 at Cambridge University Computer Laboratory, England + and a C++ version derived from a Smalltalk version written by + L Peter Deutsch. + Java version: Copyright (C) 1995 Sun Microsystems, Inc. + Translation from C++, Mario Wolczko + Outer loop added by Alex Jacoby + super() usage added by Carl Meyer +""" + +# Task IDs +I_IDLE = 1 +I_WORK = 2 +I_HANDLERA = 3 +I_HANDLERB = 4 +I_DEVA = 5 +I_DEVB = 6 + +# Packet types +K_DEV = 1000 +K_WORK = 1001 + +# Packet + +BUFSIZE = 4 + +BUFSIZE_RANGE = range(BUFSIZE) + + +class Packet: + + def __init__(self, l, i, k): + self.link = l + self.ident = i + self.kind = k + self.datum = 0 + self.data = [0] * BUFSIZE + + def append_to(self, lst): + self.link = None + if lst is None: + return self + else: + p = lst + next = p.link + while next is not None: + p = next + next = p.link + p.link = self + return lst + +# Task Records + + +class TaskRec: + pass + + +class DeviceTaskRec(TaskRec): + + def __init__(self): + self.pending = None + + +class IdleTaskRec(TaskRec): + + def __init__(self): + self.control = 1 + self.count = 10000 + + +class HandlerTaskRec(TaskRec): + + def __init__(self): + self.work_in = None + self.device_in = None + + def workInAdd(self, p): + self.work_in = p.append_to(self.work_in) + return self.work_in + + def deviceInAdd(self, p): + self.device_in = p.append_to(self.device_in) + return self.device_in + + +class WorkerTaskRec(TaskRec): + + def __init__(self): + self.destination = I_HANDLERA + self.count = 0 +# Task + + +class TaskState: + + def __init__(self): + self.packet_pending = True + self.task_waiting = False + self.task_holding = False + + def packetPending(self): + self.packet_pending = True + self.task_waiting = False + self.task_holding = False + return self + + def waiting(self): + self.packet_pending = False + self.task_waiting = True + self.task_holding = False + return self + + def running(self): + self.packet_pending = False + self.task_waiting = False + self.task_holding = False + return self + + def waitingWithPacket(self): + self.packet_pending = True + self.task_waiting = True + self.task_holding = False + return self + + def isPacketPending(self): + return self.packet_pending + + def isTaskWaiting(self): + return self.task_waiting + + def isTaskHolding(self): + return self.task_holding + + def isTaskHoldingOrWaiting(self): + return self.task_holding or (not self.packet_pending and self.task_waiting) + + def isWaitingWithPacket(self): + return self.packet_pending and self.task_waiting and not self.task_holding + + +tracing = False +layout = 0 + + +def trace(a): + global layout + layout -= 1 + if layout <= 0: + print() + layout = 50 + print(a, end='') + + +TASKTABSIZE = 10 + + +class TaskWorkArea: + + def __init__(self): + self.taskTab = [None] * TASKTABSIZE + + self.taskList = None + + self.holdCount = 0 + self.qpktCount = 0 + + +taskWorkArea = TaskWorkArea() + + +class Task(TaskState): + + def __init__(self, i, p, w, initialState, r): + self.link = taskWorkArea.taskList + self.ident = i + self.priority = p + self.input = w + + self.packet_pending = initialState.isPacketPending() + self.task_waiting = initialState.isTaskWaiting() + self.task_holding = initialState.isTaskHolding() + + self.handle = r + + taskWorkArea.taskList = self + taskWorkArea.taskTab[i] = self + + self.last_packet = None + + def fn(self, pkt, r): + self.last_packet = pkt + + def addPacket(self, p, old): + if self.input is None: + self.input = p + self.packet_pending = True + if self.priority > old.priority: + return self + else: + p.append_to(self.input) + return old + + def runTask(self): + if self.isWaitingWithPacket(): + msg = self.input + self.input = msg.link + if self.input is None: + self.running() + else: + self.packetPending() + else: + msg = None + + return self.fn(msg, self.handle) + + def waitTask(self): + self.task_waiting = True + return self + + def hold(self): + taskWorkArea.holdCount += 1 + self.task_holding = True + return self.link + + def release(self, i): + t = self.findtcb(i) + t.task_holding = False + if t.priority > self.priority: + return t + else: + return self + + def qpkt(self, pkt): + t = self.findtcb(pkt.ident) + taskWorkArea.qpktCount += 1 + pkt.link = None + pkt.ident = self.ident + return t.addPacket(pkt, self) + + def findtcb(self, id): + t = taskWorkArea.taskTab[id] + if t is None: + raise Exception("Bad task id %d" % id) + return t + + +# DeviceTask + + +class DeviceTask(Task): + + def __init__(self, i, p, w, s, r): + super().__init__(i, p, w, s, r) + + def fn(self, pkt, r): + d = r + assert isinstance(d, DeviceTaskRec) + super().fn(pkt, r) + if pkt is None: + pkt = d.pending + if pkt is None: + return self.waitTask() + else: + d.pending = None + return self.qpkt(pkt) + else: + d.pending = pkt + if tracing: + trace(pkt.datum) + return self.hold() + + +class HandlerTask(Task): + + def __init__(self, i, p, w, s, r): + super().__init__(i, p, w, s, r) + + def fn(self, pkt, r): + h = r + assert isinstance(h, HandlerTaskRec) + super().fn(pkt, r) + if pkt is not None: + if pkt.kind == K_WORK: + h.workInAdd(pkt) + else: + h.deviceInAdd(pkt) + work = h.work_in + if work is None: + return self.waitTask() + count = work.datum + if count >= BUFSIZE: + h.work_in = work.link + return self.qpkt(work) + + dev = h.device_in + if dev is None: + return self.waitTask() + + h.device_in = dev.link + dev.datum = work.data[count] + work.datum = count + 1 + return self.qpkt(dev) + +# IdleTask + + +class IdleTask(Task): + + def __init__(self, i, p, w, s, r): + super().__init__(i, 0, None, s, r) + + def fn(self, pkt, r): + i = r + assert isinstance(i, IdleTaskRec) + super().fn(pkt, r) + i.count -= 1 + if i.count == 0: + return self.hold() + elif i.control & 1 == 0: + i.control //= 2 + return self.release(I_DEVA) + else: + i.control = i.control // 2 ^ 0xd008 + return self.release(I_DEVB) + + +# WorkTask + + +A = ord('A') + + +class WorkTask(Task): + + def __init__(self, i, p, w, s, r): + super().__init__(i, p, w, s, r) + + def fn(self, pkt, r): + w = r + assert isinstance(w, WorkerTaskRec) + super().fn(pkt, r) + if pkt is None: + return self.waitTask() + + if w.destination == I_HANDLERA: + dest = I_HANDLERB + else: + dest = I_HANDLERA + + w.destination = dest + pkt.ident = dest + pkt.datum = 0 + + for i in BUFSIZE_RANGE: # range(BUFSIZE) + w.count += 1 + if w.count > 26: + w.count = 1 + pkt.data[i] = A + w.count - 1 + + return self.qpkt(pkt) + + +def schedule(): + t = taskWorkArea.taskList + while t is not None: + if tracing: + print("tcb =", t.ident) + + if t.isTaskHoldingOrWaiting(): + t = t.link + else: + if tracing: + trace(chr(ord("0") + t.ident)) + t = t.runTask() + + +class Richards: + + def run(self, iterations): + for i in range(iterations): + taskWorkArea.holdCount = 0 + taskWorkArea.qpktCount = 0 + + IdleTask(I_IDLE, 1, 10000, TaskState().running(), IdleTaskRec()) + + wkq = Packet(None, 0, K_WORK) + wkq = Packet(wkq, 0, K_WORK) + WorkTask(I_WORK, 1000, wkq, TaskState( + ).waitingWithPacket(), WorkerTaskRec()) + + wkq = Packet(None, I_DEVA, K_DEV) + wkq = Packet(wkq, I_DEVA, K_DEV) + wkq = Packet(wkq, I_DEVA, K_DEV) + HandlerTask(I_HANDLERA, 2000, wkq, TaskState( + ).waitingWithPacket(), HandlerTaskRec()) + + wkq = Packet(None, I_DEVB, K_DEV) + wkq = Packet(wkq, I_DEVB, K_DEV) + wkq = Packet(wkq, I_DEVB, K_DEV) + HandlerTask(I_HANDLERB, 3000, wkq, TaskState( + ).waitingWithPacket(), HandlerTaskRec()) + + wkq = None + DeviceTask(I_DEVA, 4000, wkq, + TaskState().waiting(), DeviceTaskRec()) + DeviceTask(I_DEVB, 5000, wkq, + TaskState().waiting(), DeviceTaskRec()) + + schedule() + + if taskWorkArea.holdCount == 9297 and taskWorkArea.qpktCount == 23246: + pass + else: + return False + + return True + + +def run_pgo(): + richard = Richards() + richard.run(1) diff --git a/Lib/test/pgo_task/bm_scimark.py b/Lib/test/pgo_task/bm_scimark.py new file mode 100644 index 00000000000000..36c28c46d4399c --- /dev/null +++ b/Lib/test/pgo_task/bm_scimark.py @@ -0,0 +1,395 @@ +from array import array +import math + + +class Array2D(object): + + def __init__(self, w, h, data=None): + self.width = w + self.height = h + self.data = array('d', [0]) * (w * h) + if data is not None: + self.setup(data) + + def _idx(self, x, y): + if 0 <= x < self.width and 0 <= y < self.height: + return y * self.width + x + raise IndexError + + def __getitem__(self, x_y): + (x, y) = x_y + return self.data[self._idx(x, y)] + + def __setitem__(self, x_y, val): + (x, y) = x_y + self.data[self._idx(x, y)] = val + + def setup(self, data): + for y in range(self.height): + for x in range(self.width): + self[x, y] = data[y][x] + return self + + def indexes(self): + for y in range(self.height): + for x in range(self.width): + yield x, y + + def copy_data_from(self, other): + self.data[:] = other.data[:] + + +class Random(object): + MDIG = 32 + ONE = 1 + m1 = (ONE << (MDIG - 2)) + ((ONE << (MDIG - 2)) - ONE) + m2 = ONE << MDIG // 2 + dm1 = 1.0 / float(m1) + + def __init__(self, seed): + self.initialize(seed) + self.left = 0.0 + self.right = 1.0 + self.width = 1.0 + self.haveRange = False + + def initialize(self, seed): + + self.seed = seed + seed = abs(seed) + jseed = min(seed, self.m1) + if (jseed % 2 == 0): + jseed -= 1 + k0 = 9069 % self.m2 + k1 = 9069 / self.m2 + j0 = jseed % self.m2 + j1 = jseed / self.m2 + self.m = array('d', [0]) * 17 + for iloop in range(17): + jseed = j0 * k0 + j1 = (jseed / self.m2 + j0 * k1 + j1 * k0) % (self.m2 / 2) + j0 = jseed % self.m2 + self.m[iloop] = j0 + self.m2 * j1 + self.i = 4 + self.j = 16 + + def nextDouble(self): + I, J, m = self.i, self.j, self.m + k = m[I] - m[J] + if (k < 0): + k += self.m1 + self.m[J] = k + + if (I == 0): + I = 16 + else: + I -= 1 + self.i = I + + if (J == 0): + J = 16 + else: + J -= 1 + self.j = J + + if (self.haveRange): + return self.left + self.dm1 * float(k) * self.width + else: + return self.dm1 * float(k) + + def RandomMatrix(self, a): + for x, y in a.indexes(): + a[x, y] = self.nextDouble() + return a + + def RandomVector(self, n): + return array('d', [self.nextDouble() for i in range(n)]) + + +def copy_vector(vec): + # Copy a vector created by Random.RandomVector() + vec2 = array('d') + vec2[:] = vec[:] + return vec2 + + +class ArrayList(Array2D): + + def __init__(self, w, h, data=None): + self.width = w + self.height = h + self.data = [array('d', [0]) * w for y in range(h)] + if data is not None: + self.setup(data) + + def __getitem__(self, idx): + if isinstance(idx, tuple): + return self.data[idx[1]][idx[0]] + else: + return self.data[idx] + + def __setitem__(self, idx, val): + if isinstance(idx, tuple): + self.data[idx[1]][idx[0]] = val + else: + self.data[idx] = val + + def copy_data_from(self, other): + for l1, l2 in zip(self.data, other.data): + l1[:] = l2 + + +def SOR_execute(omega, G, cycles, Array): + for p in range(cycles): + for y in range(1, G.height - 1): + for x in range(1, G.width - 1): + G[x, y] = (omega * 0.25 * (G[x, y - 1] + G[x, y + 1] + G[x - 1, y] + + G[x + 1, y]) + + (1.0 - omega) * G[x, y]) + + +def bench_SOR(loops, n, cycles, Array): + range_it = range(loops) + + for _ in range_it: + G = Array(n, n) + SOR_execute(1.25, G, cycles, Array) + + + +def SparseCompRow_matmult(M, y, val, row, col, x, num_iterations): + range_it = range(num_iterations) + + for _ in range_it: + for r in range(M): + sa = 0.0 + for i in range(row[r], row[r + 1]): + sa += x[col[i]] * val[i] + y[r] = sa + + + +def bench_SparseMatMult(cycles, N, nz): + x = array('d', [0]) * N + y = array('d', [0]) * N + + nr = nz // N + anz = nr * N + val = array('d', [0]) * anz + col = array('i', [0]) * nz + row = array('i', [0]) * (N + 1) + + row[0] = 0 + for r in range(N): + rowr = row[r] + step = r // nr + row[r + 1] = rowr + nr + if step < 1: + step = 1 + for i in range(nr): + col[rowr + i] = i * step + + return SparseCompRow_matmult(N, y, val, row, col, x, cycles) + + +def MonteCarlo(Num_samples): + rnd = Random(113) + under_curve = 0 + for count in range(Num_samples): + x = rnd.nextDouble() + y = rnd.nextDouble() + if x * x + y * y <= 1.0: + under_curve += 1 + return float(under_curve) / Num_samples * 4.0 + + +def bench_MonteCarlo(loops, Num_samples): + range_it = range(loops) + + for _ in range_it: + MonteCarlo(Num_samples) + + + +def LU_factor(A, pivot): + M, N = A.height, A.width + minMN = min(M, N) + for j in range(minMN): + jp = j + t = abs(A[j][j]) + for i in range(j + 1, M): + ab = abs(A[i][j]) + if ab > t: + jp = i + t = ab + pivot[j] = jp + + if A[jp][j] == 0: + raise Exception("factorization failed because of zero pivot") + + if jp != j: + A[j], A[jp] = A[jp], A[j] + + if j < M - 1: + recp = 1.0 / A[j][j] + for k in range(j + 1, M): + A[k][j] *= recp + + if j < minMN - 1: + for ii in range(j + 1, M): + for jj in range(j + 1, N): + A[ii][jj] -= A[ii][j] * A[j][jj] + + +def LU(lu, A, pivot): + lu.copy_data_from(A) + LU_factor(lu, pivot) + + +def bench_LU(cycles, N): + rnd = Random(7) + A = rnd.RandomMatrix(ArrayList(N, N)) + lu = ArrayList(N, N) + pivot = array('i', [0]) * N + range_it = range(cycles) + + for _ in range_it: + LU(lu, A, pivot) + + + +def int_log2(n): + k = 1 + log = 0 + while k < n: + k *= 2 + log += 1 + if n != 1 << log: + raise Exception("FFT: Data length is not a power of 2: %s" % n) + return log + + +def FFT_num_flops(N): + return (5.0 * N - 2) * int_log2(N) + 2 * (N + 1) + + +def FFT_transform_internal(N, data, direction): + n = N // 2 + bit = 0 + dual = 1 + if n == 1: + return + + logn = int_log2(n) + if N == 0: + return + FFT_bitreverse(N, data) + + # apply fft recursion + # this loop executed int_log2(N) times + bit = 0 + while bit < logn: + w_real = 1.0 + w_imag = 0.0 + theta = 2.0 * direction * math.pi / (2.0 * float(dual)) + s = math.sin(theta) + t = math.sin(theta / 2.0) + s2 = 2.0 * t * t + for b in range(0, n, 2 * dual): + i = 2 * b + j = 2 * (b + dual) + wd_real = data[j] + wd_imag = data[j + 1] + data[j] = data[i] - wd_real + data[j + 1] = data[i + 1] - wd_imag + data[i] += wd_real + data[i + 1] += wd_imag + for a in range(1, dual): + tmp_real = w_real - s * w_imag - s2 * w_real + tmp_imag = w_imag + s * w_real - s2 * w_imag + w_real = tmp_real + w_imag = tmp_imag + for b in range(0, n, 2 * dual): + i = 2 * (b + a) + j = 2 * (b + a + dual) + z1_real = data[j] + z1_imag = data[j + 1] + wd_real = w_real * z1_real - w_imag * z1_imag + wd_imag = w_real * z1_imag + w_imag * z1_real + data[j] = data[i] - wd_real + data[j + 1] = data[i + 1] - wd_imag + data[i] += wd_real + data[i + 1] += wd_imag + bit += 1 + dual *= 2 + + +def FFT_bitreverse(N, data): + n = N // 2 + nm1 = n - 1 + j = 0 + for i in range(nm1): + ii = i << 1 + jj = j << 1 + k = n >> 1 + if i < j: + tmp_real = data[ii] + tmp_imag = data[ii + 1] + data[ii] = data[jj] + data[ii + 1] = data[jj + 1] + data[jj] = tmp_real + data[jj + 1] = tmp_imag + while k <= j: + j -= k + k >>= 1 + j += k + + +def FFT_transform(N, data): + FFT_transform_internal(N, data, -1) + + +def FFT_inverse(N, data): + n = N / 2 + norm = 0.0 + FFT_transform_internal(N, data, +1) + norm = 1 / float(n) + for i in range(N): + data[i] *= norm + + +def bench_FFT(loops, N, cycles): + twoN = 2 * N + init_vec = Random(7).RandomVector(twoN) + range_it = range(loops) + + for _ in range_it: + x = copy_vector(init_vec) + for i in range(cycles): + FFT_transform(twoN, x) + FFT_inverse(twoN, x) + + + +def add_cmdline_args(cmd, args): + if args.benchmark: + cmd.append(args.benchmark) + + +BENCHMARKS = { + # function name => arguments + 'sor': (bench_SOR, 100, 10, Array2D), + 'sparse_mat_mult': (bench_SparseMatMult, 1000, 50 * 1000), + 'monte_carlo': (bench_MonteCarlo, 100 * 1000,), + 'lu': (bench_LU, 100,), + 'fft': (bench_FFT, 1024, 50), +} + + +def run_pgo(): + benchmarks = sorted(BENCHMARKS) + loops = 1 + for bench in benchmarks: + name = 'scimark_%s' % bench + func, *args = BENCHMARKS[bench] + func(loops, *args) diff --git a/Lib/test/pgo_task/bm_spectral_norm.py b/Lib/test/pgo_task/bm_spectral_norm.py new file mode 100644 index 00000000000000..b5572f04c079b9 --- /dev/null +++ b/Lib/test/pgo_task/bm_spectral_norm.py @@ -0,0 +1,68 @@ +""" +MathWorld: "Hundred-Dollar, Hundred-Digit Challenge Problems", Challenge #3. +http://mathworld.wolfram.com/Hundred-DollarHundred-DigitChallengeProblems.html + +The Computer Language Benchmarks Game +http://benchmarksgame.alioth.debian.org/u64q/spectralnorm-description.html#spectralnorm + +Contributed by Sebastien Loisel +Fixed by Isaac Gouy +Sped up by Josh Goldfoot +Dirtily sped up by Simon Descarpentries +Concurrency by Jason Stitt +""" + + + +DEFAULT_N = 130 + + +def eval_A(i, j): + return 1.0 / ((i + j) * (i + j + 1) // 2 + i + 1) + + +def eval_times_u(func, u): + return [func((i, u)) for i in range(len(list(u)))] + + +def eval_AtA_times_u(u): + return eval_times_u(part_At_times_u, eval_times_u(part_A_times_u, u)) + + +def part_A_times_u(i_u): + i, u = i_u + partial_sum = 0 + for j, u_j in enumerate(u): + partial_sum += eval_A(i, j) * u_j + return partial_sum + + +def part_At_times_u(i_u): + i, u = i_u + partial_sum = 0 + for j, u_j in enumerate(u): + partial_sum += eval_A(j, i) * u_j + return partial_sum + + +def bench_spectral_norm(loops): + range_it = range(loops) + + for _ in range_it: + u = [1] * DEFAULT_N + + for dummy in range(10): + v = eval_AtA_times_u(u) + u = eval_AtA_times_u(v) + + vBv = vv = 0 + + for ue, ve in zip(u, v): + vBv += ue * ve + vv += ve * ve + + + +def run_pgo(): + loops = 1 + bench_spectral_norm(loops) diff --git a/Lib/test/pgo_task/bm_sqlite_synth.py b/Lib/test/pgo_task/bm_sqlite_synth.py new file mode 100644 index 00000000000000..2ca953de350546 --- /dev/null +++ b/Lib/test/pgo_task/bm_sqlite_synth.py @@ -0,0 +1,49 @@ +""" +SQLite benchmark. + +The goal of the benchmark is to test CFFI performance and going back and forth +between SQLite and Python a lot. Therefore the queries themselves are really +simple. +""" + +import sqlite3 +import math + + +class AvgLength(object): + + def __init__(self): + self.sum = 0 + self.count = 0 + + def step(self, x): + if x is not None: + self.count += 1 + self.sum += len(x) + + def finalize(self): + return self.sum / float(self.count) + + +def bench_sqlite(loops): + conn = sqlite3.connect(":memory:") + conn.execute('create table cos (x, y, z);') + for i in range(loops): + cos_i = math.cos(i) + conn.execute('insert into cos values (?, ?, ?)', + [i, cos_i, str(i)]) + + conn.create_function("cos", 1, math.cos) + for x, cosx1, cosx2 in conn.execute("select x, cos(x), y from cos"): + assert math.cos(x) == cosx1 == cosx2 + + conn.create_aggregate("avglength", 1, AvgLength) + cursor = conn.execute("select avglength(z) from cos;") + cursor.fetchone()[0] + + conn.execute("delete from cos;") + conn.close() + + +def run_pgo(): + bench_sqlite(loops=100) diff --git a/Lib/test/pgo_task/bm_telco.py b/Lib/test/pgo_task/bm_telco.py new file mode 100644 index 00000000000000..35e967a7eb30ac --- /dev/null +++ b/Lib/test/pgo_task/bm_telco.py @@ -0,0 +1,116 @@ +# coding: UTF-8 +""" Telco Benchmark for measuring the performance of decimal calculations + +- http://speleotrove.com/decimal/telco.html +- http://speleotrove.com/decimal/telcoSpec.html + +A call type indicator, c, is set from the bottom (least significant) bit of the duration (hence c is 0 or 1). +A rate, r, is determined from the call type. Those calls with c=0 have a low r: 0.0013; the remainder (‘distance calls’) have a ‘premium’ r: 0.00894. (The rates are, very roughly, in Euros or dollarates per second.) +A price, p, for the call is then calculated (p=r*n). This is rounded to exactly 2 fractional digits using round-half-even (Banker’s round to nearest). +A basic tax, b, is calculated: b=p*0.0675 (6.75%). This is truncated to exactly 2 fractional digits (round-down), and the total basic tax variable is then incremented (sumB=sumB+b). +For distance calls: a distance tax, d, is calculated: d=p*0.0341 (3.41%). This is truncated to exactly 2 fractional digits (round-down), and then the total distance tax variable is incremented (sumD=sumD+d). +The total price, t, is calculated (t=p+b, and, if a distance call, t=t+d). +The total prices variable is incremented (sumT=sumT+t). +The total price, t, is converted to a string, s. + +""" + +from decimal import ROUND_HALF_EVEN, ROUND_DOWN, Decimal, getcontext, Context +import io +from struct import unpack +import gzip +import base64 + +# The first 8000 bytes of the "telco-bench.b" file from pyperformance. +DATA = b'''\ +H4sIAAAAAAAAA12ZZaxdVRCF9+zTIsULxQMXt+Luj1KKu/vD3S0USgsFWtxdUjwUd4eHW3EIXoIT +CFYSgkPC/b6dnH3/rMyRfbbMrFkzN6X/fwt1IfbqYloNHNeF/C32bODf4BbgAN4fz/Orc/19cBaw +F9wBnANcEJwPPBU8FDwT7Af2gCP47k7Y64Evgddwn/Wlf8GLwfNB1hX3t+cRI6vnjwUfAKfqQl4b ++z3eew28EzwHfIfnVgCPBL8CDwEfB7cBPwF3By8F3bclwX35zvPY6zM/zjOm4/pm2Odhs2/xHPZ3 +4Jhq/DXBXcE+cFFwerCnWseUzMNzYt5xGPZd2AvwHJfTjFyfAtv5vgwuw33PY05waq4zbroX+3bs +g8BTwMm47z6z78G6m5m4jh+HfsD7sQj2AeC0XD8eeyvwIa4PxsYvM/4V7pP3R1TIeDGc5xbjOvuU +9gO347lJ4B7gs7y3Cs9Naj+fvqjmezLv7Qkat6d1oTmO8ZbgPvuYngJvBPcBbwU9D+37sB/DfgUM +cDnML0H94QpwKa7fgs0+ljjRL3Usx2UdybiYq72OGML1z8FpQNf3ETiW4X/E7vC+fuj35LdhIPfT +2+DmPD8aPLc9n6TtPD4FXa9xKo9cCcI/eVh7vDiK++xvmgE8BvQ7J4Jbgg0ob81dPb8B6HmQV+Jr +7FlBziUGtOcbJ2AvDJonBrKO4dV3HedJbP3N9ejv5inPg/Mu67+E+/C6fJpuAuHNNLGa3yO8Z9y5 +D4OY72XYP4Ouz/kN5T395ypwHAjfFl4nrxifaZ4KN+5CY5yYp4n/kt87zM+4lmfuAfGrmJfnNuK6 +eZG4CeI/PQj+Am4Cmu/8ybvqguvBpUG+l1YGPwOJ87JOedlzME7UHz+Bnofj8l78ha0+wL/KPugH +7rt8cRLvf4i9KWhcoAca/f8Z8A3wB3BncGZQPlgVlCcW53vohey+ylv+OO/Q342PD8DTQXme/Fl0 +hOudvfq+++f+m2/MC8Yzess4Kud2EWi+UkcOqsaTn/2e/uH+kyfy5NjogWz+Iq+H50dcFT0jb+uv +fk8eVd94jiuB6gGwkS/UI+ShRn7X383X3A/9Vl5+C5RX9atXsdW95h/4X3+JDbGJn3Df1VnEdVbX +mx/0R3WcfHQ34/THhvcC3R2el7p1N7AH9L5x63y3B89mPvBesK5wncaB54muDM+bOM/4R9EP+rF5 +jjyaVmxfL35tfjTeR1bX7wDdr29A9ap533qDuiL0n5vB/blOfAT5plGPMW7obzdg741NHo7Xsc/C +7sM2j70AnsFl44Y82VCPFJ7z3NEdTQfbON0RlCfUqcwnG0fGpflWPjbPE+eZ58K6zrgznzheH+i+ +y5/mQ8/J/bFek+fMa9aNnq/7ZD7gnEPeo66Kse3x4mBs+UJdqj//Ccr/6vehbbvUQepz4908ZP0C +74d50Dwmz0wA9WvHZz+LTrwWW571e4eDy7bnn6/Gpq5pHJf8ksk/xl2iTgvPXT1CPRDr8Lz7ab6q +/cN9VYdyTrniC/NfQ12V1gXVjdbf8EZW5znfP7DtY5AHi56yPrBvQFxn6pHAj8LzexFEl1qPFf9U +r65VjW9+uAA0730PoptLnfVEe/5pedA+APFe9Cm8G9a31p+uuwe0D6HegKez52CcOj91KvwuH6t3 +i5/eBsJnpS52/f3a942L2AVbPdMLqnvUz5djG5+es+8bN/+AT4PyxeD2+2Ve6Ipk3tOvXLf+aP9A +HnW9zk8/H189bz55GLTOQB8FcVN0gXxrnlUPsL4S58ateVrdJ090QHkQHgn6QqUuUreTT8N6gX0L +1yUvM//G8x8FGofytfWJulkd5n4OrJ77FSTPlT4h383qFv3H9w/kvnnfOso8dgS4Bqj+Np5GV98z +DtS75hN4rdTH5mP1iPmEPkWJC3Ra6VPaZ1DXmJ/mBy8E7WdZd9br1pbn1e+u25/77fw5z6wfsX/F +r+Uv+eVokDwX6q1ebPsJ73Ld/OS+oRPDfhL1aclL+jG8Hu6b/uK5qEPlf/We5+28tOUf90U94jnZ +R0T3ln0yDuH7kkccz/oVfVfiTH53HeTHLN+od9S/8os8j3+G9Zr1O/sY1ov2pezLqEOMD/Oz+yG/ +UH+FelV947mrY9RRrlM/tE637lDfWgfLy8YPuj7kI/qrjTxvvBpH6LNsPaAOsT5x/vKO/mzf9jdQ +P1R3Oo48hv4udV9dFxpvxr962rhDN5c+kftv/9K6xP6j/GxdMLF9P9QD1pX2ndRL6gt5xvxsfYBp +3Vn0pP1d7JI3zOvWi9bN1ufuA/V9tt7xQ87Deakn/b/B/y3sa8l38qbxL8/4vH5hnI0C1Q32eYzT +bav5qou2Bu23vAkah5639Sp1W39507rCPE5+jLofbz0oX9PvLvrL/gH6vPHcJ7Svl76A/XL5y7g1 +HvmFtv7o/tb87z5bj1uvy7f2aa07rsOGf7NxL9/y/1bJp+iZxr6a/6cZB/KAeYp4yvKM+t7v9IKe +i/rUvGh9bj9EfQQfZfWV+yZ/+X/K712wn1G+K997nuo162biu/F/DvfVfnMHdJ/wy5Jn7D/YF/Xc +XKf1oTrEvjR+Hs7T/hr1nX2J/Ci2+sb4kDetzzx36zL6ISUPwSthn9D6znOQB/UneLrB/wO9XvpR +1h36q/tu38v54rchfztfdQn1UalTXZe8pX+pH/Vr+z3OR561nlb/8d3i/+YV/9e0H2v+/tjn/gNU +l8AWQB8AAA== +''' + +def bench_telco(loops): + getcontext().rounding = ROUND_DOWN + rates = list(map(Decimal, ('0.0013', '0.00894'))) + twodig = Decimal('0.01') + Banker = Context(rounding=ROUND_HALF_EVEN) + basictax = Decimal("0.0675") + disttax = Decimal("0.0341") + + data = gzip.decompress(base64.decodebytes(DATA)) + + infil = io.BytesIO(data) + outfil = io.StringIO() + + for _ in range(loops): + infil.seek(0) + + sumT = Decimal("0") # sum of total prices + sumB = Decimal("0") # sum of basic tax + sumD = Decimal("0") # sum of 'distance' tax + + for i in range(1000): + datum = infil.read(8) + if datum == '': + break + n, = unpack('>Q', datum) + + calltype = n & 1 + r = rates[calltype] + + p = Banker.quantize(r * n, twodig) + + b = p * basictax + b = b.quantize(twodig) + sumB += b + + t = p + b + + if calltype: + d = p * disttax + d = d.quantize(twodig) + sumD += d + t += d + + sumT += t + print(t, file=outfil) + + outfil.seek(0) + outfil.truncate() + + +def run_pgo(): + bench_telco(100) diff --git a/Lib/test/pgo_task/bm_typing_runtime_protocols.py b/Lib/test/pgo_task/bm_typing_runtime_protocols.py new file mode 100644 index 00000000000000..f76bf9d584d6c6 --- /dev/null +++ b/Lib/test/pgo_task/bm_typing_runtime_protocols.py @@ -0,0 +1,168 @@ +""" +Test the performance of isinstance() checks against runtime-checkable protocols. + +For programmes that make extensive use of this feature, +these calls can easily become a bottleneck. +See https://github.com/python/cpython/issues/74690 + +The following situations all exercise different code paths +in typing._ProtocolMeta.__instancecheck__, +so each is tested in this benchmark: + + (1) Comparing an instance of a class that directly inherits + from a protocol to that protocol. + (2) Comparing an instance of a class that fulfils the interface + of a protocol using instance attributes. + (3) Comparing an instance of a class that fulfils the interface + of a protocol using class attributes. + (4) Comparing an instance of a class that fulfils the interface + of a protocol using properties. + +Protocols with callable and non-callable members also +exercise different code paths in _ProtocolMeta.__instancecheck__, +so are also tested separately. +""" + +from typing import Protocol, runtime_checkable + + +################################################## +# Protocols to call isinstance() against +################################################## + + +@runtime_checkable +class HasX(Protocol): + """A runtime-checkable protocol with a single non-callable member""" + x: int + +@runtime_checkable +class HasManyAttributes(Protocol): + """A runtime-checkable protocol with many non-callable members""" + a: int + b: int + c: int + d: int + e: int + +@runtime_checkable +class SupportsInt(Protocol): + """A runtime-checkable protocol with a single callable member""" + def __int__(self) -> int: ... + +@runtime_checkable +class SupportsManyMethods(Protocol): + """A runtime-checkable protocol with many callable members""" + def one(self) -> int: ... + def two(self) -> str: ... + def three(self) -> bytes: ... + def four(self) -> memoryview: ... + def five(self) -> bytearray: ... + +@runtime_checkable +class SupportsIntAndX(Protocol): + """A runtime-checkable protocol with a mix of callable and non-callable members""" + x: int + def __int__(self) -> int: ... + + +################################################## +# Classes for comparing against the protocols +################################################## + + +class Empty: + """Empty class with no attributes""" + +class PropertyX: + """Class with a property x""" + @property + def x(self) -> int: return 42 + +class HasIntMethod: + """Class with an __int__ method""" + def __int__(self): return 42 + +class HasManyMethods: + """Class with many methods""" + def one(self): return 42 + def two(self): return "42" + def three(self): return b"42" + def four(self): return memoryview(b"42") + def five(self): return bytearray(b"42") + +class PropertyXWithInt: + """Class with a property x and an __int__ method""" + @property + def x(self) -> int: return 42 + def __int__(self): return 42 + +class ClassVarX: + """Class with a ClassVar x""" + x = 42 + +class ClassVarXWithInt: + """Class with a ClassVar x and an __int__ method""" + x = 42 + def __int__(self): return 42 + +class InstanceVarX: + """Class with an instance var x""" + def __init__(self): + self.x = 42 + +class ManyInstanceVars: + """Class with many instance vars""" + def __init__(self): + for attr in 'abcde': + setattr(self, attr, 42) + +class InstanceVarXWithInt: + """Class with an instance var x and an __int__ method""" + def __init__(self): + self.x = 42 + def __int__(self): + return 42 + +class NominalX(HasX): + """Class that explicitly subclasses HasX""" + def __init__(self): + self.x = 42 + +class NominalSupportsInt(SupportsInt): + """Class that explicitly subclasses SupportsInt""" + def __int__(self): + return 42 + +class NominalXWithInt(SupportsIntAndX): + """Class that explicitly subclasses NominalXWithInt""" + def __init__(self): + self.x = 42 + + +################################################## +# Time to test the performance of isinstance()! +################################################## + + +def bench_protocols(loops: int) -> float: + protocols = [ + HasX, HasManyAttributes, SupportsInt, SupportsManyMethods, SupportsIntAndX + ] + instances = [ + cls() + for cls in ( + Empty, PropertyX, HasIntMethod, HasManyMethods, PropertyXWithInt, + ClassVarX, ClassVarXWithInt, InstanceVarX, ManyInstanceVars, + InstanceVarXWithInt, NominalX, NominalSupportsInt, NominalXWithInt + ) + ] + + for _ in range(loops): + for protocol in protocols: + for instance in instances: + isinstance(instance, protocol) + + +def run_pgo(): + bench_protocols(100) diff --git a/Lib/test/pgo_task/bm_unpack_sequence.py b/Lib/test/pgo_task/bm_unpack_sequence.py new file mode 100644 index 00000000000000..fc3a6801f79845 --- /dev/null +++ b/Lib/test/pgo_task/bm_unpack_sequence.py @@ -0,0 +1,132 @@ +"""Microbenchmark for Python's sequence unpacking.""" + + +def do_unpacking(loops, to_unpack): + range_it = range(loops) + + for _ in range_it: + # 100 unpackings + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + a, b, c, d, e, f, g, h, i, j = to_unpack + + + +def bench_tuple_unpacking(loops): + x = tuple(range(10)) + return do_unpacking(loops, x) + + +def bench_list_unpacking(loops): + x = list(range(10)) + + return do_unpacking(loops, x) + + +def bench_all(loops): + bench_tuple_unpacking(loops) + bench_list_unpacking(loops) + + +def run_pgo(): + benchmarks = {"tuple": bench_tuple_unpacking, + "list": bench_list_unpacking} + func = bench_all + func(1000) diff --git a/Lib/test/pgo_task/bm_var_access.py b/Lib/test/pgo_task/bm_var_access.py new file mode 100644 index 00000000000000..171d3a875a4b85 --- /dev/null +++ b/Lib/test/pgo_task/bm_var_access.py @@ -0,0 +1,284 @@ +from collections import deque, namedtuple + +trials = [None] * 500 +steps_per_trial = 25 + +class A(object): + def m(self): + pass + +class B(object): + __slots__ = 'x' + def __init__(self, x): + self.x = x + +class C(object): + def __init__(self, x): + self.x = x + +def read_local(trials=trials): + v_local = 1 + for t in trials: + v_local; v_local; v_local; v_local; v_local + v_local; v_local; v_local; v_local; v_local + v_local; v_local; v_local; v_local; v_local + v_local; v_local; v_local; v_local; v_local + v_local; v_local; v_local; v_local; v_local + +def make_nonlocal_reader(): + v_nonlocal = 1 + def inner(trials=trials): + for t in trials: + v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal + v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal + v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal + v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal + v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal + inner.__name__ = 'read_nonlocal' + return inner + +read_nonlocal = make_nonlocal_reader() + +v_global = 1 +def read_global(trials=trials): + for t in trials: + v_global; v_global; v_global; v_global; v_global + v_global; v_global; v_global; v_global; v_global + v_global; v_global; v_global; v_global; v_global + v_global; v_global; v_global; v_global; v_global + v_global; v_global; v_global; v_global; v_global + +def read_builtin(trials=trials): + for t in trials: + oct; oct; oct; oct; oct + oct; oct; oct; oct; oct + oct; oct; oct; oct; oct + oct; oct; oct; oct; oct + oct; oct; oct; oct; oct + +def read_classvar_from_class(trials=trials, A=A): + A.x = 1 + for t in trials: + A.x; A.x; A.x; A.x; A.x + A.x; A.x; A.x; A.x; A.x + A.x; A.x; A.x; A.x; A.x + A.x; A.x; A.x; A.x; A.x + A.x; A.x; A.x; A.x; A.x + +def read_classvar_from_instance(trials=trials, A=A): + A.x = 1 + a = A() + for t in trials: + a.x; a.x; a.x; a.x; a.x + a.x; a.x; a.x; a.x; a.x + a.x; a.x; a.x; a.x; a.x + a.x; a.x; a.x; a.x; a.x + a.x; a.x; a.x; a.x; a.x + +def read_instancevar(trials=trials, a=C(1)): + for t in trials: + a.x; a.x; a.x; a.x; a.x + a.x; a.x; a.x; a.x; a.x + a.x; a.x; a.x; a.x; a.x + a.x; a.x; a.x; a.x; a.x + a.x; a.x; a.x; a.x; a.x + +def read_instancevar_slots(trials=trials, a=B(1)): + for t in trials: + a.x; a.x; a.x; a.x; a.x + a.x; a.x; a.x; a.x; a.x + a.x; a.x; a.x; a.x; a.x + a.x; a.x; a.x; a.x; a.x + a.x; a.x; a.x; a.x; a.x + +def read_namedtuple(trials=trials, D=namedtuple('D', ['x'])): + a = D(1) + for t in trials: + a.x; a.x; a.x; a.x; a.x + a.x; a.x; a.x; a.x; a.x + a.x; a.x; a.x; a.x; a.x + a.x; a.x; a.x; a.x; a.x + a.x; a.x; a.x; a.x; a.x + +def read_boundmethod(trials=trials, a=A()): + for t in trials: + a.m; a.m; a.m; a.m; a.m + a.m; a.m; a.m; a.m; a.m + a.m; a.m; a.m; a.m; a.m + a.m; a.m; a.m; a.m; a.m + a.m; a.m; a.m; a.m; a.m + +def write_local(trials=trials): + v_local = 1 + for t in trials: + v_local = 1; v_local = 1; v_local = 1; v_local = 1; v_local = 1 + v_local = 1; v_local = 1; v_local = 1; v_local = 1; v_local = 1 + v_local = 1; v_local = 1; v_local = 1; v_local = 1; v_local = 1 + v_local = 1; v_local = 1; v_local = 1; v_local = 1; v_local = 1 + v_local = 1; v_local = 1; v_local = 1; v_local = 1; v_local = 1 + +def make_nonlocal_writer(): + v_nonlocal = 1 + def inner(trials=trials): + nonlocal v_nonlocal + for t in trials: + v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1 + v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1 + v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1 + v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1 + v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1 + inner.__name__ = 'write_nonlocal' + return inner + +write_nonlocal = make_nonlocal_writer() + +def write_global(trials=trials): + global v_global + for t in trials: + v_global = 1; v_global = 1; v_global = 1; v_global = 1; v_global = 1 + v_global = 1; v_global = 1; v_global = 1; v_global = 1; v_global = 1 + v_global = 1; v_global = 1; v_global = 1; v_global = 1; v_global = 1 + v_global = 1; v_global = 1; v_global = 1; v_global = 1; v_global = 1 + v_global = 1; v_global = 1; v_global = 1; v_global = 1; v_global = 1 + +def write_classvar(trials=trials, A=A): + for t in trials: + A.x = 1; A.x = 1; A.x = 1; A.x = 1; A.x = 1 + A.x = 1; A.x = 1; A.x = 1; A.x = 1; A.x = 1 + A.x = 1; A.x = 1; A.x = 1; A.x = 1; A.x = 1 + A.x = 1; A.x = 1; A.x = 1; A.x = 1; A.x = 1 + A.x = 1; A.x = 1; A.x = 1; A.x = 1; A.x = 1 + +def write_instancevar(trials=trials, a=C(1)): + for t in trials: + a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1 + a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1 + a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1 + a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1 + a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1 + +def write_instancevar_slots(trials=trials, a=B(1)): + for t in trials: + a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1 + a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1 + a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1 + a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1 + a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1 + +def read_list(trials=trials, a=[1]): + for t in trials: + a[0]; a[0]; a[0]; a[0]; a[0] + a[0]; a[0]; a[0]; a[0]; a[0] + a[0]; a[0]; a[0]; a[0]; a[0] + a[0]; a[0]; a[0]; a[0]; a[0] + a[0]; a[0]; a[0]; a[0]; a[0] + +def read_deque(trials=trials, a=deque([1])): + for t in trials: + a[0]; a[0]; a[0]; a[0]; a[0] + a[0]; a[0]; a[0]; a[0]; a[0] + a[0]; a[0]; a[0]; a[0]; a[0] + a[0]; a[0]; a[0]; a[0]; a[0] + a[0]; a[0]; a[0]; a[0]; a[0] + +def read_dict(trials=trials, a={0: 1}): + for t in trials: + a[0]; a[0]; a[0]; a[0]; a[0] + a[0]; a[0]; a[0]; a[0]; a[0] + a[0]; a[0]; a[0]; a[0]; a[0] + a[0]; a[0]; a[0]; a[0]; a[0] + a[0]; a[0]; a[0]; a[0]; a[0] + +def read_strdict(trials=trials, a={'key': 1}): + for t in trials: + a['key']; a['key']; a['key']; a['key']; a['key'] + a['key']; a['key']; a['key']; a['key']; a['key'] + a['key']; a['key']; a['key']; a['key']; a['key'] + a['key']; a['key']; a['key']; a['key']; a['key'] + a['key']; a['key']; a['key']; a['key']; a['key'] + +def list_append_pop(trials=trials, a=[1]): + ap, pop = a.append, a.pop + for t in trials: + ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop() + ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop() + ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop() + ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop() + ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop() + +def deque_append_pop(trials=trials, a=deque([1])): + ap, pop = a.append, a.pop + for t in trials: + ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop() + ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop() + ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop() + ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop() + ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop() + +def deque_append_popleft(trials=trials, a=deque([1])): + ap, pop = a.append, a.popleft + for t in trials: + ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); + ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); + ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); + ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); + ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); + +def write_list(trials=trials, a=[1]): + for t in trials: + a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 + a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 + a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 + a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 + a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 + +def write_deque(trials=trials, a=deque([1])): + for t in trials: + a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 + a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 + a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 + a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 + a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 + +def write_dict(trials=trials, a={0: 1}): + for t in trials: + a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 + a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 + a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 + a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 + a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 + +def write_strdict(trials=trials, a={'key': 1}): + for t in trials: + a['key']=1; a['key']=1; a['key']=1; a['key']=1; a['key']=1 + a['key']=1; a['key']=1; a['key']=1; a['key']=1; a['key']=1 + a['key']=1; a['key']=1; a['key']=1; a['key']=1; a['key']=1 + a['key']=1; a['key']=1; a['key']=1; a['key']=1; a['key']=1 + a['key']=1; a['key']=1; a['key']=1; a['key']=1; a['key']=1 + +def loop_overhead(trials=trials): + for t in trials: + pass + +def run_pgo(): + for f in [ + 'Variable and attribute read access:', + read_local, read_nonlocal, read_global, read_builtin, + read_classvar_from_class, read_classvar_from_instance, + read_instancevar, read_instancevar_slots, + read_namedtuple, read_boundmethod, + '\nVariable and attribute write access:', + write_local, write_nonlocal, write_global, + write_classvar, write_instancevar, write_instancevar_slots, + '\nData structure read access:', + read_list, read_deque, read_dict, read_strdict, + '\nData structure write access:', + write_list, write_deque, write_dict, write_strdict, + '\nStack (or queue) operations:', + list_append_pop, deque_append_pop, deque_append_popleft, + '\nTiming loop overhead:', + loop_overhead]: + if isinstance(f, str): + continue + for _ in range(20): + f() diff --git a/Lib/test/pgo_task/data/frankenstein_intro.txt b/Lib/test/pgo_task/data/frankenstein_intro.txt new file mode 100644 index 00000000000000..b186efde160758 --- /dev/null +++ b/Lib/test/pgo_task/data/frankenstein_intro.txt @@ -0,0 +1,25 @@ +Letter 1 +To Mrs. Saville, England. + +St. Petersburgh, Dec. 11th, 17—. + +You will rejoice to hear that no disaster has accompanied the commencement of an enterprise which you have regarded with such evil forebodings. I arrived here yesterday, and my first task is to assure my dear sister of my welfare and increasing confidence in the success of my undertaking. + +I am already far north of London, and as I walk in the streets of Petersburgh, I feel a cold northern breeze play upon my cheeks, which braces my nerves and fills me with delight. Do you understand this feeling? This breeze, which has travelled from the regions towards which I am advancing, gives me a foretaste of those icy climes. Inspirited by this wind of promise, my daydreams become more fervent and vivid. I try in vain to be persuaded that the pole is the seat of frost and desolation; it ever presents itself to my imagination as the region of beauty and delight. There, Margaret, the sun is for ever visible, its broad disk just skirting the horizon and diffusing a perpetual splendour. There—for with your leave, my sister, I will put some trust in preceding navigators—there snow and frost are banished; and, sailing over a calm sea, we may be wafted to a land surpassing in wonders and in beauty every region hitherto discovered on the habitable globe. Its productions and features may be without example, as the phenomena of the heavenly bodies undoubtedly are in those undiscovered solitudes. What may not be expected in a country of eternal light? I may there discover the wondrous power which attracts the needle and may regulate a thousand celestial observations that require only this voyage to render their seeming eccentricities consistent for ever. I shall satiate my ardent curiosity with the sight of a part of the world never before visited, and may tread a land never before imprinted by the foot of man. These are my enticements, and they are sufficient to conquer all fear of danger or death and to induce me to commence this laborious voyage with the joy a child feels when he embarks in a little boat, with his holiday mates, on an expedition of discovery up his native river. But supposing all these conjectures to be false, you cannot contest the inestimable benefit which I shall confer on all mankind, to the last generation, by discovering a passage near the pole to those countries, to reach which at present so many months are requisite; or by ascertaining the secret of the magnet, which, if at all possible, can only be effected by an undertaking such as mine. + +These reflections have dispelled the agitation with which I began my letter, and I feel my heart glow with an enthusiasm which elevates me to heaven, for nothing contributes so much to tranquillise the mind as a steady purpose—a point on which the soul may fix its intellectual eye. This expedition has been the favourite dream of my early years. I have read with ardour the accounts of the various voyages which have been made in the prospect of arriving at the North Pacific Ocean through the seas which surround the pole. You may remember that a history of all the voyages made for purposes of discovery composed the whole of our good Uncle Thomas’ library. My education was neglected, yet I was passionately fond of reading. These volumes were my study day and night, and my familiarity with them increased that regret which I had felt, as a child, on learning that my father’s dying injunction had forbidden my uncle to allow me to embark in a seafaring life. + +These visions faded when I perused, for the first time, those poets whose effusions entranced my soul and lifted it to heaven. I also became a poet and for one year lived in a paradise of my own creation; I imagined that I also might obtain a niche in the temple where the names of Homer and Shakespeare are consecrated. You are well acquainted with my failure and how heavily I bore the disappointment. But just at that time I inherited the fortune of my cousin, and my thoughts were turned into the channel of their earlier bent. + +Six years have passed since I resolved on my present undertaking. I can, even now, remember the hour from which I dedicated myself to this great enterprise. I commenced by inuring my body to hardship. I accompanied the whale-fishers on several expeditions to the North Sea; I voluntarily endured cold, famine, thirst, and want of sleep; I often worked harder than the common sailors during the day and devoted my nights to the study of mathematics, the theory of medicine, and those branches of physical science from which a naval adventurer might derive the greatest practical advantage. Twice I actually hired myself as an under-mate in a Greenland whaler, and acquitted myself to admiration. I must own I felt a little proud when my captain offered me the second dignity in the vessel and entreated me to remain with the greatest earnestness, so valuable did he consider my services. + +And now, dear Margaret, do I not deserve to accomplish some great purpose? My life might have been passed in ease and luxury, but I preferred glory to every enticement that wealth placed in my path. Oh, that some encouraging voice would answer in the affirmative! My courage and my resolution is firm; but my hopes fluctuate, and my spirits are often depressed. I am about to proceed on a long and difficult voyage, the emergencies of which will demand all my fortitude: I am required not only to raise the spirits of others, but sometimes to sustain my own, when theirs are failing. + +This is the most favourable period for travelling in Russia. They fly quickly over the snow in their sledges; the motion is pleasant, and, in my opinion, far more agreeable than that of an English stagecoach. The cold is not excessive, if you are wrapped in furs—a dress which I have already adopted, for there is a great difference between walking the deck and remaining seated motionless for hours, when no exercise prevents the blood from actually freezing in your veins. I have no ambition to lose my life on the post-road between St. Petersburgh and Archangel. + +I shall depart for the latter town in a fortnight or three weeks; and my intention is to hire a ship there, which can easily be done by paying the insurance for the owner, and to engage as many sailors as I think necessary among those who are accustomed to the whale-fishing. I do not intend to sail until the month of June; and when shall I return? Ah, dear sister, how can I answer this question? If I succeed, many, many months, perhaps years, will pass before you and I may meet. If I fail, you will see me again soon, or never. + +Farewell, my dear, excellent Margaret. Heaven shower down blessings on you, and save me, that I may again and again testify my gratitude for all your love and kindness. + +Your affectionate brother, +R. Walton diff --git a/configure b/configure index 677d0e8840676f..64e4a7a79aee74 100755 --- a/configure +++ b/configure @@ -8509,7 +8509,7 @@ fi printf %s "checking PROFILE_TASK... " >&6; } if test -z "$PROFILE_TASK" then - PROFILE_TASK='-m test --pgo --timeout=$(TESTTIMEOUT)' + PROFILE_TASK='-m test.pgo_task' fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PROFILE_TASK" >&5 printf "%s\n" "$PROFILE_TASK" >&6; } diff --git a/configure.ac b/configure.ac index 7ff0251b718386..0bf4a152dea7bb 100644 --- a/configure.ac +++ b/configure.ac @@ -1890,7 +1890,7 @@ AC_ARG_VAR([PROFILE_TASK], [Python args for PGO generation task]) AC_MSG_CHECKING([PROFILE_TASK]) if test -z "$PROFILE_TASK" then - PROFILE_TASK='-m test --pgo --timeout=$(TESTTIMEOUT)' + PROFILE_TASK='-m test.pgo_task' fi AC_MSG_RESULT([$PROFILE_TASK]) From 5341cf9780ef8f0bf1b9eae714715f11c7f7d940 Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Fri, 28 Feb 2025 09:46:13 -0800 Subject: [PATCH 2/4] Add more PGO tasks. --- Lib/test/pgo_task/__main__.py | 4 + Lib/test/pgo_task/bm_argparse.py | 4 +- Lib/test/pgo_task/bm_async_tree.py | 151 +++ Lib/test/pgo_task/bm_btree.py | 370 ++++++ Lib/test/pgo_task/bm_pickle.py | 25 +- Lib/test/pgo_task/bm_regex_v8.py | 1785 ++++++++++++++++++++++++++++ Lib/test/pgo_task/bm_xml_tree.py | 211 ++++ 7 files changed, 2535 insertions(+), 15 deletions(-) create mode 100644 Lib/test/pgo_task/bm_async_tree.py create mode 100644 Lib/test/pgo_task/bm_btree.py create mode 100644 Lib/test/pgo_task/bm_regex_v8.py create mode 100644 Lib/test/pgo_task/bm_xml_tree.py diff --git a/Lib/test/pgo_task/__main__.py b/Lib/test/pgo_task/__main__.py index 475adf746de89b..fac6c3abe1c273 100644 --- a/Lib/test/pgo_task/__main__.py +++ b/Lib/test/pgo_task/__main__.py @@ -1,3 +1,4 @@ +import sys import glob import importlib import os @@ -5,6 +6,7 @@ def main(): + cmdline_tasks = set(sys.argv[1:]) tasks = [] package_dir = os.path.dirname(__file__) for fn in glob.glob(os.path.join(package_dir, 'bm_*.py')): @@ -12,6 +14,8 @@ def main(): total_time = 0 for fn in sorted(tasks): name, ext = os.path.splitext(os.path.basename(fn)) + if cmdline_tasks and name not in cmdline_tasks: + continue module = importlib.import_module(f'test.pgo_task.{name}') if not hasattr(module, 'run_pgo'): print('missing run_pgo', fn) diff --git a/Lib/test/pgo_task/bm_argparse.py b/Lib/test/pgo_task/bm_argparse.py index bdb8b66c2d2ccb..74852f7e3ae317 100644 --- a/Lib/test/pgo_task/bm_argparse.py +++ b/Lib/test/pgo_task/bm_argparse.py @@ -115,5 +115,5 @@ def add_parser_args(parser): def run_pgo(): - for bm, func in BENCHMARKS.items(): - func() + for bm_func in BENCHMARKS.values(): + bm_func() diff --git a/Lib/test/pgo_task/bm_async_tree.py b/Lib/test/pgo_task/bm_async_tree.py new file mode 100644 index 00000000000000..edc9c138a0863a --- /dev/null +++ b/Lib/test/pgo_task/bm_async_tree.py @@ -0,0 +1,151 @@ +""" +Benchmark for async tree workload, which calls asyncio.gather() on a tree +(6 levels deep, 6 branches per level) with the leaf nodes simulating some +(potentially) async work (depending on the benchmark variant). Benchmark +variants include: + +1) "none": No actual async work in the async tree. +2) "io": All leaf nodes simulate async IO workload (async sleep 50ms). +3) "memoization": All leaf nodes simulate async IO workload with 90% of + the data memoized +4) "cpu_io_mixed": Half of the leaf nodes simulate CPU-bound workload and + the other half simulate the same workload as the + "memoization" variant. + +All variants also have an "eager" flavor that uses the asyncio eager task +factory (if available), and a "tg" variant that uses TaskGroups. +""" + + +import asyncio +import math +import random + +NUM_RECURSE_LEVELS = 5 +NUM_RECURSE_BRANCHES = 5 +RANDOM_SEED = 0 +IO_SLEEP_TIME = 0.02 +MEMOIZABLE_PERCENTAGE = 90 +CPU_PROBABILITY = 0.5 +FACTORIAL_N = 500 + + +class AsyncTree: + def __init__(self, use_task_groups=False): + self.cache = {} + self.use_task_groups = use_task_groups + # set to deterministic random, so that the results are reproducible + random.seed(RANDOM_SEED) + + async def mock_io_call(self): + await asyncio.sleep(IO_SLEEP_TIME) + + async def workload_func(self): + raise NotImplementedError( + "To be implemented by each variant's derived class." + ) + + async def recurse_with_gather(self, recurse_level): + if recurse_level == 0: + await self.workload_func() + return + + await asyncio.gather( + *[self.recurse_with_gather(recurse_level - 1) + for _ in range(NUM_RECURSE_BRANCHES)] + ) + + async def recurse_with_task_group(self, recurse_level): + if recurse_level == 0: + await self.workload_func() + return + + async with asyncio.TaskGroup() as tg: + for _ in range(NUM_RECURSE_BRANCHES): + tg.create_task( + self.recurse_with_task_group(recurse_level - 1)) + + async def run(self): + if self.use_task_groups: + await self.recurse_with_task_group(NUM_RECURSE_LEVELS) + else: + await self.recurse_with_gather(NUM_RECURSE_LEVELS) + + +class EagerMixin: + async def run(self): + loop = asyncio.get_running_loop() + if hasattr(asyncio, 'eager_task_factory'): + loop.set_task_factory(asyncio.eager_task_factory) + return await super().run() + + +class NoneAsyncTree(AsyncTree): + async def workload_func(self): + return + + +class EagerAsyncTree(EagerMixin, NoneAsyncTree): + pass + + +class IOAsyncTree(AsyncTree): + async def workload_func(self): + await self.mock_io_call() + + +class EagerIOAsyncTree(EagerMixin, IOAsyncTree): + pass + + +class MemoizationAsyncTree(AsyncTree): + async def workload_func(self): + # deterministic random, seed set in AsyncTree.__init__() + data = random.randint(1, 100) + + if data <= MEMOIZABLE_PERCENTAGE: + if self.cache.get(data): + return data + + self.cache[data] = True + + await self.mock_io_call() + return data + + +class EagerMemoizationAsyncTree(EagerMixin, MemoizationAsyncTree): + pass + + +class CpuIoMixedAsyncTree(MemoizationAsyncTree): + async def workload_func(self): + # deterministic random, seed set in AsyncTree.__init__() + if random.random() < CPU_PROBABILITY: + # mock cpu-bound call + return math.factorial(FACTORIAL_N) + else: + return await MemoizationAsyncTree.workload_func(self) + + +class EagerCpuIoMixedAsyncTree(EagerMixin, CpuIoMixedAsyncTree): + pass + + +BENCHMARKS = { + "none": NoneAsyncTree, + "eager": EagerAsyncTree, + "io": IOAsyncTree, + "eager_io": EagerIOAsyncTree, + "memoization": MemoizationAsyncTree, + "eager_memoization": EagerMemoizationAsyncTree, + "cpu_io_mixed": CpuIoMixedAsyncTree, + "eager_cpu_io_mixed": EagerCpuIoMixedAsyncTree, +} + + +def run_pgo(): + for benchmark in BENCHMARKS: + async_tree_class = BENCHMARKS[benchmark] + for use_task_groups in [True, False]: + async_tree = async_tree_class(use_task_groups=use_task_groups) + asyncio.run(async_tree.run()) diff --git a/Lib/test/pgo_task/bm_btree.py b/Lib/test/pgo_task/bm_btree.py new file mode 100644 index 00000000000000..4394d1e3777ec6 --- /dev/null +++ b/Lib/test/pgo_task/bm_btree.py @@ -0,0 +1,370 @@ +""" +Benchmark for b-tree workload. This is intended to exercise the cyclic +garbage collector by presenting it with a large and interconnected +object graph. +""" + +import gc +import random +import sys + +# Total number of b-tree nodes to create. We would like this to be +# large enough so that the working set of data doesn't fit into the CPU +# cache. This benchmark is supposed to be similar to a real application +# that hold a large number of Python objects in RAM and does some +# processing on them. +NUM_NODES = 40_000 + +# Fraction of tree to re-create after initial creation. Set to zero to +# disable re-creation. +RECREATE_FRACTION = 0.2 + +# Seed value for random generator +RANDOM_SEED = 0 + + +class BNode: + """ + Instance attributes: + items: list + nodes: [BNode] + """ + + __slots__ = ['items', 'nodes'] + + minimum_degree = 16 # a.k.a. t + + def __init__(self): + self.items = [] + self.nodes = None + + def is_leaf(self): + return self.nodes is None + + def __iter__(self): + if self.is_leaf(): + yield from self.items + else: + for position, item in enumerate(self.items): + yield from self.nodes[position] + yield item + yield from self.nodes[-1] + + def is_full(self): + return len(self.items) == 2 * self.minimum_degree - 1 + + def get_position(self, key): + for position, item in enumerate(self.items): + if item[0] >= key: + return position + return len(self.items) + + def search(self, key): + """(key:anything) -> None | (key:anything, value:anything) + Return the matching pair, or None. + """ + position = self.get_position(key) + if position < len(self.items) and self.items[position][0] == key: + return self.items[position] + elif self.is_leaf(): + return None + else: + return self.nodes[position].search(key) + + def insert_item(self, item): + """(item:(key:anything, value:anything))""" + assert not self.is_full() + key = item[0] + position = self.get_position(key) + if position < len(self.items) and self.items[position][0] == key: + self.items[position] = item + elif self.is_leaf(): + self.items.insert(position, item) + else: + child = self.nodes[position] + if child.is_full(): + self.split_child(position, child) + if key == self.items[position][0]: + self.items[position] = item + else: + if key > self.items[position][0]: + position += 1 + self.nodes[position].insert_item(item) + else: + self.nodes[position].insert_item(item) + + def split_child(self, position, child): + """(position:int, child:BNode)""" + assert not self.is_full() + assert not self.is_leaf() + assert self.nodes[position] is child + assert child.is_full() + bigger = self.__class__() + middle = self.minimum_degree - 1 + splitting_key = child.items[middle] + bigger.items = child.items[middle + 1 :] + child.items = child.items[:middle] + assert len(bigger.items) == len(child.items) + if not child.is_leaf(): + bigger.nodes = child.nodes[middle + 1 :] + child.nodes = child.nodes[: middle + 1] + assert len(bigger.nodes) == len(child.nodes) + self.items.insert(position, splitting_key) + self.nodes.insert(position + 1, bigger) + + def get_count(self): + """() -> int + How many items are stored in this node and descendants? + """ + result = len(self.items) + for node in self.nodes or []: + result += node.get_count() + return result + + def get_level(self): + """() -> int + How many levels of nodes are there between this node + and descendant leaf nodes? + """ + if self.is_leaf(): + return 0 + else: + return 1 + self.nodes[0].get_level() + + def delete(self, key): + """(key:anything) + Delete the item with this key. + This is intended to follow the description in 19.3 of + 'Introduction to Algorithms' by Cormen, Lieserson, and Rivest. + """ + + def is_big(node): + # Precondition for recursively calling node.delete(key). + return node and len(node.items) >= node.minimum_degree + + p = self.get_position(key) + matches = p < len(self.items) and self.items[p][0] == key + if self.is_leaf(): + if matches: + # Case 1. + del self.items[p] + else: + raise KeyError(key) + else: + node = self.nodes[p] + lower_sibling = p > 0 and self.nodes[p - 1] + upper_sibling = p < len(self.nodes) - 1 and self.nodes[p + 1] + if matches: + # Case 2. + if is_big(node): + # Case 2a. + extreme = node.get_max_item() + node.delete(extreme[0]) + self.items[p] = extreme + elif is_big(upper_sibling): + # Case 2b. + extreme = upper_sibling.get_min_item() + upper_sibling.delete(extreme[0]) + self.items[p] = extreme + else: + # Case 2c. + extreme = upper_sibling.get_min_item() + upper_sibling.delete(extreme[0]) + node.items = node.items + [extreme] + upper_sibling.items + if not node.is_leaf(): + node.nodes = node.nodes + upper_sibling.nodes + del self.items[p] + del self.nodes[p + 1] + else: + if not is_big(node): + if is_big(lower_sibling): + # Case 3a1: Shift an item from lower_sibling. + node.items.insert(0, self.items[p - 1]) + self.items[p - 1] = lower_sibling.items[-1] + del lower_sibling.items[-1] + if not node.is_leaf(): + node.nodes.insert(0, lower_sibling.nodes[-1]) + del lower_sibling.nodes[-1] + elif is_big(upper_sibling): + # Case 3a2: Shift an item from upper_sibling. + node.items.append(self.items[p]) + self.items[p] = upper_sibling.items[0] + del upper_sibling.items[0] + if not node.is_leaf(): + node.nodes.append(upper_sibling.nodes[0]) + del upper_sibling.nodes[0] + elif lower_sibling: + # Case 3b1: Merge with lower_sibling + node.items = ( + lower_sibling.items + + [self.items[p - 1]] + + node.items + ) + if not node.is_leaf(): + node.nodes = lower_sibling.nodes + node.nodes + del self.items[p - 1] + del self.nodes[p - 1] + else: + # Case 3b2: Merge with upper_sibling + node.items = ( + node.items + [self.items[p]] + upper_sibling.items + ) + if not node.is_leaf(): + node.nodes = node.nodes + upper_sibling.nodes + del self.items[p] + del self.nodes[p + 1] + assert is_big(node) + node.delete(key) + if not self.items: + # This can happen when self is the root node. + self.items = self.nodes[0].items + self.nodes = self.nodes[0].nodes + + +class BTree: + """ + Instance attributes: + root: BNode + """ + + __slots__ = ['root'] + + def __init__(self): + self.root = BNode() + + def __bool__(self): + return bool(self.root.items) + + def iteritems(self): + yield from self.root + + def iterkeys(self): + for item in self.root: + yield item[0] + + def __iter__(self): + yield from self.iterkeys() + + def __contains__(self, key): + return self.root.search(key) is not None + + def __setitem__(self, key, value): + self.add(key, value) + + def __getitem__(self, key): + item = self.root.search(key) + if item is None: + raise KeyError(key) + return item[1] + + def __delitem__(self, key): + self.root.delete(key) + + def get(self, key, default=None): + """(key:anything, default:anything=None) -> anything""" + try: + return self[key] + except KeyError: + return default + + def add(self, key, value=True): + """(key:anything, value:anything=True) + Make self[key] == val. + """ + if self.root.is_full(): + # replace and split. + node = self.root.__class__() + node.nodes = [self.root] + node.split_child(0, node.nodes[0]) + self.root = node + self.root.insert_item((key, value)) + + def __len__(self): + """() -> int + Compute and return the total number of items.""" + return self.root.get_count() + + +class Record: + def __init__(self, a, b, c, d, e, f): + self.a = a + self.b = b + self.c = c + self.d = d + self.e = e + self.f = f + + +def make_records(num_nodes): + rnd = random.Random(RANDOM_SEED) + for node_id in range(num_nodes): + a = node_id + b = f'node {node_id}' + c = rnd.randbytes(node_id % 100) + d = rnd.random() + e = sys.intern(str(rnd.randint(0, 30))) + f = rnd.choice([None, True, False]) + yield Record(a, b, c, d, e, f) + + +def make_tree(num_nodes, records): + ids = list(range(num_nodes)) + # Create the tree with randomized key order. + random.shuffle(ids) + + tree = BTree() + for node_id in ids: + tree[node_id] = records[node_id] + + if RECREATE_FRACTION > 0: + # Re-create part of the tree. This can cause objects in memory + # to become more fragmented or shuffled since they are not allocated + # in sequence. Since we created nodes with keys in random order, we + # can delete the lowest numbered ones and re-make those. + remake_ids = range(int(num_nodes * RECREATE_FRACTION)) + for node_id in remake_ids: + del tree[node_id] + for node_id in remake_ids: + tree[node_id] = records[node_id] + + return tree + + +def run_once(gc_only, records): + obj = make_tree(NUM_NODES, records) + + gc.collect() + + if not gc_only: + # Iterate over all nodes and add up the value of the 'd' attribute. + d_total = 0.0 + for key in obj: + node = obj[key] + d_total += node.d + + # Lookup a random subset of nodes, add up value of 'd' + num_lookup = max(200, NUM_NODES // 20) + d_total = 0 + rnd = random.Random(RANDOM_SEED) + for i in range(num_lookup): + node_id = rnd.randint(0, NUM_NODES) + node = obj.get(node_id) + if node is not None: + d_total += node.d + + +def run_bench(loops, gc_only): + # Create the set of records outside the timed section. In a real + # application, the data would likely come from a file, a database or + # from some other network service. We don't want to benchmark the + # 'random' module. + records = list(make_records(NUM_NODES)) + total_time = 0 + for i in range(loops): + random.seed(RANDOM_SEED) + run_once(gc_only, records) + return total_time + + +def run_pgo(): + run_bench(1, False) diff --git a/Lib/test/pgo_task/bm_pickle.py b/Lib/test/pgo_task/bm_pickle.py index 43053f59ef2b05..bc10a1d5cabada 100644 --- a/Lib/test/pgo_task/bm_pickle.py +++ b/Lib/test/pgo_task/bm_pickle.py @@ -223,22 +223,21 @@ def bench_pickle_dict(loops, pickle, options): } -def is_accelerated_module(module): - return getattr(pickle.Pickler, '__module__', '') != 'pickle' - +def bench_all(pickle): + class options: + protocol = pickle.HIGHEST_PROTOCOL -def add_cmdline_args(cmd, args): - if args.pure_python: - cmd.append("--pure-python") - cmd.extend(("--protocol", str(args.protocol))) - cmd.append(args.benchmark) + for benchmark, inner_loops in BENCHMARKS.values(): + benchmark(inner_loops, pickle, options) def run_pgo(): - import pickle + from test.support import import_helper - class options: - protocol = pickle.HIGHEST_PROTOCOL + # C accelerated version + import pickle + bench_all(pickle) - for benchmark, inner_loops in BENCHMARKS.values(): - benchmark(10*inner_loops, pickle, options) + # pure Python version + py_pickle = import_helper.import_fresh_module('pickle', blocked=['_pickle']) + bench_all(py_pickle) diff --git a/Lib/test/pgo_task/bm_regex_v8.py b/Lib/test/pgo_task/bm_regex_v8.py new file mode 100644 index 00000000000000..30c2782c10fcd6 --- /dev/null +++ b/Lib/test/pgo_task/bm_regex_v8.py @@ -0,0 +1,1785 @@ +# Copyright 2009 the V8 project authors. All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Automatically generated on 2009-01-30. + +# This benchmark is generated by loading 50 of the most popular pages +# on the web and logging all regexp operations performed. Each +# operation is given a weight that is calculated from an estimate of +# the popularity of the pages where it occurs and the number of times +# it is executed while loading each page. Finally the literal +# letters in the data are encoded using ROT13 in a way that does not +# affect how the regexps match their input. + + +# Ported to Python for Unladen Swallow. The original JS version can be found at +# https://github.com/v8/v8/blob/master/benchmarks/regexp.js, r1243. + +# Python imports +import re +import time as pyperf + + +# The precompiled regexs that were in vars in the V8 code, split into +# tuples of (regex, flags). +compiled_regex_strings = [ + (r'^ba', ''), + (r'(((\w+):\/\/)([^\/:]*)(:(\d+))?)?([^#?]*)(\?([^#]*))?(#(.*))?', ''), + (r'^\s*|\s*$', 'g'), + (r'\bQBZPbageby_cynprubyqre\b', ''), + (r',', ''), + (r'\bQBZPbageby_cynprubyqre\b', 'g'), + (r'^[\s\xa0]+|[\s\xa0]+$', 'g'), + (r'(\d*)(\D*)', 'g'), + (r'=', ''), + (r'(^|\s)lhv\-h(\s|$)', ''), + (r'\#', 'g'), + (r'\.', 'g'), + (r'\'', 'g'), + (r'\?[\w\W]*(sevraqvq|punaaryvq|tebhcvq)=([^\&\?#]*)', 'i'), + (r'\s+', 'g'), + (r'^\s*(\S*(\s+\S+)*)\s*$', ''), + (r'(-[a-z])', 'i'), + (r'(^|[^\\])\"\\\/Qngr\((-?[0-9]+)\)\\\/\"', 'g'), + (r'^\s+|\s+$', 'g'), + (r'(?:^|\s+)ba(?:\s+|$)', ''), + (r'[+, ]', ''), + (r'ybnqrq|pbzcyrgr', ''), + (r'\bso_zrah\b', ''), + (r'^(?:(?:[^:\/?#]+):)?(?:\/\/(?:[^\/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?', ''), + (r'uggcf?:\/\/([^\/]+\.)?snprobbx\.pbz\/', ''), + (r'"', 'g'), + (r'^([^?#]+)(?:\?([^#]*))?(#.*)?', ''), + (r'-\D', 'g'), + (r'\bnpgvingr\b', ''), + (r'%2R', 'gi'), + (r'%2S', 'gi'), + (r'^(mu-(PA|GJ)|wn|xb)$', ''), + (r'\s?;\s?', ''), + (r'%\w?$', ''), + (r'TNQP=([^;]*)', 'i'), + (r'[<>]', 'g'), + (r'uers|fep|fryrpgrq', ''), + (r'\s*([+>~\s])\s*([a-zA-Z#.*:\[])', 'g'), + (r'^(\w+|\*)$', ''), + (r'\\\\', 'g'), + (r' ', 'g'), + (r'\/\xc4\/t', ''), + (r'\/\xd6\/t', ''), + (r'\/\xdc\/t', ''), + (r'\/\xdf\/t', ''), + (r'\/\xe4\/t', ''), + (r'\/\xf6\/t', ''), + (r'\/\xfc\/t', ''), + (r'\W', 'g'), + (r'uers|fep|fglyr', ''), + (r'(?:^|\s+)fryrpgrq(?:\s+|$)', ''), + (r'\&', 'g'), + (r'\+', 'g'), + (r'\?', 'g'), + (r'\t', 'g'), + (r'(\$\{nqiHey\})|(\$nqiHey\b)', 'g'), + (r'(\$\{cngu\})|(\$cngu\b)', 'g'), + (r'##yv4##', 'gi'), + (r'##yv16##', 'gi'), + (r'##yv19##', 'gi'), + (r'(?:^|\s+)bss(?:\s+|$)', ''), + (r'^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$', ''), + (r'^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$', ''), + (r'\{0\}', 'g'), + (r'\b[a-z]', 'g'), + (r'^uggc:\/\/', ''), + (r'(?:^|\s+)qvfnoyrq(?:\s+|$)', ''), + (r'zrah_byq', 'g'), + (r'^([#.]?)((?:[\w' + '\u0128-\uffff' + r'*_-]|\\.)*)', ''), + (r'\{1\}', 'g'), + (r'\s+', ''), + (r'(\$\{4\})|(\$4\b)', 'g'), + (r'(\$\{5\})|(\$5\b)', 'g'), + (r'\{2\}', 'g'), + (r'[^+>] [^+>]', ''), + (r'\bucpyv\s*=\s*([^;]*)', 'i'), + (r'\bucuvqr\s*=\s*([^;]*)', 'i'), + (r'\bucfie\s*=\s*([^;]*)', 'i'), + (r'\bhfucjrn\s*=\s*([^;]*)', 'i'), + (r'\bmvc\s*=\s*([^;]*)', 'i'), + (r'^((?:[\w' + '\u0128-\uffff' + r'*_-]|\\.)+)(#)((?:[\w' + + '\u0128-\uffff' + r'*_-]|\\.)+)', ''), + (r'^([>+~])\s*(\w*)', 'i'), + (r'^>\s*((?:[\w' + '\u0128-\uffff' + r'*_-]|\\.)+)', ''), + (r'^[\s[]?shapgvba', ''), + (r'v\/g.tvs#(.*)', 'i'), + (r'eaq_zbqobkva', ''), + (r';\s*', ''), + (r'(\$\{inyhr\})|(\$inyhr\b)', 'g'), + (r'(\$\{abj\})|(\$abj\b)', 'g'), + (r'\s+$', ''), + (r'^\s+', ''), + (r'(\\\"|\x00-|\x1f|\x7f-|\x9f|' + + '\u00ad|\u0600-|\u0604|\u070f|\u17b4|\u17b5|\u200c-|\u200f|\u2028-|\u202f|\u2060-|\u206f|\ufeff|\ufff0-|\uffff' + r')', 'g'), + (r'^(:)([\w-]+)\("?\'?(.*?(\(.*?\))?[^(]*?)"?\'?\)', ''), + (r'^([:.#]*)((?:[\w' + '\u0128-\uffff' + r'*_-]|\\.)+)', ''), + (r'^(\[) *@?([\w-]+) *([!*$^~=]*) *(\'?"?)(.*?)\4 *\]', '')] + + +# The V8 javascript engine only does one replacement unless the regexp has +# the 'g' flag. Python's sub has count = 1 to do 1 replacement and count = 0 +# to replace all matches. We set this up here. + +regexs = [] +subcount = [] + +for s in compiled_regex_strings: + if 'g' in s[1]: + subcount.append(0) + else: + subcount.append(1) + + if 'i' in s[1]: + regexs.append(re.compile(s[0], re.IGNORECASE | re.UNICODE)) + else: + regexs.append(re.compile(s[0], re.UNICODE)) + +# The strings that were in vars in the V8 benchmark + +strings = [ + r'Zbmvyyn/5.0 (Jvaqbjf; H; Jvaqbjf AG 5.1; ra-HF) NccyrJroXvg/528.9 (XUGZY, yvxr Trpxb) Puebzr/2.0.157.0 Fnsnev/528.9', + r'Fubpxjnir Synfu 9.0 e115', + r'{"anzr":"","ahzoreSbezng":{"PheeraplQrpvznyQvtvgf":2,"PheeraplQrpvznyFrcnengbe":".","VfErnqBayl":gehr,"PheeraplTebhcFvmrf":[3],"AhzoreTebhcFvmrf":[3],"CrepragTebhcFvmrf":[3],"PheeraplTebhcFrcnengbe":",","PheeraplFlzoby":"\xa4","AnAFlzoby":"AnA","PheeraplArtngvirCnggrea":0,"AhzoreArtngvirCnggrea":1,"CrepragCbfvgvirCnggrea":0,"CrepragArtngvirCnggrea":0,"ArtngvirVasvavglFlzoby":"-Vasvavgl","ArtngvirFvta":"-","AhzoreQrpvznyQvtvgf":2,"AhzoreQrpvznyFrcnengbe":".","AhzoreTebhcFrcnengbe":",","PheeraplCbfvgvirCnggrea":0,"CbfvgvirVasvavglFlzoby":"Vasvavgl","CbfvgvirFvta":"+","CrepragQrpvznyQvtvgf":2,"CrepragQrpvznyFrcnengbe":".","CrepragTebhcFrcnengbe":",","CrepragFlzoby":"%","CreZvyyrFlzoby":"\u2030","AngvirQvtvgf":["0","1","2","3","4","5","6","7","8","9"],"QvtvgFhofgvghgvba":1},"qngrGvzrSbezng":{"NZQrfvtangbe":"NZ","Pnyraqne":{"ZvaFhccbegrqQngrGvzr":"@-62135568000000@","ZnkFhccbegrqQngrGvzr":"@253402300799999@","NytbevguzGlcr":1,"PnyraqneGlcr":1,"Renf":[1],"GjbQvtvgLrneZnk":2029,"VfErnqBayl":gehr},"QngrFrcnengbe":"/","SvefgQnlBsJrrx":0,"PnyraqneJrrxEhyr":0,"ShyyQngrGvzrCnggrea":"qqqq, qq ZZZZ llll UU:zz:ff","YbatQngrCnggrea":"qqqq, qq ZZZZ llll","YbatGvzrCnggrea":"UU:zz:ff","ZbaguQnlCnggrea":"ZZZZ qq","CZQrfvtangbe":"CZ","ESP1123Cnggrea":"qqq, qq ZZZ llll UU\':\'zz\':\'ff \'TZG\'","FubegQngrCnggrea":"ZZ/qq/llll","FubegGvzrCnggrea":"UU:zz","FbegnoyrQngrGvzrCnggrea":"llll\'-\'ZZ\'-\'qq\'G\'UU\':\'zz\':\'ff","GvzrFrcnengbe":":","HavirefnyFbegnoyrQngrGvzrCnggrea":"llll\'-\'ZZ\'-\'qq UU\':\'zz\':\'ff\'M\'","LrneZbaguCnggrea":"llll ZZZZ","NooerivngrqQnlAnzrf":["Fha","Zba","Ghr","Jrq","Guh","Sev","Fng"],"FubegrfgQnlAnzrf":["Fh","Zb","Gh","Jr","Gu","Se","Fn"],"QnlAnzrf":["Fhaqnl","Zbaqnl","Ghrfqnl","Jrqarfqnl","Guhefqnl","Sevqnl","Fngheqnl"],"NooerivngrqZbaguAnzrf":["Wna","Sro","Zne","Nce","Znl","Wha","Why","Nht","Frc","Bpg","Abi","Qrp",""],"ZbaguAnzrf":["Wnahnel","Sroehnel","Znepu","Ncevy","Znl","Whar","Whyl","Nhthfg","Frcgrzore","Bpgbore","Abirzore","Qrprzore",""],"VfErnqBayl":gehr,"AngvirPnyraqneAnzr":"Tertbevna Pnyraqne","NooerivngrqZbaguTravgvirAnzrf":["Wna","Sro","Zne","Nce","Znl","Wha","Why","Nht","Frc","Bpg","Abi","Qrp",""],"ZbaguTravgvirAnzrf":["Wnahnel","Sroehnel","Znepu","Ncevy","Znl","Whar","Whyl","Nhthfg","Frcgrzore","Bpgbore","Abirzore","Qrprzore",""]}}', + r'{"anzr":"ra-HF","ahzoreSbezng":{"PheeraplQrpvznyQvtvgf":2,"PheeraplQrpvznyFrcnengbe":".","VfErnqBayl":snyfr,"PheeraplTebhcFvmrf":[3],"AhzoreTebhcFvmrf":[3],"CrepragTebhcFvmrf":[3],"PheeraplTebhcFrcnengbe":",","PheeraplFlzoby":"$","AnAFlzoby":"AnA","PheeraplArtngvirCnggrea":0,"AhzoreArtngvirCnggrea":1,"CrepragCbfvgvirCnggrea":0,"CrepragArtngvirCnggrea":0,"ArtngvirVasvavglFlzoby":"-Vasvavgl","ArtngvirFvta":"-","AhzoreQrpvznyQvtvgf":2,"AhzoreQrpvznyFrcnengbe":".","AhzoreTebhcFrcnengbe":",","PheeraplCbfvgvirCnggrea":0,"CbfvgvirVasvavglFlzoby":"Vasvavgl","CbfvgvirFvta":"+","CrepragQrpvznyQvtvgf":2,"CrepragQrpvznyFrcnengbe":".","CrepragTebhcFrcnengbe":",","CrepragFlzoby":"%","CreZvyyrFlzoby":"\u2030","AngvirQvtvgf":["0","1","2","3","4","5","6","7","8","9"],"QvtvgFhofgvghgvba":1},"qngrGvzrSbezng":{"NZQrfvtangbe":"NZ","Pnyraqne":{"ZvaFhccbegrqQngrGvzr":"@-62135568000000@","ZnkFhccbegrqQngrGvzr":"@253402300799999@","NytbevguzGlcr":1,"PnyraqneGlcr":1,"Renf":[1],"GjbQvtvgLrneZnk":2029,"VfErnqBayl":snyfr},"QngrFrcnengbe":"/","SvefgQnlBsJrrx":0,"PnyraqneJrrxEhyr":0,"ShyyQngrGvzrCnggrea":"qqqq, ZZZZ qq, llll u:zz:ff gg","YbatQngrCnggrea":"qqqq, ZZZZ qq, llll","YbatGvzrCnggrea":"u:zz:ff gg","ZbaguQnlCnggrea":"ZZZZ qq","CZQrfvtangbe":"CZ","ESP1123Cnggrea":"qqq, qq ZZZ llll UU\':\'zz\':\'ff \'TZG\'","FubegQngrCnggrea":"Z/q/llll","FubegGvzrCnggrea":"u:zz gg","FbegnoyrQngrGvzrCnggrea":"llll\'-\'ZZ\'-\'qq\'G\'UU\':\'zz\':\'ff","GvzrFrcnengbe":":","HavirefnyFbegnoyrQngrGvzrCnggrea":"llll\'-\'ZZ\'-\'qq UU\':\'zz\':\'ff\'M\'","LrneZbaguCnggrea":"ZZZZ, llll","NooerivngrqQnlAnzrf":["Fha","Zba","Ghr","Jrq","Guh","Sev","Fng"],"FubegrfgQnlAnzrf":["Fh","Zb","Gh","Jr","Gu","Se","Fn"],"QnlAnzrf":["Fhaqnl","Zbaqnl","Ghrfqnl","Jrqarfqnl","Guhefqnl","Sevqnl","Fngheqnl"],"NooerivngrqZbaguAnzrf":["Wna","Sro","Zne","Nce","Znl","Wha","Why","Nht","Frc","Bpg","Abi","Qrp",""],"ZbaguAnzrf":["Wnahnel","Sroehnel","Znepu","Ncevy","Znl","Whar","Whyl","Nhthfg","Frcgrzore","Bpgbore","Abirzore","Qrprzore",""],"VfErnqBayl":snyfr,"AngvirPnyraqneAnzr":"Tertbevna Pnyraqne","NooerivngrqZbaguTravgvirAnzrf":["Wna","Sro","Zne","Nce","Znl","Wha","Why","Nht","Frc","Bpg","Abi","Qrp",""],"ZbaguTravgvirAnzrf":["Wnahnel","Sroehnel","Znepu","Ncevy","Znl","Whar","Whyl","Nhthfg","Frcgrzore","Bpgbore","Abirzore","Qrprzore",""]}}', + r'HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q', + r'HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=', + r'uggc://jjj.snprobbx.pbz/vaqrk.cuc', + r';;jvaqbj.IjPurpxZbhfrCbfvgvbaNQ_VQ=shapgvba(r){vs(!r)ine r=jvaqbj.rirag;ine c=-1;vs(d1)c=d1.EbyybssCnary;ine bo=IjTrgBow("IjCnayNQ_VQ_"+c);vs(bo&&bo.fglyr.ivfvovyvgl=="ivfvoyr"){ine fns=IjFns?8:0;ine pheK=r.pyvragK+IjBOFpe("U")+fns,pheL=r.pyvragL+IjBOFpe("I")+fns;ine y=IjBOEC(NQ_VQ,bo,"Y"),g=IjBOEC(NQ_VQ,bo,"G");ine e=y+d1.Cnaryf[c].Jvqgu,o=g+d1.Cnaryf[c].Urvtug;vs((pheKe)||(pheLo)){vs(jvaqbj.IjBaEbyybssNQ_VQ)IjBaEbyybssNQ_VQ(c);ryfr IjPybfrNq(NQ_VQ,c,gehr,"");}ryfr erghea;}IjPnapryZbhfrYvfgrareNQ_VQ();};;jvaqbj.IjFrgEbyybssCnaryNQ_VQ=shapgvba(c){ine z="zbhfrzbir",q=qbphzrag,s=IjPurpxZbhfrCbfvgvbaNQ_VQ;c=IjTc(NQ_VQ,c);vs(d1&&d1.EbyybssCnary>-1)IjPnapryZbhfrYvfgrareNQ_VQ();vs(d1)d1.EbyybssCnary=c;gel{vs(q.nqqRiragYvfgrare)q.nqqRiragYvfgrare(z,s,snyfr);ryfr vs(q.nggnpuRirag)q.nggnpuRirag("ba"+z,s);}pngpu(r){}};;jvaqbj.IjPnapryZbhfrYvfgrareNQ_VQ=shapgvba(){ine z="zbhfrzbir",q=qbphzrag,s=IjPurpxZbhfrCbfvgvbaNQ_VQ;vs(d1)d1.EbyybssCnary=-1;gel{vs(q.erzbirRiragYvfgrare)q.erzbirRiragYvfgrare(z,s,snyfr);ryfr vs(q.qrgnpuRirag)q.qrgnpuRirag("ba"+z,s);}pngpu(r){}};;d1.IjTc=d2(n,c){ine nq=d1;vs(vfAnA(c)){sbe(ine v=0;v0){vs(nq.FzV.yratgu>0)nq.FzV+="/";nq.FzV+=vh[v];nq.FtZ[nq.FtZ.yratgu]=snyfr;}}};;d1.IjYvzvg0=d2(n,f){ine nq=d1,vh=f.fcyvg("/");sbe(ine v=0;v0){vs(nq.OvC.yratgu>0)nq.OvC+="/";nq.OvC+=vh[v];}}};;d1.IjRVST=d2(n,c){jvaqbj["IjCnayNQ_VQ_"+c+"_Bow"]=IjTrgBow("IjCnayNQ_VQ_"+c+"_Bow");vs(jvaqbj["IjCnayNQ_VQ_"+c+"_Bow"]==ahyy)frgGvzrbhg("IjRVST(NQ_VQ,"+c+")",d1.rvsg);};;d1.IjNavzSHC=d2(n,c){ine nq=d1;vs(c>nq.Cnaryf.yratgu)erghea;ine cna=nq.Cnaryf[c],nn=gehr,on=gehr,yn=gehr,en=gehr,cn=nq.Cnaryf[0],sf=nq.ShF,j=cn.Jvqgu,u=cn.Urvtug;vs(j=="100%"){j=sf;en=snyfr;yn=snyfr;}vs(u=="100%"){u=sf;nn=snyfr;on=snyfr;}vs(cn.YnY=="Y")yn=snyfr;vs(cn.YnY=="E")en=snyfr;vs(cn.GnY=="G")nn=snyfr;vs(cn.GnY=="O")on=snyfr;ine k=0,l=0;fjvgpu(nq.NshP%8){pnfr 0:oernx;pnfr 1:vs(nn)l=-sf;oernx;pnfr 2:k=j-sf;oernx;pnfr 3:vs(en)k=j;oernx;pnfr 4:k=j-sf;l=u-sf;oernx;pnfr 5:k=j-sf;vs(on)l=u;oernx;pnfr 6:l=u-sf;oernx;pnfr 7:vs(yn)k=-sf;l=u-sf;oernx;}vs(nq.NshP++ 0)||(nethzragf.yratgu==3&&bG>0))){pyrneGvzrbhg(cay.UgU);cay.UgU=frgGvzrbhg(cay.UvqrNpgvba,(nethzragf.yratgu==3?bG:cay.UvqrGvzrbhgInyhr));}};;d1.IjErfrgGvzrbhg=d2(n,c,bG){c=IjTc(n,c);IjPnapryGvzrbhg(n,c);riny("IjFgnegGvzrbhg(NQ_VQ,c"+(nethzragf.yratgu==3?",bG":"")+")");};;d1.IjErfrgNyyGvzrbhgf=d2(n){sbe(ine c=0;ce)||(pheLo)){vs(jvaqbj.IjBaEbyybssNQ_VQ)IjBaEbyybssNQ_VQ(c);ryfr IjPybfrNq(NQ_VQ,c,gehr,"");}ryfr erghea;}IjPnapryZbhfrYvfgrareNQ_VQ();};;jvaqbj.IjFrgEbyybssCnaryNQ_VQ=shapgvba(c){ine z="zbhfrzbir",q=qbphzrag,s=IjPurpxZbhfrCbfvgvbaNQ_VQ;c=IjTc(NQ_VQ,c);vs(jvaqbj.IjNqNQ_VQ&&jvaqbj.IjNqNQ_VQ.EbyybssCnary>-1)IjPnapryZbhfrYvfgrareNQ_VQ();vs(jvaqbj.IjNqNQ_VQ)jvaqbj.IjNqNQ_VQ.EbyybssCnary=c;gel{vs(q.nqqRiragYvfgrare)q.nqqRiragYvfgrare(z,s,snyfr);ryfr vs(q.nggnpuRirag)q.nggnpuRirag("ba"+z,s);}pngpu(r){}};;jvaqbj.IjPnapryZbhfrYvfgrareNQ_VQ=shapgvba(){ine z="zbhfrzbir",q=qbphzrag,s=IjPurpxZbhfrCbfvgvbaNQ_VQ;vs(jvaqbj.IjNqNQ_VQ)jvaqbj.IjNqNQ_VQ.EbyybssCnary=-1;gel{vs(q.erzbirRiragYvfgrare)q.erzbirRiragYvfgrare(z,s,snyfr);ryfr vs(q.qrgnpuRirag)q.qrgnpuRirag("ba"+z,s);}pngpu(r){}};;jvaqbj.IjNqNQ_VQ.IjTc=shapgvba(n,c){ine nq=jvaqbj.IjNqNQ_VQ;vs(vfAnA(c)){sbe(ine v=0;v0){vs(nq.FzV.yratgu>0)nq.FzV+="/";nq.FzV+=vh[v];nq.FtZ[nq.FtZ.yratgu]=snyfr;}}};;jvaqbj.IjNqNQ_VQ.IjYvzvg0=shapgvba(n,f){ine nq=jvaqbj.IjNqNQ_VQ,vh=f.fcyvg("/");sbe(ine v=0;v0){vs(nq.OvC.yratgu>0)nq.OvC+="/";nq.OvC+=vh[v];}}};;jvaqbj.IjNqNQ_VQ.IjRVST=shapgvba(n,c){jvaqbj["IjCnayNQ_VQ_"+c+"_Bow"]=IjTrgBow("IjCnayNQ_VQ_"+c+"_Bow");vs(jvaqbj["IjCnayNQ_VQ_"+c+"_Bow"]==ahyy)frgGvzrbhg("IjRVST(NQ_VQ,"+c+")",jvaqbj.IjNqNQ_VQ.rvsg);};;jvaqbj.IjNqNQ_VQ.IjNavzSHC=shapgvba(n,c){ine nq=jvaqbj.IjNqNQ_VQ;vs(c>nq.Cnaryf.yratgu)erghea;ine cna=nq.Cnaryf[c],nn=gehr,on=gehr,yn=gehr,en=gehr,cn=nq.Cnaryf[0],sf=nq.ShF,j=cn.Jvqgu,u=cn.Urvtug;vs(j=="100%"){j=sf;en=snyfr;yn=snyfr;}vs(u=="100%"){u=sf;nn=snyfr;on=snyfr;}vs(cn.YnY=="Y")yn=snyfr;vs(cn.YnY=="E")en=snyfr;vs(cn.GnY=="G")nn=snyfr;vs(cn.GnY=="O")on=snyfr;ine k=0,l=0;fjvgpu(nq.NshP%8){pnfr 0:oernx;pnfr 1:vs(nn)l=-sf;oernx;pnfr 2:k=j-sf;oernx;pnfr 3:vs(en)k=j;oernx;pnfr 4:k=j-sf;l=u-sf;oernx;pnfr 5:k=j-sf;vs(on)l=u;oernx;pnfr 6:l=u-sf;oernx;pnfr 7:vs(yn)k=-sf;l=u-sf;oernx;}vs(nq.NshP++ 0)||(nethzragf.yratgu==3&&bG>0))){pyrneGvzrbhg(cay.UgU);cay.UgU=frgGvzrbhg(cay.UvqrNpgvba,(nethzragf.yratgu==3?bG:cay.UvqrGvzrbhgInyhr));}};;jvaqbj.IjNqNQ_VQ.IjErfrgGvzrbhg=shapgvba(n,c,bG){c=IjTc(n,c);IjPnapryGvzrbhg(n,c);riny("IjFgnegGvzrbhg(NQ_VQ,c"+(nethzragf.yratgu==3?",bG":"")+")");};;jvaqbj.IjNqNQ_VQ.IjErfrgNyyGvzrbhgf=shapgvba(n){sbe(ine c=0;ce)||(pheLo)){vs(jvaqbj.IjBaEbyybssNQ_VQ)IjBaEbyybssNQ_VQ(c);ryfr IjPybfrNq(NQ_VQ,c,gehr,"");}ryfr erghea;}IjPnapryZbhfrYvfgrareNQ_VQ();};;jvaqbj.IjFrgEbyybssCnaryNQ_VQ=shapgvba(c){ine z="zbhfrzbir",q=qbphzrag,s=IjPurpxZbhfrCbfvgvbaNQ_VQ;c=IjTc(NQ_VQ,c);vs(jvaqbj.IjNqNQ_VQ&&jvaqbj.IjNqNQ_VQ.EbyybssCnary>-1)IjPnapryZbhfrYvfgrareNQ_VQ();vs(jvaqbj.IjNqNQ_VQ)jvaqbj.IjNqNQ_VQ.EbyybssCnary=c;gel{vs(q.nqqRiragYvfgrare)q.nqqRiragYvfgrare(z,s,snyfr);ryfr vs(q.nggnpuRirag)q.nggnpuRirag("ba"+z,s);}pngpu(r){}};;jvaqbj.IjPnapryZbhfrYvfgrareNQ_VQ=shapgvba(){ine z="zbhfrzbir",q=qbphzrag,s=IjPurpxZbhfrCbfvgvbaNQ_VQ;vs(jvaqbj.IjNqNQ_VQ)jvaqbj.IjNqNQ_VQ.EbyybssCnary=-1;gel{vs(q.erzbirRiragYvfgrare)q.erzbirRiragYvfgrare(z,s,snyfr);ryfr vs(q.qrgnpuRirag)q.qrgnpuRirag("ba"+z,s);}pngpu(r){}};;jvaqbj.IjNqNQ_VQ.IjTc=d2(n,c){ine nq=jvaqbj.IjNqNQ_VQ;vs(vfAnA(c)){sbe(ine v=0;v0){vs(nq.FzV.yratgu>0)nq.FzV+="/";nq.FzV+=vh[v];nq.FtZ[nq.FtZ.yratgu]=snyfr;}}};;jvaqbj.IjNqNQ_VQ.IjYvzvg0=d2(n,f){ine nq=jvaqbj.IjNqNQ_VQ,vh=f.fcyvg("/");sbe(ine v=0;v0){vs(nq.OvC.yratgu>0)nq.OvC+="/";nq.OvC+=vh[v];}}};;jvaqbj.IjNqNQ_VQ.IjRVST=d2(n,c){jvaqbj["IjCnayNQ_VQ_"+c+"_Bow"]=IjTrgBow("IjCnayNQ_VQ_"+c+"_Bow");vs(jvaqbj["IjCnayNQ_VQ_"+c+"_Bow"]==ahyy)frgGvzrbhg("IjRVST(NQ_VQ,"+c+")",jvaqbj.IjNqNQ_VQ.rvsg);};;jvaqbj.IjNqNQ_VQ.IjNavzSHC=d2(n,c){ine nq=jvaqbj.IjNqNQ_VQ;vs(c>nq.Cnaryf.yratgu)erghea;ine cna=nq.Cnaryf[c],nn=gehr,on=gehr,yn=gehr,en=gehr,cn=nq.Cnaryf[0],sf=nq.ShF,j=cn.Jvqgu,u=cn.Urvtug;vs(j=="100%"){j=sf;en=snyfr;yn=snyfr;}vs(u=="100%"){u=sf;nn=snyfr;on=snyfr;}vs(cn.YnY=="Y")yn=snyfr;vs(cn.YnY=="E")en=snyfr;vs(cn.GnY=="G")nn=snyfr;vs(cn.GnY=="O")on=snyfr;ine k=0,l=0;fjvgpu(nq.NshP%8){pnfr 0:oernx;pnfr 1:vs(nn)l=-sf;oernx;pnfr 2:k=j-sf;oernx;pnfr 3:vs(en)k=j;oernx;pnfr 4:k=j-sf;l=u-sf;oernx;pnfr 5:k=j-sf;vs(on)l=u;oernx;pnfr 6:l=u-sf;oernx;pnfr 7:vs(yn)k=-sf;l=u-sf;oernx;}vs(nq.NshP++ 0)||(nethzragf.yratgu==3&&bG>0))){pyrneGvzrbhg(cay.UgU);cay.UgU=frgGvzrbhg(cay.UvqrNpgvba,(nethzragf.yratgu==3?bG:cay.UvqrGvzrbhgInyhr));}};;jvaqbj.IjNqNQ_VQ.IjErfrgGvzrbhg=d2(n,c,bG){c=IjTc(n,c);IjPnapryGvzrbhg(n,c);riny("IjFgnegGvzrbhg(NQ_VQ,c"+(nethzragf.yratgu==3?",bG":"")+")");};;jvaqbj.IjNqNQ_VQ.IjErfrgNyyGvzrbhgf=d2(n){sbe(ine c=0;c##yv4##Cbjreshy Zvpebfbsg grpuabybtl urycf svtug fcnz naq vzcebir frphevgl.##yv19##Trg zber qbar gunaxf gb terngre rnfr naq fcrrq.##yv16##Ybgf bs fgbentr (5 TO) - zber pbby fghss ba gur jnl.##OE## ##OE## ##N##Yrnea zber##/N##', + r'Cbjreshy Zvpebfbsg grpuabybtl urycf svtug fcnz naq vzcebir frphevgl.##yv19##Trg zber qbar gunaxf gb terngre rnfr naq fcrrq.##yv16##Ybgf bs fgbentr (5 TO) - zber pbby fghss ba gur jnl.##OE## ##OE## ##N##Yrnea zber##/N##', + r'Cbjreshy Zvpebfbsg grpuabybtl urycf svtug fcnz naq vzcebir frphevgl.##yv19##Trg zber qbar gunaxf gb terngre rnfr naq fcrrq.Ybgf bs fgbentr (5 TO) - zber pbby fghss ba gur jnl.##OE## ##OE## ##N##Yrnea zber##/N##', + r'Cbjreshy Zvpebfbsg grpuabybtl urycf svtug fcnz naq vzcebir frphevgl.Trg zber qbar gunaxf gb terngre rnfr naq fcrrq.Ybgf bs fgbentr (5 TO) - zber pbby fghss ba gur jnl.##OE## ##OE## ##N##Yrnea zber##/N##', + r'Cbjreshy Zvpebfbsg grpuabybtl urycf svtug fcnz naq vzcebir frphevgl.Trg zber qbar gunaxf gb terngre rnfr naq fcrrq.Ybgf bs fgbentr (5 TO) - zber pbby fghss ba gur jnl. ##N##Yrnea zber##/N##', + r'Cbjreshy Zvpebfbsg grpuabybtl urycf svtug fcnz naq vzcebir frphevgl.Trg zber qbar gunaxf gb terngre rnfr naq fcrrq.Ybgf bs fgbentr (5 TO) - zber pbby fghss ba gur jnl. Yrnea zber##/N##', + r'Bar Jvaqbjf Yvir VQ trgf lbh vagb Ubgznvy, Zrffratre, Kobk YVIR \u2014 naq bgure cynprf lbh frr #~#argjbexybtb#~#', + r'${1}://${2}${3}${4}${5}', + r' O=6gnyg0g4znrrn&o=3&f=gc; Q=_lyu=K3bQZGSxnT4lZzD3OS9GNmV3ZGLkAQxRpTyxNmRlZmRmAmNkAQLRqTImqNZjOUEgpTjQnJ5xMKtgoN--; SCF=qy', + r'FrffvbaQQS2=4ss747o77904333q374or84qrr1s9r0nprp8r5q81534o94n; ZFPhygher=VC=74.125.75.20&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669321699093060&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=; AFP_zp_tfwsbrg-aowb_80=4413268q3660', + r'FrffvbaQQS2=4ss747o77904333q374or84qrr1s9r0nprp8r5q81534o94n; AFP_zp_tfwsbrg-aowb_80=4413268q3660; __hgzm=144631658.1231364074.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.2294274870215848400.1231364074.1231364074.1231364074.1; __hgzo=144631658.0.10.1231364074; __hgzp=144631658; ZFPhygher=VC=74.125.75.20&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669321699093060&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q', + r'uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_zlfcnpr-ubzrcntr_wf&qg=1231364057761&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231364057761&punaary=svz_zlfcnpr_ubzrcntr_abgybttrqva%2Psvz_zlfcnpr_aba_HTP%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Ssevraqf.zlfcnpr.pbz%2Svaqrk.psz&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=1667363813.1231364061&tn_fvq=1231364061&tn_uvq=1917563877&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22', + r'ZFPhygher=VC=74.125.75.20&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669321699093060&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q', + r'ZFPhygher=VC=74.125.75.20&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669321699093060&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=', + r'uggc://cebsvyr.zlfcnpr.pbz/Zbqhyrf/Nccyvpngvbaf/Cntrf/Pnainf.nfck', + r'FrffvbaQQS2=473qq1rs0n2r70q9qo1pq48n021s9468ron90nps048p4p29; ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669325184628362&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=', + r'FrffvbaQQS2=473qq1rs0n2r70q9qo1pq48n021s9468ron90nps048p4p29; __hgzm=144631658.1231364380.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.3931862196947939300.1231364380.1231364380.1231364380.1; __hgzo=144631658.0.10.1231364380; __hgzp=144631658; ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669325184628362&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q', + r'uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_vzntrf_wf&qg=1231364373088&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231364373088&punaary=svz_zlfcnpr_hfre-ivrj-pbzzragf%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Spbzzrag.zlfcnpr.pbz%2Svaqrk.psz&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=1158737789.1231364375&tn_fvq=1231364375&tn_uvq=415520832&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22', + r'ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669325184628362&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q', + r'ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669325184628362&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=', + r'#Zbq-Vasb-Vasb-WninFpevcgUvag', + r',n.svryqOgaPnapry', + r'FrffvbaQQS2=p98s8o9q42nr21or1r61pqorn1n002nsss569635984s6qp7; ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669357391353591&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=; AFP_zp_kkk-gdzogv_80=4413241q3660', + r'FrffvbaQQS2=p98s8o9q42nr21or1r61pqorn1n002nsss569635984s6qp7; AFP_zp_kkk-gdzogv_80=4413241q3660; AFP_zp_kkk-aowb_80=4413235p3660; __hgzm=144631658.1231367708.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.2770915348920628700.1231367708.1231367708.1231367708.1; __hgzo=144631658.0.10.1231367708; __hgzp=144631658; ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669357391353591&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q', + r'uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_zlfcnpr-ubzrcntr_wf&qg=1231367691141&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231367691141&punaary=svz_zlfcnpr_ubzrcntr_abgybttrqva%2Psvz_zlfcnpr_aba_HTP%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Sjjj.zlfcnpr.pbz%2S&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=320757904.1231367694&tn_fvq=1231367694&tn_uvq=1758792003&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22', + r'uggc://zfacbegny.112.2b7.arg/o/ff/zfacbegnyubzr/1/U.7-cqi-2/f55332979829981?[NDO]&aqu=1&g=7%2S0%2S2009%2014%3N38%3N42%203%20480&af=zfacbegny&cntrAnzr=HF%20UCZFSGJ&t=uggc%3N%2S%2Sjjj.zfa.pbz%2S&f=1024k768&p=24&x=L&oj=994&ou=634&uc=A&{2}&[NDR]', + r'cnerag puebzr6 fvatyr1 gno fryrpgrq ovaq qbhoyr2 ps', + r'ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669357391353591&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q', + r'ZFPhygher=VC=74.125.75.3&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669357391353591&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=', + r'ne;ng;nh;or;oe;pn;pu;py;pa;qr;qx;rf;sv;se;to;ux;vq;vr;va;vg;wc;xe;zk;zl;ay;ab;am;cu;cy;cg;eh;fr;ft;gu;ge;gj;mn;', + r'ZP1=I=3&THVQ=6nnpr9q661804s33nnop45nosqp17q85; zu=ZFSG; PHYGHER=RA-HF; SyvtugTebhcVq=97; SyvtugVq=OnfrCntr; ucfie=Z:5|S:5|G:5|R:5|Q:oyh|J:S; ucpyv=J.U|Y.|F.|E.|H.Y|P.|U.; hfucjrn=jp:HFPN0746; ZHVQ=Q783SN9O14054831N4869R51P0SO8886&GHVQ=1', + r'ZP1=I=3&THVQ=6nnpr9q661804s33nnop45nosqp17q85; zu=ZFSG; PHYGHER=RA-HF; SyvtugTebhcVq=97; SyvtugVq=OnfrCntr; ucfie=Z:5|S:5|G:5|R:5|Q:oyh|J:S; ucpyv=J.U|Y.|F.|E.|H.Y|P.|U.; hfucjrn=jp:HFPN0746; ZHVQ=Q783SN9O14054831N4869R51P0SO8886', + r'ZP1=I=3&THVQ=6nnpr9q661804s33nnop45nosqp17q85; zu=ZFSG; PHYGHER=RA-HF; SyvtugTebhcVq=97; SyvtugVq=OnfrCntr; ucfie=Z:5|S:5|G:5|R:5|Q:oyh|J:S; ucpyv=J.U|Y.|F.|E.|H.Y|P.|U.; hfucjrn=jp:HFPN0746; ZHVQ=Q783SN9O14054831N4869R51P0SO8886; mvc=m:94043|yn:37.4154|yb:-122.0585|p:HF|ue:1', + r'ZP1=I=3&THVQ=6nnpr9q661804s33nnop45nosqp17q85; zu=ZFSG; PHYGHER=RA-HF; SyvtugTebhcVq=97; SyvtugVq=OnfrCntr; ucfie=Z:5|S:5|G:5|R:5|Q:oyh|J:S; ucpyv=J.U|Y.|F.|E.|H.Y|P.|U.; hfucjrn=jp:HFPN0746; ZHVQ=Q783SN9O14054831N4869R51P0SO8886; mvc=m:94043|yn:37.4154|yb:-122.0585|p:HF', + r'uggc://gx2.fgp.f-zfa.pbz/oe/uc/11/ra-hf/pff/v/g.tvs#uggc://gx2.fgo.f-zfa.pbz/v/29/4RQP4969777N048NPS4RRR3PO2S7S.wct', + r'uggc://gx2.fgp.f-zfa.pbz/oe/uc/11/ra-hf/pff/v/g.tvs#uggc://gx2.fgo.f-zfa.pbz/v/OQ/63NP9O94NS5OQP1249Q9S1ROP7NS3.wct', + r'zbmvyyn/5.0 (jvaqbjf; h; jvaqbjf ag 5.1; ra-hf) nccyrjroxvg/528.9 (xugzy, yvxr trpxb) puebzr/2.0.157.0 fnsnev/528.9', + r'1231365729213', + r'74.125.75.3-1057165600.29978900', + r'74.125.75.3-1057165600.29978900.1231365730214', + r'Frnepu%20Zvpebfbsg.pbz', + r'FrffvbaQQS2=8sqq78r9n442851q565599o401385sp3s04r92rnn7o19ssn; ZFPhygher=VC=74.125.75.17&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669340386893867&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=', + r'FrffvbaQQS2=8sqq78r9n442851q565599o401385sp3s04r92rnn7o19ssn; __hgzm=144631658.1231365779.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.1877536177953918500.1231365779.1231365779.1231365779.1; __hgzo=144631658.0.10.1231365779; __hgzp=144631658; ZFPhygher=VC=74.125.75.17&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669340386893867&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q', + r'I=3%26THVQ=757q3ss871q44o7o805n8113n5p72q52', + r'I=3&THVQ=757q3ss871q44o7o805n8113n5p72q52', + r'uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_zlfcnpr-ubzrcntr_wf&qg=1231365765292&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231365765292&punaary=svz_zlfcnpr_ubzrcntr_abgybttrqva%2Psvz_zlfcnpr_aba_HTP%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Sohyyrgvaf.zlfcnpr.pbz%2Svaqrk.psz&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=1579793869.1231365768&tn_fvq=1231365768&tn_uvq=2056210897&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22', + r'frnepu.zvpebfbsg.pbz', + r'frnepu.zvpebfbsg.pbz/', + r'ZFPhygher=VC=74.125.75.17&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669340386893867&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q', + r'ZFPhygher=VC=74.125.75.17&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669340386893867&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=', + r'#fubhgobk .pybfr', + r'FrffvbaQQS2=102n9o0o9pq60132qn0337rr867p75953502q2s27s2s5r98; ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669341278771470&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=; AFP_zp_dfctwzssrwh-aowb_80=441326q33660', + r'FrffvbaQQS2=102n9o0o9pq60132qn0337rr867p75953502q2s27s2s5r98; AFP_zp_dfctwzssrwh-aowb_80=441326q33660; __hgzm=144631658.1231365869.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.1670816052019209000.1231365869.1231365869.1231365869.1; __hgzo=144631658.0.10.1231365869; __hgzp=144631658; ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669341278771470&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q', + r'FrffvbaQQS2=9995p6rp12rrnr893334ro7nq70o7p64p69rqn844prs1473; ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669350559478880&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=; AFP_zp_dfctwzs-aowb_80=441327q73660', + r'FrffvbaQQS2=9995p6rp12rrnr893334ro7nq70o7p64p69rqn844prs1473; AFP_zp_dfctwzs-aowb_80=441327q73660; __hgzm=144631658.1231367054.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar); __hgzn=144631658.1796080716621419500.1231367054.1231367054.1231367054.1; __hgzo=144631658.0.10.1231367054; __hgzp=144631658; ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669350559478880&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q', + r'[glcr=fhozvg]', + r'n.svryqOga,n.svryqOgaPnapry', + r'n.svryqOgaPnapry', + r'oyvpxchaxg', + r'qvi.bow-nppbeqvba qg', + r'uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_nccf_wf&qg=1231367052227&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231367052227&punaary=svz_zlfcnpr_nccf-pnainf%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Scebsvyr.zlfcnpr.pbz%2SZbqhyrf%2SNccyvpngvbaf%2SCntrf%2SPnainf.nfck&nq_glcr=grkg&rvq=6083027&rn=0&sez=1&tn_ivq=716357910.1231367056&tn_fvq=1231367056&tn_uvq=1387206491&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22', + r'uggc://tbbtyrnqf.t.qbhoyrpyvpx.arg/cntrnq/nqf?pyvrag=pn-svz_zlfcnpr_zlfcnpr-ubzrcntr_wf&qg=1231365851658&uy=ra&nqfnsr=uvtu&br=hgs8&ahz_nqf=4&bhgchg=wf&nqgrfg=bss&pbeeryngbe=1231365851658&punaary=svz_zlfcnpr_ubzrcntr_abgybttrqva%2Psvz_zlfcnpr_aba_HTP%2Psvz_zlfcnpr_havgrq-fgngrf&hey=uggc%3N%2S%2Scebsvyrrqvg.zlfcnpr.pbz%2Svaqrk.psz&nq_glcr=grkg&rvq=6083027&rn=0&sez=0&tn_ivq=1979828129.1231365855&tn_fvq=1231365855&tn_uvq=2085229649&synfu=9.0.115&h_u=768&h_j=1024&h_nu=738&h_nj=1024&h_pq=24&h_gm=-480&h_uvf=2&h_wnin=gehr&h_acyht=7&h_azvzr=22', + r'uggc://zfacbegny.112.2b7.arg/o/ff/zfacbegnyubzr/1/U.7-cqi-2/f55023338617756?[NDO]&aqu=1&g=7%2S0%2S2009%2014%3N12%3N47%203%20480&af=zfacbegny&cntrAnzr=HF%20UCZFSGJ&t=uggc%3N%2S%2Sjjj.zfa.pbz%2S&f=0k0&p=43835816&x=A&oj=994&ou=634&uc=A&{2}&[NDR]', + r'zrgn[anzr=nwnkHey]', + r'anpuevpugra', + r'b oS={\'oT\':1.1};x $8n(B){z(B!=o9)};x $S(B){O(!$8n(B))z A;O(B.4L)z\'T\';b S=7t B;O(S==\'2P\'&&B.p4){23(B.7f){12 1:z\'T\';12 3:z/\S/.2g(B.8M)?\'ox\':\'oh\'}}O(S==\'2P\'||S==\'x\'){23(B.nE){12 2V:z\'1O\';12 7I:z\'5a\';12 18:z\'4B\'}O(7t B.I==\'4F\'){O(B.3u)z\'pG\';O(B.8e)z\'1p\'}}z S};x $2p(){b 4E={};Z(b v=0;v<1p.I;v++){Z(b X 1o 1p[v]){b nc=1p[v][X];b 6E=4E[X];O(6E&&$S(nc)==\'2P\'&&$S(6E)==\'2P\')4E[X]=$2p(6E,nc);17 4E[X]=nc}}z 4E};b $E=7p.E=x(){b 1d=1p;O(!1d[1])1d=[p,1d[0]];Z(b X 1o 1d[1])1d[0][X]=1d[1][X];z 1d[0]};b $4D=7p.pJ=x(){Z(b v=0,y=1p.I;v-1:p.3F(2R)>-1},nX:x(){z p.3y(/([.*+?^${}()|[\]\/\\])/t,\'\\$1\')}});2V.E({5V:x(1O){O(p.I<3)z A;O(p.I==4&&p[3]==0&&!1O)z\'p5\';b 3P=[];Z(b v=0;v<3;v++){b 52=(p[v]-0).4h(16);3P.1x((52.I==1)?\'0\'+52:52)}z 1O?3P:\'#\'+3P.2u(\'\')},5U:x(1O){O(p.I!=3)z A;b 1i=[];Z(b v=0;v<3;v++){1i.1x(5K((p[v].I==1)?p[v]+p[v]:p[v],16))}z 1O?1i:\'1i(\'+1i.2u(\',\')+\')\'}});7F.E({3n:x(P){b J=p;P=$2p({\'L\':J,\'V\':A,\'1p\':1S,\'2x\':A,\'4s\':A,\'6W\':A},P);O($2O(P.1p)&&$S(P.1p)!=\'1O\')P.1p=[P.1p];z x(V){b 1d;O(P.V){V=V||H.V;1d=[(P.V===1r)?V:Y P.V(V)];O(P.1p)1d.E(P.1p)}17 1d=P.1p||1p;b 3C=x(){z J.3H($5S(P', + r'hagreunyghat', + r'ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669341278771470&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q', + r'ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&Pbhagel=IIZ%3Q&SbeprqRkcvengvba=633669350559478880&gvzrMbar=-8&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R%3Q', + r'ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669341278771470&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=', + r'ZFPhygher=VC=74.125.75.1&VCPhygher=ra-HF&CersreerqPhygher=ra-HF&CersreerqPhygherCraqvat=&Pbhagel=IIZ=&SbeprqRkcvengvba=633669350559478880&gvzrMbar=0&HFEYBP=DKWyLHAiMTH9AwHjWxAcqUx9GJ91oaEunJ4tIzyyqlMQo3IhqUW5D29xMG1IHlMQo3IhqUW5GzSgMG1Iozy0MJDtH3EuqTImWxEgLHAiMTH9BQN3WxkuqTy0qJEyCGZ3YwDkBGVzGT9hM2y0qJEyCF0kZwVhZQH3APMDo3A0LJkQo2EyCGx0ZQDmWyWyM2yiox5uoJH9D0R=', + r'shapgvba (){Cuk.Nccyvpngvba.Frghc.Pber();Cuk.Nccyvpngvba.Frghc.Nwnk();Cuk.Nccyvpngvba.Frghc.Synfu();Cuk.Nccyvpngvba.Frghc.Zbqhyrf()}'] + +# The 12 benchmarking blocks + + +def block0(): + for i in range(6511): + regexs[0].search(r'pyvpx') + + for i in range(1844): + regexs[1].search(r'uggc://jjj.snprobbx.pbz/ybtva.cuc') + + for i in range(739): + regexs[2].sub(r'', 'QBZPbageby_cynprubyqre', subcount[2]) + + for i in range(598): + regexs[1].search(r'uggc://jjj.snprobbx.pbz/') + + for i in range(454): + regexs[1].search(r'uggc://jjj.snprobbx.pbz/fepu.cuc') + + for i in range(352): + re.search( + r'qqqq|qqq|qq|q|ZZZZ|ZZZ|ZZ|Z|llll|ll|l|uu|u|UU|U|zz|z|ff|f|gg|g|sss|ss|s|mmm|mm|m', 'qqqq, ZZZ q, llll') + + for i in range(312): + regexs[3].search(r'vachggrkg QBZPbageby_cynprubyqre') + + for i in range(282): + regexs[4].search(r'/ZlFcnprUbzrcntr/Vaqrk-FvgrUbzr,10000000') + + for i in range(177): + regexs[5].sub(r'', 'vachggrkg', subcount[5]) + + for i in range(170): + regexs[6].sub(r'', '528.9', subcount[6]) + regexs[7].search(r'528') + + for i in range(156): + regexs[8].search(r'VCPhygher=ra-HF') + regexs[8].search(r'CersreerqPhygher=ra-HF') + + for i in range(144): + regexs[0].search(r'xrlcerff') + + for i in range(139): + regexs[6].sub(r'', '521', subcount[6]) + + # This has a different output to the V8 version. + # It could just be a difference in the engines. + regexs[7].search(r'521') + regexs[9].search(r'') + re.search(r'JroXvg\/(\S+)', strings[0]) + + for i in range(137): + regexs[10].sub(r'', 'qvi .so_zrah', subcount[10]) + re.sub(r'\[', '', 'qvi .so_zrah', 0) + regexs[11].sub(r'', 'qvi.so_zrah', subcount[11]) + + for i in range(117): + regexs[2].sub(r'', 'uvqqra_ryrz', subcount[2]) + + for i in range(95): + re.search(r'(?:^|;)\s*sevraqfgre_ynat=([^;]*)', + 'sevraqfgre_naba=nvq%3Qn6ss9p85n868ro9s059pn854735956o3%26ers%3Q%26df%3Q%26vpgl%3QHF') + + for i in range(93): + regexs[12].sub(r'', 'uggc://ubzr.zlfcnpr.pbz/vaqrk.psz', subcount[12]) + regexs[13].search(r'uggc://ubzr.zlfcnpr.pbz/vaqrk.psz') + + for i in range(92): + re.sub(r'([a-zA-Z]|\s)+', '', strings[1], 1) + + for i in range(85): + regexs[14].sub(r'', 'svefg', subcount[14]) + regexs[15].sub(r'', 'svefg', subcount[15]) + regexs[12].sub( + r'', 'uggc://cebsvyr.zlfcnpr.pbz/vaqrk.psz', subcount[12]) + regexs[14].sub(r'', 'ynfg', subcount[14]) + regexs[15].sub(r'', 'ynfg', subcount[15]) + regexs[16].search(r'qvfcynl') + regexs[13].search(r'uggc://cebsvyr.zlfcnpr.pbz/vaqrk.psz') + + +def block1(): + for i in range(81): + regexs[8].search(r'VC=74.125.75.1') + + for i in range(78): + re.sub(r'(\s)+e', '', '9.0 e115', 1) + re.sub(r'.', '', 'k', 1) + + # This prints a unicode escape where the V8 version prints the + # unicode character. + regexs[17].sub(r'', strings[2], subcount[17]) + + # This prints a unicode escape where the V8 version prints the + # unicode character. + regexs[17].sub(r'', strings[3], subcount[17]) + + regexs[8].search(r'144631658') + regexs[8].search(r'Pbhagel=IIZ%3Q') + regexs[8].search(r'Pbhagel=IIZ=') + regexs[8].search(r'CersreerqPhygherCraqvat=') + regexs[8].search(strings[4]) + regexs[8].search(strings[5]) + regexs[8].search(r'__hgzp=144631658') + regexs[8].search(r'gvzrMbar=-8') + regexs[8].search(r'gvzrMbar=0') + re.search(r'Fnsnev\/(\d+\.\d+)', strings[0]) + regexs[3].search(r'vachggrkg QBZPbageby_cynprubyqre') + regexs[0].search(r'xrlqbja') + regexs[0].search(r'xrlhc') + + for i in range(77): + regexs[12].sub( + r'', 'uggc://zrffntvat.zlfcnpr.pbz/vaqrk.psz', subcount[12]) + regexs[13].search(r'uggc://zrffntvat.zlfcnpr.pbz/vaqrk.psz') + + for i in range(73): + regexs[18].sub( + r'', 'FrffvbaFgbentr=%7O%22GnoThvq%22%3N%7O%22thvq%22%3N1231367125017%7Q%7Q', subcount[18]) + + for i in range(72): + regexs[1].search(strings[6]) + + for i in range(71): + regexs[19].search(r'') + + for i in range(70): + regexs[11].sub(r'', '3.5.0.0', subcount[11]) + re.sub(r'd1', '', strings[7], 0) + re.sub(r'NQ_VQ', '', strings[8], 0) + re.sub(r'd2', '', strings[9], 0) + re.sub( + r'_', '', 'NI%3Q1_CI%3Q1_PI%3Q1_EI%3Q1_HI%3Q1_HP%3Q1_IC%3Q0.0.0.0_IH%3Q0', 0) + regexs[20].split( + r'svz_zlfcnpr_ubzrcntr_abgybttrqva,svz_zlfcnpr_aba_HTP,svz_zlfcnpr_havgrq-fgngrf') + regexs[21].search(r'ybnqvat') + + for i in range(68): + regexs[1].search(r'#') + re.search( + r'(?:ZFVR.(\d+\.\d+))|(?:(?:Sversbk|TenaCnenqvfb|Vprjrnfry).(\d+\.\d+))|(?:Bcren.(\d+\.\d+))|(?:NccyrJroXvg.(\d+(?:\.\d+)?))', strings[0]) + re.search(r'(Znp BF K)|(Jvaqbjf;)', strings[0]) + re.search(r'Trpxb\/([0-9]+)', strings[0]) + regexs[21].search(r'ybnqrq') + + for i in range(49): + regexs[16].search(r'pbybe') + + for i in range(44): + regexs[12].sub( + r'', 'uggc://sevraqf.zlfcnpr.pbz/vaqrk.psz', subcount[12]) + regexs[13].search(r'uggc://sevraqf.zlfcnpr.pbz/vaqrk.psz') + + +def block2(): + for i in range(40): + regexs[14].sub(r'', 'fryrpgrq', subcount[14]) + regexs[15].sub(r'', 'fryrpgrq', subcount[15]) + + for i in range(39): + re.sub(r'\buvqqra_ryrz\b', '', 'vachggrkg uvqqra_ryrz', 0) + regexs[3].search(r'vachggrkg ') + regexs[3].search(r'vachggrkg') + regexs[22].search(r'HVYvaxOhggba') + regexs[22].search(r'HVYvaxOhggba_E') + regexs[22].search(r'HVYvaxOhggba_EJ') + regexs[22].search(r'zrah_ybtva_pbagnvare') + re.search(r'\buvqqra_ryrz\b', 'vachgcnffjbeq') + + for i in range(37): + regexs[8].search(r'111soqs57qo8o8480qo18sor2011r3n591q7s6s37r120904') + regexs[8].search(r'SbeprqRkcvengvba=633669315660164980') + regexs[8].search( + r'FrffvbaQQS2=111soqs57qo8o8480qo18sor2011r3n591q7s6s37r120904') + + for i in range(35): + regexs[14].sub(r'', 'puvyq p1 svefg', subcount[14]) + regexs[15].sub(r'', 'puvyq p1 svefg', subcount[15]) + regexs[14].sub(r'', 'sylbhg pybfrq', subcount[14]) + regexs[15].sub(r'', 'sylbhg pybfrq', subcount[15]) + + for i in range(34): + regexs[19].search(r'gno2') + regexs[19].search(r'gno3') + regexs[8].search(r'44132r503660') + regexs[8].search(r'SbeprqRkcvengvba=633669316860113296') + regexs[8].search(r'AFP_zp_dfctwzs-aowb_80=44132r503660') + regexs[8].search( + r'FrffvbaQQS2=s6r4579npn4rn2135s904r0s75pp1o5334p6s6pospo12696') + regexs[8].search(r's6r4579npn4rn2135s904r0s75pp1o5334p6s6pospo12696') + + for i in range(32): + re.search(r'puebzr', strings[0], re.IGNORECASE) + + for i in range(31): + regexs[23].sub(r'', 'uggc://jjj.snprobbx.pbz/', subcount[23]) + regexs[8].search(r'SbeprqRkcvengvba=633669358527244818') + regexs[8].search(r'VC=66.249.85.130') + regexs[8].search( + r'FrffvbaQQS2=s15q53p9n372sn76npr13o271n4s3p5r29p235746p908p58') + regexs[8].search(r's15q53p9n372sn76npr13o271n4s3p5r29p235746p908p58') + regexs[24].search(r'uggc://jjj.snprobbx.pbz/') + + for i in range(30): + regexs[6].sub(r'', '419', subcount[6]) + re.search(r'(?:^|\s+)gvzrfgnzc(?:\s+|$)', 'gvzrfgnzc') + regexs[7].search(r'419') + + for i in range(29): + regexs[23].sub(r'', 'uggc://jjj.snprobbx.pbz/ybtva.cuc', subcount[23]) + + for i in range(28): + regexs[25].sub(r'', 'Funer guvf tnqtrg', subcount[25]) + regexs[12].sub(r'', 'Funer guvf tnqtrg', subcount[12]) + regexs[26].search(r'uggc://jjj.tbbtyr.pbz/vt/qverpgbel') + + +def block3(): + for i in range(27): + re.sub(r'[A-Za-z]', '', 'e115', 0) + + for i in range(23): + regexs[27].sub(r'', 'qvfcynl', subcount[27]) + regexs[27].sub(r'', 'cbfvgvba', subcount[27]) + + for i in range(22): + regexs[14].sub(r'', 'unaqyr', subcount[14]) + regexs[15].sub(r'', 'unaqyr', subcount[15]) + regexs[14].sub(r'', 'yvar', subcount[14]) + regexs[15].sub(r'', 'yvar', subcount[15]) + regexs[14].sub(r'', 'cnerag puebzr6 fvatyr1 gno', subcount[14]) + regexs[15].sub(r'', 'cnerag puebzr6 fvatyr1 gno', subcount[15]) + regexs[14].sub(r'', 'fyvqre', subcount[14]) + regexs[15].sub(r'', 'fyvqre', subcount[15]) + regexs[28].search(r'') + + for i in range(21): + regexs[12].sub(r'', 'uggc://jjj.zlfcnpr.pbz/', subcount[12]) + regexs[13].search(r'uggc://jjj.zlfcnpr.pbz/') + + for i in range(20): + regexs[29].sub(r'', 'cntrivrj', subcount[29]) + regexs[30].sub(r'', 'cntrivrj', subcount[30]) + regexs[19].search(r'ynfg') + regexs[19].search(r'ba svefg') + regexs[8].search(r'VC=74.125.75.3') + + for i in range(19): + regexs[31].search(r'ra') + + for i in range(18): + regexs[32].split(strings[10]) + regexs[32].split(strings[11]) + regexs[33].sub(r'', strings[12], subcount[33]) + regexs[8].search(r'144631658.0.10.1231363570') + regexs[8].search( + r'144631658.1231363570.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)') + regexs[8].search( + r'144631658.3426875219718084000.1231363570.1231363570.1231363570.1') + regexs[8].search(strings[13]) + regexs[8].search(strings[14]) + regexs[8].search( + r'__hgzn=144631658.3426875219718084000.1231363570.1231363570.1231363570.1') + regexs[8].search(r'__hgzo=144631658.0.10.1231363570') + regexs[8].search( + r'__hgzm=144631658.1231363570.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)') + regexs[34].search(strings[10]) + regexs[34].search(strings[11]) + + for i in range(17): + re.match(r'zfvr', strings[0], re.IGNORECASE) + re.match(r'bcren', strings[0], re.IGNORECASE) + regexs[32].split(strings[15]) + regexs[32].split(strings[16]) + regexs[14].sub(r'', 'ohggba', subcount[14]) + regexs[15].sub(r'', 'ohggba', subcount[15]) + regexs[14].sub(r'', 'puvyq p1 svefg sylbhg pybfrq', subcount[14]) + regexs[15].sub(r'', 'puvyq p1 svefg sylbhg pybfrq', subcount[15]) + regexs[14].sub(r'', 'pvgvrf', subcount[14]) + regexs[15].sub(r'', 'pvgvrf', subcount[15]) + regexs[14].sub(r'', 'pybfrq', subcount[14]) + regexs[15].sub(r'', 'pybfrq', subcount[15]) + regexs[14].sub(r'', 'qry', subcount[14]) + regexs[15].sub(r'', 'qry', subcount[15]) + regexs[14].sub(r'', 'uqy_zba', subcount[14]) + regexs[15].sub(r'', 'uqy_zba', subcount[15]) + regexs[33].sub(r'', strings[17], subcount[33]) + re.sub(r'%3P', '', strings[18], 0) + re.sub(r'%3R', '', strings[18], 0) + re.sub(r'%3q', '', strings[18], 0) + regexs[35].sub(r'', strings[18], subcount[35]) + regexs[14].sub(r'', 'yvaxyvfg16', subcount[14]) + regexs[15].sub(r'', 'yvaxyvfg16', subcount[15]) + regexs[14].sub(r'', 'zvahf', subcount[14]) + regexs[15].sub(r'', 'zvahf', subcount[15]) + regexs[14].sub(r'', 'bcra', subcount[14]) + regexs[15].sub(r'', 'bcra', subcount[15]) + regexs[14].sub(r'', 'cnerag puebzr5 fvatyr1 ps NU', subcount[14]) + regexs[15].sub(r'', 'cnerag puebzr5 fvatyr1 ps NU', subcount[15]) + regexs[14].sub(r'', 'cynlre', subcount[14]) + regexs[15].sub(r'', 'cynlre', subcount[15]) + regexs[14].sub(r'', 'cyhf', subcount[14]) + regexs[15].sub(r'', 'cyhf', subcount[15]) + regexs[14].sub(r'', 'cb_uqy', subcount[14]) + regexs[15].sub(r'', 'cb_uqy', subcount[15]) + regexs[14].sub(r'', 'hyJVzt', subcount[14]) + regexs[15].sub(r'', 'hyJVzt', subcount[15]) + regexs[8].search(r'144631658.0.10.1231363638') + regexs[8].search( + r'144631658.1231363638.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)') + regexs[8].search( + r'144631658.965867047679498800.1231363638.1231363638.1231363638.1') + regexs[8].search(r'4413268q3660') + regexs[8].search(r'4ss747o77904333q374or84qrr1s9r0nprp8r5q81534o94n') + regexs[8].search(r'SbeprqRkcvengvba=633669321699093060') + regexs[8].search(r'VC=74.125.75.20') + regexs[8].search(strings[19]) + regexs[8].search(strings[20]) + regexs[8].search(r'AFP_zp_tfwsbrg-aowb_80=4413268q3660') + regexs[8].search( + r'FrffvbaQQS2=4ss747o77904333q374or84qrr1s9r0nprp8r5q81534o94n') + regexs[8].search( + r'__hgzn=144631658.965867047679498800.1231363638.1231363638.1231363638.1') + regexs[8].search(r'__hgzo=144631658.0.10.1231363638') + regexs[8].search( + r'__hgzm=144631658.1231363638.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)') + regexs[34].search(strings[15]) + regexs[34].search(strings[16]) + + +def block4(): + for i in range(16): + re.sub(r'\*', '', '', 0) + re.search(r'\bnpgvir\b', 'npgvir') + re.search(r'sversbk', strings[0], re.IGNORECASE) + regexs[36].search(r'glcr') + re.search(r'zfvr', strings[0], re.IGNORECASE) + re.search(r'bcren', strings[0], re.IGNORECASE) + + for i in range(15): + regexs[32].split(strings[21]) + regexs[32].split(strings[22]) + regexs[12].sub( + r'', 'uggc://ohyyrgvaf.zlfcnpr.pbz/vaqrk.psz', subcount[12]) + regexs[33].sub(r'', strings[23], subcount[33]) + regexs[37].sub(r'', 'yv', subcount[37]) + regexs[18].sub(r'', 'yv', subcount[18]) + regexs[8].search(r'144631658.0.10.1231367822') + regexs[8].search( + r'144631658.1231367822.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)') + regexs[8].search( + r'144631658.4127520630321984500.1231367822.1231367822.1231367822.1') + regexs[8].search(strings[24]) + regexs[8].search(strings[25]) + regexs[8].search( + r'__hgzn=144631658.4127520630321984500.1231367822.1231367822.1231367822.1') + regexs[8].search(r'__hgzo=144631658.0.10.1231367822') + regexs[8].search( + r'__hgzm=144631658.1231367822.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)') + regexs[34].search(strings[21]) + regexs[34].search(strings[22]) + + # FIXME + # The \{0,65534} should be a * + # There's a current python bug that will stop the regex compilation + # when a * appears there http://bugs.python.org/issue6156. + re.search( + r'\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)["\']?(.*?)["\']?)?\]|:([\w-]+)(?:\(["\']?(.\{0,65534}?)?["\']?\)|$)', strings[26]) + + regexs[13].search(r'uggc://ohyyrgvaf.zlfcnpr.pbz/vaqrk.psz') + regexs[38].search(r'yv') + + for i in range(14): + regexs[18].sub(r'', '', subcount[18]) + re.sub(r'(\s+e|\s+o[0-9]+)', '', '9.0 e115', 1) + re.sub(r'<', '', 'Funer guvf tnqtrg', 0) + re.sub(r'>', '', 'Funer guvf tnqtrg', 0) + regexs[39].sub(r'', 'Funer guvf tnqtrg', subcount[39]) + regexs[12].sub( + r'', 'uggc://cebsvyrrqvg.zlfcnpr.pbz/vaqrk.psz', subcount[12]) + regexs[40].sub(r'', 'grnfre', subcount[40]) + regexs[41].sub(r'', 'grnfre', subcount[41]) + regexs[42].sub(r'', 'grnfre', subcount[42]) + regexs[43].sub(r'', 'grnfre', subcount[43]) + regexs[44].sub(r'', 'grnfre', subcount[44]) + regexs[45].sub(r'', 'grnfre', subcount[45]) + regexs[46].sub(r'', 'grnfre', subcount[46]) + regexs[47].sub(r'', 'grnfre', subcount[47]) + regexs[48].sub(r'', 'grnfre', subcount[48]) + regexs[16].search(r'znetva-gbc') + regexs[16].search(r'cbfvgvba') + regexs[19].search(r'gno1') + regexs[9].search(r'qz') + regexs[9].search(r'qg') + regexs[9].search(r'zbqobk') + regexs[9].search(r'zbqobkva') + regexs[9].search(r'zbqgvgyr') + regexs[13].search(r'uggc://cebsvyrrqvg.zlfcnpr.pbz/vaqrk.psz') + regexs[26].search(r'/vt/znvytnqtrg') + regexs[49].search(r'glcr') + + +def block5(): + for i in range(13): + regexs[14].sub(r'', 'purpx', subcount[14]) + regexs[15].sub(r'', 'purpx', subcount[15]) + regexs[14].sub(r'', 'pvgl', subcount[14]) + regexs[15].sub(r'', 'pvgl', subcount[15]) + regexs[14].sub(r'', 'qrpe fyvqrgrkg', subcount[14]) + regexs[15].sub(r'', 'qrpe fyvqrgrkg', subcount[15]) + regexs[14].sub(r'', 'svefg fryrpgrq', subcount[14]) + regexs[15].sub(r'', 'svefg fryrpgrq', subcount[15]) + regexs[14].sub(r'', 'uqy_rag', subcount[14]) + regexs[15].sub(r'', 'uqy_rag', subcount[15]) + regexs[14].sub(r'', 'vape fyvqrgrkg', subcount[14]) + regexs[15].sub(r'', 'vape fyvqrgrkg', subcount[15]) + regexs[5].sub(r'', 'vachggrkg QBZPbageby_cynprubyqre', subcount[5]) + regexs[14].sub( + r'', 'cnerag puebzr6 fvatyr1 gno fryrpgrq', subcount[14]) + regexs[15].sub( + r'', 'cnerag puebzr6 fvatyr1 gno fryrpgrq', subcount[15]) + regexs[14].sub(r'', 'cb_guz', subcount[14]) + regexs[15].sub(r'', 'cb_guz', subcount[15]) + regexs[14].sub(r'', 'fhozvg', subcount[14]) + regexs[15].sub(r'', 'fhozvg', subcount[15]) + regexs[50].search(r'') + re.search(r'NccyrJroXvg\/([^\s]*)', strings[0]) + re.search(r'XUGZY', strings[0]) + + for i in range(12): + re.sub(r'(\$\{cebg\})|(\$cebg\b)', '', + '${cebg}://${ubfg}${cngu}/${dz}', 0) + regexs[40].sub(r'', '1', subcount[40]) + regexs[10].sub(r'', '1', subcount[10]) + regexs[51].sub(r'', '1', subcount[51]) + regexs[52].sub(r'', '1', subcount[52]) + regexs[53].sub(r'', '1', subcount[53]) + regexs[39].sub(r'', '1', subcount[39]) + regexs[54].sub(r'', '1', subcount[54]) + re.sub(r'^(.*)\..*$', '', '9.0 e115', 1) + re.sub(r'^.*e(.*)$', '', '9.0 e115', 1) + regexs[55].sub(r'', '', subcount[55]) + regexs[55].sub( + r'', '', subcount[55]) + re.sub(r'^.*\s+(\S+\s+\S+$)', '', strings[1], 1) + regexs[30].sub(r'', 'tzk%2Subzrcntr%2Sfgneg%2Sqr%2S', subcount[30]) + regexs[30].sub(r'', 'tzk', subcount[30]) + re.sub(r'(\$\{ubfg\})|(\$ubfg\b)', '', + 'uggc://${ubfg}${cngu}/${dz}', 0) + regexs[56].sub( + r'', 'uggc://nqpyvrag.hvzfrei.arg${cngu}/${dz}', subcount[56]) + re.sub(r'(\$\{dz\})|(\$dz\b)', '', + 'uggc://nqpyvrag.hvzfrei.arg/wf.at/${dz}', 0) + regexs[29].sub(r'', 'frpgvba', subcount[29]) + regexs[30].sub(r'', 'frpgvba', subcount[30]) + regexs[29].sub(r'', 'fvgr', subcount[29]) + regexs[30].sub(r'', 'fvgr', subcount[30]) + regexs[29].sub(r'', 'fcrpvny', subcount[29]) + regexs[30].sub(r'', 'fcrpvny', subcount[30]) + regexs[36].search(r'anzr') + re.search(r'e', '9.0 e115') + + +def block6(): + for i in range(11): + re.sub(r'(?i)##yv0##', '', strings[27], 0) + regexs[57].sub(r'', strings[27], subcount[57]) + regexs[58].sub(r'', strings[28], subcount[58]) + regexs[59].sub(r'', strings[29], subcount[59]) + re.sub(r'(?i)##\/o##', '', strings[30], 0) + re.sub(r'(?i)##\/v##', '', strings[30], 0) + re.sub(r'(?i)##\/h##', '', strings[30], 0) + re.sub(r'(?i)##o##', '', strings[30], 0) + re.sub(r'(?i)##oe##', '', strings[30], 0) + re.sub(r'(?i)##v##', '', strings[30], 0) + re.sub(r'(?i)##h##', '', strings[30], 0) + re.sub(r'(?i)##n##', '', strings[31], 0) + re.sub(r'(?i)##\/n##', '', strings[32], 0) + + # This prints a unicode escape where the V8 version + # prints the unicode character. + re.sub(r'#~#argjbexybtb#~#', '', strings[33], 0) + + re.search(r' Zbovyr\/', strings[0]) + re.search(r'##yv1##', strings[27], re.IGNORECASE) + re.search(r'##yv10##', strings[28], re.IGNORECASE) + re.search(r'##yv11##', strings[28], re.IGNORECASE) + re.search(r'##yv12##', strings[28], re.IGNORECASE) + re.search(r'##yv13##', strings[28], re.IGNORECASE) + re.search(r'##yv14##', strings[28], re.IGNORECASE) + re.search(r'##yv15##', strings[28], re.IGNORECASE) + regexs[58].search(strings[28]) + re.search(r'##yv17##', strings[29], re.IGNORECASE) + re.search(r'##yv18##', strings[29], re.IGNORECASE) + regexs[59].search(strings[29]) + re.search(r'##yv2##', strings[27], re.IGNORECASE) + re.search(r'##yv20##', strings[30], re.IGNORECASE) + re.search(r'##yv21##', strings[30], re.IGNORECASE) + re.search(r'##yv22##', strings[30], re.IGNORECASE) + re.search(r'##yv23##', strings[30], re.IGNORECASE) + re.search(r'##yv3##', strings[27], re.IGNORECASE) + regexs[57].search(strings[27]) + re.search(r'##yv5##', strings[28], re.IGNORECASE) + re.search(r'##yv6##', strings[28], re.IGNORECASE) + re.search(r'##yv7##', strings[28], re.IGNORECASE) + re.search(r'##yv8##', strings[28], re.IGNORECASE) + re.search(r'##yv9##', strings[28], re.IGNORECASE) + regexs[8].search(r'473qq1rs0n2r70q9qo1pq48n021s9468ron90nps048p4p29') + regexs[8].search(r'SbeprqRkcvengvba=633669325184628362') + regexs[8].search( + r'FrffvbaQQS2=473qq1rs0n2r70q9qo1pq48n021s9468ron90nps048p4p29') + re.search(r'AbxvnA[^\/]*', strings[0]) + + for i in range(10): + re.sub(r'(?:^|\s+)bss(?:\s+|$)', '', ' bss', 0) + re.sub(r'(\$\{0\})|(\$0\b)', '', strings[34], 0) + re.sub(r'(\$\{1\})|(\$1\b)', '', strings[34], 0) + re.sub(r'(\$\{pbzcyrgr\})|(\$pbzcyrgr\b)', '', strings[34], 0) + re.sub(r'(\$\{sentzrag\})|(\$sentzrag\b)', '', strings[34], 0) + re.sub(r'(\$\{ubfgcbeg\})|(\$ubfgcbeg\b)', '', strings[34], 0) + regexs[56].sub(r'', strings[34], subcount[56]) + re.sub(r'(\$\{cebgbpby\})|(\$cebgbpby\b)', '', strings[34], 0) + re.sub(r'(\$\{dhrel\})|(\$dhrel\b)', '', strings[34], 0) + regexs[29].sub(r'', 'nqfvmr', subcount[29]) + regexs[30].sub(r'', 'nqfvmr', subcount[30]) + re.sub(r'(\$\{2\})|(\$2\b)', '', 'uggc://${2}${3}${4}${5}', 0) + re.sub(r'(\$\{3\})|(\$3\b)', '', + 'uggc://wf.hv-cbegny.qr${3}${4}${5}', 0) + regexs[40].sub(r'', 'arjf', subcount[40]) + regexs[41].sub(r'', 'arjf', subcount[41]) + regexs[42].sub(r'', 'arjf', subcount[42]) + regexs[43].sub(r'', 'arjf', subcount[43]) + regexs[44].sub(r'', 'arjf', subcount[44]) + regexs[45].sub(r'', 'arjf', subcount[45]) + regexs[46].sub(r'', 'arjf', subcount[46]) + regexs[47].sub(r'', 'arjf', subcount[47]) + regexs[48].sub(r'', 'arjf', subcount[48]) + re.search(r' PC=i=(\d+)&oe=(.)', strings[35]) + regexs[60].search(r' ') + regexs[60].search(r' bss') + regexs[60].search(r'') + regexs[19].search(r' ') + regexs[19].search(r'svefg ba') + regexs[19].search(r'ynfg vtaber') + regexs[19].search(r'ba') + regexs[9].search(r'scnq so ') + regexs[9].search(r'zrqvgobk') + regexs[9].search(r'hsgy') + regexs[9].search(r'lhv-h') + re.search(r'Fnsnev|Xbadhrebe|XUGZY', strings[0], re.IGNORECASE) + regexs[61].search( + r'uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/onfr.wf') + regexs[62].search(r'#Ybtva_rznvy') + + +def block7(): + for i in range(9): + regexs[40].sub(r'', '0', subcount[40]) + regexs[10].sub(r'', '0', subcount[10]) + regexs[51].sub(r'', '0', subcount[51]) + regexs[52].sub(r'', '0', subcount[52]) + regexs[53].sub(r'', '0', subcount[53]) + regexs[39].sub(r'', '0', subcount[39]) + regexs[54].sub(r'', '0', subcount[54]) + regexs[40].sub(r'', 'Lrf', subcount[40]) + regexs[10].sub(r'', 'Lrf', subcount[10]) + regexs[51].sub(r'', 'Lrf', subcount[51]) + regexs[52].sub(r'', 'Lrf', subcount[52]) + regexs[53].sub(r'', 'Lrf', subcount[53]) + regexs[39].sub(r'', 'Lrf', subcount[39]) + regexs[54].sub(r'', 'Lrf', subcount[54]) + + for i in range(8): + regexs[63].sub(r'', 'Pybfr {0}', subcount[63]) + regexs[63].sub(r'', 'Bcra {0}', subcount[63]) + regexs[32].split(strings[36]) + regexs[32].split(strings[37]) + regexs[14].sub(r'', 'puvyq p1 svefg gnournqref', subcount[14]) + regexs[15].sub(r'', 'puvyq p1 svefg gnournqref', subcount[15]) + regexs[14].sub(r'', 'uqy_fcb', subcount[14]) + regexs[15].sub(r'', 'uqy_fcb', subcount[15]) + regexs[14].sub(r'', 'uvag', subcount[14]) + regexs[15].sub(r'', 'uvag', subcount[15]) + regexs[33].sub(r'', strings[38], subcount[33]) + regexs[14].sub(r'', 'yvfg', subcount[14]) + regexs[15].sub(r'', 'yvfg', subcount[15]) + regexs[30].sub(r'', 'at_bhgre', subcount[30]) + regexs[14].sub(r'', 'cnerag puebzr5 qbhoyr2 NU', subcount[14]) + regexs[15].sub(r'', 'cnerag puebzr5 qbhoyr2 NU', subcount[15]) + regexs[14].sub( + r'', 'cnerag puebzr5 dhnq5 ps NU osyvax zbarl', subcount[14]) + regexs[15].sub( + r'', 'cnerag puebzr5 dhnq5 ps NU osyvax zbarl', subcount[15]) + regexs[14].sub(r'', 'cnerag puebzr6 fvatyr1', subcount[14]) + regexs[15].sub(r'', 'cnerag puebzr6 fvatyr1', subcount[15]) + regexs[14].sub(r'', 'cb_qrs', subcount[14]) + regexs[15].sub(r'', 'cb_qrs', subcount[15]) + regexs[14].sub(r'', 'gnopbagrag', subcount[14]) + regexs[15].sub(r'', 'gnopbagrag', subcount[15]) + regexs[30].sub(r'', 'iv_svefg_gvzr', subcount[30]) + re.search(r'(^|.)(ronl|qri-ehf3.wbg)(|fgberf|zbgbef|yvirnhpgvbaf|jvxv|rkcerff|punggre).(pbz(|.nh|.pa|.ux|.zl|.ft|.oe|.zk)|pb(.hx|.xe|.am)|pn|qr|se|vg|ay|or|ng|pu|vr|va|rf|cy|cu|fr)$', 'cntrf.ronl.pbz', re.IGNORECASE) + regexs[8].search(r'144631658.0.10.1231364074') + regexs[8].search( + r'144631658.1231364074.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)') + regexs[8].search( + r'144631658.2294274870215848400.1231364074.1231364074.1231364074.1') + regexs[8].search(r'4413241q3660') + regexs[8].search(r'SbeprqRkcvengvba=633669357391353591') + regexs[8].search(strings[39]) + regexs[8].search(strings[40]) + regexs[8].search(r'AFP_zp_kkk-gdzogv_80=4413241q3660') + regexs[8].search( + r'FrffvbaQQS2=p98s8o9q42nr21or1r61pqorn1n002nsss569635984s6qp7') + regexs[8].search( + r'__hgzn=144631658.2294274870215848400.1231364074.1231364074.1231364074.1') + regexs[8].search(r'__hgzo=144631658.0.10.1231364074') + regexs[8].search( + r'__hgzm=144631658.1231364074.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)') + regexs[8].search(r'p98s8o9q42nr21or1r61pqorn1n002nsss569635984s6qp7') + regexs[34].search(strings[36]) + regexs[34].search(strings[37]) + + +def block8(): + for i in range(7): + re.match(r'\d+', strings[1]) + regexs[64].sub(r'', 'nsgre', subcount[64]) + regexs[64].sub(r'', 'orsber', subcount[64]) + regexs[64].sub(r'', 'obggbz', subcount[64]) + regexs[65].sub(r'', 'ohvygva_jrngure.kzy', subcount[65]) + regexs[37].sub(r'', 'ohggba', subcount[37]) + regexs[18].sub(r'', 'ohggba', subcount[18]) + regexs[65].sub(r'', 'qngrgvzr.kzy', subcount[65]) + regexs[65].sub( + r'', 'uggc://eff.paa.pbz/eff/paa_gbcfgbevrf.eff', subcount[65]) + regexs[37].sub(r'', 'vachg', subcount[37]) + regexs[18].sub(r'', 'vachg', subcount[18]) + regexs[64].sub(r'', 'vafvqr', subcount[64]) + regexs[27].sub(r'', 'cbvagre', subcount[27]) + re.sub(r'[A-Z]', '', 'cbfvgvba', 0) + regexs[27].sub(r'', 'gbc', subcount[27]) + regexs[64].sub(r'', 'gbc', subcount[64]) + regexs[37].sub(r'', 'hy', subcount[37]) + regexs[18].sub(r'', 'hy', subcount[18]) + regexs[37].sub(r'', strings[26], subcount[37]) + regexs[18].sub(r'', strings[26], subcount[18]) + regexs[65].sub(r'', 'lbhghor_vtbbtyr/i2/lbhghor.kzy', subcount[65]) + regexs[27].sub(r'', 'm-vaqrk', subcount[27]) + re.search(r'#([\w-]+)', strings[26]) + regexs[16].search(r'urvtug') + regexs[16].search(r'znetvaGbc') + regexs[16].search(r'jvqgu') + regexs[19].search(r'gno0 svefg ba') + regexs[19].search(r'gno0 ba') + regexs[19].search(r'gno4 ynfg') + regexs[19].search(r'gno4') + regexs[19].search(r'gno5') + regexs[19].search(r'gno6') + regexs[19].search(r'gno7') + regexs[19].search(r'gno8') + re.search(r'NqborNVE\/([^\s]*)', strings[0]) + re.search(r'NccyrJroXvg\/([^ ]*)', strings[0]) + re.search(r'XUGZY', strings[0], re.IGNORECASE) + re.search(r'^(?:obql|ugzy)$', 'YV', re.IGNORECASE) + regexs[38].search(r'ohggba') + regexs[38].search(r'vachg') + regexs[38].search(r'hy') + regexs[38].search(strings[26]) + re.search(r'^(\w+|\*)', strings[26]) + re.search(r'znp|jva|yvahk', 'Jva32', re.IGNORECASE) + re.search(r'eton?\([\d\s,]+\)', 'fgngvp') + + for i in range(6): + re.sub(r'\r', '', '', 0) + regexs[40].sub(r'', '/', subcount[40]) + regexs[10].sub(r'', '/', subcount[10]) + regexs[51].sub(r'', '/', subcount[51]) + regexs[52].sub(r'', '/', subcount[52]) + regexs[53].sub(r'', '/', subcount[53]) + regexs[39].sub(r'', '/', subcount[39]) + regexs[54].sub(r'', '/', subcount[54]) + regexs[63].sub( + r'', 'uggc://zfacbegny.112.2b7.arg/o/ff/zfacbegnyubzr/1/U.7-cqi-2/{0}?[NDO]&{1}&{2}&[NDR]', subcount[63]) + regexs[12].sub(r'', strings[41], subcount[12]) + regexs[23].sub(r'', 'uggc://jjj.snprobbx.pbz/fepu.cuc', subcount[23]) + regexs[40].sub(r'', 'freivpr', subcount[40]) + regexs[41].sub(r'', 'freivpr', subcount[41]) + regexs[42].sub(r'', 'freivpr', subcount[42]) + regexs[43].sub(r'', 'freivpr', subcount[43]) + regexs[44].sub(r'', 'freivpr', subcount[44]) + regexs[45].sub(r'', 'freivpr', subcount[45]) + regexs[46].sub(r'', 'freivpr', subcount[46]) + regexs[47].sub(r'', 'freivpr', subcount[47]) + regexs[48].sub(r'', 'freivpr', subcount[48]) + re.search(r'((ZFVR\s+([6-9]|\d\d)\.))', strings[0]) + regexs[66].search(r'') + regexs[50].search(r'fryrpgrq') + regexs[8].search(r'8sqq78r9n442851q565599o401385sp3s04r92rnn7o19ssn') + regexs[8].search(r'SbeprqRkcvengvba=633669340386893867') + regexs[8].search(r'VC=74.125.75.17') + regexs[8].search( + r'FrffvbaQQS2=8sqq78r9n442851q565599o401385sp3s04r92rnn7o19ssn') + re.search(r'Xbadhrebe|Fnsnev|XUGZY', strings[0]) + regexs[13].search(strings[41]) + regexs[49].search(r'unfsbphf') + + +def block9(): + for i in range(5): + regexs[32].split(strings[42]) + regexs[32].split(strings[43]) + regexs[20].split( + r'svz_zlfcnpr_hfre-ivrj-pbzzragf,svz_zlfcnpr_havgrq-fgngrf') + regexs[33].sub(r'', strings[44], subcount[33]) + regexs[67].sub( + r'', 'zrah_arj zrah_arj_gbttyr zrah_gbttyr', subcount[67]) + regexs[67].sub( + r'', 'zrah_byq zrah_byq_gbttyr zrah_gbttyr', subcount[67]) + regexs[8].search(r'102n9o0o9pq60132qn0337rr867p75953502q2s27s2s5r98') + regexs[8].search(r'144631658.0.10.1231364380') + regexs[8].search( + r'144631658.1231364380.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)') + regexs[8].search( + r'144631658.3931862196947939300.1231364380.1231364380.1231364380.1') + regexs[8].search(r'441326q33660') + regexs[8].search(r'SbeprqRkcvengvba=633669341278771470') + regexs[8].search(strings[45]) + regexs[8].search(strings[46]) + regexs[8].search(r'AFP_zp_dfctwzssrwh-aowb_80=441326q33660') + regexs[8].search( + r'FrffvbaQQS2=102n9o0o9pq60132qn0337rr867p75953502q2s27s2s5r98') + regexs[8].search( + r'__hgzn=144631658.3931862196947939300.1231364380.1231364380.1231364380.1') + regexs[8].search(r'__hgzo=144631658.0.10.1231364380') + regexs[8].search( + r'__hgzm=144631658.1231364380.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)') + + for i in range(4): + regexs[14].sub(r'', ' yvfg1', subcount[14]) + regexs[15].sub(r'', ' yvfg1', subcount[15]) + regexs[14].sub(r'', ' yvfg2', subcount[14]) + regexs[15].sub(r'', ' yvfg2', subcount[15]) + regexs[14].sub(r'', ' frneputebhc1', subcount[14]) + regexs[15].sub(r'', ' frneputebhc1', subcount[15]) + regexs[68].sub(r'', strings[47], subcount[68]) + regexs[18].sub(r'', strings[47], subcount[18]) + re.sub(r'&', '', '', 0) + regexs[35].sub(r'', '', subcount[35]) + regexs[63].sub(r'', '(..-{0})(|(d+)|)', subcount[63]) + regexs[18].sub(r'', strings[48], subcount[18]) + regexs[56].sub( + r'', '//vzt.jro.qr/vij/FC/${cngu}/${anzr}/${inyhr}?gf=${abj}', subcount[56]) + re.sub(r'(\$\{anzr\})|(\$anzr\b)', '', + '//vzt.jro.qr/vij/FC/tzk_uc/${anzr}/${inyhr}?gf=${abj}', 0) + regexs[69].sub( + r'', 'Jvaqbjf Yvir Ubgznvy{1}', subcount[69]) + regexs[63].sub( + r'', '{0}{1}', subcount[63]) + regexs[69].sub( + r'', '{1}', subcount[69]) + regexs[63].sub( + r'', '{1}', subcount[63]) + regexs[15].sub(r'', 'Vzntrf', subcount[15]) + regexs[15].sub(r'', 'ZFA', subcount[15]) + regexs[15].sub(r'', 'Zncf', subcount[15]) + regexs[39].sub(r'', 'Zbq-Vasb-Vasb-WninFpevcgUvag', subcount[39]) + regexs[15].sub(r'', 'Arjf', subcount[15]) + regexs[32].split(strings[49]) + regexs[32].split(strings[50]) + regexs[15].sub(r'', 'Ivqrb', subcount[15]) + regexs[15].sub(r'', 'Jro', subcount[15]) + regexs[39].sub(r'', 'n', subcount[39]) + regexs[70].split(r'nwnkFgneg') + regexs[70].split(r'nwnkFgbc') + regexs[14].sub(r'', 'ovaq', subcount[14]) + regexs[15].sub(r'', 'ovaq', subcount[15]) + regexs[63].sub( + r'', 'oevatf lbh zber. Zber fcnpr (5TO), zber frphevgl, fgvyy serr.', subcount[63]) + regexs[14].sub(r'', 'puvyq p1 svefg qrpx', subcount[14]) + regexs[15].sub(r'', 'puvyq p1 svefg qrpx', subcount[15]) + regexs[14].sub(r'', 'puvyq p1 svefg qbhoyr2', subcount[14]) + regexs[15].sub(r'', 'puvyq p1 svefg qbhoyr2', subcount[15]) + regexs[14].sub(r'', 'puvyq p2 ynfg', subcount[14]) + regexs[15].sub(r'', 'puvyq p2 ynfg', subcount[15]) + regexs[14].sub(r'', 'puvyq p2', subcount[14]) + regexs[15].sub(r'', 'puvyq p2', subcount[15]) + regexs[14].sub(r'', 'puvyq p3', subcount[14]) + regexs[15].sub(r'', 'puvyq p3', subcount[15]) + regexs[14].sub(r'', 'puvyq p4 ynfg', subcount[14]) + regexs[15].sub(r'', 'puvyq p4 ynfg', subcount[15]) + regexs[14].sub(r'', 'pbclevtug', subcount[14]) + regexs[15].sub(r'', 'pbclevtug', subcount[15]) + regexs[14].sub(r'', 'qZFAZR_1', subcount[14]) + regexs[15].sub(r'', 'qZFAZR_1', subcount[15]) + regexs[14].sub(r'', 'qbhoyr2 ps', subcount[14]) + regexs[15].sub(r'', 'qbhoyr2 ps', subcount[15]) + regexs[14].sub(r'', 'qbhoyr2', subcount[14]) + regexs[15].sub(r'', 'qbhoyr2', subcount[15]) + regexs[14].sub(r'', 'uqy_arj', subcount[14]) + regexs[15].sub(r'', 'uqy_arj', subcount[15]) + regexs[30].sub(r'', 'uc_fubccvatobk', subcount[30]) + regexs[29].sub(r'', 'ugzy%2Rvq', subcount[29]) + regexs[30].sub(r'', 'ugzy%2Rvq', subcount[30]) + regexs[33].sub(r'', strings[51], subcount[33]) + regexs[71].sub( + r'', 'uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/cebgbglcr.wf${4}${5}', subcount[71]) + regexs[72].sub( + r'', 'uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/cebgbglcr.wf${5}', subcount[72]) + regexs[73].sub(r'', strings[52], subcount[73]) + regexs[69].sub( + r'', 'uggc://zfacbegny.112.2b7.arg/o/ff/zfacbegnyubzr/1/U.7-cqi-2/f55332979829981?[NDO]&{1}&{2}&[NDR]', subcount[69]) + regexs[14].sub(r'', 'vztZFSG', subcount[14]) + regexs[15].sub(r'', 'vztZFSG', subcount[15]) + regexs[14].sub(r'', 'zfasbbg1 ps', subcount[14]) + regexs[15].sub(r'', 'zfasbbg1 ps', subcount[15]) + regexs[14].sub(r'', strings[53], subcount[14]) + regexs[15].sub(r'', strings[53], subcount[15]) + regexs[14].sub( + r'', 'cnerag puebzr6 fvatyr1 gno fryrpgrq ovaq', subcount[14]) + regexs[15].sub( + r'', 'cnerag puebzr6 fvatyr1 gno fryrpgrq ovaq', subcount[15]) + regexs[14].sub(r'', 'cevznel', subcount[14]) + regexs[15].sub(r'', 'cevznel', subcount[15]) + regexs[30].sub(r'', 'erpgnatyr', subcount[30]) + regexs[14].sub(r'', 'frpbaqnel', subcount[14]) + regexs[15].sub(r'', 'frpbaqnel', subcount[15]) + regexs[70].split(r'haybnq') + regexs[63].sub(r'', '{0}{1}1', subcount[63]) + regexs[69].sub(r'', '|{1}1', subcount[69]) + re.search(r'(..-HF)(\|(\d+)|)', 'xb-xe,ra-va,gu-gu', re.IGNORECASE) + regexs[4].search(r'/ZlFcnprNccf/NccPnainf,45000012') + regexs[8].search(r'144631658.0.10.1231367708') + regexs[8].search( + r'144631658.1231367708.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)') + regexs[8].search( + r'144631658.2770915348920628700.1231367708.1231367708.1231367708.1') + regexs[8].search(r'4413235p3660') + regexs[8].search(r'441327q73660') + regexs[8].search(r'9995p6rp12rrnr893334ro7nq70o7p64p69rqn844prs1473') + regexs[8].search(r'SbeprqRkcvengvba=633669350559478880') + regexs[8].search(strings[54]) + regexs[8].search(strings[55]) + regexs[8].search(r'AFP_zp_dfctwzs-aowb_80=441327q73660') + regexs[8].search(r'AFP_zp_kkk-aowb_80=4413235p3660') + regexs[8].search( + r'FrffvbaQQS2=9995p6rp12rrnr893334ro7nq70o7p64p69rqn844prs1473') + regexs[8].search( + r'__hgzn=144631658.2770915348920628700.1231367708.1231367708.1231367708.1') + regexs[8].search(r'__hgzo=144631658.0.10.1231367708') + regexs[8].search( + r'__hgzm=144631658.1231367708.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)') + regexs[34].search(strings[49]) + regexs[34].search(strings[50]) + re.search(r'ZFVR\s+5[.]01', strings[0]) + re.search(r'HF(?=;)', strings[56], re.IGNORECASE) + regexs[74].search(strings[47]) + regexs[28].search(r'svefg npgvir svefgNpgvir') + regexs[28].search(r'ynfg') + re.search( + r'\bp:(..)', 'm:94043|yn:37.4154|yb:-122.0585|p:HF', re.IGNORECASE) + regexs[75].search(strings[57]) + regexs[75].search(strings[58]) + regexs[76].search(strings[57]) + regexs[76].search(strings[58]) + regexs[77].search(strings[57]) + regexs[77].search(strings[58]) + re.search(r'\bhfucce\s*=\s*([^;]*)', strings[59], re.IGNORECASE) + regexs[78].search(strings[57]) + regexs[78].search(strings[58]) + re.search(r'\bjci\s*=\s*([^;]*)', strings[59], re.IGNORECASE) + regexs[79].search(strings[58]) + regexs[79].search(strings[60]) + regexs[79].search(strings[59]) + re.search( + r'\|p:([a-z]{2})', 'm:94043|yn:37.4154|yb:-122.0585|p:HF|ue:1', re.IGNORECASE) + regexs[80].search(strings[47]) + regexs[61].search(r'cebgbglcr.wf') + regexs[68].search(strings[47]) + regexs[81].search(strings[47]) + regexs[82].search(strings[47]) + re.search(r'^Fubpxjnir Synfu (\d)', strings[1]) + re.search(r'^Fubpxjnir Synfu (\d+)', strings[1]) + regexs[83].search(r'[bowrpg tybony]') + regexs[62].search(strings[47]) + regexs[84].search(strings[61]) + regexs[84].search(strings[62]) + re.search(r'jroxvg', strings[63]) + + +def block10(): + for i in range(3): + regexs[39].sub(r'', '%3Szxg=ra-HF', subcount[39]) + regexs[40].sub(r'', '-8', subcount[40]) + regexs[10].sub(r'', '-8', subcount[10]) + regexs[51].sub(r'', '-8', subcount[51]) + regexs[52].sub(r'', '-8', subcount[52]) + regexs[53].sub(r'', '-8', subcount[53]) + regexs[39].sub(r'', '-8', subcount[39]) + regexs[54].sub(r'', '-8', subcount[54]) + regexs[40].sub(r'', '1.5', subcount[40]) + regexs[10].sub(r'', '1.5', subcount[10]) + regexs[51].sub(r'', '1.5', subcount[51]) + regexs[52].sub(r'', '1.5', subcount[52]) + regexs[53].sub(r'', '1.5', subcount[53]) + regexs[39].sub(r'', '1.5', subcount[39]) + regexs[54].sub(r'', '1.5', subcount[54]) + regexs[40].sub(r'', '1024k768', subcount[40]) + regexs[10].sub(r'', '1024k768', subcount[10]) + regexs[51].sub(r'', '1024k768', subcount[51]) + regexs[52].sub(r'', '1024k768', subcount[52]) + regexs[53].sub(r'', '1024k768', subcount[53]) + regexs[39].sub(r'', '1024k768', subcount[39]) + regexs[54].sub(r'', '1024k768', subcount[54]) + regexs[40].sub(r'', strings[64], subcount[40]) + regexs[10].sub(r'', strings[64], subcount[10]) + regexs[51].sub(r'', strings[64], subcount[51]) + regexs[52].sub(r'', strings[64], subcount[52]) + regexs[53].sub(r'', strings[64], subcount[53]) + regexs[39].sub(r'', strings[64], subcount[39]) + regexs[54].sub(r'', strings[64], subcount[54]) + regexs[40].sub(r'', '14', subcount[40]) + regexs[10].sub(r'', '14', subcount[10]) + regexs[51].sub(r'', '14', subcount[51]) + regexs[52].sub(r'', '14', subcount[52]) + regexs[53].sub(r'', '14', subcount[53]) + regexs[39].sub(r'', '14', subcount[39]) + regexs[54].sub(r'', '14', subcount[54]) + regexs[40].sub(r'', '24', subcount[40]) + regexs[10].sub(r'', '24', subcount[10]) + regexs[51].sub(r'', '24', subcount[51]) + regexs[52].sub(r'', '24', subcount[52]) + regexs[53].sub(r'', '24', subcount[53]) + regexs[39].sub(r'', '24', subcount[39]) + regexs[54].sub(r'', '24', subcount[54]) + regexs[40].sub(r'', strings[65], subcount[40]) + regexs[10].sub(r'', strings[65], subcount[10]) + regexs[51].sub(r'', strings[65], subcount[51]) + regexs[52].sub(r'', strings[65], subcount[52]) + regexs[53].sub(r'', strings[65], subcount[53]) + regexs[39].sub(r'', strings[65], subcount[39]) + regexs[54].sub(r'', strings[65], subcount[54]) + regexs[40].sub(r'', strings[66], subcount[40]) + regexs[10].sub(r'', strings[66], subcount[10]) + regexs[51].sub(r'', strings[66], subcount[51]) + regexs[52].sub(r'', strings[66], subcount[52]) + regexs[53].sub(r'', strings[66], subcount[53]) + regexs[39].sub(r'', strings[66], subcount[39]) + regexs[54].sub(r'', strings[66], subcount[54]) + regexs[40].sub(r'', '9.0', subcount[40]) + regexs[10].sub(r'', '9.0', subcount[10]) + regexs[51].sub(r'', '9.0', subcount[51]) + regexs[52].sub(r'', '9.0', subcount[52]) + regexs[53].sub(r'', '9.0', subcount[53]) + regexs[39].sub(r'', '9.0', subcount[39]) + regexs[54].sub(r'', '9.0', subcount[54]) + regexs[40].sub(r'', '994k634', subcount[40]) + regexs[10].sub(r'', '994k634', subcount[10]) + regexs[51].sub(r'', '994k634', subcount[51]) + regexs[52].sub(r'', '994k634', subcount[52]) + regexs[53].sub(r'', '994k634', subcount[53]) + regexs[39].sub(r'', '994k634', subcount[39]) + regexs[54].sub(r'', '994k634', subcount[54]) + regexs[40].sub(r'', '?zxg=ra-HF', subcount[40]) + regexs[10].sub(r'', '?zxg=ra-HF', subcount[10]) + regexs[51].sub(r'', '?zxg=ra-HF', subcount[51]) + regexs[52].sub(r'', '?zxg=ra-HF', subcount[52]) + regexs[53].sub(r'', '?zxg=ra-HF', subcount[53]) + regexs[54].sub(r'', '?zxg=ra-HF', subcount[54]) + regexs[25].sub(r'', 'PAA.pbz', subcount[25]) + regexs[12].sub(r'', 'PAA.pbz', subcount[12]) + regexs[39].sub(r'', 'PAA.pbz', subcount[39]) + regexs[25].sub(r'', 'Qngr & Gvzr', subcount[25]) + regexs[12].sub(r'', 'Qngr & Gvzr', subcount[12]) + regexs[39].sub(r'', 'Qngr & Gvzr', subcount[39]) + regexs[40].sub(r'', 'Frnepu Zvpebfbsg.pbz', subcount[40]) + regexs[54].sub(r'', 'Frnepu Zvpebfbsg.pbz', subcount[54]) + regexs[10].sub(r'', strings[67], subcount[10]) + regexs[51].sub(r'', strings[67], subcount[51]) + regexs[52].sub(r'', strings[67], subcount[52]) + regexs[53].sub(r'', strings[67], subcount[53]) + regexs[39].sub(r'', strings[67], subcount[39]) + regexs[32].split(strings[68]) + regexs[32].split(strings[69]) + regexs[52].sub(r'', strings[70], subcount[52]) + regexs[53].sub(r'', strings[70], subcount[53]) + regexs[39].sub(r'', strings[70], subcount[39]) + regexs[40].sub(r'', strings[71], subcount[40]) + regexs[10].sub(r'', strings[71], subcount[10]) + regexs[51].sub(r'', strings[71], subcount[51]) + regexs[54].sub(r'', strings[71], subcount[54]) + regexs[25].sub(r'', 'Jrngure', subcount[25]) + regexs[12].sub(r'', 'Jrngure', subcount[12]) + regexs[39].sub(r'', 'Jrngure', subcount[39]) + regexs[25].sub(r'', 'LbhGhor', subcount[25]) + regexs[12].sub(r'', 'LbhGhor', subcount[12]) + regexs[39].sub(r'', 'LbhGhor', subcount[39]) + regexs[33].sub(r'', strings[72], subcount[33]) + re.sub(r'^erzbgr_vsenzr_', '', 'erzbgr_vsenzr_1', 1) + regexs[40].sub(r'', strings[73], subcount[40]) + regexs[10].sub(r'', strings[73], subcount[10]) + regexs[51].sub(r'', strings[73], subcount[51]) + regexs[52].sub(r'', strings[73], subcount[52]) + regexs[53].sub(r'', strings[73], subcount[53]) + regexs[39].sub(r'', strings[73], subcount[39]) + regexs[54].sub(r'', strings[73], subcount[54]) + regexs[40].sub(r'', strings[74], subcount[40]) + regexs[10].sub(r'', strings[74], subcount[10]) + regexs[51].sub(r'', strings[74], subcount[51]) + regexs[52].sub(r'', strings[74], subcount[52]) + regexs[53].sub(r'', strings[74], subcount[53]) + regexs[39].sub(r'', strings[74], subcount[39]) + regexs[54].sub(r'', strings[74], subcount[54]) + re.sub(r'\-', '', 'lhv-h', 0) + regexs[9].search(r'p') + regexs[9].search(r'qz p') + regexs[9].search(r'zbqynory') + regexs[9].search(r'lhv-h svefg') + regexs[8].search(r'144631658.0.10.1231365779') + regexs[8].search( + r'144631658.1231365779.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)') + regexs[8].search( + r'144631658.1877536177953918500.1231365779.1231365779.1231365779.1') + regexs[8].search(strings[75]) + regexs[8].search(strings[76]) + regexs[8].search( + r'__hgzn=144631658.1877536177953918500.1231365779.1231365779.1231365779.1') + regexs[8].search(r'__hgzo=144631658.0.10.1231365779') + regexs[8].search( + r'__hgzm=144631658.1231365779.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)') + regexs[34].search(strings[68]) + regexs[34].search(strings[69]) + re.search(r'^$', '') + regexs[31].search(r'qr') + re.search(r'^znk\d+$', '') + re.search(r'^zva\d+$', '') + re.search(r'^erfgber$', '') + regexs[85].search(r'zbqobkva zbqobk_abcnqqvat ') + regexs[85].search(r'zbqgvgyr') + regexs[85].search(r'eaq_zbqobkva ') + regexs[85].search(r'eaq_zbqgvgyr ') + re.search(r'frpgvba\d+_pbagragf', 'obggbz_ani') + + +def block11(): + for i in range(2): + regexs[18].sub(r'', ' .pybfr', subcount[18]) + regexs[18].sub(r'', ' n.svryqOgaPnapry', subcount[18]) + regexs[18].sub(r'', ' qg', subcount[18]) + regexs[68].sub(r'', strings[77], subcount[68]) + regexs[18].sub(r'', strings[77], subcount[18]) + regexs[39].sub(r'', '', subcount[39]) + re.sub(r'^', '', '', 1) + regexs[86].split(r'') + regexs[39].sub(r'', '*', subcount[39]) + regexs[68].sub(r'', '*', subcount[68]) + regexs[18].sub(r'', '*', subcount[18]) + regexs[68].sub(r'', '.pybfr', subcount[68]) + regexs[18].sub(r'', '.pybfr', subcount[18]) + regexs[87].sub( + r'', '//vzt.jro.qr/vij/FC/tzk_uc/fperra/${inyhr}?gf=${abj}', subcount[87]) + regexs[88].sub( + r'', '//vzt.jro.qr/vij/FC/tzk_uc/fperra/1024?gf=${abj}', subcount[88]) + regexs[87].sub( + r'', '//vzt.jro.qr/vij/FC/tzk_uc/jvafvmr/${inyhr}?gf=${abj}', subcount[87]) + regexs[88].sub( + r'', '//vzt.jro.qr/vij/FC/tzk_uc/jvafvmr/992/608?gf=${abj}', subcount[88]) + regexs[30].sub(r'', '300k120', subcount[30]) + regexs[30].sub(r'', '300k250', subcount[30]) + regexs[30].sub(r'', '310k120', subcount[30]) + regexs[30].sub(r'', '310k170', subcount[30]) + regexs[30].sub(r'', '310k250', subcount[30]) + re.sub(r'^.*\.(.*)\s.*$', '', '9.0 e115', 1) + regexs[2].sub(r'', 'Nppbeqvba', subcount[2]) + regexs[89].sub(r'', 'Nxghryy\x0a', subcount[89]) + regexs[90].sub(r'', 'Nxghryy\x0a', subcount[90]) + regexs[2].sub(r'', 'Nccyvpngvba', subcount[2]) + regexs[89].sub(r'', 'Oyvpxchaxg\x0a', subcount[89]) + regexs[90].sub(r'', 'Oyvpxchaxg\x0a', subcount[90]) + regexs[89].sub(r'', 'Svanamra\x0a', subcount[89]) + regexs[90].sub(r'', 'Svanamra\x0a', subcount[90]) + regexs[89].sub(r'', 'Tnzrf\x0a', subcount[89]) + regexs[90].sub(r'', 'Tnzrf\x0a', subcount[90]) + regexs[89].sub(r'', 'Ubebfxbc\x0a', subcount[89]) + regexs[90].sub(r'', 'Ubebfxbc\x0a', subcount[90]) + regexs[89].sub(r'', 'Xvab\x0a', subcount[89]) + regexs[90].sub(r'', 'Xvab\x0a', subcount[90]) + regexs[2].sub(r'', 'Zbqhyrf', subcount[2]) + regexs[89].sub(r'', 'Zhfvx\x0a', subcount[89]) + regexs[90].sub(r'', 'Zhfvx\x0a', subcount[90]) + regexs[89].sub(r'', 'Anpuevpugra\x0a', subcount[89]) + regexs[90].sub(r'', 'Anpuevpugra\x0a', subcount[90]) + regexs[2].sub(r'', 'Cuk', subcount[2]) + regexs[70].split(r'ErdhrfgSvavfu') + regexs[70].split(r'ErdhrfgSvavfu.NWNK.Cuk') + regexs[89].sub(r'', 'Ebhgr\x0a', subcount[89]) + regexs[90].sub(r'', 'Ebhgr\x0a', subcount[90]) + regexs[32].split(strings[78]) + regexs[32].split(strings[79]) + regexs[32].split(strings[80]) + regexs[32].split(strings[81]) + regexs[89].sub(r'', 'Fcbeg\x0a', subcount[89]) + regexs[90].sub(r'', 'Fcbeg\x0a', subcount[90]) + regexs[89].sub(r'', 'GI-Fcbg\x0a', subcount[89]) + regexs[90].sub(r'', 'GI-Fcbg\x0a', subcount[90]) + regexs[89].sub(r'', 'Gbhe\x0a', subcount[89]) + regexs[90].sub(r'', 'Gbhe\x0a', subcount[90]) + regexs[89].sub(r'', 'Hagreunyghat\x0a', subcount[89]) + regexs[90].sub(r'', 'Hagreunyghat\x0a', subcount[90]) + regexs[89].sub(r'', 'Ivqrb\x0a', subcount[89]) + regexs[90].sub(r'', 'Ivqrb\x0a', subcount[90]) + regexs[89].sub(r'', 'Jrggre\x0a', subcount[89]) + regexs[90].sub(r'', 'Jrggre\x0a', subcount[90]) + regexs[68].sub(r'', strings[82], subcount[68]) + regexs[18].sub(r'', strings[82], subcount[18]) + regexs[68].sub(r'', strings[83], subcount[68]) + regexs[18].sub(r'', strings[83], subcount[18]) + regexs[68].sub(r'', strings[84], subcount[68]) + regexs[18].sub(r'', strings[84], subcount[18]) + regexs[30].sub(r'', 'nqiFreivprObk', subcount[30]) + regexs[30].sub(r'', 'nqiFubccvatObk', subcount[30]) + regexs[39].sub(r'', 'nwnk', subcount[39]) + regexs[40].sub(r'', 'nxghryy', subcount[40]) + regexs[41].sub(r'', 'nxghryy', subcount[41]) + regexs[42].sub(r'', 'nxghryy', subcount[42]) + regexs[43].sub(r'', 'nxghryy', subcount[43]) + regexs[44].sub(r'', 'nxghryy', subcount[44]) + regexs[45].sub(r'', 'nxghryy', subcount[45]) + regexs[46].sub(r'', 'nxghryy', subcount[46]) + regexs[47].sub(r'', 'nxghryy', subcount[47]) + regexs[48].sub(r'', 'nxghryy', subcount[48]) + regexs[40].sub(r'', strings[85], subcount[40]) + regexs[41].sub(r'', strings[85], subcount[41]) + regexs[42].sub(r'', strings[85], subcount[42]) + regexs[43].sub(r'', strings[85], subcount[43]) + regexs[44].sub(r'', strings[85], subcount[44]) + regexs[45].sub(r'', strings[85], subcount[45]) + regexs[46].sub(r'', strings[85], subcount[46]) + regexs[47].sub(r'', strings[85], subcount[47]) + regexs[48].sub(r'', strings[85], subcount[48]) + regexs[29].sub(r'', 'pngrtbel', subcount[29]) + regexs[30].sub(r'', 'pngrtbel', subcount[30]) + regexs[39].sub(r'', 'pybfr', subcount[39]) + regexs[39].sub(r'', 'qvi', subcount[39]) + regexs[68].sub(r'', strings[86], subcount[68]) + regexs[18].sub(r'', strings[86], subcount[18]) + regexs[39].sub(r'', 'qg', subcount[39]) + regexs[68].sub(r'', 'qg', subcount[68]) + regexs[18].sub(r'', 'qg', subcount[18]) + regexs[39].sub(r'', 'rzorq', subcount[39]) + regexs[68].sub(r'', 'rzorq', subcount[68]) + regexs[18].sub(r'', 'rzorq', subcount[18]) + regexs[39].sub(r'', 'svryqOga', subcount[39]) + regexs[39].sub(r'', 'svryqOgaPnapry', subcount[39]) + regexs[20].split(r'svz_zlfcnpr_nccf-pnainf,svz_zlfcnpr_havgrq-fgngrf') + regexs[40].sub(r'', 'svanamra', subcount[40]) + regexs[41].sub(r'', 'svanamra', subcount[41]) + regexs[42].sub(r'', 'svanamra', subcount[42]) + regexs[43].sub(r'', 'svanamra', subcount[43]) + regexs[44].sub(r'', 'svanamra', subcount[44]) + regexs[45].sub(r'', 'svanamra', subcount[45]) + regexs[46].sub(r'', 'svanamra', subcount[46]) + regexs[47].sub(r'', 'svanamra', subcount[47]) + regexs[48].sub(r'', 'svanamra', subcount[48]) + regexs[70].split(r'sbphf') + regexs[70].split(r'sbphf.gno sbphfva.gno') + regexs[70].split(r'sbphfva') + regexs[39].sub(r'', 'sbez', subcount[39]) + regexs[68].sub(r'', 'sbez.nwnk', subcount[68]) + regexs[18].sub(r'', 'sbez.nwnk', subcount[18]) + regexs[40].sub(r'', 'tnzrf', subcount[40]) + regexs[41].sub(r'', 'tnzrf', subcount[41]) + regexs[42].sub(r'', 'tnzrf', subcount[42]) + regexs[43].sub(r'', 'tnzrf', subcount[43]) + regexs[44].sub(r'', 'tnzrf', subcount[44]) + regexs[45].sub(r'', 'tnzrf', subcount[45]) + regexs[46].sub(r'', 'tnzrf', subcount[46]) + regexs[47].sub(r'', 'tnzrf', subcount[47]) + regexs[48].sub(r'', 'tnzrf', subcount[48]) + regexs[30].sub(r'', 'ubzrcntr', subcount[30]) + regexs[40].sub(r'', 'ubebfxbc', subcount[40]) + regexs[41].sub(r'', 'ubebfxbc', subcount[41]) + regexs[42].sub(r'', 'ubebfxbc', subcount[42]) + regexs[43].sub(r'', 'ubebfxbc', subcount[43]) + regexs[44].sub(r'', 'ubebfxbc', subcount[44]) + regexs[45].sub(r'', 'ubebfxbc', subcount[45]) + regexs[46].sub(r'', 'ubebfxbc', subcount[46]) + regexs[47].sub(r'', 'ubebfxbc', subcount[47]) + regexs[48].sub(r'', 'ubebfxbc', subcount[48]) + regexs[30].sub(r'', 'uc_cebzbobk_ugzy%2Puc_cebzbobk_vzt', subcount[30]) + regexs[30].sub(r'', 'uc_erpgnatyr', subcount[30]) + regexs[33].sub(r'', strings[87], subcount[33]) + regexs[33].sub(r'', strings[88], subcount[33]) + regexs[71].sub( + r'', 'uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/onfr.wf${4}${5}', subcount[71]) + regexs[72].sub( + r'', 'uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/onfr.wf${5}', subcount[72]) + regexs[71].sub( + r'', 'uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/qlaYvo.wf${4}${5}', subcount[71]) + regexs[72].sub( + r'', 'uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/qlaYvo.wf${5}', subcount[72]) + regexs[71].sub( + r'', 'uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/rssrpgYvo.wf${4}${5}', subcount[71]) + regexs[72].sub( + r'', 'uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/rssrpgYvo.wf${5}', subcount[72]) + regexs[73].sub(r'', strings[89], subcount[73]) + regexs[69].sub( + r'', 'uggc://zfacbegny.112.2b7.arg/o/ff/zfacbegnyubzr/1/U.7-cqi-2/f55023338617756?[NDO]&{1}&{2}&[NDR]', subcount[69]) + regexs[23].sub(r'', strings[6], subcount[23]) + regexs[40].sub(r'', 'xvab', subcount[40]) + regexs[41].sub(r'', 'xvab', subcount[41]) + regexs[42].sub(r'', 'xvab', subcount[42]) + regexs[43].sub(r'', 'xvab', subcount[43]) + regexs[44].sub(r'', 'xvab', subcount[44]) + regexs[45].sub(r'', 'xvab', subcount[45]) + regexs[46].sub(r'', 'xvab', subcount[46]) + regexs[47].sub(r'', 'xvab', subcount[47]) + regexs[48].sub(r'', 'xvab', subcount[48]) + regexs[70].split(r'ybnq') + regexs[18].sub( + r'', 'zrqvnzbqgno lhv-anifrg lhv-anifrg-gbc', subcount[18]) + regexs[39].sub(r'', 'zrgn', subcount[39]) + regexs[68].sub(r'', strings[90], subcount[68]) + regexs[18].sub(r'', strings[90], subcount[18]) + regexs[70].split(r'zbhfrzbir') + regexs[70].split(r'zbhfrzbir.gno') + re.sub(r'^.*jroxvg\/(\d+(\.\d+)?).*$', '', strings[63], 1) + regexs[40].sub(r'', 'zhfvx', subcount[40]) + regexs[41].sub(r'', 'zhfvx', subcount[41]) + regexs[42].sub(r'', 'zhfvx', subcount[42]) + regexs[43].sub(r'', 'zhfvx', subcount[43]) + regexs[44].sub(r'', 'zhfvx', subcount[44]) + regexs[45].sub(r'', 'zhfvx', subcount[45]) + regexs[46].sub(r'', 'zhfvx', subcount[46]) + regexs[47].sub(r'', 'zhfvx', subcount[47]) + regexs[48].sub(r'', 'zhfvx', subcount[48]) + regexs[52].sub(r'', 'zlfcnpr_nccf_pnainf', subcount[52]) + regexs[40].sub(r'', strings[91], subcount[40]) + regexs[41].sub(r'', strings[91], subcount[41]) + regexs[42].sub(r'', strings[91], subcount[42]) + regexs[43].sub(r'', strings[91], subcount[43]) + regexs[44].sub(r'', strings[91], subcount[44]) + regexs[45].sub(r'', strings[91], subcount[45]) + regexs[46].sub(r'', strings[91], subcount[46]) + regexs[47].sub(r'', strings[91], subcount[47]) + regexs[48].sub(r'', strings[91], subcount[48]) + regexs[39].sub(r'', 'anzr', subcount[39]) + + # This prints something different to the V8 version + # The V8 version is escaping different things in the string that + # has the substitutions performed on it. + # + # V8 treats /\S/ like / + escaped S + / + # Python treats it like / + \ + S + / + re.sub(r'\b\w+\b', '', strings[92], 0) + + regexs[39].sub(r'', 'bow-nppbeqvba', subcount[39]) + regexs[39].sub(r'', 'bowrpg', subcount[39]) + regexs[68].sub(r'', 'bowrpg', subcount[68]) + regexs[18].sub(r'', 'bowrpg', subcount[18]) + regexs[29].sub(r'', 'cnenzf%2Rfglyrf', subcount[29]) + regexs[30].sub(r'', 'cnenzf%2Rfglyrf', subcount[30]) + regexs[30].sub(r'', 'cbchc', subcount[30]) + regexs[40].sub(r'', 'ebhgr', subcount[40]) + regexs[41].sub(r'', 'ebhgr', subcount[41]) + regexs[42].sub(r'', 'ebhgr', subcount[42]) + regexs[43].sub(r'', 'ebhgr', subcount[43]) + regexs[44].sub(r'', 'ebhgr', subcount[44]) + regexs[45].sub(r'', 'ebhgr', subcount[45]) + regexs[46].sub(r'', 'ebhgr', subcount[46]) + regexs[47].sub(r'', 'ebhgr', subcount[47]) + regexs[48].sub(r'', 'ebhgr', subcount[48]) + regexs[30].sub(r'', 'freivprobk_uc', subcount[30]) + regexs[30].sub(r'', 'fubccvatobk_uc', subcount[30]) + regexs[39].sub(r'', 'fubhgobk', subcount[39]) + regexs[40].sub(r'', 'fcbeg', subcount[40]) + regexs[41].sub(r'', 'fcbeg', subcount[41]) + regexs[42].sub(r'', 'fcbeg', subcount[42]) + regexs[43].sub(r'', 'fcbeg', subcount[43]) + regexs[44].sub(r'', 'fcbeg', subcount[44]) + regexs[45].sub(r'', 'fcbeg', subcount[45]) + regexs[46].sub(r'', 'fcbeg', subcount[46]) + regexs[47].sub(r'', 'fcbeg', subcount[47]) + regexs[48].sub(r'', 'fcbeg', subcount[48]) + regexs[40].sub(r'', 'gbhe', subcount[40]) + regexs[41].sub(r'', 'gbhe', subcount[41]) + regexs[42].sub(r'', 'gbhe', subcount[42]) + regexs[43].sub(r'', 'gbhe', subcount[43]) + regexs[44].sub(r'', 'gbhe', subcount[44]) + regexs[45].sub(r'', 'gbhe', subcount[45]) + regexs[46].sub(r'', 'gbhe', subcount[46]) + regexs[47].sub(r'', 'gbhe', subcount[47]) + regexs[48].sub(r'', 'gbhe', subcount[48]) + regexs[40].sub(r'', 'gi-fcbg', subcount[40]) + regexs[41].sub(r'', 'gi-fcbg', subcount[41]) + regexs[42].sub(r'', 'gi-fcbg', subcount[42]) + regexs[43].sub(r'', 'gi-fcbg', subcount[43]) + regexs[44].sub(r'', 'gi-fcbg', subcount[44]) + regexs[45].sub(r'', 'gi-fcbg', subcount[45]) + regexs[46].sub(r'', 'gi-fcbg', subcount[46]) + regexs[47].sub(r'', 'gi-fcbg', subcount[47]) + regexs[48].sub(r'', 'gi-fcbg', subcount[48]) + regexs[39].sub(r'', 'glcr', subcount[39]) + re.sub(r'\/', '', 'haqrsvarq', 0) + regexs[40].sub(r'', strings[93], subcount[40]) + regexs[41].sub(r'', strings[93], subcount[41]) + regexs[42].sub(r'', strings[93], subcount[42]) + regexs[43].sub(r'', strings[93], subcount[43]) + regexs[44].sub(r'', strings[93], subcount[44]) + regexs[45].sub(r'', strings[93], subcount[45]) + regexs[46].sub(r'', strings[93], subcount[46]) + regexs[47].sub(r'', strings[93], subcount[47]) + regexs[48].sub(r'', strings[93], subcount[48]) + regexs[40].sub(r'', 'ivqrb', subcount[40]) + regexs[41].sub(r'', 'ivqrb', subcount[41]) + regexs[42].sub(r'', 'ivqrb', subcount[42]) + regexs[43].sub(r'', 'ivqrb', subcount[43]) + regexs[44].sub(r'', 'ivqrb', subcount[44]) + regexs[45].sub(r'', 'ivqrb', subcount[45]) + regexs[46].sub(r'', 'ivqrb', subcount[46]) + regexs[47].sub(r'', 'ivqrb', subcount[47]) + regexs[48].sub(r'', 'ivqrb', subcount[48]) + regexs[86].split(r'ivfvgf=1') + regexs[40].sub(r'', 'jrggre', subcount[40]) + regexs[41].sub(r'', 'jrggre', subcount[41]) + regexs[42].sub(r'', 'jrggre', subcount[42]) + regexs[43].sub(r'', 'jrggre', subcount[43]) + regexs[44].sub(r'', 'jrggre', subcount[44]) + regexs[45].sub(r'', 'jrggre', subcount[45]) + regexs[46].sub(r'', 'jrggre', subcount[46]) + regexs[47].sub(r'', 'jrggre', subcount[47]) + regexs[48].sub(r'', 'jrggre', subcount[48]) + re.search(r'#[a-z0-9]+$', + 'uggc://jjj.fpuhryreim.arg/Qrsnhyg', re.IGNORECASE) + regexs[66].search(r'fryrpgrq') + re.search(r'(?:^|\s+)lhv-ani(?:\s+|$)', 'sff lhv-ani') + re.search(r'(?:^|\s+)lhv-anifrg(?:\s+|$)', 'zrqvnzbqgno lhv-anifrg') + re.search(r'(?:^|\s+)lhv-anifrg-gbc(?:\s+|$)', + 'zrqvnzbqgno lhv-anifrg') + regexs[91].search(r'GnoThvq') + regexs[91].search(r'thvq') + re.search(r'(pbzcngvoyr|jroxvg)', strings[63]) + re.search(r'.+(?:ei|vg|en|vr)[\/: ]([\d.]+)', strings[63]) + regexs[8].search(r'144631658.0.10.1231365869') + regexs[8].search(r'144631658.0.10.1231367054') + regexs[8].search( + r'144631658.1231365869.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)') + regexs[8].search( + r'144631658.1231367054.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)') + regexs[8].search( + r'144631658.1670816052019209000.1231365869.1231365869.1231365869.1') + regexs[8].search( + r'144631658.1796080716621419500.1231367054.1231367054.1231367054.1') + regexs[8].search(strings[94]) + regexs[8].search(strings[95]) + regexs[8].search(strings[96]) + regexs[8].search(strings[97]) + regexs[8].search( + r'__hgzn=144631658.1670816052019209000.1231365869.1231365869.1231365869.1') + regexs[8].search( + r'__hgzn=144631658.1796080716621419500.1231367054.1231367054.1231367054.1') + regexs[8].search(r'__hgzo=144631658.0.10.1231365869') + regexs[8].search(r'__hgzo=144631658.0.10.1231367054') + regexs[8].search( + r'__hgzm=144631658.1231365869.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)') + regexs[8].search( + r'__hgzm=144631658.1231367054.1.1.hgzpfe=(qverpg)|hgzppa=(qverpg)|hgzpzq=(abar)') + regexs[34].search(strings[78]) + regexs[34].search(strings[79]) + regexs[34].search(strings[81]) + regexs[74].search(strings[77]) + regexs[74].search(r'*') + regexs[74].search(strings[82]) + regexs[74].search(strings[83]) + regexs[74].search(strings[86]) + regexs[74].search(r'rzorq') + regexs[74].search(r'sbez.nwnk') + regexs[74].search(strings[90]) + regexs[74].search(r'bowrpg') + re.search(r'\/onfr.wf(\?.+)?$', + '/uggc://wf.hv-cbegny.qr/tzk/ubzr/wf/20080602/onfr.wf') + regexs[28].search(r'uvag ynfgUvag ynfg') + regexs[75].search(r'') + regexs[76].search(r'') + regexs[77].search(r'') + regexs[78].search(r'') + regexs[80].search(strings[77]) + regexs[80].search(r'*') + regexs[80].search(r'.pybfr') + regexs[80].search(strings[82]) + regexs[80].search(strings[83]) + regexs[80].search(strings[84]) + regexs[80].search(strings[86]) + regexs[80].search(r'qg') + regexs[80].search(r'rzorq') + regexs[80].search(r'sbez.nwnk') + regexs[80].search(strings[90]) + regexs[80].search(r'bowrpg') + regexs[61].search(r'qlaYvo.wf') + regexs[61].search(r'rssrpgYvo.wf') + regexs[61].search(r'uggc://jjj.tzk.arg/qr/?fgnghf=uvajrvf') + regexs[92].search(r' .pybfr') + regexs[92].search(r' n.svryqOgaPnapry') + regexs[92].search(r' qg') + regexs[92].search(strings[48]) + regexs[92].search(r'.nwnk') + regexs[92].search(r'.svryqOga,n.svryqOgaPnapry') + regexs[92].search(r'.svryqOgaPnapry') + regexs[92].search(r'.bow-nppbeqvba qg') + regexs[68].search(strings[77]) + regexs[68].search(r'*') + regexs[68].search(r'.pybfr') + regexs[68].search(strings[82]) + regexs[68].search(strings[83]) + regexs[68].search(strings[84]) + regexs[68].search(strings[86]) + regexs[68].search(r'qg') + regexs[68].search(r'rzorq') + regexs[68].search(r'sbez.nwnk') + regexs[68].search(strings[90]) + regexs[68].search(r'bowrpg') + regexs[93].search(r' .pybfr') + regexs[93].search(r' n.svryqOgaPnapry') + regexs[93].search(r' qg') + regexs[93].search(strings[48]) + regexs[93].search(r'.nwnk') + regexs[93].search(r'.svryqOga,n.svryqOgaPnapry') + regexs[93].search(r'.svryqOgaPnapry') + regexs[93].search(r'.bow-nppbeqvba qg') + regexs[81].search(strings[77]) + regexs[81].search(r'*') + regexs[81].search(strings[48]) + regexs[81].search(r'.pybfr') + regexs[81].search(strings[82]) + regexs[81].search(strings[83]) + regexs[81].search(strings[84]) + regexs[81].search(strings[86]) + regexs[81].search(r'qg') + regexs[81].search(r'rzorq') + regexs[81].search(r'sbez.nwnk') + regexs[81].search(strings[90]) + regexs[81].search(r'bowrpg') + regexs[94].search(r' .pybfr') + regexs[94].search(r' n.svryqOgaPnapry') + regexs[94].search(r' qg') + regexs[94].search(strings[48]) + regexs[94].search(r'.nwnk') + regexs[94].search(r'.svryqOga,n.svryqOgaPnapry') + regexs[94].search(r'.svryqOgaPnapry') + regexs[94].search(r'.bow-nppbeqvba qg') + regexs[94].search(r'[anzr=nwnkHey]') + regexs[94].search(strings[82]) + regexs[31].search(r'rf') + regexs[31].search(r'wn') + regexs[82].search(strings[77]) + regexs[82].search(r'*') + regexs[82].search(strings[48]) + regexs[82].search(r'.pybfr') + regexs[82].search(strings[82]) + regexs[82].search(strings[83]) + regexs[82].search(strings[84]) + regexs[82].search(strings[86]) + regexs[82].search(r'qg') + regexs[82].search(r'rzorq') + regexs[82].search(r'sbez.nwnk') + regexs[82].search(strings[90]) + regexs[82].search(r'bowrpg') + regexs[83].search(strings[98]) + regexs[83].search(r'shapgvba sbphf() { [angvir pbqr] }') + regexs[62].search(r'#Ybtva') + regexs[62].search(r'#Ybtva_cnffjbeq') + regexs[62].search(strings[77]) + regexs[62].search(r'#fubhgobkWf') + regexs[62].search(r'#fubhgobkWfReebe') + regexs[62].search(r'#fubhgobkWfFhpprff') + regexs[62].search(r'*') + regexs[62].search(strings[82]) + regexs[62].search(strings[83]) + regexs[62].search(strings[86]) + regexs[62].search(r'rzorq') + regexs[62].search(r'sbez.nwnk') + regexs[62].search(strings[90]) + regexs[62].search(r'bowrpg') + regexs[49].search(r'pbagrag') + regexs[24].search(strings[6]) + re.search(r'xbadhrebe', strings[63]) + re.search(r'znp', 'jva32') + re.search(r'zbmvyyn', strings[63]) + re.search(r'zfvr', strings[63]) + re.search(r'ag\s5\.1', strings[63]) + re.search(r'bcren', strings[63]) + re.search(r'fnsnev', strings[63]) + re.search(r'jva', 'jva32') + re.search(r'jvaqbjf', strings[63]) + + +def bench_regex_v8(loops): + t0 = pyperf.perf_counter() + for loops in range(loops): + block0() + block1() + block2() + block3() + block4() + block5() + block6() + block7() + block8() + block9() + block10() + block11() + return pyperf.perf_counter() - t0 + + +def run_pgo(): + bench_regex_v8(10) diff --git a/Lib/test/pgo_task/bm_xml_tree.py b/Lib/test/pgo_task/bm_xml_tree.py new file mode 100644 index 00000000000000..371a2d3cf4c602 --- /dev/null +++ b/Lib/test/pgo_task/bm_xml_tree.py @@ -0,0 +1,211 @@ + +"""Benchmark script for testing the performance of ElementTree. + +This is intended to support Unladen Swallow's pyperf.py. + +This will have ElementTree, cElementTree and lxml (if available) +parse a generated XML file, search it, create new XML trees from +it and serialise the result. +""" + +import io +import os +import tempfile +from collections import defaultdict + + +__author__ = "stefan_ml@behnel.de (Stefan Behnel)" + +FALLBACK_ETMODULE = 'xml.etree.ElementTree' + + +def build_xml_tree(etree): + SubElement = etree.SubElement + root = etree.Element('root') + + # create a couple of repetitive broad subtrees + for c in range(50): + child = SubElement(root, 'child-%d' % c, + tag_type="child") + for i in range(100): + SubElement(child, 'subchild').text = 'LEAF-%d-%d' % (c, i) + + # create a deep subtree + deep = SubElement(root, 'deepchildren', tag_type="deepchild") + for i in range(50): + deep = SubElement(deep, 'deepchild') + SubElement(deep, 'deepleaf', tag_type="leaf").text = "LEAF" + + # store the number of elements for later + nb_elems = sum(1 for elem in root.iter()) + root.set('nb-elems', str(nb_elems)) + + return root + + +def process(etree, xml_root=None): + SubElement = etree.SubElement + + if xml_root is not None: + root = xml_root + else: + root = build_xml_tree(etree) + + # find*() + found = sum(child.find('.//deepleaf') is not None + for child in root) + if found != 1: + raise RuntimeError("find() failed") + + text = 'LEAF-5-99' + found = any(1 for child in root + for el in child.iterfind('.//subchild') + if el.text == text) + if not found: + raise RuntimeError("iterfind() failed") + + found = sum(el.text == 'LEAF' + for el in root.findall('.//deepchild/deepleaf')) + if found != 1: + raise RuntimeError("findall() failed") + + # tree creation based on original tree + dest = etree.Element('root2') + target = SubElement(dest, 'result-1') + for child in root: + SubElement(target, child.tag).text = str(len(child)) + if len(target) != len(root): + raise RuntimeError("transform #1 failed") + + target = SubElement(dest, 'result-2') + for child in root.iterfind('.//subchild'): + SubElement(target, child.tag, attr=child.text).text = "found" + + if (len(target) < len(root) + or not all(el.text == 'found' + for el in target.iterfind('subchild'))): + raise RuntimeError("transform #2 failed") + + # moving subtrees around + orig_len = len(root[0]) + new_root = root.makeelement('parent', {}) + new_root[:] = root[0] + el = root[0] + del el[:] + for child in new_root: + if child is not None: + el.append(child) + if len(el) != orig_len: + raise RuntimeError("child moving failed") + + # check iteration tree consistency + d = defaultdict(list) + for child in root: + tags = d[child.get('tag_type')] + for sub in child.iter(): + tags.append(sub) + + check_dict = dict((n, iter(ch)) for n, ch in d.items()) + target = SubElement(dest, 'transform-2') + for child in root: + tags = check_dict[child.get('tag_type')] + for sub in child.iter(): + # note: explicit object identity check to make sure + # users can properly keep state in the tree + if sub is not next(tags): + raise RuntimeError("tree iteration consistency check failed") + SubElement(target, sub.tag).text = 'worked' + + # final probability check for serialisation (we added enough content + # to make the result tree larger than the original) + orig = etree.tostring(root, encoding='utf8') + result = etree.tostring(dest, encoding='utf8') + if (len(result) < len(orig) + or b'worked' not in result + or b'>LEAF<' not in orig): + raise RuntimeError("serialisation probability check failed") + return result + + +def bench_iterparse(etree, xml_file, xml_data, xml_root): + for _ in range(10): + it = etree.iterparse(xml_file, ('start', 'end')) + events1 = [(event, elem.tag) for event, elem in it] + it = etree.iterparse(io.BytesIO(xml_data), ('start', 'end')) + events2 = [(event, elem.tag) for event, elem in it] + nb_elems = int(xml_root.get('nb-elems')) + if len(events1) != 2 * nb_elems or events1 != events2: + raise RuntimeError("parsing check failed:\n%r\n%r\n" % + (len(events1), events2[:10])) + + +def bench_parse(etree, xml_file, xml_data, xml_root): + for _ in range(30): + root1 = etree.parse(xml_file).getroot() + root2 = etree.fromstring(xml_data) + result1 = etree.tostring(root1) + result2 = etree.tostring(root2) + if result1 != result2: + raise RuntimeError("serialisation check failed") + + +def bench_process(etree, xml_file, xml_data, xml_root): + result1 = process(etree, xml_root=xml_root) + result2 = process(etree, xml_root=xml_root) + if result1 != result2 or b'>found<' not in result2: + raise RuntimeError("serialisation check failed") + + +def bench_generate(etree, xml_file, xml_data, xml_root): + output = [] + for _ in range(10): + root = build_xml_tree(etree) + output.append(etree.tostring(root)) + + length = None + for xml in output: + if length is None: + length = len(xml) + elif length != len(xml): + raise RuntimeError("inconsistent output detected") + if b'>LEAF<' not in xml: + raise RuntimeError("unexpected output detected") + + +def bench_etree(iterations, etree, bench_func): + xml_root = build_xml_tree(etree) + xml_data = etree.tostring(xml_root) + + # not using NamedTemporaryFile() here as re-opening it is not portable + tf, file_path = tempfile.mkstemp() + try: + etree.ElementTree(xml_root).write(file_path) + + for _ in range(iterations): + bench_func(etree, file_path, xml_data, xml_root) + + finally: + try: + os.close(tf) + except EnvironmentError: + pass + try: + os.unlink(file_path) + except EnvironmentError: + pass + + +BENCHMARKS = 'parse iterparse generate process'.split() + + +def run_pgo(): + from importlib import import_module + import xml.etree.ElementTree as etree_module + + benchmarks = BENCHMARKS + + # Run the benchmark + iterations = 1 + for bench in benchmarks: + bench_func = globals()['bench_%s' % bench] + bench_etree(iterations, etree_module, bench_func) From 2cd5822454c1f9532d222804bb4cb30bddf9e605 Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Fri, 28 Feb 2025 10:17:35 -0800 Subject: [PATCH 3/4] Adjust PGO task loops. --- Lib/test/pgo_task/bm_argparse.py | 3 ++- Lib/test/pgo_task/bm_async_generators.py | 3 ++- Lib/test/pgo_task/bm_coroutines.py | 2 +- Lib/test/pgo_task/bm_deepcopy.py | 2 +- Lib/test/pgo_task/bm_deltablue.py | 2 +- Lib/test/pgo_task/bm_float.py | 3 ++- Lib/test/pgo_task/bm_gc_collect.py | 2 +- Lib/test/pgo_task/bm_gc_traversal.py | 2 +- Lib/test/pgo_task/bm_generators.py | 2 +- Lib/test/pgo_task/bm_go.py | 3 ++- Lib/test/pgo_task/bm_hexiom.py | 2 +- Lib/test/pgo_task/bm_json_loads.py | 2 +- Lib/test/pgo_task/bm_logging.py | 2 +- Lib/test/pgo_task/bm_meteor_contest.py | 2 +- Lib/test/pgo_task/bm_pathlib.py | 2 +- Lib/test/pgo_task/bm_pidigits.py | 3 ++- Lib/test/pgo_task/bm_regex_effbot.py | 4 ++-- Lib/test/pgo_task/bm_richards.py | 2 +- Lib/test/pgo_task/bm_richards_super.py | 2 +- Lib/test/pgo_task/bm_spectral_norm.py | 2 +- Lib/test/pgo_task/bm_sqlite_synth.py | 3 ++- Lib/test/pgo_task/bm_typing_runtime_protocols.py | 3 ++- Lib/test/pgo_task/bm_unpack_sequence.py | 3 ++- 23 files changed, 32 insertions(+), 24 deletions(-) diff --git a/Lib/test/pgo_task/bm_argparse.py b/Lib/test/pgo_task/bm_argparse.py index 74852f7e3ae317..940ffdc7fe9d68 100644 --- a/Lib/test/pgo_task/bm_argparse.py +++ b/Lib/test/pgo_task/bm_argparse.py @@ -116,4 +116,5 @@ def add_parser_args(parser): def run_pgo(): for bm_func in BENCHMARKS.values(): - bm_func() + for _ in range(10): + bm_func() diff --git a/Lib/test/pgo_task/bm_async_generators.py b/Lib/test/pgo_task/bm_async_generators.py index 9e229cb5fe4496..d26e0edc9e17fb 100644 --- a/Lib/test/pgo_task/bm_async_generators.py +++ b/Lib/test/pgo_task/bm_async_generators.py @@ -39,4 +39,5 @@ async def bench_async_generators(loops=100000) -> None: def run_pgo(): import asyncio - asyncio.run(bench_async_generators(1000)) + for _ in range(10): + asyncio.run(bench_async_generators(1000)) diff --git a/Lib/test/pgo_task/bm_coroutines.py b/Lib/test/pgo_task/bm_coroutines.py index 6ba750b80994f5..8085e9fbca46fe 100644 --- a/Lib/test/pgo_task/bm_coroutines.py +++ b/Lib/test/pgo_task/bm_coroutines.py @@ -23,4 +23,4 @@ def bench_coroutines(loops: int) -> float: def run_pgo(): - bench_coroutines(1) + bench_coroutines(10) diff --git a/Lib/test/pgo_task/bm_deepcopy.py b/Lib/test/pgo_task/bm_deepcopy.py index f200250aec642e..63875f21989a6c 100644 --- a/Lib/test/pgo_task/bm_deepcopy.py +++ b/Lib/test/pgo_task/bm_deepcopy.py @@ -68,7 +68,7 @@ def benchmark(n): def run_pgo(): - loops = 100 + loops = 1000 benchmark(loops) benchmark_reduce(loops) benchmark_memo(loops) diff --git a/Lib/test/pgo_task/bm_deltablue.py b/Lib/test/pgo_task/bm_deltablue.py index 0ddaab0e7a55c8..b667690281d658 100644 --- a/Lib/test/pgo_task/bm_deltablue.py +++ b/Lib/test/pgo_task/bm_deltablue.py @@ -627,5 +627,5 @@ def delta_blue(n): def run_pgo(): - n = 1000 + n = 5000 delta_blue(n) diff --git a/Lib/test/pgo_task/bm_float.py b/Lib/test/pgo_task/bm_float.py index 7314d7aed1e331..6d8e71b3001a7d 100644 --- a/Lib/test/pgo_task/bm_float.py +++ b/Lib/test/pgo_task/bm_float.py @@ -53,4 +53,5 @@ def benchmark(n): def run_pgo(): points = POINTS - benchmark(points) + for _ in range(5): + benchmark(points) diff --git a/Lib/test/pgo_task/bm_gc_collect.py b/Lib/test/pgo_task/bm_gc_collect.py index eac319c3d4c887..ca810377e5903a 100644 --- a/Lib/test/pgo_task/bm_gc_collect.py +++ b/Lib/test/pgo_task/bm_gc_collect.py @@ -56,4 +56,4 @@ def benchamark_collection(loops, cycles, links): def run_pgo(): - benchamark_collection(1, CYCLES, LINKS) + benchamark_collection(10, CYCLES, LINKS) diff --git a/Lib/test/pgo_task/bm_gc_traversal.py b/Lib/test/pgo_task/bm_gc_traversal.py index 2f2be099bb252b..7ad56d8acf1fa8 100644 --- a/Lib/test/pgo_task/bm_gc_traversal.py +++ b/Lib/test/pgo_task/bm_gc_traversal.py @@ -27,4 +27,4 @@ def benchamark_collection(loops, n_levels): def run_pgo(): - benchamark_collection(1, N_LEVELS) + benchamark_collection(10, N_LEVELS) diff --git a/Lib/test/pgo_task/bm_generators.py b/Lib/test/pgo_task/bm_generators.py index ddd89b367eaab8..412362a3248f74 100644 --- a/Lib/test/pgo_task/bm_generators.py +++ b/Lib/test/pgo_task/bm_generators.py @@ -40,4 +40,4 @@ def bench_generators(loops: int) -> float: pass def run_pgo(): - bench_generators(1) + bench_generators(5) diff --git a/Lib/test/pgo_task/bm_go.py b/Lib/test/pgo_task/bm_go.py index c57eaa282c36fd..37312e54628340 100644 --- a/Lib/test/pgo_task/bm_go.py +++ b/Lib/test/pgo_task/bm_go.py @@ -450,4 +450,5 @@ def versus_cpu(): def run_pgo(): - versus_cpu() + for _ in range(5): + versus_cpu() diff --git a/Lib/test/pgo_task/bm_hexiom.py b/Lib/test/pgo_task/bm_hexiom.py index eb545ec207d769..2a69b551de6c7b 100644 --- a/Lib/test/pgo_task/bm_hexiom.py +++ b/Lib/test/pgo_task/bm_hexiom.py @@ -640,4 +640,4 @@ def main(loops, level): def run_pgo(): - main(10, level=DEFAULT_LEVEL) + main(20, level=DEFAULT_LEVEL) diff --git a/Lib/test/pgo_task/bm_json_loads.py b/Lib/test/pgo_task/bm_json_loads.py index 857b5fcda24713..186ce9f0c93728 100644 --- a/Lib/test/pgo_task/bm_json_loads.py +++ b/Lib/test/pgo_task/bm_json_loads.py @@ -97,5 +97,5 @@ def run_pgo(): json_dict_group = json.dumps(DICT_GROUP) objs = (json_dict, json_tuple, json_dict_group) - for _ in range(10): + for _ in range(200): bench_json_loads(objs) diff --git a/Lib/test/pgo_task/bm_logging.py b/Lib/test/pgo_task/bm_logging.py index 33654a50edfed1..5a0885b285e49d 100644 --- a/Lib/test/pgo_task/bm_logging.py +++ b/Lib/test/pgo_task/bm_logging.py @@ -126,4 +126,4 @@ def run_pgo(): name = 'logging_%s' % bench bench_func = BENCHMARKS[bench] - bench_func(100, logger, stream) + bench_func(200, logger, stream) diff --git a/Lib/test/pgo_task/bm_meteor_contest.py b/Lib/test/pgo_task/bm_meteor_contest.py index 046fc53143b460..d5daf96945161e 100644 --- a/Lib/test/pgo_task/bm_meteor_contest.py +++ b/Lib/test/pgo_task/bm_meteor_contest.py @@ -208,5 +208,5 @@ def run_pgo(): se_nh = get_senh(board, cti) solve_arg = SOLVE_ARG - loops = 1 + loops = 10 bench_meteor_contest(loops, board, pieces, solve_arg, fps, se_nh) diff --git a/Lib/test/pgo_task/bm_pathlib.py b/Lib/test/pgo_task/bm_pathlib.py index de5443eaa2dcce..d221d107d5981c 100644 --- a/Lib/test/pgo_task/bm_pathlib.py +++ b/Lib/test/pgo_task/bm_pathlib.py @@ -61,7 +61,7 @@ def bench_pathlib(loops, tmp_path): def run_pgo(): modname = pathlib.__name__ tmp_path = setup(NUM_FILES) - loops = 1 + loops = 10 try: bench_pathlib(loops, tmp_path) finally: diff --git a/Lib/test/pgo_task/bm_pidigits.py b/Lib/test/pgo_task/bm_pidigits.py index a9ad7431fba161..e5652b49a91335 100644 --- a/Lib/test/pgo_task/bm_pidigits.py +++ b/Lib/test/pgo_task/bm_pidigits.py @@ -50,4 +50,5 @@ def calc_ndigits(n): def run_pgo(): - calc_ndigits(DEFAULT_DIGITS) + for _ in range(5): + calc_ndigits(DEFAULT_DIGITS) diff --git a/Lib/test/pgo_task/bm_regex_effbot.py b/Lib/test/pgo_task/bm_regex_effbot.py index aa954bf5978fba..2f7c84425d822d 100644 --- a/Lib/test/pgo_task/bm_regex_effbot.py +++ b/Lib/test/pgo_task/bm_regex_effbot.py @@ -154,6 +154,6 @@ def bench_regex_effbot(loops): def run_pgo(): global USE_BYTES - bench_regex_effbot(1) + bench_regex_effbot(10) USE_BYTES = True - bench_regex_effbot(1) + bench_regex_effbot(10) diff --git a/Lib/test/pgo_task/bm_richards.py b/Lib/test/pgo_task/bm_richards.py index bb91fef6692e10..8ab6c37b967105 100644 --- a/Lib/test/pgo_task/bm_richards.py +++ b/Lib/test/pgo_task/bm_richards.py @@ -415,4 +415,4 @@ def run(self, iterations): def run_pgo(): richard = Richards() - richard.run(1) + richard.run(10) diff --git a/Lib/test/pgo_task/bm_richards_super.py b/Lib/test/pgo_task/bm_richards_super.py index acf0a497f84046..2d782102e39225 100644 --- a/Lib/test/pgo_task/bm_richards_super.py +++ b/Lib/test/pgo_task/bm_richards_super.py @@ -421,4 +421,4 @@ def run(self, iterations): def run_pgo(): richard = Richards() - richard.run(1) + richard.run(10) diff --git a/Lib/test/pgo_task/bm_spectral_norm.py b/Lib/test/pgo_task/bm_spectral_norm.py index b5572f04c079b9..ea2b635f99fd4f 100644 --- a/Lib/test/pgo_task/bm_spectral_norm.py +++ b/Lib/test/pgo_task/bm_spectral_norm.py @@ -64,5 +64,5 @@ def bench_spectral_norm(loops): def run_pgo(): - loops = 1 + loops = 5 bench_spectral_norm(loops) diff --git a/Lib/test/pgo_task/bm_sqlite_synth.py b/Lib/test/pgo_task/bm_sqlite_synth.py index 2ca953de350546..375ca608b848b6 100644 --- a/Lib/test/pgo_task/bm_sqlite_synth.py +++ b/Lib/test/pgo_task/bm_sqlite_synth.py @@ -46,4 +46,5 @@ def bench_sqlite(loops): def run_pgo(): - bench_sqlite(loops=100) + for _ in range(20): + bench_sqlite(loops=200) diff --git a/Lib/test/pgo_task/bm_typing_runtime_protocols.py b/Lib/test/pgo_task/bm_typing_runtime_protocols.py index f76bf9d584d6c6..1f875b6e85d3c4 100644 --- a/Lib/test/pgo_task/bm_typing_runtime_protocols.py +++ b/Lib/test/pgo_task/bm_typing_runtime_protocols.py @@ -165,4 +165,5 @@ def bench_protocols(loops: int) -> float: def run_pgo(): - bench_protocols(100) + for _ in range(10): + bench_protocols(100) diff --git a/Lib/test/pgo_task/bm_unpack_sequence.py b/Lib/test/pgo_task/bm_unpack_sequence.py index fc3a6801f79845..0ca40db9effc2d 100644 --- a/Lib/test/pgo_task/bm_unpack_sequence.py +++ b/Lib/test/pgo_task/bm_unpack_sequence.py @@ -129,4 +129,5 @@ def run_pgo(): benchmarks = {"tuple": bench_tuple_unpacking, "list": bench_list_unpacking} func = bench_all - func(1000) + for _ in range(10): + func(1000) From 8dd8862d4043c400842e1e93d63b0181fb840d88 Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Fri, 28 Feb 2025 10:31:26 -0800 Subject: [PATCH 4/4] Use argparse, tweak output. --- Lib/test/pgo_task/__main__.py | 23 ++++++++++++++++++----- Lib/test/pgo_task/bm_chaos.py | 5 +++-- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/Lib/test/pgo_task/__main__.py b/Lib/test/pgo_task/__main__.py index fac6c3abe1c273..d5e9e5e8b53085 100644 --- a/Lib/test/pgo_task/__main__.py +++ b/Lib/test/pgo_task/__main__.py @@ -3,29 +3,42 @@ import importlib import os import time +import argparse def main(): - cmdline_tasks = set(sys.argv[1:]) + parser = argparse.ArgumentParser() + parser.add_argument( + '-n', + '--iterations', + type=int, + default=1, + help='Number of iterations to run.', + ) + parser.add_argument('tasks', nargs='*', help='Name of tasks to run.') + args = parser.parse_args() + cmdline_tasks = set(args.tasks) tasks = [] package_dir = os.path.dirname(__file__) for fn in glob.glob(os.path.join(package_dir, 'bm_*.py')): tasks.append(fn) total_time = 0 + print('Running PGO tasks...') for fn in sorted(tasks): name, ext = os.path.splitext(os.path.basename(fn)) if cmdline_tasks and name not in cmdline_tasks: continue module = importlib.import_module(f'test.pgo_task.{name}') if not hasattr(module, 'run_pgo'): - print('missing run_pgo', fn) + print('task module missing run_pgo()', fn) continue t0 = time.perf_counter() - print('Running task', name, end='...') - module.run_pgo() + print(f'{name:>40}', end='', flush=True) + for _ in range(args.iterations): + module.run_pgo() tm = time.perf_counter() - t0 total_time += tm - print(f' {tm:.3f} seconds.') + print(f' {tm:.3f}s') print(f'Total time for tasks {total_time:.3f} seconds') diff --git a/Lib/test/pgo_task/bm_chaos.py b/Lib/test/pgo_task/bm_chaos.py index 635c9379e53904..c2e1560aa10884 100644 --- a/Lib/test/pgo_task/bm_chaos.py +++ b/Lib/test/pgo_task/bm_chaos.py @@ -286,5 +286,6 @@ def run_pgo(): type=int, default=DEFAULT_RNG_SEED, help="Random number generator seed (default: %s)" % DEFAULT_RNG_SEED) - args = cmd.parse_args() - main(args) + args = cmd.parse_args([]) + for _ in range(5): + main(args)