From 550cc8cc033e07f3550b6c78e38116052df9b16a Mon Sep 17 00:00:00 2001 From: McLavish Date: Thu, 30 Oct 2025 08:53:26 +0100 Subject: [PATCH 01/58] added bert as a test inference benchmark --- .../412.language-bert/config.json | 6 + .../400.inference/412.language-bert/input.py | 31 ++++ .../412.language-bert/python/function.py | 152 ++++++++++++++++++ .../412.language-bert/python/init.sh | 3 + .../412.language-bert/python/package.sh | 35 ++++ .../412.language-bert/python/requirements.txt | 3 + .../python/requirements.txt.3.10 | 3 + .../python/requirements.txt.3.11 | 3 + .../python/requirements.txt.3.8 | 3 + .../python/requirements.txt.3.9 | 3 + docs/benchmarks.md | 6 +- sebs/regression.py | 1 + 12 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 benchmarks/400.inference/412.language-bert/config.json create mode 100644 benchmarks/400.inference/412.language-bert/input.py create mode 100644 benchmarks/400.inference/412.language-bert/python/function.py create mode 100755 benchmarks/400.inference/412.language-bert/python/init.sh create mode 100644 benchmarks/400.inference/412.language-bert/python/package.sh create mode 100644 benchmarks/400.inference/412.language-bert/python/requirements.txt create mode 100644 benchmarks/400.inference/412.language-bert/python/requirements.txt.3.10 create mode 100644 benchmarks/400.inference/412.language-bert/python/requirements.txt.3.11 create mode 100644 benchmarks/400.inference/412.language-bert/python/requirements.txt.3.8 create mode 100644 benchmarks/400.inference/412.language-bert/python/requirements.txt.3.9 diff --git a/benchmarks/400.inference/412.language-bert/config.json b/benchmarks/400.inference/412.language-bert/config.json new file mode 100644 index 000000000..94ede7925 --- /dev/null +++ b/benchmarks/400.inference/412.language-bert/config.json @@ -0,0 +1,6 @@ +{ + "timeout": 60, + "memory": 512, + "languages": ["python"], + "modules": ["storage"] +} diff --git a/benchmarks/400.inference/412.language-bert/input.py b/benchmarks/400.inference/412.language-bert/input.py new file mode 100644 index 000000000..f3daa83bc --- /dev/null +++ b/benchmarks/400.inference/412.language-bert/input.py @@ -0,0 +1,31 @@ +import os + + +def buckets_count(): + # model bucket and text bucket + return (2, 0) + + +def upload_files(data_root, data_dir, upload_func): + for root, _, files in os.walk(data_dir): + prefix = os.path.relpath(root, data_root) + for file in files: + filepath = os.path.join(root, file) + relative_key = os.path.join(prefix, file) + upload_func(0, relative_key, filepath) + + +def generate_input(data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func): + model_archive = "bert-tiny-onnx.tar.gz" + upload_func(0, model_archive, os.path.join(data_dir, "model", model_archive)) + + text_filename = "sentences.jsonl" + upload_func(1, text_filename, os.path.join(data_dir, "text", text_filename)) + + input_config = {"object": {}, "bucket": {}} + input_config["object"]["model"] = model_archive + input_config["object"]["input"] = text_filename + input_config["bucket"]["bucket"] = benchmarks_bucket + input_config["bucket"]["model"] = input_paths[0] + input_config["bucket"]["text"] = input_paths[1] + return input_config diff --git a/benchmarks/400.inference/412.language-bert/python/function.py b/benchmarks/400.inference/412.language-bert/python/function.py new file mode 100644 index 000000000..3f0761428 --- /dev/null +++ b/benchmarks/400.inference/412.language-bert/python/function.py @@ -0,0 +1,152 @@ +import datetime +import json +import os +import tarfile +import uuid +from typing import Dict, List, Optional + +import numpy as np +import onnxruntime as ort +from tokenizers import Tokenizer + +from . import storage + +client = storage.storage.get_instance() + +MODEL_ARCHIVE = "bert-tiny-onnx.tar.gz" +MODEL_DIRECTORY = "/tmp/bert_language_model" +MODEL_SUBDIR = "bert-tiny-onnx" + +_session: Optional[ort.InferenceSession] = None +_tokenizer: Optional[Tokenizer] = None +_labels: Optional[Dict[int, str]] = None + + +def _ensure_model(bucket: str, model_prefix: str): + """ + Lazily download and initialize the ONNX model and tokenizer. + """ + global _session, _tokenizer, _labels + + model_path = os.path.join(MODEL_DIRECTORY, MODEL_SUBDIR) + model_download_begin = datetime.datetime.now() + model_download_end = model_download_begin + + if _session is None or _tokenizer is None or _labels is None: + if not os.path.exists(model_path): + os.makedirs(MODEL_DIRECTORY, exist_ok=True) + archive_path = os.path.join("/tmp", f"{uuid.uuid4()}-{MODEL_ARCHIVE}") + client.download(bucket, os.path.join(model_prefix, MODEL_ARCHIVE), archive_path) + model_download_end = datetime.datetime.now() + + with tarfile.open(archive_path, "r:gz") as tar: + tar.extractall(MODEL_DIRECTORY) + os.remove(archive_path) + else: + model_download_begin = datetime.datetime.now() + model_download_end = model_download_begin + + model_process_begin = datetime.datetime.now() + tokenizer_path = os.path.join(model_path, "tokenizer.json") + _tokenizer = Tokenizer.from_file(tokenizer_path) + _tokenizer.enable_truncation(max_length=128) + _tokenizer.enable_padding(length=128) + + label_map_path = os.path.join(model_path, "label_map.json") + with open(label_map_path, "r") as f: + raw_labels = json.load(f) + _labels = {int(idx): label for idx, label in raw_labels.items()} + + onnx_path = os.path.join(model_path, "model.onnx") + _session = ort.InferenceSession(onnx_path, providers=["CPUExecutionProvider"]) + model_process_end = datetime.datetime.now() + else: + model_process_begin = datetime.datetime.now() + model_process_end = model_process_begin + + model_download_time = (model_download_end - model_download_begin) / datetime.timedelta( + microseconds=1 + ) + model_process_time = (model_process_end - model_process_begin) / datetime.timedelta( + microseconds=1 + ) + + return model_download_time, model_process_time + + +def _prepare_inputs(sentences: List[str]): + assert _tokenizer is not None + + encodings = _tokenizer.encode_batch(sentences) + + input_ids = np.array([enc.ids for enc in encodings], dtype=np.int64) + attention_mask = np.array([enc.attention_mask for enc in encodings], dtype=np.int64) + token_type_ids = np.array( + [enc.type_ids if enc.type_ids else [0] * len(enc.ids) for enc in encodings], + dtype=np.int64, + ) + + return { + "input_ids": input_ids, + "attention_mask": attention_mask, + "token_type_ids": token_type_ids, + } + + +def _softmax(logits: np.ndarray) -> np.ndarray: + shifted = logits - np.max(logits, axis=1, keepdims=True) + exp = np.exp(shifted) + return exp / np.sum(exp, axis=1, keepdims=True) + + +def handler(event): + bucket = event.get("bucket", {}).get("bucket") + model_prefix = event.get("bucket", {}).get("model") + text_prefix = event.get("bucket", {}).get("text") + text_key = event.get("object", {}).get("input") + + download_begin = datetime.datetime.now() + text_download_path = os.path.join("/tmp", f"{uuid.uuid4()}-{os.path.basename(text_key)}") + client.download(bucket, os.path.join(text_prefix, text_key), text_download_path) + download_end = datetime.datetime.now() + + model_download_time, model_process_time = _ensure_model(bucket, model_prefix) + assert _session is not None and _labels is not None and _tokenizer is not None + + with open(text_download_path, "r") as f: + sentences = [json.loads(line)["text"] for line in f if line.strip()] + + os.remove(text_download_path) + + inference_begin = datetime.datetime.now() + inputs = _prepare_inputs(sentences) + outputs = _session.run(None, inputs) + logits = outputs[0] + probabilities = _softmax(logits) + inference_end = datetime.datetime.now() + + results = [] + for sentence, probs in zip(sentences, probabilities): + label_idx = int(np.argmax(probs)) + label = _labels.get(label_idx, str(label_idx)) + results.append( + { + "text": sentence, + "label": label, + "confidence": float(probs[label_idx]), + "raw_scores": probs.tolist(), + } + ) + + download_time = (download_end - download_begin) / datetime.timedelta(microseconds=1) + compute_time = (inference_end - inference_begin) / datetime.timedelta(microseconds=1) + + return { + "result": {"predictions": results}, + "measurement": { + "download_time": download_time + model_download_time, + "compute_time": compute_time + model_process_time, + "model_time": model_process_time, + "model_download_time": model_download_time, + }, + } diff --git a/benchmarks/400.inference/412.language-bert/python/init.sh b/benchmarks/400.inference/412.language-bert/python/init.sh new file mode 100755 index 000000000..160852abe --- /dev/null +++ b/benchmarks/400.inference/412.language-bert/python/init.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +# No additional initialization required for the BERT inference benchmark. diff --git a/benchmarks/400.inference/412.language-bert/python/package.sh b/benchmarks/400.inference/412.language-bert/python/package.sh new file mode 100644 index 000000000..edb27ebe0 --- /dev/null +++ b/benchmarks/400.inference/412.language-bert/python/package.sh @@ -0,0 +1,35 @@ +# Stripping package code is based on https://github.com/ryfeus/lambda-packs repo + +PACKAGE_DIR=$1 +echo "Original size $(du -sh $1 | cut -f1)" + +CUR_DIR=$(pwd) +cd $1 +# cleaning libs +rm -rf external +find . -type d -name "tests" -exec rm -rf {} + +find . -type d -name "test" -exec rm -rf {} + +find . -type d -name "bin" -not -path "*/torch/*" -exec rm -rf {} + + +# cleaning +# stripping some of the numpy libs - libgfortran-2e0d59d6.so.5.0.0 - causes issues on Azure +find -name "*.so" -not -path "*/PIL/*" -not -path "*/Pillow.libs/*" -not -path "*libgfortran*" | xargs strip +find -name "*.so.*" -not -path "*/PIL/*" -not -path "*/Pillow.libs/*" -not -path "*libgfortran*" | xargs strip + +rm -r pip >/dev/null +rm -r pip-* >/dev/null +rm -r wheel >/dev/null +rm -r wheel-* >/dev/null +rm easy_install.py >/dev/null +find . -name \*.pyc -delete +cd ${CUR_DIR} +echo "Stripped size $(du -sh $1 | cut -f1)" + +TORCH_DIR=".python_packages/lib/site-packages/torch" +if [ -d "$1/${TORCH_DIR}" ]; then + cd $1 + zip -qr torch.zip ${TORCH_DIR} + rm -rf ${TORCH_DIR} + cd ${CUR_DIR} + echo "Torch-zipped size $(du -sh $1 | cut -f1)" +fi diff --git a/benchmarks/400.inference/412.language-bert/python/requirements.txt b/benchmarks/400.inference/412.language-bert/python/requirements.txt new file mode 100644 index 000000000..b692be1f7 --- /dev/null +++ b/benchmarks/400.inference/412.language-bert/python/requirements.txt @@ -0,0 +1,3 @@ +numpy==1.24.4 +onnxruntime==1.16.3 +tokenizers==0.13.3 diff --git a/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.10 b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.10 new file mode 100644 index 000000000..b692be1f7 --- /dev/null +++ b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.10 @@ -0,0 +1,3 @@ +numpy==1.24.4 +onnxruntime==1.16.3 +tokenizers==0.13.3 diff --git a/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.11 b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.11 new file mode 100644 index 000000000..b692be1f7 --- /dev/null +++ b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.11 @@ -0,0 +1,3 @@ +numpy==1.24.4 +onnxruntime==1.16.3 +tokenizers==0.13.3 diff --git a/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.8 b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.8 new file mode 100644 index 000000000..b692be1f7 --- /dev/null +++ b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.8 @@ -0,0 +1,3 @@ +numpy==1.24.4 +onnxruntime==1.16.3 +tokenizers==0.13.3 diff --git a/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.9 b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.9 new file mode 100644 index 000000000..b692be1f7 --- /dev/null +++ b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.9 @@ -0,0 +1,3 @@ +numpy==1.24.4 +onnxruntime==1.16.3 +tokenizers==0.13.3 diff --git a/docs/benchmarks.md b/docs/benchmarks.md index e292a4b04..73056c86c 100644 --- a/docs/benchmarks.md +++ b/docs/benchmarks.md @@ -10,6 +10,7 @@ | Multimedia | 220.video-processing | Python | x64, arm64 | Add a watermark and generate gif of a video file. | | Utilities | 311.compression | Python | x64, arm64 | Create a .zip file for a group of files in storage and return to user to download. | | Inference | 411.image-recognition | Python | x64 | Image recognition with ResNet and pytorch. | +| Inference | 412.language-bert | Python | x64 | Sentence classification with a compact BERT model served via ONNX Runtime. | | Scientific | 501.graph-pagerank | Python | x64, arm64 | PageRank implementation with igraph. | | Scientific | 502.graph-mst | Python | x64, arm64 | Minimum spanning tree (MST) implementation with igraph. | | Scientific | 503.graph-bfs | Python | x64, arm64 | Breadth-first search (BFS) implementation with igraph. | @@ -70,6 +71,10 @@ It implements the .zip file creation with the help of the `shutil` standard libr The benchmark is inspired by MLPerf and implements image recognition with Resnet50. It downloads the input and model from the storage and uses the CPU-only `pytorch` library in Python. +### Language Inference + +This benchmark runs sequence classification with a compact BERT model exported to ONNX. The function downloads the model archive and text samples from storage, tokenizes the sentences, executes the ONNX Runtime session, and returns the predicted labels together with confidences. + ## Scientific ### Graph PageRank, BFS, MST @@ -87,4 +92,3 @@ This benchmark is inspired by the [DNAVisualization](https://github.com/Benjamin ## Applications **(WiP)** Coming soon! - diff --git a/sebs/regression.py b/sebs/regression.py index 579760a1c..e0eaf7f4f 100644 --- a/sebs/regression.py +++ b/sebs/regression.py @@ -21,6 +21,7 @@ "220.video-processing", "311.compression", "411.image-recognition", + "412.language-bert", "501.graph-pagerank", "502.graph-mst", "503.graph-bfs", From f9c3817f0992b849f972d38144b4ad92053bb83b Mon Sep 17 00:00:00 2001 From: McLavish Date: Mon, 3 Nov 2025 22:11:05 +0100 Subject: [PATCH 02/58] hotfix to enable gpu capabilities --- sebs/local/local.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sebs/local/local.py b/sebs/local/local.py index 32b9f9ffb..4bfa069a7 100644 --- a/sebs/local/local.py +++ b/sebs/local/local.py @@ -221,8 +221,9 @@ def _start_container( container_kwargs["command"] = f"/bin/bash /sebs/run_server.sh {port}" container_kwargs["ports"] = {f"{port}/tcp": port} - - container = self._docker_client.containers.run(**container_kwargs) + + from docker.types import DeviceRequest + container = self._docker_client.containers.run(**container_kwargs, device_requests=[DeviceRequest(driver="nvidia", count=-1, capabilities=[["gpu"]])], ) pid: Optional[int] = None if self.measurements_enabled and self._memory_measurement_path is not None: From 0f93b6608007844099f5f13f177a24b3bc6c2b2b Mon Sep 17 00:00:00 2001 From: McLavish Date: Tue, 4 Nov 2025 15:38:39 +0100 Subject: [PATCH 03/58] added pre-commit hooks for linting and formatting --- .pre-commit-config.yaml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..3389b494a --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,21 @@ +# .pre-commit-config.yaml +repos: + - repo: local + hooks: + - id: flake8-local + name: flake8 (project env) + entry: flake8 + language: system + args: ["--config=.flake8.cfg"] + types: [python] + files: ^sebs/ + - repo: local + hooks: + - id: black-check-local + name: black --check (project env) + entry: black + language: system + args: ["--config=.black.toml", "--check", "--diff"] + types: [python] + files: ^sebs/ + From b965d7bd302782d130766c7bdc6a2938928627e0 Mon Sep 17 00:00:00 2001 From: McLavish Date: Tue, 4 Nov 2025 16:34:14 +0100 Subject: [PATCH 04/58] linting and formatting setting for whoever uses vscode + black + flake8 extensions --- .vscode/settings.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..127ae8a76 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,15 @@ +{ + "[python]": { + "editor.defaultFormatter": "ms-python.black-formatter", + "editor.formatOnSave": true + }, + + "black-formatter.importStrategy": "fromEnvironment", + "black-formatter.path": [], + "black-formatter.args": ["--config=.black.toml"], + + "flake8.importStrategy": "fromEnvironment", + "flake8.path": [], + "flake8.args": ["--config=.flake8.cfg"], + "flake8.enabled": true +} From e9916db6ea0a5e7cd019487d90b2b315ee0f2073 Mon Sep 17 00:00:00 2001 From: McLavish Date: Tue, 4 Nov 2025 17:25:51 +0100 Subject: [PATCH 05/58] reformatted local file so it passes linting/format --- .pre-commit-config.yaml | 6 ++++-- sebs/local/local.py | 8 ++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3389b494a..22e59d275 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,8 +4,9 @@ repos: hooks: - id: flake8-local name: flake8 (project env) + language: python + additional_dependencies: ["flake8==7.1.1"] entry: flake8 - language: system args: ["--config=.flake8.cfg"] types: [python] files: ^sebs/ @@ -13,8 +14,9 @@ repos: hooks: - id: black-check-local name: black --check (project env) + language: python + additional_dependencies: ["black==22.8.0"] entry: black - language: system args: ["--config=.black.toml", "--check", "--diff"] types: [python] files: ^sebs/ diff --git a/sebs/local/local.py b/sebs/local/local.py index 4bfa069a7..7f49974e5 100644 --- a/sebs/local/local.py +++ b/sebs/local/local.py @@ -221,9 +221,13 @@ def _start_container( container_kwargs["command"] = f"/bin/bash /sebs/run_server.sh {port}" container_kwargs["ports"] = {f"{port}/tcp": port} - + from docker.types import DeviceRequest - container = self._docker_client.containers.run(**container_kwargs, device_requests=[DeviceRequest(driver="nvidia", count=-1, capabilities=[["gpu"]])], ) + + container = self._docker_client.containers.run( + **container_kwargs, + device_requests=[DeviceRequest(driver="nvidia", count=-1, capabilities=[["gpu"]])], + ) pid: Optional[int] = None if self.measurements_enabled and self._memory_measurement_path is not None: From 813af03cce3261e1a5cd52d8bc47842bbea08474 Mon Sep 17 00:00:00 2001 From: McLavish Date: Tue, 4 Nov 2025 17:48:16 +0100 Subject: [PATCH 06/58] bert now uses gpu --- benchmarks/400.inference/412.language-bert/input.py | 4 +++- .../400.inference/412.language-bert/python/function.py | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/benchmarks/400.inference/412.language-bert/input.py b/benchmarks/400.inference/412.language-bert/input.py index f3daa83bc..9af7ecb56 100644 --- a/benchmarks/400.inference/412.language-bert/input.py +++ b/benchmarks/400.inference/412.language-bert/input.py @@ -15,7 +15,9 @@ def upload_files(data_root, data_dir, upload_func): upload_func(0, relative_key, filepath) -def generate_input(data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func): +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): model_archive = "bert-tiny-onnx.tar.gz" upload_func(0, model_archive, os.path.join(data_dir, "model", model_archive)) diff --git a/benchmarks/400.inference/412.language-bert/python/function.py b/benchmarks/400.inference/412.language-bert/python/function.py index 3f0761428..b3d6efe12 100644 --- a/benchmarks/400.inference/412.language-bert/python/function.py +++ b/benchmarks/400.inference/412.language-bert/python/function.py @@ -58,7 +58,11 @@ def _ensure_model(bucket: str, model_prefix: str): _labels = {int(idx): label for idx, label in raw_labels.items()} onnx_path = os.path.join(model_path, "model.onnx") - _session = ort.InferenceSession(onnx_path, providers=["CPUExecutionProvider"]) + available_providers = ort.get_available_providers() + execution_providers = ["CUDAExecutionProvider"] if "CUDAExecutionProvider" in available_providers else [] + execution_providers.append("CPUExecutionProvider") + # Prefer GPU execution when available, otherwise fall back to CPU. + _session = ort.InferenceSession(onnx_path, providers=execution_providers) model_process_end = datetime.datetime.now() else: model_process_begin = datetime.datetime.now() From 3a96f0433db368dcdf87be1d13175bd4f5a7ff22 Mon Sep 17 00:00:00 2001 From: McLavish Date: Tue, 4 Nov 2025 18:13:33 +0100 Subject: [PATCH 07/58] changed data repo to be OUR forked data repo --- .gitmodules | 2 +- install.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 4feae9bfb..c33a17880 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,4 +3,4 @@ url = https://github.com/mcopik/pypapi.git [submodule "benchmarks-data"] path = benchmarks-data - url = https://github.com/spcl/serverless-benchmarks-data.git + url = https://github.com/McLavish/serverless-benchmarks-data-dphpc.git diff --git a/install.py b/install.py index 57f047d23..b856e45b7 100755 --- a/install.py +++ b/install.py @@ -86,7 +86,7 @@ def execute(cmd, cwd=None): execute(f"git pull", cwd=data_dir) # clone else: - execute(f"git clone https://github.com/spcl/serverless-benchmarks-data.git {data_dir}") + execute(f"git clone https://github.com/McLavish/serverless-benchmarks-data-dphpc.git {data_dir}") else: raise error @@ -99,4 +99,3 @@ def execute(cmd, cwd=None): execute("python3 setup.py build") execute("python3 pypapi/papi_build.py") os.chdir(cur_dir) - From d4d5d30ab57f99946d19247f3bf60c9c1d5c4eeb Mon Sep 17 00:00:00 2001 From: Russellpang Date: Wed, 5 Nov 2025 01:16:51 +0100 Subject: [PATCH 08/58] change data loading path to own forked repo --- install.py | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/install.py b/install.py index 57f047d23..784b0ab28 100755 --- a/install.py +++ b/install.py @@ -5,28 +5,46 @@ import subprocess parser = argparse.ArgumentParser(description="Install SeBS and dependencies.") -parser.add_argument('--venv', metavar='DIR', type=str, default="python-venv", help='destination of local Python virtual environment') -parser.add_argument('--python-path', metavar='DIR', type=str, default="python3", help='Path to local Python installation.') +parser.add_argument( + "--venv", + metavar="DIR", + type=str, + default="python-venv", + help="destination of local Python virtual environment", +) +parser.add_argument( + "--python-path", + metavar="DIR", + type=str, + default="python3", + help="Path to local Python installation.", +) for deployment in ["aws", "azure", "gcp", "openwhisk"]: - parser.add_argument(f"--{deployment}", action="store_const", const=True, default=True, dest=deployment) - parser.add_argument(f"--no-{deployment}", action="store_const", const=False, default=True, dest=deployment) + parser.add_argument( + f"--{deployment}", action="store_const", const=True, default=True, dest=deployment + ) + parser.add_argument( + f"--no-{deployment}", action="store_const", const=False, default=True, dest=deployment + ) for deployment in ["local"]: - parser.add_argument(f"--{deployment}", action="store_const", default=True, const=True, dest=deployment) + parser.add_argument( + f"--{deployment}", action="store_const", default=True, const=True, dest=deployment + ) parser.add_argument(f"--no-{deployment}", action="store_const", const=False, dest=deployment) parser.add_argument("--with-pypapi", action="store_true") args = parser.parse_args() + def execute(cmd, cwd=None): - ret = subprocess.run( - cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, cwd=cwd - ) + ret = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, cwd=cwd) if ret.returncode: raise RuntimeError( "Running {} failed!\n Output: {}".format(cmd, ret.stdout.decode("utf-8")) ) return ret.stdout.decode("utf-8") -env_dir=args.venv + +env_dir = args.venv if not os.path.exists(env_dir): print("Creating Python virtualenv at {}".format(env_dir)) @@ -86,7 +104,9 @@ def execute(cmd, cwd=None): execute(f"git pull", cwd=data_dir) # clone else: - execute(f"git clone https://github.com/spcl/serverless-benchmarks-data.git {data_dir}") + execute( + f"git clone https://github.com/McLavish/serverless-benchmarks-data-dphpc.git {data_dir}" + ) else: raise error @@ -99,4 +119,3 @@ def execute(cmd, cwd=None): execute("python3 setup.py build") execute("python3 pypapi/papi_build.py") os.chdir(cur_dir) - From 1b7deb7c03c86bc6491e8da47964feb59c6bc920 Mon Sep 17 00:00:00 2001 From: Russellpang Date: Wed, 5 Nov 2025 01:21:34 +0100 Subject: [PATCH 09/58] change data loading path to own forked repo --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 4feae9bfb..362530502 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,4 +3,4 @@ url = https://github.com/mcopik/pypapi.git [submodule "benchmarks-data"] path = benchmarks-data - url = https://github.com/spcl/serverless-benchmarks-data.git + url = https://github.com/McLavish/serverless-benchmarks-data-dphpc.git \ No newline at end of file From 668652c58a794bb14411032f1564063d8da6bb12 Mon Sep 17 00:00:00 2001 From: Russellpang Date: Wed, 5 Nov 2025 02:23:21 +0100 Subject: [PATCH 10/58] update benchmark function --- .../413.image-classification/config.json | 6 + .../413.image-classification/input.py | 51 ++++++ .../python/function.py | 156 ++++++++++++++++++ .../python/imagenet_class_index.json | 1 + .../413.image-classification/python/init.sh | 10 ++ .../python/package.sh | 32 ++++ .../python/requirements.txt | 4 + .../python/requirements.txt.3.10 | 5 + .../python/requirements.txt.3.11 | 5 + .../python/requirements.txt.3.6 | 4 + .../python/requirements.txt.3.7 | 4 + .../python/requirements.txt.3.8 | 3 + .../python/requirements.txt.3.9 | 3 + 13 files changed, 284 insertions(+) create mode 100644 benchmarks/400.inference/413.image-classification/config.json create mode 100644 benchmarks/400.inference/413.image-classification/input.py create mode 100644 benchmarks/400.inference/413.image-classification/python/function.py create mode 100755 benchmarks/400.inference/413.image-classification/python/imagenet_class_index.json create mode 100755 benchmarks/400.inference/413.image-classification/python/init.sh create mode 100644 benchmarks/400.inference/413.image-classification/python/package.sh create mode 100644 benchmarks/400.inference/413.image-classification/python/requirements.txt create mode 100644 benchmarks/400.inference/413.image-classification/python/requirements.txt.3.10 create mode 100644 benchmarks/400.inference/413.image-classification/python/requirements.txt.3.11 create mode 100644 benchmarks/400.inference/413.image-classification/python/requirements.txt.3.6 create mode 100644 benchmarks/400.inference/413.image-classification/python/requirements.txt.3.7 create mode 100644 benchmarks/400.inference/413.image-classification/python/requirements.txt.3.8 create mode 100644 benchmarks/400.inference/413.image-classification/python/requirements.txt.3.9 diff --git a/benchmarks/400.inference/413.image-classification/config.json b/benchmarks/400.inference/413.image-classification/config.json new file mode 100644 index 000000000..94ede7925 --- /dev/null +++ b/benchmarks/400.inference/413.image-classification/config.json @@ -0,0 +1,6 @@ +{ + "timeout": 60, + "memory": 512, + "languages": ["python"], + "modules": ["storage"] +} diff --git a/benchmarks/400.inference/413.image-classification/input.py b/benchmarks/400.inference/413.image-classification/input.py new file mode 100644 index 000000000..e97d38057 --- /dev/null +++ b/benchmarks/400.inference/413.image-classification/input.py @@ -0,0 +1,51 @@ +import glob, os + + +def buckets_count(): + return (2, 0) + + +def upload_files(data_root, data_dir, upload_func): + + for root, dirs, files in os.walk(data_dir): + prefix = os.path.relpath(root, data_root) + for file in files: + file_name = prefix + "/" + file + filepath = os.path.join(root, file) + upload_func(0, file_name, filepath) + + +""" + Generate test, small and large workload for compression test. + + :param data_dir: directory where benchmark data is placed + :param size: workload size + :param input_buckets: input storage containers for this benchmark + :param output_buckets: + :param upload_func: upload function taking three params(bucket_idx, key, filepath) +""" + + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): + + # upload model + model_name = "resnet50.tar.gz" + upload_func(0, model_name, os.path.join(data_dir, "model", model_name)) + + input_images = [] + resnet_path = os.path.join(data_dir, "fake-resnet") + with open(os.path.join(resnet_path, "val_map.txt"), "r") as f: + for line in f: + img, img_class = line.split() + input_images.append((img, img_class)) + upload_func(1, img, os.path.join(resnet_path, img)) + + input_config = {"object": {}, "bucket": {}} + input_config["object"]["model"] = model_name + input_config["object"]["input"] = input_images[0][0] + input_config["bucket"]["bucket"] = benchmarks_bucket + input_config["bucket"]["input"] = input_paths[1] + input_config["bucket"]["model"] = input_paths[0] + return input_config diff --git a/benchmarks/400.inference/413.image-classification/python/function.py b/benchmarks/400.inference/413.image-classification/python/function.py new file mode 100644 index 000000000..1ee9d653a --- /dev/null +++ b/benchmarks/400.inference/413.image-classification/python/function.py @@ -0,0 +1,156 @@ +import datetime, json, os, tarfile +from pathlib import Path + +from PIL import Image +import torch +from torchvision import transforms +from torchvision.models import resnet50 + +# ---------- Config ---------- +# Optional env overrides; event fields take precedence if provided +ENV_MODEL_PATH = os.getenv("MODEL_PATH") # /abs/path/resnet50.tar.gz or .pth/.pt +ENV_IMAGE_PATH = os.getenv("IMAGE_PATH") # /abs/path/test.jpg +USE_AMP = True # autocast for faster inference on CUDA +# ---------------------------- + +SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__)) +class_idx = json.load(open(os.path.join(SCRIPT_DIR, "imagenet_class_index.json"), "r")) +idx2label = [class_idx[str(k)][1] for k in range(len(class_idx))] + +DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") +torch.backends.cudnn.benchmark = True + +model = None # cache across invocations (same as your original) + + +def _extract_pth_from_tar(tar_path: str, out_dir: str = "/tmp/resnet50_unpack") -> str: + """Extract .tar.gz/.tgz and return the first .pth/.pt found.""" + out = Path(out_dir) + out.mkdir(parents=True, exist_ok=True) + with tarfile.open(tar_path, "r:gz") as tar: + tar.extractall(out) + for ext in ("*.pth", "*.pt"): + found = list(out.rglob(ext)) + if found: + return str(found[0]) + raise FileNotFoundError(f"No .pth/.pt found in archive: {tar_path}") + + +def _load_resnet50_from_path(model_path: str) -> torch.nn.Module: + """Load torchvision ResNet-50 from a local .tar.gz or .pth/.pt (CPU), then return it.""" + if model_path.endswith((".tar.gz", ".tgz")): + weight_path = _extract_pth_from_tar(model_path) + else: + weight_path = model_path + + ckpt = torch.load(weight_path, map_location="cpu") + if isinstance(ckpt, dict): + state = ckpt.get("state_dict", ckpt.get("model", ckpt)) + if not isinstance(state, dict): + state = ckpt + if len(state) > 0 and next(iter(state)).startswith("module."): + state = {k.replace("module.", "", 1): v for k, v in state.items()} + m = resnet50(pretrained=False) + m.load_state_dict(state, strict=False) + m.eval() + return m + elif isinstance(ckpt, torch.nn.Module): + ckpt.eval() + return ckpt + else: + raise TypeError(f"Unsupported checkpoint type: {type(ckpt)}") + + +def _maybe_sync(): + if DEVICE.type == "cuda": + torch.cuda.synchronize() + + +def handler(event): + """ + Accepts local paths via event (preferred for your benchmark runner): + event = { + "local_model_archive": "/abs/path/resnet50.tar.gz" or ".pth", + "local_image_path": "/abs/path/image.jpg" + } + Falls back to env MODEL_PATH / IMAGE_PATH if not provided. + Returns the SAME structure as your existing function.py. + """ + if not torch.cuda.is_available(): + raise RuntimeError("CUDA not available. Run on a GPU machine/container.") + + # -------- resolve inputs -------- + model_path = event.get("local_model_archive") or ENV_MODEL_PATH + image_path = event.get("local_image_path") or ENV_IMAGE_PATH + assert model_path, "Provide local_model_archive in event or set MODEL_PATH" + assert image_path, "Provide local_image_path in event or set IMAGE_PATH" + + # -------- timings: image "download" (local -> count as zero) -------- + image_download_begin = datetime.datetime.now() + image_download_end = image_download_begin # local file, no download + + # -------- lazy model load (cache like your original) -------- + global model + if model is None: + model_download_begin = datetime.datetime.now() + model_download_end = model_download_begin # local file, no remote download + + model_process_begin = datetime.datetime.now() + # load on CPU, then move to GPU + m = _load_resnet50_from_path(model_path) + model = m.to(DEVICE, non_blocking=True).eval() + _maybe_sync() + model_process_end = datetime.datetime.now() + else: + # reuse cached model + model_download_begin = model_download_end = datetime.datetime.now() + model_process_begin = model_process_end = model_download_begin + + # -------- preprocess + inference on GPU (with proper sync) -------- + input_image = Image.open(image_path).convert("RGB") + preprocess = transforms.Compose( + [ + transforms.Resize(256), + transforms.CenterCrop(224), + transforms.ToTensor(), + transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), + ] + ) + input_tensor = preprocess(input_image).unsqueeze(0) # [1,3,224,224] + + _maybe_sync() + process_begin = datetime.datetime.now() + with torch.inference_mode(): + x = input_tensor.to(DEVICE, non_blocking=True) + if USE_AMP and DEVICE.type == "cuda": + with torch.cuda.amp.autocast(): + y = model(x) + else: + y = model(x) + _maybe_sync() + process_end = datetime.datetime.now() + + # -------- postprocess -------- + probs = torch.softmax(y[0], dim=0) + idx = int(torch.argmax(probs).item()) + pred = idx2label[idx] + + # -------- SAME measurement keys (microseconds) -------- + download_time = (image_download_end - image_download_begin) / datetime.timedelta(microseconds=1) + model_download_time = (model_download_end - model_download_begin) / datetime.timedelta( + microseconds=1 + ) + model_process_time = (model_process_end - model_process_begin) / datetime.timedelta( + microseconds=1 + ) + process_time = (process_end - process_begin) / datetime.timedelta(microseconds=1) + + return { + "result": {"idx": idx, "class": pred}, + "measurement": { + "download_time": download_time + model_download_time, + "compute_time": process_time + model_process_time, + "model_time": model_process_time, + "model_download_time": model_download_time, + }, + } diff --git a/benchmarks/400.inference/413.image-classification/python/imagenet_class_index.json b/benchmarks/400.inference/413.image-classification/python/imagenet_class_index.json new file mode 100755 index 000000000..5fe0dfefc --- /dev/null +++ b/benchmarks/400.inference/413.image-classification/python/imagenet_class_index.json @@ -0,0 +1 @@ +{"0": ["n01440764", "tench"], "1": ["n01443537", "goldfish"], "2": ["n01484850", "great_white_shark"], "3": ["n01491361", "tiger_shark"], "4": ["n01494475", "hammerhead"], "5": ["n01496331", "electric_ray"], "6": ["n01498041", "stingray"], "7": ["n01514668", "cock"], "8": ["n01514859", "hen"], "9": ["n01518878", "ostrich"], "10": ["n01530575", "brambling"], "11": ["n01531178", "goldfinch"], "12": ["n01532829", "house_finch"], "13": ["n01534433", "junco"], "14": ["n01537544", "indigo_bunting"], "15": ["n01558993", "robin"], "16": ["n01560419", "bulbul"], "17": ["n01580077", "jay"], "18": ["n01582220", "magpie"], "19": ["n01592084", "chickadee"], "20": ["n01601694", "water_ouzel"], "21": ["n01608432", "kite"], "22": ["n01614925", "bald_eagle"], "23": ["n01616318", "vulture"], "24": ["n01622779", "great_grey_owl"], "25": ["n01629819", "European_fire_salamander"], "26": ["n01630670", "common_newt"], "27": ["n01631663", "eft"], "28": ["n01632458", "spotted_salamander"], "29": ["n01632777", "axolotl"], "30": ["n01641577", "bullfrog"], "31": ["n01644373", "tree_frog"], "32": ["n01644900", "tailed_frog"], "33": ["n01664065", "loggerhead"], "34": ["n01665541", "leatherback_turtle"], "35": ["n01667114", "mud_turtle"], "36": ["n01667778", "terrapin"], "37": ["n01669191", "box_turtle"], "38": ["n01675722", "banded_gecko"], "39": ["n01677366", "common_iguana"], "40": ["n01682714", "American_chameleon"], "41": ["n01685808", "whiptail"], "42": ["n01687978", "agama"], "43": ["n01688243", "frilled_lizard"], "44": ["n01689811", "alligator_lizard"], "45": ["n01692333", "Gila_monster"], "46": ["n01693334", "green_lizard"], "47": ["n01694178", "African_chameleon"], "48": ["n01695060", "Komodo_dragon"], "49": ["n01697457", "African_crocodile"], "50": ["n01698640", "American_alligator"], "51": ["n01704323", "triceratops"], "52": ["n01728572", "thunder_snake"], "53": ["n01728920", "ringneck_snake"], "54": ["n01729322", "hognose_snake"], "55": ["n01729977", "green_snake"], "56": ["n01734418", "king_snake"], "57": ["n01735189", "garter_snake"], "58": ["n01737021", "water_snake"], "59": ["n01739381", "vine_snake"], "60": ["n01740131", "night_snake"], "61": ["n01742172", "boa_constrictor"], "62": ["n01744401", "rock_python"], "63": ["n01748264", "Indian_cobra"], "64": ["n01749939", "green_mamba"], "65": ["n01751748", "sea_snake"], "66": ["n01753488", "horned_viper"], "67": ["n01755581", "diamondback"], "68": ["n01756291", "sidewinder"], "69": ["n01768244", "trilobite"], "70": ["n01770081", "harvestman"], "71": ["n01770393", "scorpion"], "72": ["n01773157", "black_and_gold_garden_spider"], "73": ["n01773549", "barn_spider"], "74": ["n01773797", "garden_spider"], "75": ["n01774384", "black_widow"], "76": ["n01774750", "tarantula"], "77": ["n01775062", "wolf_spider"], "78": ["n01776313", "tick"], "79": ["n01784675", "centipede"], "80": ["n01795545", "black_grouse"], "81": ["n01796340", "ptarmigan"], "82": ["n01797886", "ruffed_grouse"], "83": ["n01798484", "prairie_chicken"], "84": ["n01806143", "peacock"], "85": ["n01806567", "quail"], "86": ["n01807496", "partridge"], "87": ["n01817953", "African_grey"], "88": ["n01818515", "macaw"], "89": ["n01819313", "sulphur-crested_cockatoo"], "90": ["n01820546", "lorikeet"], "91": ["n01824575", "coucal"], "92": ["n01828970", "bee_eater"], "93": ["n01829413", "hornbill"], "94": ["n01833805", "hummingbird"], "95": ["n01843065", "jacamar"], "96": ["n01843383", "toucan"], "97": ["n01847000", "drake"], "98": ["n01855032", "red-breasted_merganser"], "99": ["n01855672", "goose"], "100": ["n01860187", "black_swan"], "101": ["n01871265", "tusker"], "102": ["n01872401", "echidna"], "103": ["n01873310", "platypus"], "104": ["n01877812", "wallaby"], "105": ["n01882714", "koala"], "106": ["n01883070", "wombat"], "107": ["n01910747", "jellyfish"], "108": ["n01914609", "sea_anemone"], "109": ["n01917289", "brain_coral"], "110": ["n01924916", "flatworm"], "111": ["n01930112", "nematode"], "112": ["n01943899", "conch"], "113": ["n01944390", "snail"], "114": ["n01945685", "slug"], "115": ["n01950731", "sea_slug"], "116": ["n01955084", "chiton"], "117": ["n01968897", "chambered_nautilus"], "118": ["n01978287", "Dungeness_crab"], "119": ["n01978455", "rock_crab"], "120": ["n01980166", "fiddler_crab"], "121": ["n01981276", "king_crab"], "122": ["n01983481", "American_lobster"], "123": ["n01984695", "spiny_lobster"], "124": ["n01985128", "crayfish"], "125": ["n01986214", "hermit_crab"], "126": ["n01990800", "isopod"], "127": ["n02002556", "white_stork"], "128": ["n02002724", "black_stork"], "129": ["n02006656", "spoonbill"], "130": ["n02007558", "flamingo"], "131": ["n02009229", "little_blue_heron"], "132": ["n02009912", "American_egret"], "133": ["n02011460", "bittern"], "134": ["n02012849", "crane"], "135": ["n02013706", "limpkin"], "136": ["n02017213", "European_gallinule"], "137": ["n02018207", "American_coot"], "138": ["n02018795", "bustard"], "139": ["n02025239", "ruddy_turnstone"], "140": ["n02027492", "red-backed_sandpiper"], "141": ["n02028035", "redshank"], "142": ["n02033041", "dowitcher"], "143": ["n02037110", "oystercatcher"], "144": ["n02051845", "pelican"], "145": ["n02056570", "king_penguin"], "146": ["n02058221", "albatross"], "147": ["n02066245", "grey_whale"], "148": ["n02071294", "killer_whale"], "149": ["n02074367", "dugong"], "150": ["n02077923", "sea_lion"], "151": ["n02085620", "Chihuahua"], "152": ["n02085782", "Japanese_spaniel"], "153": ["n02085936", "Maltese_dog"], "154": ["n02086079", "Pekinese"], "155": ["n02086240", "Shih-Tzu"], "156": ["n02086646", "Blenheim_spaniel"], "157": ["n02086910", "papillon"], "158": ["n02087046", "toy_terrier"], "159": ["n02087394", "Rhodesian_ridgeback"], "160": ["n02088094", "Afghan_hound"], "161": ["n02088238", "basset"], "162": ["n02088364", "beagle"], "163": ["n02088466", "bloodhound"], "164": ["n02088632", "bluetick"], "165": ["n02089078", "black-and-tan_coonhound"], "166": ["n02089867", "Walker_hound"], "167": ["n02089973", "English_foxhound"], "168": ["n02090379", "redbone"], "169": ["n02090622", "borzoi"], "170": ["n02090721", "Irish_wolfhound"], "171": ["n02091032", "Italian_greyhound"], "172": ["n02091134", "whippet"], "173": ["n02091244", "Ibizan_hound"], "174": ["n02091467", "Norwegian_elkhound"], "175": ["n02091635", "otterhound"], "176": ["n02091831", "Saluki"], "177": ["n02092002", "Scottish_deerhound"], "178": ["n02092339", "Weimaraner"], "179": ["n02093256", "Staffordshire_bullterrier"], "180": ["n02093428", "American_Staffordshire_terrier"], "181": ["n02093647", "Bedlington_terrier"], "182": ["n02093754", "Border_terrier"], "183": ["n02093859", "Kerry_blue_terrier"], "184": ["n02093991", "Irish_terrier"], "185": ["n02094114", "Norfolk_terrier"], "186": ["n02094258", "Norwich_terrier"], "187": ["n02094433", "Yorkshire_terrier"], "188": ["n02095314", "wire-haired_fox_terrier"], "189": ["n02095570", "Lakeland_terrier"], "190": ["n02095889", "Sealyham_terrier"], "191": ["n02096051", "Airedale"], "192": ["n02096177", "cairn"], "193": ["n02096294", "Australian_terrier"], "194": ["n02096437", "Dandie_Dinmont"], "195": ["n02096585", "Boston_bull"], "196": ["n02097047", "miniature_schnauzer"], "197": ["n02097130", "giant_schnauzer"], "198": ["n02097209", "standard_schnauzer"], "199": ["n02097298", "Scotch_terrier"], "200": ["n02097474", "Tibetan_terrier"], "201": ["n02097658", "silky_terrier"], "202": ["n02098105", "soft-coated_wheaten_terrier"], "203": ["n02098286", "West_Highland_white_terrier"], "204": ["n02098413", "Lhasa"], "205": ["n02099267", "flat-coated_retriever"], "206": ["n02099429", "curly-coated_retriever"], "207": ["n02099601", "golden_retriever"], "208": ["n02099712", "Labrador_retriever"], "209": ["n02099849", "Chesapeake_Bay_retriever"], "210": ["n02100236", "German_short-haired_pointer"], "211": ["n02100583", "vizsla"], "212": ["n02100735", "English_setter"], "213": ["n02100877", "Irish_setter"], "214": ["n02101006", "Gordon_setter"], "215": ["n02101388", "Brittany_spaniel"], "216": ["n02101556", "clumber"], "217": ["n02102040", "English_springer"], "218": ["n02102177", "Welsh_springer_spaniel"], "219": ["n02102318", "cocker_spaniel"], "220": ["n02102480", "Sussex_spaniel"], "221": ["n02102973", "Irish_water_spaniel"], "222": ["n02104029", "kuvasz"], "223": ["n02104365", "schipperke"], "224": ["n02105056", "groenendael"], "225": ["n02105162", "malinois"], "226": ["n02105251", "briard"], "227": ["n02105412", "kelpie"], "228": ["n02105505", "komondor"], "229": ["n02105641", "Old_English_sheepdog"], "230": ["n02105855", "Shetland_sheepdog"], "231": ["n02106030", "collie"], "232": ["n02106166", "Border_collie"], "233": ["n02106382", "Bouvier_des_Flandres"], "234": ["n02106550", "Rottweiler"], "235": ["n02106662", "German_shepherd"], "236": ["n02107142", "Doberman"], "237": ["n02107312", "miniature_pinscher"], "238": ["n02107574", "Greater_Swiss_Mountain_dog"], "239": ["n02107683", "Bernese_mountain_dog"], "240": ["n02107908", "Appenzeller"], "241": ["n02108000", "EntleBucher"], "242": ["n02108089", "boxer"], "243": ["n02108422", "bull_mastiff"], "244": ["n02108551", "Tibetan_mastiff"], "245": ["n02108915", "French_bulldog"], "246": ["n02109047", "Great_Dane"], "247": ["n02109525", "Saint_Bernard"], "248": ["n02109961", "Eskimo_dog"], "249": ["n02110063", "malamute"], "250": ["n02110185", "Siberian_husky"], "251": ["n02110341", "dalmatian"], "252": ["n02110627", "affenpinscher"], "253": ["n02110806", "basenji"], "254": ["n02110958", "pug"], "255": ["n02111129", "Leonberg"], "256": ["n02111277", "Newfoundland"], "257": ["n02111500", "Great_Pyrenees"], "258": ["n02111889", "Samoyed"], "259": ["n02112018", "Pomeranian"], "260": ["n02112137", "chow"], "261": ["n02112350", "keeshond"], "262": ["n02112706", "Brabancon_griffon"], "263": ["n02113023", "Pembroke"], "264": ["n02113186", "Cardigan"], "265": ["n02113624", "toy_poodle"], "266": ["n02113712", "miniature_poodle"], "267": ["n02113799", "standard_poodle"], "268": ["n02113978", "Mexican_hairless"], "269": ["n02114367", "timber_wolf"], "270": ["n02114548", "white_wolf"], "271": ["n02114712", "red_wolf"], "272": ["n02114855", "coyote"], "273": ["n02115641", "dingo"], "274": ["n02115913", "dhole"], "275": ["n02116738", "African_hunting_dog"], "276": ["n02117135", "hyena"], "277": ["n02119022", "red_fox"], "278": ["n02119789", "kit_fox"], "279": ["n02120079", "Arctic_fox"], "280": ["n02120505", "grey_fox"], "281": ["n02123045", "tabby"], "282": ["n02123159", "tiger_cat"], "283": ["n02123394", "Persian_cat"], "284": ["n02123597", "Siamese_cat"], "285": ["n02124075", "Egyptian_cat"], "286": ["n02125311", "cougar"], "287": ["n02127052", "lynx"], "288": ["n02128385", "leopard"], "289": ["n02128757", "snow_leopard"], "290": ["n02128925", "jaguar"], "291": ["n02129165", "lion"], "292": ["n02129604", "tiger"], "293": ["n02130308", "cheetah"], "294": ["n02132136", "brown_bear"], "295": ["n02133161", "American_black_bear"], "296": ["n02134084", "ice_bear"], "297": ["n02134418", "sloth_bear"], "298": ["n02137549", "mongoose"], "299": ["n02138441", "meerkat"], "300": ["n02165105", "tiger_beetle"], "301": ["n02165456", "ladybug"], "302": ["n02167151", "ground_beetle"], "303": ["n02168699", "long-horned_beetle"], "304": ["n02169497", "leaf_beetle"], "305": ["n02172182", "dung_beetle"], "306": ["n02174001", "rhinoceros_beetle"], "307": ["n02177972", "weevil"], "308": ["n02190166", "fly"], "309": ["n02206856", "bee"], "310": ["n02219486", "ant"], "311": ["n02226429", "grasshopper"], "312": ["n02229544", "cricket"], "313": ["n02231487", "walking_stick"], "314": ["n02233338", "cockroach"], "315": ["n02236044", "mantis"], "316": ["n02256656", "cicada"], "317": ["n02259212", "leafhopper"], "318": ["n02264363", "lacewing"], "319": ["n02268443", "dragonfly"], "320": ["n02268853", "damselfly"], "321": ["n02276258", "admiral"], "322": ["n02277742", "ringlet"], "323": ["n02279972", "monarch"], "324": ["n02280649", "cabbage_butterfly"], "325": ["n02281406", "sulphur_butterfly"], "326": ["n02281787", "lycaenid"], "327": ["n02317335", "starfish"], "328": ["n02319095", "sea_urchin"], "329": ["n02321529", "sea_cucumber"], "330": ["n02325366", "wood_rabbit"], "331": ["n02326432", "hare"], "332": ["n02328150", "Angora"], "333": ["n02342885", "hamster"], "334": ["n02346627", "porcupine"], "335": ["n02356798", "fox_squirrel"], "336": ["n02361337", "marmot"], "337": ["n02363005", "beaver"], "338": ["n02364673", "guinea_pig"], "339": ["n02389026", "sorrel"], "340": ["n02391049", "zebra"], "341": ["n02395406", "hog"], "342": ["n02396427", "wild_boar"], "343": ["n02397096", "warthog"], "344": ["n02398521", "hippopotamus"], "345": ["n02403003", "ox"], "346": ["n02408429", "water_buffalo"], "347": ["n02410509", "bison"], "348": ["n02412080", "ram"], "349": ["n02415577", "bighorn"], "350": ["n02417914", "ibex"], "351": ["n02422106", "hartebeest"], "352": ["n02422699", "impala"], "353": ["n02423022", "gazelle"], "354": ["n02437312", "Arabian_camel"], "355": ["n02437616", "llama"], "356": ["n02441942", "weasel"], "357": ["n02442845", "mink"], "358": ["n02443114", "polecat"], "359": ["n02443484", "black-footed_ferret"], "360": ["n02444819", "otter"], "361": ["n02445715", "skunk"], "362": ["n02447366", "badger"], "363": ["n02454379", "armadillo"], "364": ["n02457408", "three-toed_sloth"], "365": ["n02480495", "orangutan"], "366": ["n02480855", "gorilla"], "367": ["n02481823", "chimpanzee"], "368": ["n02483362", "gibbon"], "369": ["n02483708", "siamang"], "370": ["n02484975", "guenon"], "371": ["n02486261", "patas"], "372": ["n02486410", "baboon"], "373": ["n02487347", "macaque"], "374": ["n02488291", "langur"], "375": ["n02488702", "colobus"], "376": ["n02489166", "proboscis_monkey"], "377": ["n02490219", "marmoset"], "378": ["n02492035", "capuchin"], "379": ["n02492660", "howler_monkey"], "380": ["n02493509", "titi"], "381": ["n02493793", "spider_monkey"], "382": ["n02494079", "squirrel_monkey"], "383": ["n02497673", "Madagascar_cat"], "384": ["n02500267", "indri"], "385": ["n02504013", "Indian_elephant"], "386": ["n02504458", "African_elephant"], "387": ["n02509815", "lesser_panda"], "388": ["n02510455", "giant_panda"], "389": ["n02514041", "barracouta"], "390": ["n02526121", "eel"], "391": ["n02536864", "coho"], "392": ["n02606052", "rock_beauty"], "393": ["n02607072", "anemone_fish"], "394": ["n02640242", "sturgeon"], "395": ["n02641379", "gar"], "396": ["n02643566", "lionfish"], "397": ["n02655020", "puffer"], "398": ["n02666196", "abacus"], "399": ["n02667093", "abaya"], "400": ["n02669723", "academic_gown"], "401": ["n02672831", "accordion"], "402": ["n02676566", "acoustic_guitar"], "403": ["n02687172", "aircraft_carrier"], "404": ["n02690373", "airliner"], "405": ["n02692877", "airship"], "406": ["n02699494", "altar"], "407": ["n02701002", "ambulance"], "408": ["n02704792", "amphibian"], "409": ["n02708093", "analog_clock"], "410": ["n02727426", "apiary"], "411": ["n02730930", "apron"], "412": ["n02747177", "ashcan"], "413": ["n02749479", "assault_rifle"], "414": ["n02769748", "backpack"], "415": ["n02776631", "bakery"], "416": ["n02777292", "balance_beam"], "417": ["n02782093", "balloon"], "418": ["n02783161", "ballpoint"], "419": ["n02786058", "Band_Aid"], "420": ["n02787622", "banjo"], "421": ["n02788148", "bannister"], "422": ["n02790996", "barbell"], "423": ["n02791124", "barber_chair"], "424": ["n02791270", "barbershop"], "425": ["n02793495", "barn"], "426": ["n02794156", "barometer"], "427": ["n02795169", "barrel"], "428": ["n02797295", "barrow"], "429": ["n02799071", "baseball"], "430": ["n02802426", "basketball"], "431": ["n02804414", "bassinet"], "432": ["n02804610", "bassoon"], "433": ["n02807133", "bathing_cap"], "434": ["n02808304", "bath_towel"], "435": ["n02808440", "bathtub"], "436": ["n02814533", "beach_wagon"], "437": ["n02814860", "beacon"], "438": ["n02815834", "beaker"], "439": ["n02817516", "bearskin"], "440": ["n02823428", "beer_bottle"], "441": ["n02823750", "beer_glass"], "442": ["n02825657", "bell_cote"], "443": ["n02834397", "bib"], "444": ["n02835271", "bicycle-built-for-two"], "445": ["n02837789", "bikini"], "446": ["n02840245", "binder"], "447": ["n02841315", "binoculars"], "448": ["n02843684", "birdhouse"], "449": ["n02859443", "boathouse"], "450": ["n02860847", "bobsled"], "451": ["n02865351", "bolo_tie"], "452": ["n02869837", "bonnet"], "453": ["n02870880", "bookcase"], "454": ["n02871525", "bookshop"], "455": ["n02877765", "bottlecap"], "456": ["n02879718", "bow"], "457": ["n02883205", "bow_tie"], "458": ["n02892201", "brass"], "459": ["n02892767", "brassiere"], "460": ["n02894605", "breakwater"], "461": ["n02895154", "breastplate"], "462": ["n02906734", "broom"], "463": ["n02909870", "bucket"], "464": ["n02910353", "buckle"], "465": ["n02916936", "bulletproof_vest"], "466": ["n02917067", "bullet_train"], "467": ["n02927161", "butcher_shop"], "468": ["n02930766", "cab"], "469": ["n02939185", "caldron"], "470": ["n02948072", "candle"], "471": ["n02950826", "cannon"], "472": ["n02951358", "canoe"], "473": ["n02951585", "can_opener"], "474": ["n02963159", "cardigan"], "475": ["n02965783", "car_mirror"], "476": ["n02966193", "carousel"], "477": ["n02966687", "carpenter's_kit"], "478": ["n02971356", "carton"], "479": ["n02974003", "car_wheel"], "480": ["n02977058", "cash_machine"], "481": ["n02978881", "cassette"], "482": ["n02979186", "cassette_player"], "483": ["n02980441", "castle"], "484": ["n02981792", "catamaran"], "485": ["n02988304", "CD_player"], "486": ["n02992211", "cello"], "487": ["n02992529", "cellular_telephone"], "488": ["n02999410", "chain"], "489": ["n03000134", "chainlink_fence"], "490": ["n03000247", "chain_mail"], "491": ["n03000684", "chain_saw"], "492": ["n03014705", "chest"], "493": ["n03016953", "chiffonier"], "494": ["n03017168", "chime"], "495": ["n03018349", "china_cabinet"], "496": ["n03026506", "Christmas_stocking"], "497": ["n03028079", "church"], "498": ["n03032252", "cinema"], "499": ["n03041632", "cleaver"], "500": ["n03042490", "cliff_dwelling"], "501": ["n03045698", "cloak"], "502": ["n03047690", "clog"], "503": ["n03062245", "cocktail_shaker"], "504": ["n03063599", "coffee_mug"], "505": ["n03063689", "coffeepot"], "506": ["n03065424", "coil"], "507": ["n03075370", "combination_lock"], "508": ["n03085013", "computer_keyboard"], "509": ["n03089624", "confectionery"], "510": ["n03095699", "container_ship"], "511": ["n03100240", "convertible"], "512": ["n03109150", "corkscrew"], "513": ["n03110669", "cornet"], "514": ["n03124043", "cowboy_boot"], "515": ["n03124170", "cowboy_hat"], "516": ["n03125729", "cradle"], "517": ["n03126707", "crane"], "518": ["n03127747", "crash_helmet"], "519": ["n03127925", "crate"], "520": ["n03131574", "crib"], "521": ["n03133878", "Crock_Pot"], "522": ["n03134739", "croquet_ball"], "523": ["n03141823", "crutch"], "524": ["n03146219", "cuirass"], "525": ["n03160309", "dam"], "526": ["n03179701", "desk"], "527": ["n03180011", "desktop_computer"], "528": ["n03187595", "dial_telephone"], "529": ["n03188531", "diaper"], "530": ["n03196217", "digital_clock"], "531": ["n03197337", "digital_watch"], "532": ["n03201208", "dining_table"], "533": ["n03207743", "dishrag"], "534": ["n03207941", "dishwasher"], "535": ["n03208938", "disk_brake"], "536": ["n03216828", "dock"], "537": ["n03218198", "dogsled"], "538": ["n03220513", "dome"], "539": ["n03223299", "doormat"], "540": ["n03240683", "drilling_platform"], "541": ["n03249569", "drum"], "542": ["n03250847", "drumstick"], "543": ["n03255030", "dumbbell"], "544": ["n03259280", "Dutch_oven"], "545": ["n03271574", "electric_fan"], "546": ["n03272010", "electric_guitar"], "547": ["n03272562", "electric_locomotive"], "548": ["n03290653", "entertainment_center"], "549": ["n03291819", "envelope"], "550": ["n03297495", "espresso_maker"], "551": ["n03314780", "face_powder"], "552": ["n03325584", "feather_boa"], "553": ["n03337140", "file"], "554": ["n03344393", "fireboat"], "555": ["n03345487", "fire_engine"], "556": ["n03347037", "fire_screen"], "557": ["n03355925", "flagpole"], "558": ["n03372029", "flute"], "559": ["n03376595", "folding_chair"], "560": ["n03379051", "football_helmet"], "561": ["n03384352", "forklift"], "562": ["n03388043", "fountain"], "563": ["n03388183", "fountain_pen"], "564": ["n03388549", "four-poster"], "565": ["n03393912", "freight_car"], "566": ["n03394916", "French_horn"], "567": ["n03400231", "frying_pan"], "568": ["n03404251", "fur_coat"], "569": ["n03417042", "garbage_truck"], "570": ["n03424325", "gasmask"], "571": ["n03425413", "gas_pump"], "572": ["n03443371", "goblet"], "573": ["n03444034", "go-kart"], "574": ["n03445777", "golf_ball"], "575": ["n03445924", "golfcart"], "576": ["n03447447", "gondola"], "577": ["n03447721", "gong"], "578": ["n03450230", "gown"], "579": ["n03452741", "grand_piano"], "580": ["n03457902", "greenhouse"], "581": ["n03459775", "grille"], "582": ["n03461385", "grocery_store"], "583": ["n03467068", "guillotine"], "584": ["n03476684", "hair_slide"], "585": ["n03476991", "hair_spray"], "586": ["n03478589", "half_track"], "587": ["n03481172", "hammer"], "588": ["n03482405", "hamper"], "589": ["n03483316", "hand_blower"], "590": ["n03485407", "hand-held_computer"], "591": ["n03485794", "handkerchief"], "592": ["n03492542", "hard_disc"], "593": ["n03494278", "harmonica"], "594": ["n03495258", "harp"], "595": ["n03496892", "harvester"], "596": ["n03498962", "hatchet"], "597": ["n03527444", "holster"], "598": ["n03529860", "home_theater"], "599": ["n03530642", "honeycomb"], "600": ["n03532672", "hook"], "601": ["n03534580", "hoopskirt"], "602": ["n03535780", "horizontal_bar"], "603": ["n03538406", "horse_cart"], "604": ["n03544143", "hourglass"], "605": ["n03584254", "iPod"], "606": ["n03584829", "iron"], "607": ["n03590841", "jack-o'-lantern"], "608": ["n03594734", "jean"], "609": ["n03594945", "jeep"], "610": ["n03595614", "jersey"], "611": ["n03598930", "jigsaw_puzzle"], "612": ["n03599486", "jinrikisha"], "613": ["n03602883", "joystick"], "614": ["n03617480", "kimono"], "615": ["n03623198", "knee_pad"], "616": ["n03627232", "knot"], "617": ["n03630383", "lab_coat"], "618": ["n03633091", "ladle"], "619": ["n03637318", "lampshade"], "620": ["n03642806", "laptop"], "621": ["n03649909", "lawn_mower"], "622": ["n03657121", "lens_cap"], "623": ["n03658185", "letter_opener"], "624": ["n03661043", "library"], "625": ["n03662601", "lifeboat"], "626": ["n03666591", "lighter"], "627": ["n03670208", "limousine"], "628": ["n03673027", "liner"], "629": ["n03676483", "lipstick"], "630": ["n03680355", "Loafer"], "631": ["n03690938", "lotion"], "632": ["n03691459", "loudspeaker"], "633": ["n03692522", "loupe"], "634": ["n03697007", "lumbermill"], "635": ["n03706229", "magnetic_compass"], "636": ["n03709823", "mailbag"], "637": ["n03710193", "mailbox"], "638": ["n03710637", "maillot"], "639": ["n03710721", "maillot"], "640": ["n03717622", "manhole_cover"], "641": ["n03720891", "maraca"], "642": ["n03721384", "marimba"], "643": ["n03724870", "mask"], "644": ["n03729826", "matchstick"], "645": ["n03733131", "maypole"], "646": ["n03733281", "maze"], "647": ["n03733805", "measuring_cup"], "648": ["n03742115", "medicine_chest"], "649": ["n03743016", "megalith"], "650": ["n03759954", "microphone"], "651": ["n03761084", "microwave"], "652": ["n03763968", "military_uniform"], "653": ["n03764736", "milk_can"], "654": ["n03769881", "minibus"], "655": ["n03770439", "miniskirt"], "656": ["n03770679", "minivan"], "657": ["n03773504", "missile"], "658": ["n03775071", "mitten"], "659": ["n03775546", "mixing_bowl"], "660": ["n03776460", "mobile_home"], "661": ["n03777568", "Model_T"], "662": ["n03777754", "modem"], "663": ["n03781244", "monastery"], "664": ["n03782006", "monitor"], "665": ["n03785016", "moped"], "666": ["n03786901", "mortar"], "667": ["n03787032", "mortarboard"], "668": ["n03788195", "mosque"], "669": ["n03788365", "mosquito_net"], "670": ["n03791053", "motor_scooter"], "671": ["n03792782", "mountain_bike"], "672": ["n03792972", "mountain_tent"], "673": ["n03793489", "mouse"], "674": ["n03794056", "mousetrap"], "675": ["n03796401", "moving_van"], "676": ["n03803284", "muzzle"], "677": ["n03804744", "nail"], "678": ["n03814639", "neck_brace"], "679": ["n03814906", "necklace"], "680": ["n03825788", "nipple"], "681": ["n03832673", "notebook"], "682": ["n03837869", "obelisk"], "683": ["n03838899", "oboe"], "684": ["n03840681", "ocarina"], "685": ["n03841143", "odometer"], "686": ["n03843555", "oil_filter"], "687": ["n03854065", "organ"], "688": ["n03857828", "oscilloscope"], "689": ["n03866082", "overskirt"], "690": ["n03868242", "oxcart"], "691": ["n03868863", "oxygen_mask"], "692": ["n03871628", "packet"], "693": ["n03873416", "paddle"], "694": ["n03874293", "paddlewheel"], "695": ["n03874599", "padlock"], "696": ["n03876231", "paintbrush"], "697": ["n03877472", "pajama"], "698": ["n03877845", "palace"], "699": ["n03884397", "panpipe"], "700": ["n03887697", "paper_towel"], "701": ["n03888257", "parachute"], "702": ["n03888605", "parallel_bars"], "703": ["n03891251", "park_bench"], "704": ["n03891332", "parking_meter"], "705": ["n03895866", "passenger_car"], "706": ["n03899768", "patio"], "707": ["n03902125", "pay-phone"], "708": ["n03903868", "pedestal"], "709": ["n03908618", "pencil_box"], "710": ["n03908714", "pencil_sharpener"], "711": ["n03916031", "perfume"], "712": ["n03920288", "Petri_dish"], "713": ["n03924679", "photocopier"], "714": ["n03929660", "pick"], "715": ["n03929855", "pickelhaube"], "716": ["n03930313", "picket_fence"], "717": ["n03930630", "pickup"], "718": ["n03933933", "pier"], "719": ["n03935335", "piggy_bank"], "720": ["n03937543", "pill_bottle"], "721": ["n03938244", "pillow"], "722": ["n03942813", "ping-pong_ball"], "723": ["n03944341", "pinwheel"], "724": ["n03947888", "pirate"], "725": ["n03950228", "pitcher"], "726": ["n03954731", "plane"], "727": ["n03956157", "planetarium"], "728": ["n03958227", "plastic_bag"], "729": ["n03961711", "plate_rack"], "730": ["n03967562", "plow"], "731": ["n03970156", "plunger"], "732": ["n03976467", "Polaroid_camera"], "733": ["n03976657", "pole"], "734": ["n03977966", "police_van"], "735": ["n03980874", "poncho"], "736": ["n03982430", "pool_table"], "737": ["n03983396", "pop_bottle"], "738": ["n03991062", "pot"], "739": ["n03992509", "potter's_wheel"], "740": ["n03995372", "power_drill"], "741": ["n03998194", "prayer_rug"], "742": ["n04004767", "printer"], "743": ["n04005630", "prison"], "744": ["n04008634", "projectile"], "745": ["n04009552", "projector"], "746": ["n04019541", "puck"], "747": ["n04023962", "punching_bag"], "748": ["n04026417", "purse"], "749": ["n04033901", "quill"], "750": ["n04033995", "quilt"], "751": ["n04037443", "racer"], "752": ["n04039381", "racket"], "753": ["n04040759", "radiator"], "754": ["n04041544", "radio"], "755": ["n04044716", "radio_telescope"], "756": ["n04049303", "rain_barrel"], "757": ["n04065272", "recreational_vehicle"], "758": ["n04067472", "reel"], "759": ["n04069434", "reflex_camera"], "760": ["n04070727", "refrigerator"], "761": ["n04074963", "remote_control"], "762": ["n04081281", "restaurant"], "763": ["n04086273", "revolver"], "764": ["n04090263", "rifle"], "765": ["n04099969", "rocking_chair"], "766": ["n04111531", "rotisserie"], "767": ["n04116512", "rubber_eraser"], "768": ["n04118538", "rugby_ball"], "769": ["n04118776", "rule"], "770": ["n04120489", "running_shoe"], "771": ["n04125021", "safe"], "772": ["n04127249", "safety_pin"], "773": ["n04131690", "saltshaker"], "774": ["n04133789", "sandal"], "775": ["n04136333", "sarong"], "776": ["n04141076", "sax"], "777": ["n04141327", "scabbard"], "778": ["n04141975", "scale"], "779": ["n04146614", "school_bus"], "780": ["n04147183", "schooner"], "781": ["n04149813", "scoreboard"], "782": ["n04152593", "screen"], "783": ["n04153751", "screw"], "784": ["n04154565", "screwdriver"], "785": ["n04162706", "seat_belt"], "786": ["n04179913", "sewing_machine"], "787": ["n04192698", "shield"], "788": ["n04200800", "shoe_shop"], "789": ["n04201297", "shoji"], "790": ["n04204238", "shopping_basket"], "791": ["n04204347", "shopping_cart"], "792": ["n04208210", "shovel"], "793": ["n04209133", "shower_cap"], "794": ["n04209239", "shower_curtain"], "795": ["n04228054", "ski"], "796": ["n04229816", "ski_mask"], "797": ["n04235860", "sleeping_bag"], "798": ["n04238763", "slide_rule"], "799": ["n04239074", "sliding_door"], "800": ["n04243546", "slot"], "801": ["n04251144", "snorkel"], "802": ["n04252077", "snowmobile"], "803": ["n04252225", "snowplow"], "804": ["n04254120", "soap_dispenser"], "805": ["n04254680", "soccer_ball"], "806": ["n04254777", "sock"], "807": ["n04258138", "solar_dish"], "808": ["n04259630", "sombrero"], "809": ["n04263257", "soup_bowl"], "810": ["n04264628", "space_bar"], "811": ["n04265275", "space_heater"], "812": ["n04266014", "space_shuttle"], "813": ["n04270147", "spatula"], "814": ["n04273569", "speedboat"], "815": ["n04275548", "spider_web"], "816": ["n04277352", "spindle"], "817": ["n04285008", "sports_car"], "818": ["n04286575", "spotlight"], "819": ["n04296562", "stage"], "820": ["n04310018", "steam_locomotive"], "821": ["n04311004", "steel_arch_bridge"], "822": ["n04311174", "steel_drum"], "823": ["n04317175", "stethoscope"], "824": ["n04325704", "stole"], "825": ["n04326547", "stone_wall"], "826": ["n04328186", "stopwatch"], "827": ["n04330267", "stove"], "828": ["n04332243", "strainer"], "829": ["n04335435", "streetcar"], "830": ["n04336792", "stretcher"], "831": ["n04344873", "studio_couch"], "832": ["n04346328", "stupa"], "833": ["n04347754", "submarine"], "834": ["n04350905", "suit"], "835": ["n04355338", "sundial"], "836": ["n04355933", "sunglass"], "837": ["n04356056", "sunglasses"], "838": ["n04357314", "sunscreen"], "839": ["n04366367", "suspension_bridge"], "840": ["n04367480", "swab"], "841": ["n04370456", "sweatshirt"], "842": ["n04371430", "swimming_trunks"], "843": ["n04371774", "swing"], "844": ["n04372370", "switch"], "845": ["n04376876", "syringe"], "846": ["n04380533", "table_lamp"], "847": ["n04389033", "tank"], "848": ["n04392985", "tape_player"], "849": ["n04398044", "teapot"], "850": ["n04399382", "teddy"], "851": ["n04404412", "television"], "852": ["n04409515", "tennis_ball"], "853": ["n04417672", "thatch"], "854": ["n04418357", "theater_curtain"], "855": ["n04423845", "thimble"], "856": ["n04428191", "thresher"], "857": ["n04429376", "throne"], "858": ["n04435653", "tile_roof"], "859": ["n04442312", "toaster"], "860": ["n04443257", "tobacco_shop"], "861": ["n04447861", "toilet_seat"], "862": ["n04456115", "torch"], "863": ["n04458633", "totem_pole"], "864": ["n04461696", "tow_truck"], "865": ["n04462240", "toyshop"], "866": ["n04465501", "tractor"], "867": ["n04467665", "trailer_truck"], "868": ["n04476259", "tray"], "869": ["n04479046", "trench_coat"], "870": ["n04482393", "tricycle"], "871": ["n04483307", "trimaran"], "872": ["n04485082", "tripod"], "873": ["n04486054", "triumphal_arch"], "874": ["n04487081", "trolleybus"], "875": ["n04487394", "trombone"], "876": ["n04493381", "tub"], "877": ["n04501370", "turnstile"], "878": ["n04505470", "typewriter_keyboard"], "879": ["n04507155", "umbrella"], "880": ["n04509417", "unicycle"], "881": ["n04515003", "upright"], "882": ["n04517823", "vacuum"], "883": ["n04522168", "vase"], "884": ["n04523525", "vault"], "885": ["n04525038", "velvet"], "886": ["n04525305", "vending_machine"], "887": ["n04532106", "vestment"], "888": ["n04532670", "viaduct"], "889": ["n04536866", "violin"], "890": ["n04540053", "volleyball"], "891": ["n04542943", "waffle_iron"], "892": ["n04548280", "wall_clock"], "893": ["n04548362", "wallet"], "894": ["n04550184", "wardrobe"], "895": ["n04552348", "warplane"], "896": ["n04553703", "washbasin"], "897": ["n04554684", "washer"], "898": ["n04557648", "water_bottle"], "899": ["n04560804", "water_jug"], "900": ["n04562935", "water_tower"], "901": ["n04579145", "whiskey_jug"], "902": ["n04579432", "whistle"], "903": ["n04584207", "wig"], "904": ["n04589890", "window_screen"], "905": ["n04590129", "window_shade"], "906": ["n04591157", "Windsor_tie"], "907": ["n04591713", "wine_bottle"], "908": ["n04592741", "wing"], "909": ["n04596742", "wok"], "910": ["n04597913", "wooden_spoon"], "911": ["n04599235", "wool"], "912": ["n04604644", "worm_fence"], "913": ["n04606251", "wreck"], "914": ["n04612504", "yawl"], "915": ["n04613696", "yurt"], "916": ["n06359193", "web_site"], "917": ["n06596364", "comic_book"], "918": ["n06785654", "crossword_puzzle"], "919": ["n06794110", "street_sign"], "920": ["n06874185", "traffic_light"], "921": ["n07248320", "book_jacket"], "922": ["n07565083", "menu"], "923": ["n07579787", "plate"], "924": ["n07583066", "guacamole"], "925": ["n07584110", "consomme"], "926": ["n07590611", "hot_pot"], "927": ["n07613480", "trifle"], "928": ["n07614500", "ice_cream"], "929": ["n07615774", "ice_lolly"], "930": ["n07684084", "French_loaf"], "931": ["n07693725", "bagel"], "932": ["n07695742", "pretzel"], "933": ["n07697313", "cheeseburger"], "934": ["n07697537", "hotdog"], "935": ["n07711569", "mashed_potato"], "936": ["n07714571", "head_cabbage"], "937": ["n07714990", "broccoli"], "938": ["n07715103", "cauliflower"], "939": ["n07716358", "zucchini"], "940": ["n07716906", "spaghetti_squash"], "941": ["n07717410", "acorn_squash"], "942": ["n07717556", "butternut_squash"], "943": ["n07718472", "cucumber"], "944": ["n07718747", "artichoke"], "945": ["n07720875", "bell_pepper"], "946": ["n07730033", "cardoon"], "947": ["n07734744", "mushroom"], "948": ["n07742313", "Granny_Smith"], "949": ["n07745940", "strawberry"], "950": ["n07747607", "orange"], "951": ["n07749582", "lemon"], "952": ["n07753113", "fig"], "953": ["n07753275", "pineapple"], "954": ["n07753592", "banana"], "955": ["n07754684", "jackfruit"], "956": ["n07760859", "custard_apple"], "957": ["n07768694", "pomegranate"], "958": ["n07802026", "hay"], "959": ["n07831146", "carbonara"], "960": ["n07836838", "chocolate_sauce"], "961": ["n07860988", "dough"], "962": ["n07871810", "meat_loaf"], "963": ["n07873807", "pizza"], "964": ["n07875152", "potpie"], "965": ["n07880968", "burrito"], "966": ["n07892512", "red_wine"], "967": ["n07920052", "espresso"], "968": ["n07930864", "cup"], "969": ["n07932039", "eggnog"], "970": ["n09193705", "alp"], "971": ["n09229709", "bubble"], "972": ["n09246464", "cliff"], "973": ["n09256479", "coral_reef"], "974": ["n09288635", "geyser"], "975": ["n09332890", "lakeside"], "976": ["n09399592", "promontory"], "977": ["n09421951", "sandbar"], "978": ["n09428293", "seashore"], "979": ["n09468604", "valley"], "980": ["n09472597", "volcano"], "981": ["n09835506", "ballplayer"], "982": ["n10148035", "groom"], "983": ["n10565667", "scuba_diver"], "984": ["n11879895", "rapeseed"], "985": ["n11939491", "daisy"], "986": ["n12057211", "yellow_lady's_slipper"], "987": ["n12144580", "corn"], "988": ["n12267677", "acorn"], "989": ["n12620546", "hip"], "990": ["n12768682", "buckeye"], "991": ["n12985857", "coral_fungus"], "992": ["n12998815", "agaric"], "993": ["n13037406", "gyromitra"], "994": ["n13040303", "stinkhorn"], "995": ["n13044778", "earthstar"], "996": ["n13052670", "hen-of-the-woods"], "997": ["n13054560", "bolete"], "998": ["n13133613", "ear"], "999": ["n15075141", "toilet_tissue"]} \ No newline at end of file diff --git a/benchmarks/400.inference/413.image-classification/python/init.sh b/benchmarks/400.inference/413.image-classification/python/init.sh new file mode 100755 index 000000000..71a2e39c0 --- /dev/null +++ b/benchmarks/400.inference/413.image-classification/python/init.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +DIR=$1 +VERBOSE=$2 +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +path="${SCRIPT_DIR}/imagenet_class_index.json" +if [ "$VERBOSE" = true ]; then + echo "Update ${DIR} with json ${path}" +fi +cp ${path} ${DIR} diff --git a/benchmarks/400.inference/413.image-classification/python/package.sh b/benchmarks/400.inference/413.image-classification/python/package.sh new file mode 100644 index 000000000..038fac7c5 --- /dev/null +++ b/benchmarks/400.inference/413.image-classification/python/package.sh @@ -0,0 +1,32 @@ +# Stripping package code is based on https://github.com/ryfeus/lambda-packs repo + +PACKAGE_DIR=$1 +echo "Original size $(du -sh $1 | cut -f1)" + +CUR_DIR=$(pwd) +cd $1 +# cleaning libs +rm -rf external +find . -type d -name "tests" -exec rm -rf {} + +find . -type d -name "test" -exec rm -rf {} + +find . -type d -name "bin" -not -path "*/torch/*" -exec rm -rf {} + + +# cleaning +# stripping some of the numpy libs - libgfortran-2e0d59d6.so.5.0.0 - causes issues on Azure +find -name "*.so" -not -path "*/PIL/*" -not -path "*/Pillow.libs/*" -not -path "*libgfortran*" | xargs strip +find -name "*.so.*" -not -path "*/PIL/*" -not -path "*/Pillow.libs/*" -not -path "*libgfortran*" | xargs strip + +rm -r pip >/dev/null +rm -r pip-* >/dev/null +rm -r wheel >/dev/null +rm -r wheel-* >/dev/null +rm easy_install.py >/dev/null +find . -name \*.pyc -delete +cd ${CUR_DIR} +echo "Stripped size $(du -sh $1 | cut -f1)" + +if ([[ "${PLATFORM}" == "AWS" ]] || [[ "${PLATFORM}" == "GCP" ]]) && ([[ "${PYTHON_VERSION}" == "3.8" ]] || [[ "${PYTHON_VERSION}" == "3.9" ]]); then + zip -qr torch.zip $1/torch + rm -rf $1/torch + echo "Torch-zipped size $(du -sh ${CUR_DIR} | cut -f1)" +fi diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt b/benchmarks/400.inference/413.image-classification/python/requirements.txt new file mode 100644 index 000000000..d191dc6dd --- /dev/null +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt @@ -0,0 +1,4 @@ +#torch==1.2.0+cpu +#torchvision==0.4.0+cpu +#https://download.pytorch.org/whl/cpu/torch-1.0.1.post2-cp37-cp37m-linux_x86_64.whl +#torch==1.0.1.post2+cpu diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.10 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.10 new file mode 100644 index 000000000..ab734881f --- /dev/null +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.10 @@ -0,0 +1,5 @@ +pillow==10.3.0 +https://download.pytorch.org/whl/cpu/torch-1.11.0%2Bcpu-cp310-cp310-linux_x86_64.whl +torchvision==0.12 +# prevent installing numpy 2.0 +numpy==1.22.0 diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.11 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.11 new file mode 100644 index 000000000..3288171f8 --- /dev/null +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.11 @@ -0,0 +1,5 @@ +pillow==10.3.0 +https://download.pytorch.org/whl/cpu/torch-2.0.0%2Bcpu-cp311-cp311-linux_x86_64.whl +torchvision==0.15.1 +# prevent installing numpy 2.0 +numpy==1.24.0 diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.6 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.6 new file mode 100644 index 000000000..63409acaa --- /dev/null +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.6 @@ -0,0 +1,4 @@ +Pillow==6.1 +numpy==1.16 +https://download.pytorch.org/whl/cpu/torch-1.0.1.post2-cp36-cp36m-linux_x86_64.whl +torchvision==0.2.1 diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.7 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.7 new file mode 100644 index 000000000..54bddbd58 --- /dev/null +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.7 @@ -0,0 +1,4 @@ +Pillow==6.1 +numpy==1.16 +https://download.pytorch.org/whl/cpu/torch-1.0.1.post2-cp37-cp37m-linux_x86_64.whl +torchvision==0.2.1 diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.8 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.8 new file mode 100644 index 000000000..7b873eafa --- /dev/null +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.8 @@ -0,0 +1,3 @@ +numpy==1.18 +https://download.pytorch.org/whl/cpu/torch-1.4.0%2Bcpu-cp38-cp38-linux_x86_64.whl +torchvision==0.5 diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.9 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.9 new file mode 100644 index 000000000..c7fc0663e --- /dev/null +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.9 @@ -0,0 +1,3 @@ +numpy==1.20 +https://download.pytorch.org/whl/cpu/torch-1.8.0%2Bcpu-cp39-cp39-linux_x86_64.whl +torchvision==0.9.0 From aae1023e3a03549c93f56f2c3adb0a1868a0fad4 Mon Sep 17 00:00:00 2001 From: McLavish Date: Wed, 5 Nov 2025 09:54:07 +0100 Subject: [PATCH 11/58] fix: replaced onnxruntime requirement from CPU to GPU. now it actually uses the gpu --- .../412.language-bert/python/function.py | 11 ++++++----- .../412.language-bert/python/requirements.txt | 2 +- .../412.language-bert/python/requirements.txt.3.10 | 2 +- .../412.language-bert/python/requirements.txt.3.11 | 2 +- .../412.language-bert/python/requirements.txt.3.8 | 2 +- .../412.language-bert/python/requirements.txt.3.9 | 2 +- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/benchmarks/400.inference/412.language-bert/python/function.py b/benchmarks/400.inference/412.language-bert/python/function.py index b3d6efe12..7e4f981ef 100644 --- a/benchmarks/400.inference/412.language-bert/python/function.py +++ b/benchmarks/400.inference/412.language-bert/python/function.py @@ -58,11 +58,12 @@ def _ensure_model(bucket: str, model_prefix: str): _labels = {int(idx): label for idx, label in raw_labels.items()} onnx_path = os.path.join(model_path, "model.onnx") - available_providers = ort.get_available_providers() - execution_providers = ["CUDAExecutionProvider"] if "CUDAExecutionProvider" in available_providers else [] - execution_providers.append("CPUExecutionProvider") - # Prefer GPU execution when available, otherwise fall back to CPU. - _session = ort.InferenceSession(onnx_path, providers=execution_providers) + + available = ort.get_available_providers() + if "CUDAExecutionProvider" not in available: + raise RuntimeError(f"CUDAExecutionProvider unavailable (have: {available})") + + _session = ort.InferenceSession(onnx_path, providers=["CUDAExecutionProvider"]) model_process_end = datetime.datetime.now() else: model_process_begin = datetime.datetime.now() diff --git a/benchmarks/400.inference/412.language-bert/python/requirements.txt b/benchmarks/400.inference/412.language-bert/python/requirements.txt index b692be1f7..67a8c1e18 100644 --- a/benchmarks/400.inference/412.language-bert/python/requirements.txt +++ b/benchmarks/400.inference/412.language-bert/python/requirements.txt @@ -1,3 +1,3 @@ numpy==1.24.4 -onnxruntime==1.16.3 +onnxruntime-gpu==1.16.3 tokenizers==0.13.3 diff --git a/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.10 b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.10 index b692be1f7..67a8c1e18 100644 --- a/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.10 +++ b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.10 @@ -1,3 +1,3 @@ numpy==1.24.4 -onnxruntime==1.16.3 +onnxruntime-gpu==1.16.3 tokenizers==0.13.3 diff --git a/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.11 b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.11 index b692be1f7..67a8c1e18 100644 --- a/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.11 +++ b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.11 @@ -1,3 +1,3 @@ numpy==1.24.4 -onnxruntime==1.16.3 +onnxruntime-gpu==1.16.3 tokenizers==0.13.3 diff --git a/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.8 b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.8 index b692be1f7..67a8c1e18 100644 --- a/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.8 +++ b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.8 @@ -1,3 +1,3 @@ numpy==1.24.4 -onnxruntime==1.16.3 +onnxruntime-gpu==1.16.3 tokenizers==0.13.3 diff --git a/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.9 b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.9 index b692be1f7..67a8c1e18 100644 --- a/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.9 +++ b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.9 @@ -1,3 +1,3 @@ numpy==1.24.4 -onnxruntime==1.16.3 +onnxruntime-gpu==1.16.3 tokenizers==0.13.3 From 25fd1d9616f1cb5ebb31207b9da011d73cc1f4bf Mon Sep 17 00:00:00 2001 From: McLavish Date: Wed, 5 Nov 2025 10:24:36 +0100 Subject: [PATCH 12/58] circleci mypy fix? --- .mypy.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.mypy.ini b/.mypy.ini index e202650ed..636105bfa 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -3,6 +3,9 @@ [mypy-docker] ignore_missing_imports = True +[mypy-docker.*] +ignore_missing_imports = True + [mypy-tzlocal] ignore_missing_imports = True From d6c422745a9d2d399e316b5e58232054a8f11b06 Mon Sep 17 00:00:00 2001 From: McLavish Date: Wed, 5 Nov 2025 10:45:00 +0100 Subject: [PATCH 13/58] benchmarks is now flake8/black compliant. pre-commit hooks also check this --- .pre-commit-config.yaml | 4 +- .../000.microbenchmarks/010.sleep/input.py | 13 +-- .../010.sleep/python/function.py | 6 +- .../020.network-benchmark/input.py | 10 +- .../020.network-benchmark/python/function.py | 35 +++--- .../030.clock-synchronization/input.py | 13 ++- .../python/function.py | 41 +++---- .../040.server-reply/input.py | 13 +-- .../040.server-reply/python/function.py | 5 +- .../100.webapps/110.dynamic-html/input.py | 14 +-- .../110.dynamic-html/python/function.py | 19 ++-- benchmarks/100.webapps/120.uploader/input.py | 24 ++-- .../120.uploader/python/function.py | 39 ++++--- .../200.multimedia/210.thumbnailer/input.py | 33 +++--- .../210.thumbnailer/python/function.py | 54 +++++---- .../220.video-processing/input.py | 33 +++--- .../220.video-processing/python/function.py | 104 ++++++++++-------- .../300.utilities/311.compression/input.py | 26 +++-- .../311.compression/python/function.py | 47 ++++---- .../411.image-recognition/input.py | 39 ++++--- .../411.image-recognition/python/function.py | 86 ++++++++------- .../501.graph-pagerank/input.py | 13 +-- .../501.graph-pagerank/python/function.py | 17 +-- .../500.scientific/502.graph-mst/input.py | 13 +-- .../502.graph-mst/python/function.py | 17 +-- .../500.scientific/503.graph-bfs/input.py | 13 +-- .../503.graph-bfs/python/function.py | 17 +-- .../504.dna-visualisation/input.py | 21 ++-- .../504.dna-visualisation/python/function.py | 33 +++--- benchmarks/wrappers/aws/python/handler.py | 72 ++++++------ benchmarks/wrappers/aws/python/setup.py | 11 +- benchmarks/wrappers/aws/python/storage.py | 16 ++- benchmarks/wrappers/azure/python/handler.py | 81 ++++++++------ benchmarks/wrappers/azure/python/storage.py | 27 ++--- benchmarks/wrappers/gcp/python/handler.py | 76 +++++++------ benchmarks/wrappers/gcp/python/storage.py | 8 +- benchmarks/wrappers/local/python/storage.py | 25 ++--- .../wrappers/openwhisk/python/__main__.py | 20 ++-- benchmarks/wrappers/openwhisk/python/nosql.py | 5 +- benchmarks/wrappers/openwhisk/python/setup.py | 12 +- .../wrappers/openwhisk/python/storage.py | 21 ++-- 41 files changed, 628 insertions(+), 548 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 22e59d275..fce4c4da7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: entry: flake8 args: ["--config=.flake8.cfg"] types: [python] - files: ^sebs/ + files: ^(sebs/|benchmarks/) - repo: local hooks: - id: black-check-local @@ -19,5 +19,5 @@ repos: entry: black args: ["--config=.black.toml", "--check", "--diff"] types: [python] - files: ^sebs/ + files: ^(sebs/|benchmarks/) diff --git a/benchmarks/000.microbenchmarks/010.sleep/input.py b/benchmarks/000.microbenchmarks/010.sleep/input.py index 041d2ba7f..af0427a6c 100644 --- a/benchmarks/000.microbenchmarks/010.sleep/input.py +++ b/benchmarks/000.microbenchmarks/010.sleep/input.py @@ -1,12 +1,11 @@ +size_generators = {"test": 1, "small": 100, "large": 1000} -size_generators = { - 'test' : 1, - 'small' : 100, - 'large': 1000 -} def buckets_count(): return (0, 0) -def generate_input(data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func): - return { 'sleep': size_generators[size] } + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): + return {"sleep": size_generators[size]} diff --git a/benchmarks/000.microbenchmarks/010.sleep/python/function.py b/benchmarks/000.microbenchmarks/010.sleep/python/function.py index 7dda59a57..64be15557 100644 --- a/benchmarks/000.microbenchmarks/010.sleep/python/function.py +++ b/benchmarks/000.microbenchmarks/010.sleep/python/function.py @@ -1,9 +1,9 @@ - from time import sleep + def handler(event): # start timing - sleep_time = event.get('sleep') + sleep_time = event.get("sleep") sleep(sleep_time) - return { 'result': sleep_time } + return {"result": sleep_time} diff --git a/benchmarks/000.microbenchmarks/020.network-benchmark/input.py b/benchmarks/000.microbenchmarks/020.network-benchmark/input.py index 0d969bc74..8f43ffc5a 100644 --- a/benchmarks/000.microbenchmarks/020.network-benchmark/input.py +++ b/benchmarks/000.microbenchmarks/020.network-benchmark/input.py @@ -2,10 +2,12 @@ def buckets_count(): return 0, 1 -def generate_input(data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func): +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): return { - 'bucket': { - 'bucket': benchmarks_bucket, - 'output': output_paths[0], + "bucket": { + "bucket": benchmarks_bucket, + "output": output_paths[0], }, } diff --git a/benchmarks/000.microbenchmarks/020.network-benchmark/python/function.py b/benchmarks/000.microbenchmarks/020.network-benchmark/python/function.py index eb8ccdcf2..58c376a2d 100644 --- a/benchmarks/000.microbenchmarks/020.network-benchmark/python/function.py +++ b/benchmarks/000.microbenchmarks/020.network-benchmark/python/function.py @@ -1,27 +1,26 @@ import csv -import json import os.path import socket from datetime import datetime -from time import sleep from . import storage + def handler(event): - request_id = event['request-id'] - address = event['server-address'] - port = event['server-port'] - repetitions = event['repetitions'] - output_bucket = event.get('bucket').get('bucket') - output_prefix = event.get('bucket').get('output') + request_id = event["request-id"] + address = event["server-address"] + port = event["server-port"] + repetitions = event["repetitions"] + output_bucket = event.get("bucket").get("bucket") + output_prefix = event.get("bucket").get("output") times = [] i = 0 socket.setdefaulttimeout(3) server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server_socket.bind(('', 0)) - message = request_id.encode('utf-8') + server_socket.bind(("", 0)) + message = request_id.encode("utf-8") adr = (address, port) consecutive_failures = 0 while i < repetitions + 1: @@ -43,16 +42,16 @@ def handler(event): consecutive_failures = 0 server_socket.settimeout(2) server_socket.close() - + if consecutive_failures != 5: - with open('/tmp/data.csv', 'w', newline='') as csvfile: - writer = csv.writer(csvfile, delimiter=',') - writer.writerow(["id", "client_send", "client_rcv"]) + with open("/tmp/data.csv", "w", newline="") as csvfile: + writer = csv.writer(csvfile, delimiter=",") + writer.writerow(["id", "client_send", "client_rcv"]) for row in times: writer.writerow(row) - + client = storage.storage.get_instance() - filename = 'results-{}.csv'.format(request_id) - key = client.upload(output_bucket, os.path.join(output_prefix, filename), '/tmp/data.csv') + filename = "results-{}.csv".format(request_id) + key = client.upload(output_bucket, os.path.join(output_prefix, filename), "/tmp/data.csv") - return { 'result': key } + return {"result": key} diff --git a/benchmarks/000.microbenchmarks/030.clock-synchronization/input.py b/benchmarks/000.microbenchmarks/030.clock-synchronization/input.py index 427215380..8f43ffc5a 100644 --- a/benchmarks/000.microbenchmarks/030.clock-synchronization/input.py +++ b/benchmarks/000.microbenchmarks/030.clock-synchronization/input.py @@ -1,12 +1,13 @@ - - def buckets_count(): return 0, 1 -def generate_input(data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func): + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): return { - 'bucket': { - 'bucket': benchmarks_bucket, - 'output': output_paths[0], + "bucket": { + "bucket": benchmarks_bucket, + "output": output_paths[0], }, } diff --git a/benchmarks/000.microbenchmarks/030.clock-synchronization/python/function.py b/benchmarks/000.microbenchmarks/030.clock-synchronization/python/function.py index 9ffd978ae..9cf93eccf 100644 --- a/benchmarks/000.microbenchmarks/030.clock-synchronization/python/function.py +++ b/benchmarks/000.microbenchmarks/030.clock-synchronization/python/function.py @@ -1,28 +1,27 @@ import csv -import json import os import socket from datetime import datetime -from time import sleep from . import storage + def handler(event): - request_id = event['request-id'] - address = event['server-address'] - port = event['server-port'] - repetitions = event['repetitions'] - output_bucket = event.get('bucket').get('bucket') - output_prefix = event.get('bucket').get('output') + request_id = event["request-id"] + address = event["server-address"] + port = event["server-port"] + repetitions = event["repetitions"] + output_bucket = event.get("bucket").get("bucket") + output_prefix = event.get("bucket").get("output") times = [] print("Starting communication with {}:{}".format(address, port)) i = 0 socket.setdefaulttimeout(4) server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server_socket.bind(('', 0)) - message = request_id.encode('utf-8') + server_socket.bind(("", 0)) + message = request_id.encode("utf-8") adr = (address, port) consecutive_failures = 0 measurements_not_smaller = 0 @@ -43,11 +42,13 @@ def handler(event): if i > 0: times.append([i, send_begin, recv_end]) cur_time = recv_end - send_begin - print("Time {} Min Time {} NotSmaller {}".format(cur_time, cur_min, measurements_not_smaller)) + print( + "Time {} Min Time {} NotSmaller {}".format(cur_time, cur_min, measurements_not_smaller) + ) if cur_time > cur_min and cur_min > 0: measurements_not_smaller += 1 if measurements_not_smaller == repetitions: - message = "stop".encode('utf-8') + message = "stop".encode("utf-8") server_socket.sendto(message, adr) break else: @@ -57,18 +58,18 @@ def handler(event): consecutive_failures = 0 server_socket.settimeout(4) server_socket.close() - + if consecutive_failures != 5: - with open('/tmp/data.csv', 'w', newline='') as csvfile: - writer = csv.writer(csvfile, delimiter=',') - writer.writerow(["id", "client_send", "client_rcv"]) + with open("/tmp/data.csv", "w", newline="") as csvfile: + writer = csv.writer(csvfile, delimiter=",") + writer.writerow(["id", "client_send", "client_rcv"]) for row in times: writer.writerow(row) - + client = storage.storage.get_instance() - filename = 'results-{}.csv'.format(request_id) - key = client.upload(output_bucket, os.path.join(output_prefix, filename), '/tmp/data.csv') + filename = "results-{}.csv".format(request_id) + key = client.upload(output_bucket, os.path.join(output_prefix, filename), "/tmp/data.csv") else: key = None - return { 'result': {'bucket-key': key, 'timestamp': event['income-timestamp']} } + return {"result": {"bucket-key": key, "timestamp": event["income-timestamp"]}} diff --git a/benchmarks/000.microbenchmarks/040.server-reply/input.py b/benchmarks/000.microbenchmarks/040.server-reply/input.py index 041d2ba7f..af0427a6c 100644 --- a/benchmarks/000.microbenchmarks/040.server-reply/input.py +++ b/benchmarks/000.microbenchmarks/040.server-reply/input.py @@ -1,12 +1,11 @@ +size_generators = {"test": 1, "small": 100, "large": 1000} -size_generators = { - 'test' : 1, - 'small' : 100, - 'large': 1000 -} def buckets_count(): return (0, 0) -def generate_input(data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func): - return { 'sleep': size_generators[size] } + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): + return {"sleep": size_generators[size]} diff --git a/benchmarks/000.microbenchmarks/040.server-reply/python/function.py b/benchmarks/000.microbenchmarks/040.server-reply/python/function.py index fb5b57aa3..4c2a294ba 100644 --- a/benchmarks/000.microbenchmarks/040.server-reply/python/function.py +++ b/benchmarks/000.microbenchmarks/040.server-reply/python/function.py @@ -1,11 +1,10 @@ - import socket -from time import sleep + def handler(event): # start timing - addr = (event.get('ip-address'), event.get('port')) + addr = (event.get("ip-address"), event.get("port")) socket.setdefaulttimeout(20) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(addr) diff --git a/benchmarks/100.webapps/110.dynamic-html/input.py b/benchmarks/100.webapps/110.dynamic-html/input.py index 98dac88b2..c20154ec3 100644 --- a/benchmarks/100.webapps/110.dynamic-html/input.py +++ b/benchmarks/100.webapps/110.dynamic-html/input.py @@ -1,11 +1,9 @@ +size_generators = {"test": 10, "small": 1000, "large": 100000} -size_generators = { - 'test' : 10, - 'small' : 1000, - 'large': 100000 -} -def generate_input(data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func): - input_config = {'username': 'testname'} - input_config['random_len'] = size_generators[size] +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): + input_config = {"username": "testname"} + input_config["random_len"] = size_generators[size] return input_config diff --git a/benchmarks/100.webapps/110.dynamic-html/python/function.py b/benchmarks/100.webapps/110.dynamic-html/python/function.py index 7c990f4eb..6f7b42bc5 100644 --- a/benchmarks/100.webapps/110.dynamic-html/python/function.py +++ b/benchmarks/100.webapps/110.dynamic-html/python/function.py @@ -1,22 +1,21 @@ -from datetime import datetime -from random import sample +from datetime import datetime +from random import sample from os import path -from time import time -import os from jinja2 import Template SCRIPT_DIR = path.abspath(path.join(path.dirname(__file__))) + def handler(event): # start timing - name = event.get('username') - size = event.get('random_len') + name = event.get("username") + size = event.get("random_len") cur_time = datetime.now() random_numbers = sample(range(0, 1000000), size) - template = Template( open(path.join(SCRIPT_DIR, 'templates', 'template.html'), 'r').read()) - html = template.render(username = name, cur_time = cur_time, random_numbers = random_numbers) + template = Template(open(path.join(SCRIPT_DIR, "templates", "template.html"), "r").read()) + html = template.render(username=name, cur_time=cur_time, random_numbers=random_numbers) # end timing - # dump stats - return {'result': html} + # dump stats + return {"result": html} diff --git a/benchmarks/100.webapps/120.uploader/input.py b/benchmarks/100.webapps/120.uploader/input.py index ce6169ccb..7aafb2b22 100644 --- a/benchmarks/100.webapps/120.uploader/input.py +++ b/benchmarks/100.webapps/120.uploader/input.py @@ -1,19 +1,25 @@ - url_generators = { # source: mlperf fake_imagenet.sh. 230 kB - 'test' : 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/Jammlich_crop.jpg/800px-Jammlich_crop.jpg', + "test": ( + "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/" + "Jammlich_crop.jpg/800px-Jammlich_crop.jpg" + ), # video: HPX source code, 6.7 MB - 'small': 'https://github.com/STEllAR-GROUP/hpx/archive/refs/tags/1.4.0.zip', + "small": "https://github.com/STEllAR-GROUP/hpx/archive/refs/tags/1.4.0.zip", # resnet model from pytorch. 98M - 'large': 'https://download.pytorch.org/models/resnet50-19c8e357.pth' + "large": "https://download.pytorch.org/models/resnet50-19c8e357.pth", } + def buckets_count(): return (0, 1) -def generate_input(data_dir, size, benchmarks_bucket, input_buckets, output_buckets, upload_func, nosql_func): - input_config = {'object': {}, 'bucket': {}} - input_config['object']['url'] = url_generators[size] - input_config['bucket']['bucket'] = benchmarks_bucket - input_config['bucket']['output'] = output_buckets[0] + +def generate_input( + data_dir, size, benchmarks_bucket, input_buckets, output_buckets, upload_func, nosql_func +): + input_config = {"object": {}, "bucket": {}} + input_config["object"]["url"] = url_generators[size] + input_config["bucket"]["bucket"] = benchmarks_bucket + input_config["bucket"]["output"] = output_buckets[0] return input_config diff --git a/benchmarks/100.webapps/120.uploader/python/function.py b/benchmarks/100.webapps/120.uploader/python/function.py index d032bbdb6..cb17131f1 100755 --- a/benchmarks/100.webapps/120.uploader/python/function.py +++ b/benchmarks/100.webapps/120.uploader/python/function.py @@ -1,26 +1,29 @@ - import datetime import os import urllib.request from . import storage + client = storage.storage.get_instance() -SEBS_USER_AGENT = "SeBS/1.2 (https://github.com/spcl/serverless-benchmarks) SeBS Benchmark Suite/1.2" +SEBS_USER_AGENT = ( + "SeBS/1.2 (https://github.com/spcl/serverless-benchmarks) SeBS Benchmark Suite/1.2" +) + def handler(event): - bucket = event.get('bucket').get('bucket') - output_prefix = event.get('bucket').get('output') - url = event.get('object').get('url') + bucket = event.get("bucket").get("bucket") + output_prefix = event.get("bucket").get("output") + url = event.get("object").get("url") name = os.path.basename(url) - download_path = '/tmp/{}'.format(name) + download_path = "/tmp/{}".format(name) process_begin = datetime.datetime.now() req = urllib.request.Request(url) - req.add_header('User-Agent', SEBS_USER_AGENT) - with open(download_path, 'wb') as f: + req.add_header("User-Agent", SEBS_USER_AGENT) + with open(download_path, "wb") as f: with urllib.request.urlopen(req) as response: f.write(response.read()) size = os.path.getsize(download_path) @@ -33,16 +36,12 @@ def handler(event): process_time = (process_end - process_begin) / datetime.timedelta(microseconds=1) upload_time = (upload_end - upload_begin) / datetime.timedelta(microseconds=1) return { - 'result': { - 'bucket': bucket, - 'url': url, - 'key': key_name - }, - 'measurement': { - 'download_time': 0, - 'download_size': 0, - 'upload_time': upload_time, - 'upload_size': size, - 'compute_time': process_time - } + "result": {"bucket": bucket, "url": url, "key": key_name}, + "measurement": { + "download_time": 0, + "download_size": 0, + "upload_time": upload_time, + "upload_size": size, + "compute_time": process_time, + }, } diff --git a/benchmarks/200.multimedia/210.thumbnailer/input.py b/benchmarks/200.multimedia/210.thumbnailer/input.py index 8943effed..6f04bfafb 100644 --- a/benchmarks/200.multimedia/210.thumbnailer/input.py +++ b/benchmarks/200.multimedia/210.thumbnailer/input.py @@ -1,9 +1,12 @@ -import glob, os +import glob +import os + def buckets_count(): return (1, 1) -''' + +""" Generate test, small and large workload for thumbnailer. :param data_dir: directory where benchmark data is placed @@ -11,19 +14,23 @@ def buckets_count(): :param input_buckets: input storage containers for this benchmark :param output_buckets: :param upload_func: upload function taking three params(bucket_idx, key, filepath) -''' -def generate_input(data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func): +""" + + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): - for file in glob.glob(os.path.join(data_dir, '*.jpg')): + for file in glob.glob(os.path.join(data_dir, "*.jpg")): img = os.path.relpath(file, data_dir) upload_func(0, img, file) - #TODO: multiple datasets - input_config = {'object': {}, 'bucket': {}} - input_config['object']['key'] = img - input_config['object']['width'] = 200 - input_config['object']['height'] = 200 - input_config['bucket']['bucket'] = benchmarks_bucket - input_config['bucket']['input'] = input_paths[0] - input_config['bucket']['output'] = output_paths[0] + # TODO: multiple datasets + input_config = {"object": {}, "bucket": {}} + input_config["object"]["key"] = img + input_config["object"]["width"] = 200 + input_config["object"]["height"] = 200 + input_config["bucket"]["bucket"] = benchmarks_bucket + input_config["bucket"]["input"] = input_paths[0] + input_config["bucket"]["output"] = output_paths[0] return input_config diff --git a/benchmarks/200.multimedia/210.thumbnailer/python/function.py b/benchmarks/200.multimedia/210.thumbnailer/python/function.py index 20527067b..2df0a7bfb 100755 --- a/benchmarks/200.multimedia/210.thumbnailer/python/function.py +++ b/benchmarks/200.multimedia/210.thumbnailer/python/function.py @@ -1,44 +1,45 @@ import datetime import io import os -import sys -import uuid from urllib.parse import unquote_plus from PIL import Image from . import storage + client = storage.storage.get_instance() # Disk-based solution -#def resize_image(image_path, resized_path, w, h): +# def resize_image(image_path, resized_path, w, h): # with Image.open(image_path) as image: # image.thumbnail((w,h)) # image.save(resized_path) + # Memory-based solution def resize_image(image_bytes, w, h): with Image.open(io.BytesIO(image_bytes)) as image: - image.thumbnail((w,h)) + image.thumbnail((w, h)) out = io.BytesIO() - image.save(out, format='jpeg') + image.save(out, format="jpeg") # necessary to rewind to the beginning of the buffer out.seek(0) return out + def handler(event): - - bucket = event.get('bucket').get('bucket') - input_prefix = event.get('bucket').get('input') - output_prefix = event.get('bucket').get('output') - key = unquote_plus(event.get('object').get('key')) - width = event.get('object').get('width') - height = event.get('object').get('height') + + bucket = event.get("bucket").get("bucket") + input_prefix = event.get("bucket").get("input") + output_prefix = event.get("bucket").get("output") + key = unquote_plus(event.get("object").get("key")) + width = event.get("object").get("width") + height = event.get("object").get("height") # UUID to handle multiple calls - #download_path = '/tmp/{}-{}'.format(uuid.uuid4(), key) - #upload_path = '/tmp/resized-{}'.format(key) - #client.download(input_bucket, key, download_path) - #resize_image(download_path, upload_path, width, height) - #client.upload(output_bucket, key, upload_path) + # download_path = '/tmp/{}-{}'.format(uuid.uuid4(), key) + # upload_path = '/tmp/resized-{}'.format(key) + # client.download(input_bucket, key, download_path) + # resize_image(download_path, upload_path, width, height) + # client.upload(output_bucket, key, upload_path) download_begin = datetime.datetime.now() img = client.download_stream(bucket, os.path.join(input_prefix, key)) download_end = datetime.datetime.now() @@ -56,15 +57,12 @@ def handler(event): upload_time = (upload_end - upload_begin) / datetime.timedelta(microseconds=1) process_time = (process_end - process_begin) / datetime.timedelta(microseconds=1) return { - 'result': { - 'bucket': bucket, - 'key': key_name - }, - 'measurement': { - 'download_time': download_time, - 'download_size': len(img), - 'upload_time': upload_time, - 'upload_size': resized_size, - 'compute_time': process_time - } + "result": {"bucket": bucket, "key": key_name}, + "measurement": { + "download_time": download_time, + "download_size": len(img), + "upload_time": upload_time, + "upload_size": resized_size, + "compute_time": process_time, + }, } diff --git a/benchmarks/200.multimedia/220.video-processing/input.py b/benchmarks/200.multimedia/220.video-processing/input.py index 6da31647f..86c7191cb 100644 --- a/benchmarks/200.multimedia/220.video-processing/input.py +++ b/benchmarks/200.multimedia/220.video-processing/input.py @@ -1,9 +1,12 @@ -import glob, os +import glob +import os + def buckets_count(): return (1, 1) -''' + +""" Generate test, small and large workload for thumbnailer. :param data_dir: directory where benchmark data is placed @@ -11,17 +14,21 @@ def buckets_count(): :param input_buckets: input storage containers for this benchmark :param output_buckets: :param upload_func: upload function taking three params(bucket_idx, key, filepath) -''' -def generate_input(data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func): - for file in glob.glob(os.path.join(data_dir, '*.mp4')): +""" + + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): + for file in glob.glob(os.path.join(data_dir, "*.mp4")): img = os.path.relpath(file, data_dir) upload_func(0, img, file) - #TODO: multiple datasets - input_config = {'object': {}, 'bucket': {}} - input_config['object']['key'] = img - input_config['object']['op'] = 'watermark' - input_config['object']['duration'] = 1 - input_config['bucket']['bucket'] = benchmarks_bucket - input_config['bucket']['input'] = input_paths[0] - input_config['bucket']['output'] = output_paths[0] + # TODO: multiple datasets + input_config = {"object": {}, "bucket": {}} + input_config["object"]["key"] = img + input_config["object"]["op"] = "watermark" + input_config["object"]["duration"] = 1 + input_config["bucket"]["bucket"] = benchmarks_bucket + input_config["bucket"]["input"] = input_paths[0] + input_config["bucket"]["output"] = output_paths[0] return input_config diff --git a/benchmarks/200.multimedia/220.video-processing/python/function.py b/benchmarks/200.multimedia/220.video-processing/python/function.py index 9f8a869aa..ab132ba2e 100755 --- a/benchmarks/200.multimedia/220.video-processing/python/function.py +++ b/benchmarks/200.multimedia/220.video-processing/python/function.py @@ -7,62 +7,84 @@ from . import storage + client = storage.storage.get_instance() SCRIPT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__))) + def call_ffmpeg(args): - ret = subprocess.run([os.path.join(SCRIPT_DIR, 'ffmpeg', 'ffmpeg'), '-y'] + args, - #subprocess might inherit Lambda's input for some reason - stdin=subprocess.DEVNULL, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT + ret = subprocess.run( + [os.path.join(SCRIPT_DIR, "ffmpeg", "ffmpeg"), "-y"] + args, + # subprocess might inherit Lambda's input for some reason + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, ) if ret.returncode != 0: - print('Invocation of ffmpeg failed!') - print('Out: ', ret.stdout.decode('utf-8')) + print("Invocation of ffmpeg failed!") + print("Out: ", ret.stdout.decode("utf-8")) raise RuntimeError() + # https://superuser.com/questions/556029/how-do-i-convert-a-video-to-gif-using-ffmpeg-with-reasonable-quality def to_gif(video, duration, event): - output = '/tmp/processed-{}.gif'.format(os.path.basename(video)) - call_ffmpeg(["-i", video, - "-t", - "{0}".format(duration), - "-vf", - "fps=10,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse", - "-loop", "0", - output]) + output = "/tmp/processed-{}.gif".format(os.path.basename(video)) + call_ffmpeg( + [ + "-i", + video, + "-t", + "{0}".format(duration), + "-vf", + "fps=10,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse", + "-loop", + "0", + output, + ] + ) return output + # https://devopstar.com/2019/01/28/serverless-watermark-using-aws-lambda-layers-ffmpeg/ def watermark(video, duration, event): - output = '/tmp/processed-{}'.format(os.path.basename(video)) + output = "/tmp/processed-{}".format(os.path.basename(video)) watermark_file = os.path.dirname(os.path.realpath(__file__)) - call_ffmpeg([ - "-i", video, - "-i", os.path.join(watermark_file, os.path.join('resources', 'watermark.png')), - "-t", "{0}".format(duration), - "-filter_complex", "overlay=main_w/2-overlay_w/2:main_h/2-overlay_h/2", - output]) + call_ffmpeg( + [ + "-i", + video, + "-i", + os.path.join(watermark_file, os.path.join("resources", "watermark.png")), + "-t", + "{0}".format(duration), + "-filter_complex", + "overlay=main_w/2-overlay_w/2:main_h/2-overlay_h/2", + output, + ] + ) return output + def transcode_mp3(video, duration, event): pass -operations = { 'transcode' : transcode_mp3, 'extract-gif' : to_gif, 'watermark' : watermark } + +operations = {"transcode": transcode_mp3, "extract-gif": to_gif, "watermark": watermark} + def handler(event): - bucket = event.get('bucket').get('bucket') - input_prefix = event.get('bucket').get('input') - output_prefix = event.get('bucket').get('output') - key = event.get('object').get('key') - duration = event.get('object').get('duration') - op = event.get('object').get('op') - download_path = '/tmp/{}'.format(key) + bucket = event.get("bucket").get("bucket") + input_prefix = event.get("bucket").get("input") + output_prefix = event.get("bucket").get("output") + key = event.get("object").get("key") + duration = event.get("object").get("duration") + op = event.get("object").get("op") + download_path = "/tmp/{}".format(key) # Restore executable permission - ffmpeg_binary = os.path.join(SCRIPT_DIR, 'ffmpeg', 'ffmpeg') + ffmpeg_binary = os.path.join(SCRIPT_DIR, "ffmpeg", "ffmpeg") # needed on Azure but read-only filesystem on AWS try: st = os.stat(ffmpeg_binary) @@ -89,16 +111,12 @@ def handler(event): upload_time = (upload_stop - upload_begin) / datetime.timedelta(microseconds=1) process_time = (process_end - process_begin) / datetime.timedelta(microseconds=1) return { - 'result': { - 'bucket': bucket, - 'key': upload_key - }, - 'measurement': { - 'download_time': download_time, - 'download_size': download_size, - 'upload_time': upload_time, - 'upload_size': upload_size, - 'compute_time': process_time - } - } - + "result": {"bucket": bucket, "key": upload_key}, + "measurement": { + "download_time": download_time, + "download_size": download_size, + "upload_time": upload_time, + "upload_size": upload_size, + "compute_time": process_time, + }, + } diff --git a/benchmarks/300.utilities/311.compression/input.py b/benchmarks/300.utilities/311.compression/input.py index 5f88bc91a..e9e706bd5 100644 --- a/benchmarks/300.utilities/311.compression/input.py +++ b/benchmarks/300.utilities/311.compression/input.py @@ -1,4 +1,5 @@ -import glob, os +import os + def buckets_count(): return (1, 1) @@ -9,11 +10,12 @@ def upload_files(data_root, data_dir, upload_func): for root, dirs, files in os.walk(data_dir): prefix = os.path.relpath(root, data_root) for file in files: - file_name = prefix + '/' + file + file_name = prefix + "/" + file filepath = os.path.join(root, file) upload_func(0, file_name, filepath) -''' + +""" Generate test, small and large workload for compression test. :param data_dir: directory where benchmark data is placed @@ -21,8 +23,12 @@ def upload_files(data_root, data_dir, upload_func): :param input_buckets: input storage containers for this benchmark :param output_buckets: :param upload_func: upload function taking three params(bucket_idx, key, filepath) -''' -def generate_input(data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func): +""" + + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): # upload different datasets datasets = [] @@ -30,9 +36,9 @@ def generate_input(data_dir, size, benchmarks_bucket, input_paths, output_paths, datasets.append(dir) upload_files(data_dir, os.path.join(data_dir, dir), upload_func) - input_config = {'object': {}, 'bucket': {}} - input_config['object']['key'] = datasets[0] - input_config['bucket']['bucket'] = benchmarks_bucket - input_config['bucket']['input'] = input_paths[0] - input_config['bucket']['output'] = output_paths[0] + input_config = {"object": {}, "bucket": {}} + input_config["object"]["key"] = datasets[0] + input_config["bucket"]["bucket"] = benchmarks_bucket + input_config["bucket"]["input"] = input_paths[0] + input_config["bucket"]["output"] = output_paths[0] return input_config diff --git a/benchmarks/300.utilities/311.compression/python/function.py b/benchmarks/300.utilities/311.compression/python/function.py index f758e14e4..8ceb52d2f 100755 --- a/benchmarks/300.utilities/311.compression/python/function.py +++ b/benchmarks/300.utilities/311.compression/python/function.py @@ -1,13 +1,13 @@ import datetime -import io import os import shutil import uuid -import zlib from . import storage + client = storage.storage.get_instance() + def parse_directory(directory): size = 0 @@ -16,13 +16,14 @@ def parse_directory(directory): size += os.path.getsize(os.path.join(root, file)) return size + def handler(event): - - bucket = event.get('bucket').get('bucket') - input_prefix = event.get('bucket').get('input') - output_prefix = event.get('bucket').get('output') - key = event.get('object').get('key') - download_path = '/tmp/{}-{}'.format(key, uuid.uuid4()) + + bucket = event.get("bucket").get("bucket") + input_prefix = event.get("bucket").get("input") + output_prefix = event.get("bucket").get("output") + key = event.get("object").get("key") + download_path = "/tmp/{}-{}".format(key, uuid.uuid4()) os.makedirs(download_path) s3_download_begin = datetime.datetime.now() @@ -31,29 +32,27 @@ def handler(event): size = parse_directory(download_path) compress_begin = datetime.datetime.now() - shutil.make_archive(os.path.join(download_path, key), 'zip', root_dir=download_path) + shutil.make_archive(os.path.join(download_path, key), "zip", root_dir=download_path) compress_end = datetime.datetime.now() s3_upload_begin = datetime.datetime.now() - archive_name = '{}.zip'.format(key) + archive_name = "{}.zip".format(key) archive_size = os.path.getsize(os.path.join(download_path, archive_name)) - key_name = client.upload(bucket, os.path.join(output_prefix, archive_name), os.path.join(download_path, archive_name)) + key_name = client.upload( + bucket, os.path.join(output_prefix, archive_name), os.path.join(download_path, archive_name) + ) s3_upload_stop = datetime.datetime.now() download_time = (s3_download_stop - s3_download_begin) / datetime.timedelta(microseconds=1) upload_time = (s3_upload_stop - s3_upload_begin) / datetime.timedelta(microseconds=1) process_time = (compress_end - compress_begin) / datetime.timedelta(microseconds=1) return { - 'result': { - 'bucket': bucket, - 'key': key_name - }, - 'measurement': { - 'download_time': download_time, - 'download_size': size, - 'upload_time': upload_time, - 'upload_size': archive_size, - 'compute_time': process_time - } - } - + "result": {"bucket": bucket, "key": key_name}, + "measurement": { + "download_time": download_time, + "download_size": size, + "upload_time": upload_time, + "upload_size": archive_size, + "compute_time": process_time, + }, + } diff --git a/benchmarks/400.inference/411.image-recognition/input.py b/benchmarks/400.inference/411.image-recognition/input.py index 45d7215a6..c5ce190d0 100644 --- a/benchmarks/400.inference/411.image-recognition/input.py +++ b/benchmarks/400.inference/411.image-recognition/input.py @@ -1,18 +1,21 @@ -import glob, os +import os + def buckets_count(): return (2, 0) + def upload_files(data_root, data_dir, upload_func): for root, dirs, files in os.walk(data_dir): prefix = os.path.relpath(root, data_root) for file in files: - file_name = prefix + '/' + file + file_name = prefix + "/" + file filepath = os.path.join(root, file) upload_func(0, file_name, filepath) -''' + +""" Generate test, small and large workload for compression test. :param data_dir: directory where benchmark data is placed @@ -20,25 +23,29 @@ def upload_files(data_root, data_dir, upload_func): :param input_buckets: input storage containers for this benchmark :param output_buckets: :param upload_func: upload function taking three params(bucket_idx, key, filepath) -''' -def generate_input(data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func): +""" + + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): # upload model - model_name = 'resnet50-19c8e357.pth' - upload_func(0, model_name, os.path.join(data_dir, 'model', model_name)) + model_name = "resnet50-19c8e357.pth" + upload_func(0, model_name, os.path.join(data_dir, "model", model_name)) input_images = [] - resnet_path = os.path.join(data_dir, 'fake-resnet') - with open(os.path.join(resnet_path, 'val_map.txt'), 'r') as f: + resnet_path = os.path.join(data_dir, "fake-resnet") + with open(os.path.join(resnet_path, "val_map.txt"), "r") as f: for line in f: img, img_class = line.split() input_images.append((img, img_class)) upload_func(1, img, os.path.join(resnet_path, img)) - - input_config = {'object': {}, 'bucket': {}} - input_config['object']['model'] = model_name - input_config['object']['input'] = input_images[0][0] - input_config['bucket']['bucket'] = benchmarks_bucket - input_config['bucket']['input'] = input_paths[1] - input_config['bucket']['model'] = input_paths[0] + + input_config = {"object": {}, "bucket": {}} + input_config["object"]["model"] = model_name + input_config["object"]["input"] = input_images[0][0] + input_config["bucket"]["bucket"] = benchmarks_bucket + input_config["bucket"]["input"] = input_paths[1] + input_config["bucket"]["model"] = input_paths[0] return input_config diff --git a/benchmarks/400.inference/411.image-recognition/python/function.py b/benchmarks/400.inference/411.image-recognition/python/function.py index 411386419..0cfa1c57f 100644 --- a/benchmarks/400.inference/411.image-recognition/python/function.py +++ b/benchmarks/400.inference/411.image-recognition/python/function.py @@ -1,14 +1,20 @@ - -import datetime, json, os, uuid +import datetime +import json +import os +import uuid # Extract zipped torch model - used in Python 3.8 and 3.9 # The reason is that torch versions supported for these Python # versions are too large for Lambda packages. -if os.path.exists('function/torch.zip'): - import zipfile, sys +if os.path.exists("function/torch.zip"): + import sys + import zipfile + # we cannot write to the read-only filesystem - zipfile.ZipFile('function/torch.zip').extractall('/tmp/') - sys.path.append(os.path.join(os.path.dirname(__file__), '/tmp/.python_packages/lib/site-packages')) + zipfile.ZipFile("function/torch.zip").extractall("/tmp/") + sys.path.append( + os.path.join(os.path.dirname(__file__), "/tmp/.python_packages/lib/site-packages") + ) from PIL import Image import torch @@ -16,21 +22,23 @@ from torchvision.models import resnet50 from . import storage + client = storage.storage.get_instance() SCRIPT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__))) -class_idx = json.load(open(os.path.join(SCRIPT_DIR, "imagenet_class_index.json"), 'r')) +class_idx = json.load(open(os.path.join(SCRIPT_DIR, "imagenet_class_index.json"), "r")) idx2label = [class_idx[str(k)][1] for k in range(len(class_idx))] model = None + def handler(event): - - bucket = event.get('bucket').get('bucket') - input_prefix = event.get('bucket').get('input') - model_prefix = event.get('bucket').get('model') - key = event.get('object').get('input') - model_key = event.get('object').get('model') - download_path = '/tmp/{}-{}'.format(key, uuid.uuid4()) + + bucket = event.get("bucket").get("bucket") + input_prefix = event.get("bucket").get("input") + model_prefix = event.get("bucket").get("model") + key = event.get("object").get("input") + model_key = event.get("object").get("model") + download_path = "/tmp/{}-{}".format(key, uuid.uuid4()) image_download_begin = datetime.datetime.now() image_path = download_path @@ -40,7 +48,7 @@ def handler(event): global model if not model: model_download_begin = datetime.datetime.now() - model_path = os.path.join('/tmp', model_key) + model_path = os.path.join("/tmp", model_key) client.download(bucket, os.path.join(model_prefix, model_key), model_path) model_download_end = datetime.datetime.now() model_process_begin = datetime.datetime.now() @@ -53,36 +61,38 @@ def handler(event): model_download_end = model_download_begin model_process_begin = datetime.datetime.now() model_process_end = model_process_begin - + process_begin = datetime.datetime.now() input_image = Image.open(image_path) - preprocess = transforms.Compose([ - transforms.Resize(256), - transforms.CenterCrop(224), - transforms.ToTensor(), - transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), - ]) + preprocess = transforms.Compose( + [ + transforms.Resize(256), + transforms.CenterCrop(224), + transforms.ToTensor(), + transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), + ] + ) input_tensor = preprocess(input_image) - input_batch = input_tensor.unsqueeze(0) # create a mini-batch as expected by the model + input_batch = input_tensor.unsqueeze(0) # create a mini-batch as expected by the model output = model(input_batch) _, index = torch.max(output, 1) - # The output has unnormalized scores. To get probabilities, you can run a softmax on it. - prob = torch.nn.functional.softmax(output[0], dim=0) - _, indices = torch.sort(output, descending = True) ret = idx2label[index] process_end = datetime.datetime.now() - download_time = (image_download_end- image_download_begin) / datetime.timedelta(microseconds=1) - model_download_time = (model_download_end - model_download_begin) / datetime.timedelta(microseconds=1) - model_process_time = (model_process_end - model_process_begin) / datetime.timedelta(microseconds=1) + download_time = (image_download_end - image_download_begin) / datetime.timedelta(microseconds=1) + model_download_time = (model_download_end - model_download_begin) / datetime.timedelta( + microseconds=1 + ) + model_process_time = (model_process_end - model_process_begin) / datetime.timedelta( + microseconds=1 + ) process_time = (process_end - process_begin) / datetime.timedelta(microseconds=1) return { - 'result': {'idx': index.item(), 'class': ret}, - 'measurement': { - 'download_time': download_time + model_download_time, - 'compute_time': process_time + model_process_time, - 'model_time': model_process_time, - 'model_download_time': model_download_time - } - } - + "result": {"idx": index.item(), "class": ret}, + "measurement": { + "download_time": download_time + model_download_time, + "compute_time": process_time + model_process_time, + "model_time": model_process_time, + "model_download_time": model_download_time, + }, + } diff --git a/benchmarks/500.scientific/501.graph-pagerank/input.py b/benchmarks/500.scientific/501.graph-pagerank/input.py index e20a6dcd1..a4ab10fb8 100644 --- a/benchmarks/500.scientific/501.graph-pagerank/input.py +++ b/benchmarks/500.scientific/501.graph-pagerank/input.py @@ -1,8 +1,7 @@ -size_generators = { - 'test' : 10, - 'small' : 10000, - 'large': 100000 -} +size_generators = {"test": 10, "small": 10000, "large": 100000} -def generate_input(data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func): - return { 'size': size_generators[size], 'seed': 42} + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): + return {"size": size_generators[size], "seed": 42} diff --git a/benchmarks/500.scientific/501.graph-pagerank/python/function.py b/benchmarks/500.scientific/501.graph-pagerank/python/function.py index 0e462e9b4..461fc14a9 100755 --- a/benchmarks/500.scientific/501.graph-pagerank/python/function.py +++ b/benchmarks/500.scientific/501.graph-pagerank/python/function.py @@ -1,9 +1,10 @@ import datetime import igraph + def handler(event): - size = event.get('size') + size = event.get("size") if "seed" in event: import random @@ -17,13 +18,15 @@ def handler(event): result = graph.pagerank() process_end = datetime.datetime.now() - graph_generating_time = (graph_generating_end - graph_generating_begin) / datetime.timedelta(microseconds=1) + graph_generating_time = (graph_generating_end - graph_generating_begin) / datetime.timedelta( + microseconds=1 + ) process_time = (process_end - process_begin) / datetime.timedelta(microseconds=1) return { - 'result': result[0], - 'measurement': { - 'graph_generating_time': graph_generating_time, - 'compute_time': process_time - } + "result": result[0], + "measurement": { + "graph_generating_time": graph_generating_time, + "compute_time": process_time, + }, } diff --git a/benchmarks/500.scientific/502.graph-mst/input.py b/benchmarks/500.scientific/502.graph-mst/input.py index e20a6dcd1..a4ab10fb8 100644 --- a/benchmarks/500.scientific/502.graph-mst/input.py +++ b/benchmarks/500.scientific/502.graph-mst/input.py @@ -1,8 +1,7 @@ -size_generators = { - 'test' : 10, - 'small' : 10000, - 'large': 100000 -} +size_generators = {"test": 10, "small": 10000, "large": 100000} -def generate_input(data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func): - return { 'size': size_generators[size], 'seed': 42} + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): + return {"size": size_generators[size], "seed": 42} diff --git a/benchmarks/500.scientific/502.graph-mst/python/function.py b/benchmarks/500.scientific/502.graph-mst/python/function.py index b63fbdce2..69ad77678 100755 --- a/benchmarks/500.scientific/502.graph-mst/python/function.py +++ b/benchmarks/500.scientific/502.graph-mst/python/function.py @@ -1,9 +1,10 @@ import datetime import igraph + def handler(event): - size = event.get('size') + size = event.get("size") if "seed" in event: import random @@ -17,13 +18,15 @@ def handler(event): result = graph.spanning_tree(None, False) process_end = datetime.datetime.now() - graph_generating_time = (graph_generating_end - graph_generating_begin) / datetime.timedelta(microseconds=1) + graph_generating_time = (graph_generating_end - graph_generating_begin) / datetime.timedelta( + microseconds=1 + ) process_time = (process_end - process_begin) / datetime.timedelta(microseconds=1) return { - 'result': result[0], - 'measurement': { - 'graph_generating_time': graph_generating_time, - 'compute_time': process_time - } + "result": result[0], + "measurement": { + "graph_generating_time": graph_generating_time, + "compute_time": process_time, + }, } diff --git a/benchmarks/500.scientific/503.graph-bfs/input.py b/benchmarks/500.scientific/503.graph-bfs/input.py index e20a6dcd1..a4ab10fb8 100644 --- a/benchmarks/500.scientific/503.graph-bfs/input.py +++ b/benchmarks/500.scientific/503.graph-bfs/input.py @@ -1,8 +1,7 @@ -size_generators = { - 'test' : 10, - 'small' : 10000, - 'large': 100000 -} +size_generators = {"test": 10, "small": 10000, "large": 100000} -def generate_input(data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func): - return { 'size': size_generators[size], 'seed': 42} + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): + return {"size": size_generators[size], "seed": 42} diff --git a/benchmarks/500.scientific/503.graph-bfs/python/function.py b/benchmarks/500.scientific/503.graph-bfs/python/function.py index 18423ae1a..51a37346b 100755 --- a/benchmarks/500.scientific/503.graph-bfs/python/function.py +++ b/benchmarks/500.scientific/503.graph-bfs/python/function.py @@ -1,9 +1,10 @@ import datetime import igraph + def handler(event): - size = event.get('size') + size = event.get("size") if "seed" in event: import random @@ -17,13 +18,15 @@ def handler(event): result = graph.bfs(0) process_end = datetime.datetime.now() - graph_generating_time = (graph_generating_end - graph_generating_begin) / datetime.timedelta(microseconds=1) + graph_generating_time = (graph_generating_end - graph_generating_begin) / datetime.timedelta( + microseconds=1 + ) process_time = (process_end - process_begin) / datetime.timedelta(microseconds=1) return { - 'result': result, - 'measurement': { - 'graph_generating_time': graph_generating_time, - 'compute_time': process_time - } + "result": result, + "measurement": { + "graph_generating_time": graph_generating_time, + "compute_time": process_time, + }, } diff --git a/benchmarks/500.scientific/504.dna-visualisation/input.py b/benchmarks/500.scientific/504.dna-visualisation/input.py index a9f376ea2..ea26f48c0 100644 --- a/benchmarks/500.scientific/504.dna-visualisation/input.py +++ b/benchmarks/500.scientific/504.dna-visualisation/input.py @@ -1,16 +1,21 @@ -import glob, os +import glob +import os + def buckets_count(): return (1, 1) -def generate_input(data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func): - for file in glob.glob(os.path.join(data_dir, '*.fasta')): +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): + + for file in glob.glob(os.path.join(data_dir, "*.fasta")): data = os.path.relpath(file, data_dir) upload_func(0, data, file) - input_config = {'object': {}, 'bucket': {}} - input_config['object']['key'] = data - input_config['bucket']['bucket'] = benchmarks_bucket - input_config['bucket']['input'] = input_paths[0] - input_config['bucket']['output'] = output_paths[0] + input_config = {"object": {}, "bucket": {}} + input_config["object"]["key"] = data + input_config["bucket"]["bucket"] = benchmarks_bucket + input_config["bucket"]["input"] = input_paths[0] + input_config["bucket"]["output"] = output_paths[0] return input_config diff --git a/benchmarks/500.scientific/504.dna-visualisation/python/function.py b/benchmarks/500.scientific/504.dna-visualisation/python/function.py index 8362a73a1..ca9f5975e 100755 --- a/benchmarks/500.scientific/504.dna-visualisation/python/function.py +++ b/benchmarks/500.scientific/504.dna-visualisation/python/function.py @@ -1,17 +1,23 @@ -import datetime, io, json, os +import datetime +import io +import json +import os + # using https://squiggle.readthedocs.io/en/latest/ from squiggle import transform from . import storage + client = storage.storage.get_instance() + def handler(event): - bucket = event.get('bucket').get('bucket') - input_prefix = event.get('bucket').get('input') - output_prefix = event.get('bucket').get('output') - key = event.get('object').get('key') - download_path = '/tmp/{}'.format(key) + bucket = event.get("bucket").get("bucket") + input_prefix = event.get("bucket").get("input") + output_prefix = event.get("bucket").get("output") + key = event.get("object").get("key") + download_path = "/tmp/{}".format(key) download_begin = datetime.datetime.now() client.download(bucket, os.path.join(input_prefix, key), download_path) @@ -34,13 +40,10 @@ def handler(event): process_time = (process_end - process_begin) / datetime.timedelta(microseconds=1) return { - 'result': { - 'bucket': bucket, - 'key': key_name - }, - 'measurement': { - 'download_time': download_time, - 'compute_time': process_time, - 'upload_time': process_time - } + "result": {"bucket": bucket, "key": key_name}, + "measurement": { + "download_time": download_time, + "compute_time": process_time, + "upload_time": upload_time, + }, } diff --git a/benchmarks/wrappers/aws/python/handler.py b/benchmarks/wrappers/aws/python/handler.py index 907b2c612..f5a1d4195 100644 --- a/benchmarks/wrappers/aws/python/handler.py +++ b/benchmarks/wrappers/aws/python/handler.py @@ -1,39 +1,46 @@ - -import datetime, io, json, os, sys, uuid +import datetime +import io +import json +import os +import sys +import uuid # Add current directory to allow location of packages -sys.path.append(os.path.join(os.path.dirname(__file__), '.python_packages/lib/site-packages')) +sys.path.append(os.path.join(os.path.dirname(__file__), ".python_packages/lib/site-packages")) # TODO: usual trigger # implement support for S3 and others + + def handler(event, context): income_timestamp = datetime.datetime.now().timestamp() # HTTP trigger with API Gateaway - if 'body' in event: - event = json.loads(event['body']) + if "body" in event: + event = json.loads(event["body"]) req_id = context.aws_request_id - event['request-id'] = req_id - event['income-timestamp'] = income_timestamp + event["request-id"] = req_id + event["income-timestamp"] = income_timestamp begin = datetime.datetime.now() from function import function + ret = function.handler(event) end = datetime.datetime.now() - log_data = { - 'output': ret['result'] - } - if 'measurement' in ret: - log_data['measurement'] = ret['measurement'] - if 'logs' in event: - log_data['time'] = (end - begin) / datetime.timedelta(microseconds=1) + log_data = {"output": ret["result"]} + if "measurement" in ret: + log_data["measurement"] = ret["measurement"] + if "logs" in event: + log_data["time"] = (end - begin) / datetime.timedelta(microseconds=1) results_begin = datetime.datetime.now() from function import storage + storage_inst = storage.storage.get_instance() - b = event.get('logs').get('bucket') - storage_inst.upload_stream(b, '{}.json'.format(req_id), - io.BytesIO(json.dumps(log_data).encode('utf-8'))) + b = event.get("logs").get("bucket") + storage_inst.upload_stream( + b, "{}.json".format(req_id), io.BytesIO(json.dumps(log_data).encode("utf-8")) + ) results_end = datetime.datetime.now() results_time = (results_end - results_begin) / datetime.timedelta(microseconds=1) else: @@ -41,14 +48,14 @@ def handler(event, context): # cold test is_cold = False - fname = os.path.join('/tmp', 'cold_run') + fname = os.path.join("/tmp", "cold_run") if not os.path.exists(fname): is_cold = True container_id = str(uuid.uuid4())[0:8] - with open(fname, 'a') as f: + with open(fname, "a") as f: f.write(container_id) else: - with open(fname, 'r') as f: + with open(fname, "r") as f: container_id = f.read() cold_start_var = "" @@ -56,16 +63,17 @@ def handler(event, context): cold_start_var = os.environ["cold_start"] return { - 'statusCode': 200, - 'body': json.dumps({ - 'begin': begin.strftime('%s.%f'), - 'end': end.strftime('%s.%f'), - 'results_time': results_time, - 'is_cold': is_cold, - 'result': log_data, - 'request_id': context.aws_request_id, - 'cold_start_var': cold_start_var, - 'container_id': container_id, - }) + "statusCode": 200, + "body": json.dumps( + { + "begin": begin.strftime("%s.%f"), + "end": end.strftime("%s.%f"), + "results_time": results_time, + "is_cold": is_cold, + "result": log_data, + "request_id": context.aws_request_id, + "cold_start_var": cold_start_var, + "container_id": container_id, + } + ), } - diff --git a/benchmarks/wrappers/aws/python/setup.py b/benchmarks/wrappers/aws/python/setup.py index b3d878351..016974465 100644 --- a/benchmarks/wrappers/aws/python/setup.py +++ b/benchmarks/wrappers/aws/python/setup.py @@ -2,14 +2,13 @@ from glob import glob from pkg_resources import parse_requirements -with open('requirements.txt') as f: +with open("requirements.txt") as f: requirements = [str(r) for r in parse_requirements(f)] setup( - name='function', + name="function", install_requires=requirements, - packages=['function'], - package_dir={'function': '.'}, - package_data={'function': glob('**', recursive=True)}, + packages=["function"], + package_dir={"function": "."}, + package_data={"function": glob("**", recursive=True)}, ) - diff --git a/benchmarks/wrappers/aws/python/storage.py b/benchmarks/wrappers/aws/python/storage.py index 4be0025e8..50875fbfc 100644 --- a/benchmarks/wrappers/aws/python/storage.py +++ b/benchmarks/wrappers/aws/python/storage.py @@ -10,16 +10,14 @@ class storage: client = None def __init__(self): - self.client = boto3.client('s3') + self.client = boto3.client("s3") @staticmethod def unique_name(name): name, extension = os.path.splitext(name) - return '{name}.{random}{extension}'.format( - name=name, - extension=extension, - random=str(uuid.uuid4()).split('-')[0] - ) + return "{name}.{random}{extension}".format( + name=name, extension=extension, random=str(uuid.uuid4()).split("-")[0] + ) def upload(self, bucket, file, filepath): key_name = storage.unique_name(file) @@ -31,8 +29,8 @@ def download(self, bucket, file, filepath): def download_directory(self, bucket, prefix, path): objects = self.client.list_objects_v2(Bucket=bucket, Prefix=prefix) - for obj in objects['Contents']: - file_name = obj['Key'] + for obj in objects["Contents"]: + file_name = obj["Key"] path_to_file = os.path.dirname(file_name) os.makedirs(os.path.join(path, path_to_file), exist_ok=True) self.download(bucket, file_name, os.path.join(path, file_name)) @@ -46,7 +44,7 @@ def download_stream(self, bucket, file): data = io.BytesIO() self.client.download_fileobj(bucket, file, data) return data.getbuffer() - + def get_instance(): if storage.instance is None: storage.instance = storage() diff --git a/benchmarks/wrappers/azure/python/handler.py b/benchmarks/wrappers/azure/python/handler.py index 88e44baf6..964fc2fde 100644 --- a/benchmarks/wrappers/azure/python/handler.py +++ b/benchmarks/wrappers/azure/python/handler.py @@ -1,52 +1,60 @@ - -import datetime, io, json, os, uuid +import datetime +import io +import json +import os +import uuid import azure.functions as func -if 'NOSQL_STORAGE_DATABASE' in os.environ: +if "NOSQL_STORAGE_DATABASE" in os.environ: from . import nosql nosql.nosql.get_instance( - os.environ['NOSQL_STORAGE_DATABASE'], - os.environ['NOSQL_STORAGE_URL'], - os.environ['NOSQL_STORAGE_CREDS'] + os.environ["NOSQL_STORAGE_DATABASE"], + os.environ["NOSQL_STORAGE_URL"], + os.environ["NOSQL_STORAGE_CREDS"], ) -if 'STORAGE_CONNECTION_STRING' in os.environ: +if "STORAGE_CONNECTION_STRING" in os.environ: from . import storage - client = storage.storage.get_instance(os.environ['STORAGE_CONNECTION_STRING']) + + client = storage.storage.get_instance(os.environ["STORAGE_CONNECTION_STRING"]) + # TODO: usual trigger # implement support for blob and others + + def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse: income_timestamp = datetime.datetime.now().timestamp() req_json = req.get_json() - req_json['request-id'] = context.invocation_id - req_json['income-timestamp'] = income_timestamp + req_json["request-id"] = context.invocation_id + req_json["income-timestamp"] = income_timestamp begin = datetime.datetime.now() # We are deployed in the same directory from . import function + ret = function.handler(req_json) end = datetime.datetime.now() - log_data = { - 'output': ret['result'] - } - if 'measurement' in ret: - log_data['measurement'] = ret['measurement'] - if 'logs' in req_json: - log_data['time'] = (end - begin) / datetime.timedelta(microseconds=1) + log_data = {"output": ret["result"]} + if "measurement" in ret: + log_data["measurement"] = ret["measurement"] + if "logs" in req_json: + log_data["time"] = (end - begin) / datetime.timedelta(microseconds=1) results_begin = datetime.datetime.now() from . import storage + storage_inst = storage.storage.get_instance() - b = req_json.get('logs').get('bucket') + b = req_json.get("logs").get("bucket") req_id = context.invocation_id - storage_inst.upload_stream(b, '{}.json'.format(req_id), - io.BytesIO(json.dumps(log_data).encode('utf-8'))) + storage_inst.upload_stream( + b, "{}.json".format(req_id), io.BytesIO(json.dumps(log_data).encode("utf-8")) + ) results_end = datetime.datetime.now() results_time = (results_end - results_begin) / datetime.timedelta(microseconds=1) else: @@ -54,14 +62,14 @@ def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse: # cold test is_cold = False - fname = os.path.join('/tmp','cold_run') + fname = os.path.join("/tmp", "cold_run") if not os.path.exists(fname): is_cold = True container_id = str(uuid.uuid4())[0:8] - with open(fname, 'a') as f: + with open(fname, "a") as f: f.write(container_id) else: - with open(fname, 'r') as f: + with open(fname, "r") as f: container_id = f.read() is_cold_worker = False @@ -73,17 +81,18 @@ def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse: is_cold_worker = True return func.HttpResponse( - json.dumps({ - 'begin': begin.strftime('%s.%f'), - 'end': end.strftime('%s.%f'), - 'results_time': results_time, - 'result': log_data, - 'is_cold': is_cold, - 'is_cold_worker': is_cold_worker, - 'container_id': container_id, - 'environ_container_id': os.environ['CONTAINER_NAME'], - 'request_id': context.invocation_id - }), - mimetype="application/json" + json.dumps( + { + "begin": begin.strftime("%s.%f"), + "end": end.strftime("%s.%f"), + "results_time": results_time, + "result": log_data, + "is_cold": is_cold, + "is_cold_worker": is_cold_worker, + "container_id": container_id, + "environ_container_id": os.environ["CONTAINER_NAME"], + "request_id": context.invocation_id, + } + ), + mimetype="application/json", ) - diff --git a/benchmarks/wrappers/azure/python/storage.py b/benchmarks/wrappers/azure/python/storage.py index 42b129c89..fabd8e6a1 100644 --- a/benchmarks/wrappers/azure/python/storage.py +++ b/benchmarks/wrappers/azure/python/storage.py @@ -1,10 +1,10 @@ - import os import uuid from typing import Optional from azure.storage.blob import BlobServiceClient + class storage: instance = None client = None @@ -15,20 +15,18 @@ def __init__(self, connection_string: str): @staticmethod def unique_name(name): name, extension = os.path.splitext(name) - return '{name}.{random}{extension}'.format( - name=name, - extension=extension, - random=str(uuid.uuid4()).split('-')[0] - ) + return "{name}.{random}{extension}".format( + name=name, extension=extension, random=str(uuid.uuid4()).split("-")[0] + ) def upload(self, container, file, filepath): - with open(filepath, 'rb') as data: + with open(filepath, "rb") as data: return self.upload_stream(container, file, data) def download(self, container, file, filepath): - with open(filepath, 'wb') as download_file: - download_file.write( self.download_stream(container, file) ) - + with open(filepath, "wb") as download_file: + download_file.write(self.download_stream(container, file)) + def download_directory(self, container, prefix, path): client = self.client.get_container_client(container=container) objects = client.list_blobs(name_starts_with=prefix) @@ -37,20 +35,17 @@ def download_directory(self, container, prefix, path): path_to_file = os.path.dirname(file_name) os.makedirs(os.path.join(path, path_to_file), exist_ok=True) self.download(container, file_name, os.path.join(path, file_name)) - + def upload_stream(self, container, file, data): key_name = storage.unique_name(file) - client = self.client.get_blob_client( - container=container, - blob=key_name - ) + client = self.client.get_blob_client(container=container, blob=key_name) client.upload_blob(data) return key_name def download_stream(self, container, file): client = self.client.get_blob_client(container=container, blob=file) return client.download_blob().readall() - + @staticmethod def get_instance(connection_string: Optional[str] = None): if storage.instance is None: diff --git a/benchmarks/wrappers/gcp/python/handler.py b/benchmarks/wrappers/gcp/python/handler.py index 9b6989611..57e1d000b 100644 --- a/benchmarks/wrappers/gcp/python/handler.py +++ b/benchmarks/wrappers/gcp/python/handler.py @@ -1,44 +1,46 @@ -import datetime, io, json, os, uuid, sys +import datetime +import io +import json +import os +import sys +import uuid -sys.path.append(os.path.join(os.path.dirname(__file__), '.python_packages/lib/site-packages')) +sys.path.append(os.path.join(os.path.dirname(__file__), ".python_packages/lib/site-packages")) # This variable is defined by SeBS during function creation. -if 'NOSQL_STORAGE_DATABASE' in os.environ: +if "NOSQL_STORAGE_DATABASE" in os.environ: from function import nosql - nosql.nosql.get_instance( - os.environ['NOSQL_STORAGE_DATABASE'] - ) + nosql.nosql.get_instance(os.environ["NOSQL_STORAGE_DATABASE"]) def handler(req): income_timestamp = datetime.datetime.now().timestamp() - req_id = req.headers.get('Function-Execution-Id') - + req_id = req.headers.get("Function-Execution-Id") req_json = req.get_json() - req_json['request-id'] = req_id - req_json['income-timestamp'] = income_timestamp + req_json["request-id"] = req_id + req_json["income-timestamp"] = income_timestamp begin = datetime.datetime.now() # We are deployed in the same directorygit status from function import function + ret = function.handler(req_json) end = datetime.datetime.now() - - log_data = { - 'output': ret['result'] - } - if 'measurement' in ret: - log_data['measurement'] = ret['measurement'] - if 'logs' in req_json: - log_data['time'] = (end - begin) / datetime.timedelta(microseconds=1) + log_data = {"output": ret["result"]} + if "measurement" in ret: + log_data["measurement"] = ret["measurement"] + if "logs" in req_json: + log_data["time"] = (end - begin) / datetime.timedelta(microseconds=1) results_begin = datetime.datetime.now() from function import storage + storage_inst = storage.storage.get_instance() - b = req_json.get('logs').get('bucket') - storage_inst.upload_stream(b, '{}.json'.format(req_id), - io.BytesIO(json.dumps(log_data).encode('utf-8'))) + b = req_json.get("logs").get("bucket") + storage_inst.upload_stream( + b, "{}.json".format(req_id), io.BytesIO(json.dumps(log_data).encode("utf-8")) + ) results_end = datetime.datetime.now() results_time = (results_end - results_begin) / datetime.timedelta(microseconds=1) else: @@ -46,27 +48,33 @@ def handler(req): # cold test is_cold = False - fname = os.path.join('/tmp', 'cold_run') + fname = os.path.join("/tmp", "cold_run") if not os.path.exists(fname): is_cold = True container_id = str(uuid.uuid4())[0:8] - with open(fname, 'a') as f: + with open(fname, "a") as f: f.write(container_id) else: - with open(fname, 'r') as f: + with open(fname, "r") as f: container_id = f.read() cold_start_var = "" if "cold_start" in os.environ: cold_start_var = os.environ["cold_start"] - return json.dumps({ - 'begin': begin.strftime('%s.%f'), - 'end': end.strftime('%s.%f'), - 'results_time': results_time, - 'is_cold': is_cold, - 'result': log_data, - 'request_id': req_id, - 'cold_start_var': cold_start_var, - 'container_id': container_id, - }), 200, {'ContentType': 'application/json'} + return ( + json.dumps( + { + "begin": begin.strftime("%s.%f"), + "end": end.strftime("%s.%f"), + "results_time": results_time, + "is_cold": is_cold, + "result": log_data, + "request_id": req_id, + "cold_start_var": cold_start_var, + "container_id": container_id, + } + ), + 200, + {"ContentType": "application/json"}, + ) diff --git a/benchmarks/wrappers/gcp/python/storage.py b/benchmarks/wrappers/gcp/python/storage.py index 81163cb34..70f182618 100644 --- a/benchmarks/wrappers/gcp/python/storage.py +++ b/benchmarks/wrappers/gcp/python/storage.py @@ -15,11 +15,9 @@ def __init__(self): @staticmethod def unique_name(name): name, extension = os.path.splitext(name) - return '{name}.{random}{extension}'.format( - name=name, - extension=extension, - random=str(uuid.uuid4()).split('-')[0] - ) + return "{name}.{random}{extension}".format( + name=name, extension=extension, random=str(uuid.uuid4()).split("-")[0] + ) def upload(self, bucket, file, filepath): key_name = storage.unique_name(file) diff --git a/benchmarks/wrappers/local/python/storage.py b/benchmarks/wrappers/local/python/storage.py index b44968408..d25583a13 100644 --- a/benchmarks/wrappers/local/python/storage.py +++ b/benchmarks/wrappers/local/python/storage.py @@ -1,32 +1,28 @@ -import io import os import uuid import minio + class storage: instance = None client = None def __init__(self): - if 'MINIO_ADDRESS' in os.environ: - address = os.environ['MINIO_ADDRESS'] - access_key = os.environ['MINIO_ACCESS_KEY'] - secret_key = os.environ['MINIO_SECRET_KEY'] + if "MINIO_ADDRESS" in os.environ: + address = os.environ["MINIO_ADDRESS"] + access_key = os.environ["MINIO_ACCESS_KEY"] + secret_key = os.environ["MINIO_SECRET_KEY"] self.client = minio.Minio( - address, - access_key=access_key, - secret_key=secret_key, - secure=False) + address, access_key=access_key, secret_key=secret_key, secure=False + ) @staticmethod def unique_name(name): name, extension = os.path.splitext(name) - return '{name}.{random}{extension}'.format( - name=name, - extension=extension, - random=str(uuid.uuid4()).split('-')[0] - ) + return "{name}.{random}{extension}".format( + name=name, extension=extension, random=str(uuid.uuid4()).split("-")[0] + ) def upload(self, bucket, file, filepath): key_name = storage.unique_name(file) @@ -55,4 +51,3 @@ def get_instance(): if storage.instance is None: storage.instance = storage() return storage.instance - diff --git a/benchmarks/wrappers/openwhisk/python/__main__.py b/benchmarks/wrappers/openwhisk/python/__main__.py index 3ae44f9c2..3833bff8c 100644 --- a/benchmarks/wrappers/openwhisk/python/__main__.py +++ b/benchmarks/wrappers/openwhisk/python/__main__.py @@ -2,24 +2,30 @@ import datetime import os + def main(args): logging.getLogger().setLevel(logging.INFO) begin = datetime.datetime.now() - args['request-id'] = os.getenv('__OW_ACTIVATION_ID') - args['income-timestamp'] = begin.timestamp() + args["request-id"] = os.getenv("__OW_ACTIVATION_ID") + args["income-timestamp"] = begin.timestamp() - for arg in ["MINIO_STORAGE_CONNECTION_URL", "MINIO_STORAGE_ACCESS_KEY", "MINIO_STORAGE_SECRET_KEY"]: + for arg in [ + "MINIO_STORAGE_CONNECTION_URL", + "MINIO_STORAGE_ACCESS_KEY", + "MINIO_STORAGE_SECRET_KEY", + ]: os.environ[arg] = args[arg] del args[arg] key_list = list(args.keys()) for arg in key_list: - if 'NOSQL_STORAGE_' in arg: + if "NOSQL_STORAGE_" in arg: os.environ[arg] = args[arg] del args[arg] try: from function import function + ret = function.handler(args) end = datetime.datetime.now() logging.info("Function result: {}".format(ret)) @@ -38,7 +44,7 @@ def main(args): return { "begin": begin.strftime("%s.%f"), "end": end.strftime("%s.%f"), - "request_id": os.getenv('__OW_ACTIVATION_ID'), + "request_id": os.getenv("__OW_ACTIVATION_ID"), "results_time": results_time, "is_cold": is_cold, "result": log_data, @@ -49,7 +55,7 @@ def main(args): return { "begin": begin.strftime("%s.%f"), "end": end.strftime("%s.%f"), - "request_id": os.getenv('__OW_ACTIVATION_ID'), + "request_id": os.getenv("__OW_ACTIVATION_ID"), "results_time": results_time, - "result": f"Error - invocation failed! Reason: {e}" + "result": f"Error - invocation failed! Reason: {e}", } diff --git a/benchmarks/wrappers/openwhisk/python/nosql.py b/benchmarks/wrappers/openwhisk/python/nosql.py index da8245009..4a8676d36 100644 --- a/benchmarks/wrappers/openwhisk/python/nosql.py +++ b/benchmarks/wrappers/openwhisk/python/nosql.py @@ -5,6 +5,7 @@ import boto3 from botocore.client import Config + class nosql: instance: Optional["nosql"] = None @@ -14,14 +15,14 @@ def __init__(self): if environ["NOSQL_STORAGE_TYPE"] != "scylladb": raise RuntimeError(f"Unsupported NoSQL storage type: {environ['NOSQL_STORAGE_TYPE']}!") - config = Config(connect_timeout=5, retries={'max_attempts': 0}) + config = Config(connect_timeout=5, retries={"max_attempts": 0}) self.client = boto3.resource( "dynamodb", region_name="None", aws_access_key_id="None", aws_secret_access_key="None", endpoint_url=f"http://{environ['NOSQL_STORAGE_ENDPOINT']}", - config=config + config=config, ) self._tables = {} diff --git a/benchmarks/wrappers/openwhisk/python/setup.py b/benchmarks/wrappers/openwhisk/python/setup.py index b942d059b..016974465 100644 --- a/benchmarks/wrappers/openwhisk/python/setup.py +++ b/benchmarks/wrappers/openwhisk/python/setup.py @@ -2,13 +2,13 @@ from glob import glob from pkg_resources import parse_requirements -with open('requirements.txt') as f: +with open("requirements.txt") as f: requirements = [str(r) for r in parse_requirements(f)] setup( - name='function', + name="function", install_requires=requirements, - packages=['function'], - package_dir={'function': '.'}, - package_data={'function': glob('**', recursive=True)}, -) \ No newline at end of file + packages=["function"], + package_dir={"function": "."}, + package_data={"function": glob("**", recursive=True)}, +) diff --git a/benchmarks/wrappers/openwhisk/python/storage.py b/benchmarks/wrappers/openwhisk/python/storage.py index 76c7e3e8e..09b9e78a7 100644 --- a/benchmarks/wrappers/openwhisk/python/storage.py +++ b/benchmarks/wrappers/openwhisk/python/storage.py @@ -1,8 +1,8 @@ +import logging import os import uuid -import json + import minio -import logging class storage: @@ -25,14 +25,14 @@ def __init__(self): maxsize=10, retries=urllib3.Retry( total=5, backoff_factor=0.2, status_forcelist=[500, 502, 503, 504] - ) + ), ) self.client = minio.Minio( os.getenv("MINIO_STORAGE_CONNECTION_URL"), access_key=os.getenv("MINIO_STORAGE_ACCESS_KEY"), secret_key=os.getenv("MINIO_STORAGE_SECRET_KEY"), secure=False, - http_client=mgr + http_client=mgr, ) except Exception as e: logging.info(e) @@ -41,12 +41,9 @@ def __init__(self): @staticmethod def unique_name(name): name, extension = os.path.splitext(name) - return '{name}.{random}{extension}'.format( - name=name, - extension=extension, - random=str(uuid.uuid4()).split('-')[0] - ) - + return "{name}.{random}{extension}".format( + name=name, extension=extension, random=str(uuid.uuid4()).split("-")[0] + ) def upload(self, bucket, file, filepath): key_name = storage.unique_name(file) @@ -64,9 +61,7 @@ def download_directory(self, bucket, prefix, path): def upload_stream(self, bucket, file, bytes_data): key_name = storage.unique_name(file) - self.client.put_object( - bucket, key_name, bytes_data, bytes_data.getbuffer().nbytes - ) + self.client.put_object(bucket, key_name, bytes_data, bytes_data.getbuffer().nbytes) return key_name def download_stream(self, bucket, file): From 27b14d691b1911e84003be31c07810e07c52a824 Mon Sep 17 00:00:00 2001 From: Russellpang Date: Wed, 5 Nov 2025 17:55:59 +0100 Subject: [PATCH 14/58] add linalg benchmarks --- .../600.linearalgebra/601.matmul/config.json | 6 ++ .../600.linearalgebra/601.matmul/input.py | 7 ++ .../601.matmul/python/function.py | 59 ++++++++++++++++ .../601.matmul/python/requirements.txt | 1 + .../601.matmul/python/requirements.txt.3.10 | 0 .../601.matmul/python/requirements.txt.3.11 | 0 .../601.matmul/python/requirements.txt.3.12 | 0 .../601.matmul/python/requirements.txt.3.7 | 0 .../601.matmul/python/requirements.txt.3.8 | 0 .../601.matmul/python/requirements.txt.3.9 | 0 .../python/requirements.txt.arm.3.8 | 0 .../python/requirements.txt.arm.3.9 | 0 .../600.linearalgebra/602.axpy/config.json | 6 ++ .../600.linearalgebra/602.axpy/input.py | 7 ++ .../602.axpy/python/function.py | 59 ++++++++++++++++ .../602.axpy/python/requirements.txt | 1 + .../602.axpy/python/requirements.txt.3.10 | 0 .../602.axpy/python/requirements.txt.3.11 | 0 .../602.axpy/python/requirements.txt.3.12 | 0 .../602.axpy/python/requirements.txt.3.7 | 0 .../602.axpy/python/requirements.txt.3.8 | 0 .../602.axpy/python/requirements.txt.3.9 | 0 .../602.axpy/python/requirements.txt.arm.3.8 | 0 .../602.axpy/python/requirements.txt.arm.3.9 | 0 .../603.jacobi2d/config.json | 6 ++ .../600.linearalgebra/603.jacobi2d/input.py | 7 ++ .../603.jacobi2d/python/function.py | 69 +++++++++++++++++++ .../603.jacobi2d/python/requirements.txt | 1 + .../603.jacobi2d/python/requirements.txt.3.10 | 0 .../603.jacobi2d/python/requirements.txt.3.11 | 0 .../603.jacobi2d/python/requirements.txt.3.12 | 0 .../603.jacobi2d/python/requirements.txt.3.7 | 0 .../603.jacobi2d/python/requirements.txt.3.8 | 0 .../603.jacobi2d/python/requirements.txt.3.9 | 0 .../python/requirements.txt.arm.3.8 | 0 .../python/requirements.txt.arm.3.9 | 0 .../604.cholesky/config.json | 6 ++ .../600.linearalgebra/604.cholesky/input.py | 7 ++ .../604.cholesky/python/function.py | 57 +++++++++++++++ .../604.cholesky/python/requirements.txt | 1 + .../604.cholesky/python/requirements.txt.3.10 | 0 .../604.cholesky/python/requirements.txt.3.11 | 0 .../604.cholesky/python/requirements.txt.3.12 | 0 .../604.cholesky/python/requirements.txt.3.7 | 0 .../604.cholesky/python/requirements.txt.3.8 | 0 .../604.cholesky/python/requirements.txt.3.9 | 0 .../python/requirements.txt.arm.3.8 | 0 .../python/requirements.txt.arm.3.9 | 0 48 files changed, 300 insertions(+) create mode 100644 benchmarks/600.linearalgebra/601.matmul/config.json create mode 100644 benchmarks/600.linearalgebra/601.matmul/input.py create mode 100755 benchmarks/600.linearalgebra/601.matmul/python/function.py create mode 100755 benchmarks/600.linearalgebra/601.matmul/python/requirements.txt create mode 100644 benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.3.10 create mode 100644 benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.3.11 create mode 100644 benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.3.12 create mode 100755 benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.3.7 create mode 100755 benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.3.8 create mode 100755 benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.3.9 create mode 100644 benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.arm.3.8 create mode 100644 benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.arm.3.9 create mode 100644 benchmarks/600.linearalgebra/602.axpy/config.json create mode 100644 benchmarks/600.linearalgebra/602.axpy/input.py create mode 100755 benchmarks/600.linearalgebra/602.axpy/python/function.py create mode 100755 benchmarks/600.linearalgebra/602.axpy/python/requirements.txt create mode 100644 benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.3.10 create mode 100644 benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.3.11 create mode 100644 benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.3.12 create mode 100755 benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.3.7 create mode 100755 benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.3.8 create mode 100755 benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.3.9 create mode 100644 benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.arm.3.8 create mode 100644 benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.arm.3.9 create mode 100644 benchmarks/600.linearalgebra/603.jacobi2d/config.json create mode 100644 benchmarks/600.linearalgebra/603.jacobi2d/input.py create mode 100755 benchmarks/600.linearalgebra/603.jacobi2d/python/function.py create mode 100755 benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt create mode 100644 benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.3.10 create mode 100644 benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.3.11 create mode 100644 benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.3.12 create mode 100755 benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.3.7 create mode 100755 benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.3.8 create mode 100755 benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.3.9 create mode 100644 benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.arm.3.8 create mode 100644 benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.arm.3.9 create mode 100644 benchmarks/600.linearalgebra/604.cholesky/config.json create mode 100644 benchmarks/600.linearalgebra/604.cholesky/input.py create mode 100755 benchmarks/600.linearalgebra/604.cholesky/python/function.py create mode 100755 benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt create mode 100644 benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.3.10 create mode 100644 benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.3.11 create mode 100644 benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.3.12 create mode 100755 benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.3.7 create mode 100755 benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.3.8 create mode 100755 benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.3.9 create mode 100644 benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.arm.3.8 create mode 100644 benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.arm.3.9 diff --git a/benchmarks/600.linearalgebra/601.matmul/config.json b/benchmarks/600.linearalgebra/601.matmul/config.json new file mode 100644 index 000000000..e80fb4351 --- /dev/null +++ b/benchmarks/600.linearalgebra/601.matmul/config.json @@ -0,0 +1,6 @@ +{ + "timeout": 120, + "memory": 512, + "languages": ["python"], + "modules": [] +} diff --git a/benchmarks/600.linearalgebra/601.matmul/input.py b/benchmarks/600.linearalgebra/601.matmul/input.py new file mode 100644 index 000000000..79ff6f5cb --- /dev/null +++ b/benchmarks/600.linearalgebra/601.matmul/input.py @@ -0,0 +1,7 @@ +size_generators = {"test": 10, "small": 100, "large": 1000} + + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): + return {"size": size_generators[size], "seed": 42} diff --git a/benchmarks/600.linearalgebra/601.matmul/python/function.py b/benchmarks/600.linearalgebra/601.matmul/python/function.py new file mode 100755 index 000000000..c3aefa7c6 --- /dev/null +++ b/benchmarks/600.linearalgebra/601.matmul/python/function.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +import sys, json, math, torch +import datetime + + +def initialize_torch(NI, NJ, NK, dtype=torch.float32, device="cuda"): + alpha = torch.tensor(1.5, dtype=dtype, device=device) + beta = torch.tensor(1.2, dtype=dtype, device=device) + i = torch.arange(NI, device=device) + j = torch.arange(NJ, device=device) + k = torch.arange(NK, device=device) + C = ((i[:, None] * j[None, :] + 1) % NI).to(dtype) / NI + A = ((i[:, None] * (k[None, :] + 1)) % NK).to(dtype) / NK + B = ((k[:, None] * (j[None, :] + 2)) % NJ).to(dtype) / NJ + return alpha, beta, C, A, B + + +def kernel_gemm(alpha, beta, C, A, B, reps=1): + torch.cuda.synchronize() + _ = alpha * (A @ B) + beta * C # warmup + torch.cuda.synchronize() + start = torch.cuda.Event(enable_timing=True) + end = torch.cuda.Event(enable_timing=True) + start.record() + for _ in range(reps): + C = alpha * (A @ B) + beta * C + end.record() + torch.cuda.synchronize() + return C, float(start.elapsed_time(end)) # ms for all reps + + +def handler(event): + + size = event.get("size") + if "seed" in event: + import random + + random.seed(event["seed"]) + + matrix_generating_begin = datetime.datetime.now() + alpha, beta, C, A, B = initialize_torch(size, size, size, dtype=torch.float32, device="cuda") + matrix_generating_end = datetime.datetime.now() + + matmul_begin = datetime.datetime.now() + C_out, gpu_ms = kernel_gemm(alpha, beta, C, A, B, reps=1) + matmul_end = datetime.datetime.now() + + matrix_generating_time = (matrix_generating_end - matrix_generating_begin) / datetime.timedelta( + microseconds=1 + ) + matmul_time = (matmul_end - matmul_begin) / datetime.timedelta(microseconds=1) + + return { + # "result": result[0], + "measurement": { + "graph_generating_time": matrix_generating_time, + "compute_time": matmul_time, + }, + } diff --git a/benchmarks/600.linearalgebra/601.matmul/python/requirements.txt b/benchmarks/600.linearalgebra/601.matmul/python/requirements.txt new file mode 100755 index 000000000..d8d966118 --- /dev/null +++ b/benchmarks/600.linearalgebra/601.matmul/python/requirements.txt @@ -0,0 +1 @@ +torch==2.4.1 diff --git a/benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.3.10 b/benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.3.10 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.3.11 b/benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.3.11 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.3.12 b/benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.3.12 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.3.7 b/benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.3.7 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.3.8 b/benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.3.8 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.3.9 b/benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.3.9 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.arm.3.8 b/benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.arm.3.8 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.arm.3.9 b/benchmarks/600.linearalgebra/601.matmul/python/requirements.txt.arm.3.9 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/602.axpy/config.json b/benchmarks/600.linearalgebra/602.axpy/config.json new file mode 100644 index 000000000..e80fb4351 --- /dev/null +++ b/benchmarks/600.linearalgebra/602.axpy/config.json @@ -0,0 +1,6 @@ +{ + "timeout": 120, + "memory": 512, + "languages": ["python"], + "modules": [] +} diff --git a/benchmarks/600.linearalgebra/602.axpy/input.py b/benchmarks/600.linearalgebra/602.axpy/input.py new file mode 100644 index 000000000..79ff6f5cb --- /dev/null +++ b/benchmarks/600.linearalgebra/602.axpy/input.py @@ -0,0 +1,7 @@ +size_generators = {"test": 10, "small": 100, "large": 1000} + + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): + return {"size": size_generators[size], "seed": 42} diff --git a/benchmarks/600.linearalgebra/602.axpy/python/function.py b/benchmarks/600.linearalgebra/602.axpy/python/function.py new file mode 100755 index 000000000..c3aefa7c6 --- /dev/null +++ b/benchmarks/600.linearalgebra/602.axpy/python/function.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +import sys, json, math, torch +import datetime + + +def initialize_torch(NI, NJ, NK, dtype=torch.float32, device="cuda"): + alpha = torch.tensor(1.5, dtype=dtype, device=device) + beta = torch.tensor(1.2, dtype=dtype, device=device) + i = torch.arange(NI, device=device) + j = torch.arange(NJ, device=device) + k = torch.arange(NK, device=device) + C = ((i[:, None] * j[None, :] + 1) % NI).to(dtype) / NI + A = ((i[:, None] * (k[None, :] + 1)) % NK).to(dtype) / NK + B = ((k[:, None] * (j[None, :] + 2)) % NJ).to(dtype) / NJ + return alpha, beta, C, A, B + + +def kernel_gemm(alpha, beta, C, A, B, reps=1): + torch.cuda.synchronize() + _ = alpha * (A @ B) + beta * C # warmup + torch.cuda.synchronize() + start = torch.cuda.Event(enable_timing=True) + end = torch.cuda.Event(enable_timing=True) + start.record() + for _ in range(reps): + C = alpha * (A @ B) + beta * C + end.record() + torch.cuda.synchronize() + return C, float(start.elapsed_time(end)) # ms for all reps + + +def handler(event): + + size = event.get("size") + if "seed" in event: + import random + + random.seed(event["seed"]) + + matrix_generating_begin = datetime.datetime.now() + alpha, beta, C, A, B = initialize_torch(size, size, size, dtype=torch.float32, device="cuda") + matrix_generating_end = datetime.datetime.now() + + matmul_begin = datetime.datetime.now() + C_out, gpu_ms = kernel_gemm(alpha, beta, C, A, B, reps=1) + matmul_end = datetime.datetime.now() + + matrix_generating_time = (matrix_generating_end - matrix_generating_begin) / datetime.timedelta( + microseconds=1 + ) + matmul_time = (matmul_end - matmul_begin) / datetime.timedelta(microseconds=1) + + return { + # "result": result[0], + "measurement": { + "graph_generating_time": matrix_generating_time, + "compute_time": matmul_time, + }, + } diff --git a/benchmarks/600.linearalgebra/602.axpy/python/requirements.txt b/benchmarks/600.linearalgebra/602.axpy/python/requirements.txt new file mode 100755 index 000000000..d8d966118 --- /dev/null +++ b/benchmarks/600.linearalgebra/602.axpy/python/requirements.txt @@ -0,0 +1 @@ +torch==2.4.1 diff --git a/benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.3.10 b/benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.3.10 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.3.11 b/benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.3.11 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.3.12 b/benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.3.12 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.3.7 b/benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.3.7 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.3.8 b/benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.3.8 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.3.9 b/benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.3.9 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.arm.3.8 b/benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.arm.3.8 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.arm.3.9 b/benchmarks/600.linearalgebra/602.axpy/python/requirements.txt.arm.3.9 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/603.jacobi2d/config.json b/benchmarks/600.linearalgebra/603.jacobi2d/config.json new file mode 100644 index 000000000..e80fb4351 --- /dev/null +++ b/benchmarks/600.linearalgebra/603.jacobi2d/config.json @@ -0,0 +1,6 @@ +{ + "timeout": 120, + "memory": 512, + "languages": ["python"], + "modules": [] +} diff --git a/benchmarks/600.linearalgebra/603.jacobi2d/input.py b/benchmarks/600.linearalgebra/603.jacobi2d/input.py new file mode 100644 index 000000000..79ff6f5cb --- /dev/null +++ b/benchmarks/600.linearalgebra/603.jacobi2d/input.py @@ -0,0 +1,7 @@ +size_generators = {"test": 10, "small": 100, "large": 1000} + + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): + return {"size": size_generators[size], "seed": 42} diff --git a/benchmarks/600.linearalgebra/603.jacobi2d/python/function.py b/benchmarks/600.linearalgebra/603.jacobi2d/python/function.py new file mode 100755 index 000000000..e212cf8c5 --- /dev/null +++ b/benchmarks/600.linearalgebra/603.jacobi2d/python/function.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +import sys, json, math, torch +import datetime + + +def initialize_torch(N, dtype=torch.float32, device="cuda"): + i = torch.arange(N, device=device, dtype=dtype).view(-1, 1) + j = torch.arange(N, device=device, dtype=dtype).view(1, -1) + + A = i * (j + 2) / N + B = i * (j + 3) / N + return A, B + + +def kernel_jacobi2d(A, B, iters=50): + torch.cuda.synchronize() + # warmup + if A.shape[0] > 2 and A.shape[1] > 2: + B_inner = 0.2 * (A[1:-1, 1:-1] + A[1:-1, :-2] + A[1:-1, 2:] + A[2:, 1:-1] + A[:-2, 1:-1]) + B[1:-1, 1:-1].copy_(B_inner) + + A_inner = 0.2 * (B[1:-1, 1:-1] + B[1:-1, :-2] + B[1:-1, 2:] + B[2:, 1:-1] + B[:-2, 1:-1]) + A[1:-1, 1:-1].copy_(A_inner) + torch.cuda.synchronize() + + start_evt = torch.cuda.Event(enable_timing=True) + end_evt = torch.cuda.Event(enable_timing=True) + start_evt.record() + for _ in range(iters): + B_inner = 0.2 * (A[1:-1, 1:-1] + A[1:-1, :-2] + A[1:-1, 2:] + A[2:, 1:-1] + A[:-2, 1:-1]) + B[1:-1, 1:-1].copy_(B_inner) + + A_inner = 0.2 * (B[1:-1, 1:-1] + B[1:-1, :-2] + B[1:-1, 2:] + B[2:, 1:-1] + B[:-2, 1:-1]) + A[1:-1, 1:-1].copy_(A_inner) + end_evt.record() + torch.cuda.synchronize() + gpu_ms = float(start_evt.elapsed_time(end_evt)) + return A, B, gpu_ms + + +def handler(event): + + size = event.get("size") + if "seed" in event: + import random + + random.seed(event["seed"]) + + matrix_generating_begin = datetime.datetime.now() + A, B = initialize_torch(size, dtype=torch.float32, device="cuda") + matrix_generating_end = datetime.datetime.now() + + matmul_begin = datetime.datetime.now() + A_out, B_out, gpu_ms = kernel_jacobi2d(A, B, reps=50) + matmul_end = datetime.datetime.now() + + matrix_generating_time = (matrix_generating_end - matrix_generating_begin) / datetime.timedelta( + microseconds=1 + ) + matmul_time = (matmul_end - matmul_begin) / datetime.timedelta(microseconds=1) + + return { + # "result": result[0], + "measurement": { + "graph_generating_time": matrix_generating_time, + "compute_time": matmul_time, + "gpu_time": gpu_ms, + }, + } diff --git a/benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt b/benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt new file mode 100755 index 000000000..d8d966118 --- /dev/null +++ b/benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt @@ -0,0 +1 @@ +torch==2.4.1 diff --git a/benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.3.10 b/benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.3.10 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.3.11 b/benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.3.11 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.3.12 b/benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.3.12 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.3.7 b/benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.3.7 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.3.8 b/benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.3.8 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.3.9 b/benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.3.9 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.arm.3.8 b/benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.arm.3.8 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.arm.3.9 b/benchmarks/600.linearalgebra/603.jacobi2d/python/requirements.txt.arm.3.9 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/604.cholesky/config.json b/benchmarks/600.linearalgebra/604.cholesky/config.json new file mode 100644 index 000000000..e80fb4351 --- /dev/null +++ b/benchmarks/600.linearalgebra/604.cholesky/config.json @@ -0,0 +1,6 @@ +{ + "timeout": 120, + "memory": 512, + "languages": ["python"], + "modules": [] +} diff --git a/benchmarks/600.linearalgebra/604.cholesky/input.py b/benchmarks/600.linearalgebra/604.cholesky/input.py new file mode 100644 index 000000000..79ff6f5cb --- /dev/null +++ b/benchmarks/600.linearalgebra/604.cholesky/input.py @@ -0,0 +1,7 @@ +size_generators = {"test": 10, "small": 100, "large": 1000} + + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): + return {"size": size_generators[size], "seed": 42} diff --git a/benchmarks/600.linearalgebra/604.cholesky/python/function.py b/benchmarks/600.linearalgebra/604.cholesky/python/function.py new file mode 100755 index 000000000..f01983ecf --- /dev/null +++ b/benchmarks/600.linearalgebra/604.cholesky/python/function.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +import sys, json, torch, datetime + + +def initialize_torch(N, dtype=torch.float32, device="cuda"): + j = torch.arange(N, device=device) + v = (torch.remainder(-j, N).to(dtype) / N) + 1 + + L = v.expand(N, -1).clone() + L = torch.tril(L) + L.fill_diagonal_(1.0) + + A = L @ L.transpose(-1, -2) + return A + + +def kernel_cholesky(A): + torch.cuda.synchronize() + _ = torch.linalg.cholesky(A) # warmup + torch.cuda.synchronize() + + start_evt = torch.cuda.Event(enable_timing=True) + end_evt = torch.cuda.Event(enable_timing=True) + start_evt.record() + for _ in range(A.size(0)): + L = torch.linalg.cholesky(A) + end_evt.record() + torch.cuda.synchronize() + gpu_ms = float(start_evt.elapsed_time(end_evt)) + return L, gpu_ms + + +def handler(event): + size = event.get("size") + if "seed" in event: + import random + + random.seed(event["seed"]) + + gen_begin = datetime.datetime.now() + A = initialize_torch(size, dtype=torch.float32, device="cuda") + gen_end = datetime.datetime.now() + + comp_begin = datetime.datetime.now() + L, gpu_ms = kernel_cholesky(A) + comp_end = datetime.datetime.now() + + gen_us = (gen_end - gen_begin) / datetime.timedelta(microseconds=1) + comp_us = (comp_end - comp_begin) / datetime.timedelta(microseconds=1) + + return { + "measurement": { + "graph_generating_time": gen_us, + "compute_time": comp_us, + "gpu_time": gpu_ms, + } + } diff --git a/benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt b/benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt new file mode 100755 index 000000000..d8d966118 --- /dev/null +++ b/benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt @@ -0,0 +1 @@ +torch==2.4.1 diff --git a/benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.3.10 b/benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.3.10 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.3.11 b/benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.3.11 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.3.12 b/benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.3.12 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.3.7 b/benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.3.7 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.3.8 b/benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.3.8 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.3.9 b/benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.3.9 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.arm.3.8 b/benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.arm.3.8 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.arm.3.9 b/benchmarks/600.linearalgebra/604.cholesky/python/requirements.txt.arm.3.9 new file mode 100644 index 000000000..e69de29bb From ace23355b27ef073c0f0ef3aa0d8db8fef36cf1c Mon Sep 17 00:00:00 2001 From: Russellpang Date: Wed, 5 Nov 2025 18:05:07 +0100 Subject: [PATCH 15/58] add linalg benchmarks --- .../601.matmul/python/function.py | 3 + .../602.axpy/python/function.py | 69 +++++++++---------- .../603.jacobi2d/python/function.py | 3 + .../604.cholesky/python/function.py | 3 + 4 files changed, 43 insertions(+), 35 deletions(-) diff --git a/benchmarks/600.linearalgebra/601.matmul/python/function.py b/benchmarks/600.linearalgebra/601.matmul/python/function.py index c3aefa7c6..33c06ae2e 100755 --- a/benchmarks/600.linearalgebra/601.matmul/python/function.py +++ b/benchmarks/600.linearalgebra/601.matmul/python/function.py @@ -37,6 +37,9 @@ def handler(event): random.seed(event["seed"]) + seed = event.get("seed", 42) + seed = int(seed) + matrix_generating_begin = datetime.datetime.now() alpha, beta, C, A, B = initialize_torch(size, size, size, dtype=torch.float32, device="cuda") matrix_generating_end = datetime.datetime.now() diff --git a/benchmarks/600.linearalgebra/602.axpy/python/function.py b/benchmarks/600.linearalgebra/602.axpy/python/function.py index c3aefa7c6..7f55d540b 100755 --- a/benchmarks/600.linearalgebra/602.axpy/python/function.py +++ b/benchmarks/600.linearalgebra/602.axpy/python/function.py @@ -1,59 +1,58 @@ #!/usr/bin/env python3 -import sys, json, math, torch -import datetime +import sys, json, torch, datetime -def initialize_torch(NI, NJ, NK, dtype=torch.float32, device="cuda"): - alpha = torch.tensor(1.5, dtype=dtype, device=device) - beta = torch.tensor(1.2, dtype=dtype, device=device) - i = torch.arange(NI, device=device) - j = torch.arange(NJ, device=device) - k = torch.arange(NK, device=device) - C = ((i[:, None] * j[None, :] + 1) % NI).to(dtype) / NI - A = ((i[:, None] * (k[None, :] + 1)) % NK).to(dtype) / NK - B = ((k[:, None] * (j[None, :] + 2)) % NJ).to(dtype) / NJ - return alpha, beta, C, A, B +def initialize_torch(N, dtype=torch.float32, device="cuda", seed=42): + if seed is not None: + torch.manual_seed(seed) + torch.cuda.manual_seed_all(seed) + alpha = torch.randn((), dtype=dtype, device=device) + x = torch.randn(N, dtype=dtype, device=device) + y = torch.randn(N, dtype=dtype, device=device) + return alpha, x, y -def kernel_gemm(alpha, beta, C, A, B, reps=1): +def kernel_axpy(alpha, x, y, reps=100): torch.cuda.synchronize() - _ = alpha * (A @ B) + beta * C # warmup + _ = alpha * x + y # warmup torch.cuda.synchronize() - start = torch.cuda.Event(enable_timing=True) - end = torch.cuda.Event(enable_timing=True) - start.record() + + start_evt = torch.cuda.Event(enable_timing=True) + end_evt = torch.cuda.Event(enable_timing=True) + start_evt.record() for _ in range(reps): - C = alpha * (A @ B) + beta * C - end.record() + y = alpha * x + y + end_evt.record() torch.cuda.synchronize() - return C, float(start.elapsed_time(end)) # ms for all reps + gpu_ms = float(start_evt.elapsed_time(end_evt)) + return y, gpu_ms def handler(event): - size = event.get("size") if "seed" in event: import random random.seed(event["seed"]) - matrix_generating_begin = datetime.datetime.now() - alpha, beta, C, A, B = initialize_torch(size, size, size, dtype=torch.float32, device="cuda") - matrix_generating_end = datetime.datetime.now() + seed = event.get("seed", 42) + seed = int(seed) + + gen_begin = datetime.datetime.now() + alpha, x, y = initialize_torch(size, dtype=torch.float32, device="cuda", seed=seed) + gen_end = datetime.datetime.now() - matmul_begin = datetime.datetime.now() - C_out, gpu_ms = kernel_gemm(alpha, beta, C, A, B, reps=1) - matmul_end = datetime.datetime.now() + comp_begin = datetime.datetime.now() + y_out, gpu_ms = kernel_axpy(alpha, x, y, reps=100) + comp_end = datetime.datetime.now() - matrix_generating_time = (matrix_generating_end - matrix_generating_begin) / datetime.timedelta( - microseconds=1 - ) - matmul_time = (matmul_end - matmul_begin) / datetime.timedelta(microseconds=1) + gen_us = (gen_end - gen_begin) / datetime.timedelta(microseconds=1) + comp_us = (comp_end - comp_begin) / datetime.timedelta(microseconds=1) return { - # "result": result[0], "measurement": { - "graph_generating_time": matrix_generating_time, - "compute_time": matmul_time, - }, + "graph_generating_time": gen_us, + "compute_time": comp_us, + "gpu_time": gpu_ms, + } } diff --git a/benchmarks/600.linearalgebra/603.jacobi2d/python/function.py b/benchmarks/600.linearalgebra/603.jacobi2d/python/function.py index e212cf8c5..5f10c44f7 100755 --- a/benchmarks/600.linearalgebra/603.jacobi2d/python/function.py +++ b/benchmarks/600.linearalgebra/603.jacobi2d/python/function.py @@ -46,6 +46,9 @@ def handler(event): random.seed(event["seed"]) + seed = event.get("seed", 42) + seed = int(seed) + matrix_generating_begin = datetime.datetime.now() A, B = initialize_torch(size, dtype=torch.float32, device="cuda") matrix_generating_end = datetime.datetime.now() diff --git a/benchmarks/600.linearalgebra/604.cholesky/python/function.py b/benchmarks/600.linearalgebra/604.cholesky/python/function.py index f01983ecf..c0776d568 100755 --- a/benchmarks/600.linearalgebra/604.cholesky/python/function.py +++ b/benchmarks/600.linearalgebra/604.cholesky/python/function.py @@ -37,6 +37,9 @@ def handler(event): random.seed(event["seed"]) + seed = event.get("seed", 42) + seed = int(seed) + gen_begin = datetime.datetime.now() A = initialize_torch(size, dtype=torch.float32, device="cuda") gen_end = datetime.datetime.now() From ad3023dc02fd14a888e10c663b76692f50066449 Mon Sep 17 00:00:00 2001 From: McLavish Date: Wed, 5 Nov 2025 20:50:24 +0100 Subject: [PATCH 16/58] changed CI/CD to run linting on the benchmarks folder ONLY. disabled mypy checks --- .circleci/config.yml | 14 +++++++------- .pre-commit-config.yaml | 7 +++++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a841c1584..77243ae8a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,18 +21,18 @@ jobs: - run: command: | . python-venv/bin/activate - black sebs --check --config .black.toml + black benchmarks --check --config .black.toml name: Python code formatting with black - run: command: | . python-venv/bin/activate - flake8 sebs --config=.flake8.cfg --tee --output-file flake-reports + flake8 benchmarks --config=.flake8.cfg --tee --output-file flake-reports name: Python code lint with flake8 - - run: - command: | - . python-venv/bin/activate - mypy sebs --config-file=.mypy.ini - name: Python static code verification with mypy + # - run: + # command: | + # . python-venv/bin/activate + # mypy sebs --config-file=.mypy.ini + # name: Python static code verification with mypy - store_artifacts: path: flake-reports destination: flake-reports diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fce4c4da7..58f8adb8d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,4 +20,11 @@ repos: args: ["--config=.black.toml", "--check", "--diff"] types: [python] files: ^(sebs/|benchmarks/) + # - repo: local + # hooks: + # - id: mypy-local + # name: mypy (project venv) + # language: system + # entry: bash -lc 'python -m mypy --config-file=.mypy.ini sebs' + # types: [python] From 52f30c038a5639884e7e7eaeeba1ba57eeb327e1 Mon Sep 17 00:00:00 2001 From: Russellpang Date: Thu, 6 Nov 2025 02:08:53 +0100 Subject: [PATCH 17/58] fix typo --- .../601.matmul/python/function.py | 2 +- .../602.axpy/python/function.py | 2 +- .../603.jacobi2d/python/function.py | 2 +- .../604.cholesky/python/function.py | 2 +- config/local_deployment.json | 125 ++++++++++++++++++ out_storage.json | 33 +++++ 6 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 config/local_deployment.json create mode 100644 out_storage.json diff --git a/benchmarks/600.linearalgebra/601.matmul/python/function.py b/benchmarks/600.linearalgebra/601.matmul/python/function.py index 33c06ae2e..ee1ceaff7 100755 --- a/benchmarks/600.linearalgebra/601.matmul/python/function.py +++ b/benchmarks/600.linearalgebra/601.matmul/python/function.py @@ -56,7 +56,7 @@ def handler(event): return { # "result": result[0], "measurement": { - "graph_generating_time": matrix_generating_time, + "generating_time": matrix_generating_time, "compute_time": matmul_time, }, } diff --git a/benchmarks/600.linearalgebra/602.axpy/python/function.py b/benchmarks/600.linearalgebra/602.axpy/python/function.py index 7f55d540b..9c31c05bd 100755 --- a/benchmarks/600.linearalgebra/602.axpy/python/function.py +++ b/benchmarks/600.linearalgebra/602.axpy/python/function.py @@ -51,7 +51,7 @@ def handler(event): return { "measurement": { - "graph_generating_time": gen_us, + "generating_time": gen_us, "compute_time": comp_us, "gpu_time": gpu_ms, } diff --git a/benchmarks/600.linearalgebra/603.jacobi2d/python/function.py b/benchmarks/600.linearalgebra/603.jacobi2d/python/function.py index 5f10c44f7..b83230f04 100755 --- a/benchmarks/600.linearalgebra/603.jacobi2d/python/function.py +++ b/benchmarks/600.linearalgebra/603.jacobi2d/python/function.py @@ -65,7 +65,7 @@ def handler(event): return { # "result": result[0], "measurement": { - "graph_generating_time": matrix_generating_time, + "generating_time": matrix_generating_time, "compute_time": matmul_time, "gpu_time": gpu_ms, }, diff --git a/benchmarks/600.linearalgebra/604.cholesky/python/function.py b/benchmarks/600.linearalgebra/604.cholesky/python/function.py index c0776d568..537015e56 100755 --- a/benchmarks/600.linearalgebra/604.cholesky/python/function.py +++ b/benchmarks/600.linearalgebra/604.cholesky/python/function.py @@ -53,7 +53,7 @@ def handler(event): return { "measurement": { - "graph_generating_time": gen_us, + "generating_time": gen_us, "compute_time": comp_us, "gpu_time": gpu_ms, } diff --git a/config/local_deployment.json b/config/local_deployment.json new file mode 100644 index 000000000..d89b3a968 --- /dev/null +++ b/config/local_deployment.json @@ -0,0 +1,125 @@ +{ + "experiments": { + "deployment": "local", + "update_code": false, + "update_storage": false, + "download_results": false, + "architecture": "x64", + "container_deployment": true, + "runtime": { + "language": "python", + "version": "3.11" + }, + "type": "invocation-overhead", + "perf-cost": { + "benchmark": "601.matmul", + "experiments": [ + "cold", + "warm", + "burst", + "sequential" + ], + "input-size": "test", + "repetitions": 50, + "concurrent-invocations": 50, + "memory-sizes": [ + 128, + 256 + ] + }, + "network-ping-pong": { + "invocations": 50, + "repetitions": 1000, + "threads": 1 + }, + "invocation-overhead": { + "repetitions": 5, + "N": 20, + "type": "payload", + "payload_begin": 1024, + "payload_end": 6251000, + "payload_points": 20, + "code_begin": 1048576, + "code_end": 261619712, + "code_points": 20 + }, + "eviction-model": { + "invocations": 1, + "function_copy_idx": 0, + "repetitions": 5, + "sleep": 1 + } + }, + "deployment": { + "name": "local", + "aws": { + "region": "us-east-1", + "lambda-role": "" + }, + "azure": { + "region": "westeurope" + }, + "gcp": { + "region": "europe-west1", + "project_name": "", + "credentials": "" + }, + "local": { + "storage": { + "object": { + "type": "minio", + "minio": { + "address": "192.168.1.101:9011", + "mapped_port": 9011, + "access_key": "Ux22nOcFoUaZAnmg-kULuIzvXmiFNVRiZkzcOaDawpU", + "secret_key": "9bb8b39326b0fde8bdfa5d013f743c03e57d146f10433fe2fe3ccce7225078d5", + "instance_id": "f337f509c0375ca4457f815cc0f67352088f6093053ba33c1e45aca0012e0a9f", + "output_buckets": [], + "input_buckets": [], + "version": "RELEASE.2024-07-16T23-46-41Z", + "data_volume": "minio-volume", + "type": "minio" + } + }, + "nosql": { + "type": "scylladb", + "scylladb": { + "address": "192.168.1.101:9012", + "mapped_port": 9012, + "alternator_port": 8000, + "access_key": "None", + "secret_key": "None", + "instance_id": "c7be7d211bb211b92f41afb073f75635d9f5f2a222abeb6d9b17673b02d079ca", + "region": "None", + "cpus": 1, + "memory": "750", + "version": "6.0", + "data_volume": "scylladb-volume" + } + } + } + }, + "openwhisk": { + "shutdownStorage": false, + "removeCluster": false, + "wskBypassSecurity": "true", + "wskExec": "wsk", + "experimentalManifest": false, + "docker_registry": { + "registry": "", + "username": "", + "password": "" + }, + "storage": { + "address": "", + "mapped_port": -1, + "access_key": "", + "secret_key": "", + "instance_id": "", + "input_buckets": [], + "output_buckets": [], + "type": "minio" + } + } + } +} diff --git a/out_storage.json b/out_storage.json new file mode 100644 index 000000000..16c13dba6 --- /dev/null +++ b/out_storage.json @@ -0,0 +1,33 @@ +{ + "object": { + "type": "minio", + "minio": { + "address": "172.17.0.2:9000", + "mapped_port": 9011, + "access_key": "vTIGFqQKDU9CVlE_eFkJ7kZFt823CoiiG1GRgxLFczc", + "secret_key": "01872a84cd3ec4af4b897cc57fa515ca7a704a5e4557b5ecde5b98fe41ecc489", + "instance_id": "39a39aa73d44cee61a627a73fecd962f8fdcdbc415f70f702d850eff2afae3a3", + "output_buckets": [], + "input_buckets": [], + "version": "RELEASE.2024-07-16T23-46-41Z", + "data_volume": "minio-volume", + "type": "minio" + } + }, + "nosql": { + "type": "scylladb", + "scylladb": { + "address": "172.17.0.3:8000", + "mapped_port": 9012, + "alternator_port": 8000, + "access_key": "None", + "secret_key": "None", + "instance_id": "b302608abce0d96e1518260ff38c366bbe0dfe279935c521ef682d740d84fe69", + "region": "None", + "cpus": 1, + "memory": "750", + "version": "6.0", + "data_volume": "scylladb-volume" + } + } +} \ No newline at end of file From 4efff4d794abc3ded0835acb7d02287d70066f19 Mon Sep 17 00:00:00 2001 From: Russellpang Date: Thu, 6 Nov 2025 02:43:33 +0100 Subject: [PATCH 18/58] update code --- .../python/function.py | 198 ++++++++---------- 1 file changed, 91 insertions(+), 107 deletions(-) diff --git a/benchmarks/400.inference/413.image-classification/python/function.py b/benchmarks/400.inference/413.image-classification/python/function.py index 1ee9d653a..7c241d525 100644 --- a/benchmarks/400.inference/413.image-classification/python/function.py +++ b/benchmarks/400.inference/413.image-classification/python/function.py @@ -1,141 +1,119 @@ -import datetime, json, os, tarfile -from pathlib import Path +import datetime, json, os, uuid + +# Extract zipped torch model - used in Python 3.8 and 3.9 +if os.path.exists("function/torch.zip"): + import zipfile, sys + + zipfile.ZipFile("function/torch.zip").extractall("/tmp/") + sys.path.append( + os.path.join(os.path.dirname(__file__), "/tmp/.python_packages/lib/site-packages") + ) from PIL import Image import torch from torchvision import transforms from torchvision.models import resnet50 -# ---------- Config ---------- -# Optional env overrides; event fields take precedence if provided -ENV_MODEL_PATH = os.getenv("MODEL_PATH") # /abs/path/resnet50.tar.gz or .pth/.pt -ENV_IMAGE_PATH = os.getenv("IMAGE_PATH") # /abs/path/test.jpg -USE_AMP = True # autocast for faster inference on CUDA -# ---------------------------- +from . import storage -SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__)) +client = storage.storage.get_instance() + +SCRIPT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__))) class_idx = json.load(open(os.path.join(SCRIPT_DIR, "imagenet_class_index.json"), "r")) idx2label = [class_idx[str(k)][1] for k in range(len(class_idx))] -DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") -torch.backends.cudnn.benchmark = True - -model = None # cache across invocations (same as your original) +model = None +device = "cuda" if torch.cuda.is_available() else "cpu" -def _extract_pth_from_tar(tar_path: str, out_dir: str = "/tmp/resnet50_unpack") -> str: - """Extract .tar.gz/.tgz and return the first .pth/.pt found.""" - out = Path(out_dir) - out.mkdir(parents=True, exist_ok=True) - with tarfile.open(tar_path, "r:gz") as tar: - tar.extractall(out) - for ext in ("*.pth", "*.pt"): - found = list(out.rglob(ext)) - if found: - return str(found[0]) - raise FileNotFoundError(f"No .pth/.pt found in archive: {tar_path}") - - -def _load_resnet50_from_path(model_path: str) -> torch.nn.Module: - """Load torchvision ResNet-50 from a local .tar.gz or .pth/.pt (CPU), then return it.""" - if model_path.endswith((".tar.gz", ".tgz")): - weight_path = _extract_pth_from_tar(model_path) - else: - weight_path = model_path - - ckpt = torch.load(weight_path, map_location="cpu") - if isinstance(ckpt, dict): - state = ckpt.get("state_dict", ckpt.get("model", ckpt)) - if not isinstance(state, dict): - state = ckpt - if len(state) > 0 and next(iter(state)).startswith("module."): - state = {k.replace("module.", "", 1): v for k, v in state.items()} - m = resnet50(pretrained=False) - m.load_state_dict(state, strict=False) - m.eval() - return m - elif isinstance(ckpt, torch.nn.Module): - ckpt.eval() - return ckpt - else: - raise TypeError(f"Unsupported checkpoint type: {type(ckpt)}") - - -def _maybe_sync(): - if DEVICE.type == "cuda": - torch.cuda.synchronize() +def handler(event): + bucket = event.get("bucket").get("bucket") + input_prefix = event.get("bucket").get("input") + model_prefix = event.get("bucket").get("model") + key = event.get("object").get("input") + model_key = event.get("object").get("model") + download_path = "/tmp/{}-{}".format(key, uuid.uuid4()) -def handler(event): - """ - Accepts local paths via event (preferred for your benchmark runner): - event = { - "local_model_archive": "/abs/path/resnet50.tar.gz" or ".pth", - "local_image_path": "/abs/path/image.jpg" - } - Falls back to env MODEL_PATH / IMAGE_PATH if not provided. - Returns the SAME structure as your existing function.py. - """ - if not torch.cuda.is_available(): - raise RuntimeError("CUDA not available. Run on a GPU machine/container.") - - # -------- resolve inputs -------- - model_path = event.get("local_model_archive") or ENV_MODEL_PATH - image_path = event.get("local_image_path") or ENV_IMAGE_PATH - assert model_path, "Provide local_model_archive in event or set MODEL_PATH" - assert image_path, "Provide local_image_path in event or set IMAGE_PATH" - - # -------- timings: image "download" (local -> count as zero) -------- + # --- Download image --- image_download_begin = datetime.datetime.now() - image_download_end = image_download_begin # local file, no download + image_path = download_path + client.download(bucket, os.path.join(input_prefix, key), download_path) + image_download_end = datetime.datetime.now() - # -------- lazy model load (cache like your original) -------- global model if model is None: + # --- Download weights --- model_download_begin = datetime.datetime.now() - model_download_end = model_download_begin # local file, no remote download + model_path = os.path.join("/tmp", model_key) + client.download(bucket, os.path.join(model_prefix, model_key), model_path) + model_download_end = datetime.datetime.now() + # --- Load model (CPU), then move to GPU --- model_process_begin = datetime.datetime.now() - # load on CPU, then move to GPU - m = _load_resnet50_from_path(model_path) - model = m.to(DEVICE, non_blocking=True).eval() - _maybe_sync() + model = resnet50(pretrained=False) + state = torch.load(model_path, map_location="cpu") # robust for CPU-saved checkpoints + # handle checkpoints that wrap state dict: + state = state.get("state_dict", state) + model.load_state_dict(state) + model.eval() + model.to(device) + # speed on cuDNN-convolutional nets + if device == "cuda": + torch.backends.cudnn.benchmark = True model_process_end = datetime.datetime.now() else: - # reuse cached model + # model already cached model_download_begin = model_download_end = datetime.datetime.now() - model_process_begin = model_process_end = model_download_begin + model_process_begin = model_process_end = datetime.datetime.now() - # -------- preprocess + inference on GPU (with proper sync) -------- + # --- Preprocess (CPU) --- + process_begin = datetime.datetime.now() input_image = Image.open(image_path).convert("RGB") preprocess = transforms.Compose( [ transforms.Resize(256), transforms.CenterCrop(224), - transforms.ToTensor(), + transforms.ToTensor(), # [0,1], CHW transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ] ) - input_tensor = preprocess(input_image).unsqueeze(0) # [1,3,224,224] + input_tensor = preprocess(input_image) # CPU tensor + input_batch = input_tensor.unsqueeze(0).to(device, non_blocking=True) # NCHW on GPU + + # --- Inference (GPU) --- + with torch.no_grad(): + # Ensure wall-clock timing includes GPU work + if device == "cuda": + torch.cuda.synchronize() + # GPU event timing (kernel time) + start_evt = end_evt = None + if device == "cuda": + start_evt = torch.cuda.Event(enable_timing=True) + end_evt = torch.cuda.Event(enable_timing=True) + start_evt.record() + + output = model(input_batch) # logits [1,1000] + + if device == "cuda": + end_evt.record() + torch.cuda.synchronize() + + # compute top-1 / top-5 on CPU + probs = torch.nn.functional.softmax(output, dim=1) + conf, index = torch.max(probs, 1) + # make Python types + top1_idx = index.item() + top1_conf = float(conf.item()) + # (optional) top-5 + _, top5_idx = torch.topk(probs, k=5, dim=1) + top5_idx = top5_idx[0].tolist() + + ret = idx2label[top1_idx] # <- use .item() result - _maybe_sync() - process_begin = datetime.datetime.now() - with torch.inference_mode(): - x = input_tensor.to(DEVICE, non_blocking=True) - if USE_AMP and DEVICE.type == "cuda": - with torch.cuda.amp.autocast(): - y = model(x) - else: - y = model(x) - _maybe_sync() process_end = datetime.datetime.now() - # -------- postprocess -------- - probs = torch.softmax(y[0], dim=0) - idx = int(torch.argmax(probs).item()) - pred = idx2label[idx] - - # -------- SAME measurement keys (microseconds) -------- + # timings download_time = (image_download_end - image_download_begin) / datetime.timedelta(microseconds=1) model_download_time = (model_download_end - model_download_begin) / datetime.timedelta( microseconds=1 @@ -145,12 +123,18 @@ def handler(event): ) process_time = (process_end - process_begin) / datetime.timedelta(microseconds=1) + # optional precise GPU kernel time (ms) + gpu_time_ms = 0.0 + if start_evt is not None and end_evt is not None: + gpu_time_ms = float(start_evt.elapsed_time(end_evt)) # milliseconds + return { - "result": {"idx": idx, "class": pred}, + "result": {"idx": top1_idx, "class": ret, "confidence": top1_conf, "top5_idx": top5_idx}, "measurement": { - "download_time": download_time + model_download_time, - "compute_time": process_time + model_process_time, - "model_time": model_process_time, - "model_download_time": model_download_time, + "download_time": download_time + model_download_time, # µs + "compute_time": process_time + model_process_time, # µs (wall time, includes GPU) + "model_time": model_process_time, # µs + "model_download_time": model_download_time, # µs + "gpu_time_ms": round(gpu_time_ms, 3), # extra: CUDA kernel time }, } From adf54a5edf58e8b11d395d8e24726d3e52c5b88d Mon Sep 17 00:00:00 2001 From: McLavish Date: Thu, 6 Nov 2025 18:29:32 +0100 Subject: [PATCH 19/58] migrated from CircleCI to Github Actions --- .circleci/config.yml | 81 ----------------------- .github/ISSUE_TEMPLATE/workflows/lint.yml | 55 +++++++++++++++ 2 files changed, 55 insertions(+), 81 deletions(-) delete mode 100644 .circleci/config.yml create mode 100644 .github/ISSUE_TEMPLATE/workflows/lint.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 77243ae8a..000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,81 +0,0 @@ -version: 2.1 - -orbs: - python: circleci/python@1.4.0 - -jobs: - linting: - executor: python/default - steps: - - checkout - - restore_cache: - key: deps1-{{ .Branch }}-{{ checksum "requirements.txt" }} - - run: - command: | - sudo apt update && sudo apt install libcurl4-openssl-dev - name: Install curl-config from Ubuntu APT - - run: - command: | - python3 install.py --aws --azure --gcp --no-local - name: Install pip dependencies - - run: - command: | - . python-venv/bin/activate - black benchmarks --check --config .black.toml - name: Python code formatting with black - - run: - command: | - . python-venv/bin/activate - flake8 benchmarks --config=.flake8.cfg --tee --output-file flake-reports - name: Python code lint with flake8 - # - run: - # command: | - # . python-venv/bin/activate - # mypy sebs --config-file=.mypy.ini - # name: Python static code verification with mypy - - store_artifacts: - path: flake-reports - destination: flake-reports - test-aws: - executor: python/default - steps: - - checkout - - setup_remote_docker - - restore_cache: - key: deps1-{{ .Branch }}-{{ checksum "requirements.txt" }} - - run: - command: | - if [[ -d $HOME/docker ]]; - then - ls $HOME/docker/*.tar.gz | xargs -I {file} sh -c "zcat {file} | docker load"; - else - docker pull mcopik/serverless-benchmarks:build.aws.python.3.7 - docker pull mcopik/serverless-benchmarks:build.aws.nodejs.12.x - fi - name: Load Docker images - - run: - command: | - python3 install.py --aws - name: Install pip dependencies - - run: - command: | - mkdir -p $HOME/docker - docker images mcopik/serverless-benchmarks --filter='dangling=false' --format '{{.Repository}}:{{.Tag}} {{.ID}}' |\ - xargs -n 2 -t sh -c 'test -e $HOME/docker/$1.tar.gz || docker save $0 | gzip -2 > $HOME/docker/$1.tar.gz' - name: Save Docker images - - save_cache: - key: deps1-{{ .Branch }}-{{ checksum "requirements.txt" }} - paths: - - "sebs-virtualenv" - - $HOME/docker - - run: - command: | - . sebs-virtualenv/bin/activate - tests/test_runner.py --deployment aws - name: Execute AWS tests - -workflows: - main: - jobs: - - linting - diff --git a/.github/ISSUE_TEMPLATE/workflows/lint.yml b/.github/ISSUE_TEMPLATE/workflows/lint.yml new file mode 100644 index 000000000..6cb6444bd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/workflows/lint.yml @@ -0,0 +1,55 @@ +name: Lint + +on: + push: + pull_request: + +jobs: + linting: + runs-on: ubuntu-latest + + steps: + - name: Check out code + uses: actions/checkout@v4 + + - name: Set up Python + id: setup-python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + + - name: Cache virtualenv + uses: actions/cache@v4 + with: + path: python-venv + key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('requirements.txt') }}-${{ github.ref_name }} + restore-keys: | + venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('requirements.txt') }}- + venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}- + + - name: Install system packages + run: | + sudo apt-get update + sudo apt-get install -y libcurl4-openssl-dev + + - name: Install Python dependencies (via install.py) + run: | + python3 install.py --aws --azure --gcp --no-local + + - name: Black (check) + run: | + . python-venv/bin/activate + black benchmarks --check --config .black.toml + + - name: Flake8 (lint) + run: | + . python-venv/bin/activate + # write to file and echo to stdout (requires flake8 with --tee support) + flake8 benchmarks --config=.flake8.cfg --tee --output-file flake-reports + + - name: Upload flake report + if: always() + uses: actions/upload-artifact@v4 + with: + name: flake-reports + path: flake-reports From 67772e2e5a48c6dcddebe426952279a9e876356f Mon Sep 17 00:00:00 2001 From: McLavish Date: Thu, 6 Nov 2025 18:40:24 +0100 Subject: [PATCH 20/58] fixed workflow directory --- .github/{ISSUE_TEMPLATE => }/workflows/lint.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{ISSUE_TEMPLATE => }/workflows/lint.yml (100%) diff --git a/.github/ISSUE_TEMPLATE/workflows/lint.yml b/.github/workflows/lint.yml similarity index 100% rename from .github/ISSUE_TEMPLATE/workflows/lint.yml rename to .github/workflows/lint.yml From 8f02b6679a25240c1192eab07187a3491ae6122f Mon Sep 17 00:00:00 2001 From: McLavish Date: Thu, 6 Nov 2025 19:00:02 +0100 Subject: [PATCH 21/58] pip dependencies take too long --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 6cb6444bd..1043be62e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -34,7 +34,7 @@ jobs: - name: Install Python dependencies (via install.py) run: | - python3 install.py --aws --azure --gcp --no-local + python3 install.py --no-aws --no-azure --no-gcp --no-openwhisk --no-local - name: Black (check) run: | From e06985cf48c86dab3357c77c6d704dd55e921572 Mon Sep 17 00:00:00 2001 From: McLavish Date: Mon, 10 Nov 2025 19:36:28 +0100 Subject: [PATCH 22/58] new benchmark data --- benchmarks-data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks-data b/benchmarks-data index 6a17a460f..25c2bb40b 160000 --- a/benchmarks-data +++ b/benchmarks-data @@ -1 +1 @@ -Subproject commit 6a17a460f289e166abb47ea6298fb939e80e8beb +Subproject commit 25c2bb40b8bde342395534b534ba62f8f0ff3549 From 037f6c34859683012e8838cedb4570d66b15f31f Mon Sep 17 00:00:00 2001 From: xipang Date: Wed, 12 Nov 2025 20:24:53 +0100 Subject: [PATCH 23/58] Bring folder from other-branch --- .../412.language-bert/config.json | 6 + .../400.inference/412.language-bert/input.py | 33 ++++ .../412.language-bert/python/function.py | 157 ++++++++++++++++++ .../412.language-bert/python/init.sh | 3 + .../412.language-bert/python/package.sh | 35 ++++ .../412.language-bert/python/requirements.txt | 3 + .../python/requirements.txt.3.10 | 3 + .../python/requirements.txt.3.11 | 3 + .../python/requirements.txt.3.8 | 3 + .../python/requirements.txt.3.9 | 3 + 10 files changed, 249 insertions(+) create mode 100644 benchmarks/400.inference/412.language-bert/config.json create mode 100644 benchmarks/400.inference/412.language-bert/input.py create mode 100644 benchmarks/400.inference/412.language-bert/python/function.py create mode 100755 benchmarks/400.inference/412.language-bert/python/init.sh create mode 100644 benchmarks/400.inference/412.language-bert/python/package.sh create mode 100644 benchmarks/400.inference/412.language-bert/python/requirements.txt create mode 100644 benchmarks/400.inference/412.language-bert/python/requirements.txt.3.10 create mode 100644 benchmarks/400.inference/412.language-bert/python/requirements.txt.3.11 create mode 100644 benchmarks/400.inference/412.language-bert/python/requirements.txt.3.8 create mode 100644 benchmarks/400.inference/412.language-bert/python/requirements.txt.3.9 diff --git a/benchmarks/400.inference/412.language-bert/config.json b/benchmarks/400.inference/412.language-bert/config.json new file mode 100644 index 000000000..94ede7925 --- /dev/null +++ b/benchmarks/400.inference/412.language-bert/config.json @@ -0,0 +1,6 @@ +{ + "timeout": 60, + "memory": 512, + "languages": ["python"], + "modules": ["storage"] +} diff --git a/benchmarks/400.inference/412.language-bert/input.py b/benchmarks/400.inference/412.language-bert/input.py new file mode 100644 index 000000000..9af7ecb56 --- /dev/null +++ b/benchmarks/400.inference/412.language-bert/input.py @@ -0,0 +1,33 @@ +import os + + +def buckets_count(): + # model bucket and text bucket + return (2, 0) + + +def upload_files(data_root, data_dir, upload_func): + for root, _, files in os.walk(data_dir): + prefix = os.path.relpath(root, data_root) + for file in files: + filepath = os.path.join(root, file) + relative_key = os.path.join(prefix, file) + upload_func(0, relative_key, filepath) + + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): + model_archive = "bert-tiny-onnx.tar.gz" + upload_func(0, model_archive, os.path.join(data_dir, "model", model_archive)) + + text_filename = "sentences.jsonl" + upload_func(1, text_filename, os.path.join(data_dir, "text", text_filename)) + + input_config = {"object": {}, "bucket": {}} + input_config["object"]["model"] = model_archive + input_config["object"]["input"] = text_filename + input_config["bucket"]["bucket"] = benchmarks_bucket + input_config["bucket"]["model"] = input_paths[0] + input_config["bucket"]["text"] = input_paths[1] + return input_config diff --git a/benchmarks/400.inference/412.language-bert/python/function.py b/benchmarks/400.inference/412.language-bert/python/function.py new file mode 100644 index 000000000..7e4f981ef --- /dev/null +++ b/benchmarks/400.inference/412.language-bert/python/function.py @@ -0,0 +1,157 @@ +import datetime +import json +import os +import tarfile +import uuid +from typing import Dict, List, Optional + +import numpy as np +import onnxruntime as ort +from tokenizers import Tokenizer + +from . import storage + +client = storage.storage.get_instance() + +MODEL_ARCHIVE = "bert-tiny-onnx.tar.gz" +MODEL_DIRECTORY = "/tmp/bert_language_model" +MODEL_SUBDIR = "bert-tiny-onnx" + +_session: Optional[ort.InferenceSession] = None +_tokenizer: Optional[Tokenizer] = None +_labels: Optional[Dict[int, str]] = None + + +def _ensure_model(bucket: str, model_prefix: str): + """ + Lazily download and initialize the ONNX model and tokenizer. + """ + global _session, _tokenizer, _labels + + model_path = os.path.join(MODEL_DIRECTORY, MODEL_SUBDIR) + model_download_begin = datetime.datetime.now() + model_download_end = model_download_begin + + if _session is None or _tokenizer is None or _labels is None: + if not os.path.exists(model_path): + os.makedirs(MODEL_DIRECTORY, exist_ok=True) + archive_path = os.path.join("/tmp", f"{uuid.uuid4()}-{MODEL_ARCHIVE}") + client.download(bucket, os.path.join(model_prefix, MODEL_ARCHIVE), archive_path) + model_download_end = datetime.datetime.now() + + with tarfile.open(archive_path, "r:gz") as tar: + tar.extractall(MODEL_DIRECTORY) + os.remove(archive_path) + else: + model_download_begin = datetime.datetime.now() + model_download_end = model_download_begin + + model_process_begin = datetime.datetime.now() + tokenizer_path = os.path.join(model_path, "tokenizer.json") + _tokenizer = Tokenizer.from_file(tokenizer_path) + _tokenizer.enable_truncation(max_length=128) + _tokenizer.enable_padding(length=128) + + label_map_path = os.path.join(model_path, "label_map.json") + with open(label_map_path, "r") as f: + raw_labels = json.load(f) + _labels = {int(idx): label for idx, label in raw_labels.items()} + + onnx_path = os.path.join(model_path, "model.onnx") + + available = ort.get_available_providers() + if "CUDAExecutionProvider" not in available: + raise RuntimeError(f"CUDAExecutionProvider unavailable (have: {available})") + + _session = ort.InferenceSession(onnx_path, providers=["CUDAExecutionProvider"]) + model_process_end = datetime.datetime.now() + else: + model_process_begin = datetime.datetime.now() + model_process_end = model_process_begin + + model_download_time = (model_download_end - model_download_begin) / datetime.timedelta( + microseconds=1 + ) + model_process_time = (model_process_end - model_process_begin) / datetime.timedelta( + microseconds=1 + ) + + return model_download_time, model_process_time + + +def _prepare_inputs(sentences: List[str]): + assert _tokenizer is not None + + encodings = _tokenizer.encode_batch(sentences) + + input_ids = np.array([enc.ids for enc in encodings], dtype=np.int64) + attention_mask = np.array([enc.attention_mask for enc in encodings], dtype=np.int64) + token_type_ids = np.array( + [enc.type_ids if enc.type_ids else [0] * len(enc.ids) for enc in encodings], + dtype=np.int64, + ) + + return { + "input_ids": input_ids, + "attention_mask": attention_mask, + "token_type_ids": token_type_ids, + } + + +def _softmax(logits: np.ndarray) -> np.ndarray: + shifted = logits - np.max(logits, axis=1, keepdims=True) + exp = np.exp(shifted) + return exp / np.sum(exp, axis=1, keepdims=True) + + +def handler(event): + bucket = event.get("bucket", {}).get("bucket") + model_prefix = event.get("bucket", {}).get("model") + text_prefix = event.get("bucket", {}).get("text") + text_key = event.get("object", {}).get("input") + + download_begin = datetime.datetime.now() + text_download_path = os.path.join("/tmp", f"{uuid.uuid4()}-{os.path.basename(text_key)}") + client.download(bucket, os.path.join(text_prefix, text_key), text_download_path) + download_end = datetime.datetime.now() + + model_download_time, model_process_time = _ensure_model(bucket, model_prefix) + assert _session is not None and _labels is not None and _tokenizer is not None + + with open(text_download_path, "r") as f: + sentences = [json.loads(line)["text"] for line in f if line.strip()] + + os.remove(text_download_path) + + inference_begin = datetime.datetime.now() + inputs = _prepare_inputs(sentences) + outputs = _session.run(None, inputs) + logits = outputs[0] + probabilities = _softmax(logits) + inference_end = datetime.datetime.now() + + results = [] + for sentence, probs in zip(sentences, probabilities): + label_idx = int(np.argmax(probs)) + label = _labels.get(label_idx, str(label_idx)) + results.append( + { + "text": sentence, + "label": label, + "confidence": float(probs[label_idx]), + "raw_scores": probs.tolist(), + } + ) + + download_time = (download_end - download_begin) / datetime.timedelta(microseconds=1) + compute_time = (inference_end - inference_begin) / datetime.timedelta(microseconds=1) + + return { + "result": {"predictions": results}, + "measurement": { + "download_time": download_time + model_download_time, + "compute_time": compute_time + model_process_time, + "model_time": model_process_time, + "model_download_time": model_download_time, + }, + } diff --git a/benchmarks/400.inference/412.language-bert/python/init.sh b/benchmarks/400.inference/412.language-bert/python/init.sh new file mode 100755 index 000000000..160852abe --- /dev/null +++ b/benchmarks/400.inference/412.language-bert/python/init.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +# No additional initialization required for the BERT inference benchmark. diff --git a/benchmarks/400.inference/412.language-bert/python/package.sh b/benchmarks/400.inference/412.language-bert/python/package.sh new file mode 100644 index 000000000..edb27ebe0 --- /dev/null +++ b/benchmarks/400.inference/412.language-bert/python/package.sh @@ -0,0 +1,35 @@ +# Stripping package code is based on https://github.com/ryfeus/lambda-packs repo + +PACKAGE_DIR=$1 +echo "Original size $(du -sh $1 | cut -f1)" + +CUR_DIR=$(pwd) +cd $1 +# cleaning libs +rm -rf external +find . -type d -name "tests" -exec rm -rf {} + +find . -type d -name "test" -exec rm -rf {} + +find . -type d -name "bin" -not -path "*/torch/*" -exec rm -rf {} + + +# cleaning +# stripping some of the numpy libs - libgfortran-2e0d59d6.so.5.0.0 - causes issues on Azure +find -name "*.so" -not -path "*/PIL/*" -not -path "*/Pillow.libs/*" -not -path "*libgfortran*" | xargs strip +find -name "*.so.*" -not -path "*/PIL/*" -not -path "*/Pillow.libs/*" -not -path "*libgfortran*" | xargs strip + +rm -r pip >/dev/null +rm -r pip-* >/dev/null +rm -r wheel >/dev/null +rm -r wheel-* >/dev/null +rm easy_install.py >/dev/null +find . -name \*.pyc -delete +cd ${CUR_DIR} +echo "Stripped size $(du -sh $1 | cut -f1)" + +TORCH_DIR=".python_packages/lib/site-packages/torch" +if [ -d "$1/${TORCH_DIR}" ]; then + cd $1 + zip -qr torch.zip ${TORCH_DIR} + rm -rf ${TORCH_DIR} + cd ${CUR_DIR} + echo "Torch-zipped size $(du -sh $1 | cut -f1)" +fi diff --git a/benchmarks/400.inference/412.language-bert/python/requirements.txt b/benchmarks/400.inference/412.language-bert/python/requirements.txt new file mode 100644 index 000000000..67a8c1e18 --- /dev/null +++ b/benchmarks/400.inference/412.language-bert/python/requirements.txt @@ -0,0 +1,3 @@ +numpy==1.24.4 +onnxruntime-gpu==1.16.3 +tokenizers==0.13.3 diff --git a/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.10 b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.10 new file mode 100644 index 000000000..67a8c1e18 --- /dev/null +++ b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.10 @@ -0,0 +1,3 @@ +numpy==1.24.4 +onnxruntime-gpu==1.16.3 +tokenizers==0.13.3 diff --git a/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.11 b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.11 new file mode 100644 index 000000000..67a8c1e18 --- /dev/null +++ b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.11 @@ -0,0 +1,3 @@ +numpy==1.24.4 +onnxruntime-gpu==1.16.3 +tokenizers==0.13.3 diff --git a/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.8 b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.8 new file mode 100644 index 000000000..67a8c1e18 --- /dev/null +++ b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.8 @@ -0,0 +1,3 @@ +numpy==1.24.4 +onnxruntime-gpu==1.16.3 +tokenizers==0.13.3 diff --git a/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.9 b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.9 new file mode 100644 index 000000000..67a8c1e18 --- /dev/null +++ b/benchmarks/400.inference/412.language-bert/python/requirements.txt.3.9 @@ -0,0 +1,3 @@ +numpy==1.24.4 +onnxruntime-gpu==1.16.3 +tokenizers==0.13.3 From 377d949c57999970dd65134b4d839a113efd3e14 Mon Sep 17 00:00:00 2001 From: xipang Date: Wed, 12 Nov 2025 20:31:53 +0100 Subject: [PATCH 24/58] update code --- benchmarks-data | 2 +- .../python/function.py | 215 ++++++++++-------- config/local_deployment.tmp | 0 3 files changed, 116 insertions(+), 101 deletions(-) create mode 100644 config/local_deployment.tmp diff --git a/benchmarks-data b/benchmarks-data index 6a17a460f..25c2bb40b 160000 --- a/benchmarks-data +++ b/benchmarks-data @@ -1 +1 @@ -Subproject commit 6a17a460f289e166abb47ea6298fb939e80e8beb +Subproject commit 25c2bb40b8bde342395534b534ba62f8f0ff3549 diff --git a/benchmarks/400.inference/413.image-classification/python/function.py b/benchmarks/400.inference/413.image-classification/python/function.py index 7c241d525..71a14fe79 100644 --- a/benchmarks/400.inference/413.image-classification/python/function.py +++ b/benchmarks/400.inference/413.image-classification/python/function.py @@ -1,13 +1,17 @@ -import datetime, json, os, uuid +import datetime +import json +import os +import uuid +from typing import List, Optional, Tuple # Extract zipped torch model - used in Python 3.8 and 3.9 -if os.path.exists("function/torch.zip"): - import zipfile, sys +# if os.path.exists("function/torch.zip"): +# import zipfile, sys - zipfile.ZipFile("function/torch.zip").extractall("/tmp/") - sys.path.append( - os.path.join(os.path.dirname(__file__), "/tmp/.python_packages/lib/site-packages") - ) +# zipfile.ZipFile("function/torch.zip").extractall("/tmp/") +# sys.path.append( +# os.path.join(os.path.dirname(__file__), "/tmp/.python_packages/lib/site-packages") +# ) from PIL import Image import torch @@ -22,119 +26,130 @@ class_idx = json.load(open(os.path.join(SCRIPT_DIR, "imagenet_class_index.json"), "r")) idx2label = [class_idx[str(k)][1] for k in range(len(class_idx))] -model = None -device = "cuda" if torch.cuda.is_available() else "cpu" - - -def handler(event): - bucket = event.get("bucket").get("bucket") - input_prefix = event.get("bucket").get("input") - model_prefix = event.get("bucket").get("model") - key = event.get("object").get("input") - model_key = event.get("object").get("model") - - download_path = "/tmp/{}-{}".format(key, uuid.uuid4()) - - # --- Download image --- - image_download_begin = datetime.datetime.now() - image_path = download_path - client.download(bucket, os.path.join(input_prefix, key), download_path) - image_download_end = datetime.datetime.now() +MODEL_DIRECTORY = "resnet50.tar.gz" +_model: Optional[torch.nn.Module] = None +_model_key: Optional[str] = None +_device = "cuda" if torch.cuda.is_available() else "cpu" +_preprocess = transforms.Compose( + [ + transforms.Resize(256), + transforms.CenterCrop(224), + transforms.ToTensor(), + transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), + ] +) + + +def _ensure_model(bucket: str, model_prefix: str, model_key: str) -> Tuple[float, float]: + """ + Lazily download and load the ResNet model so repeated invocations stay warm. + """ + global _model, _model_key + + model_download_begin = datetime.datetime.now() + model_download_end = model_download_begin + model_process_begin = datetime.datetime.now() + model_process_end = model_process_begin + + if _model is None or _model_key != model_key: + os.makedirs(MODEL_DIRECTORY, exist_ok=True) + weights_name = os.path.basename(model_key) + weights_path = os.path.join(MODEL_DIRECTORY, weights_name) + + if not os.path.exists(weights_path): + client.download(bucket, os.path.join(model_prefix, model_key), weights_path) + model_download_end = datetime.datetime.now() + else: + model_download_begin = datetime.datetime.now() + model_download_end = model_download_begin - global model - if model is None: - # --- Download weights --- - model_download_begin = datetime.datetime.now() - model_path = os.path.join("/tmp", model_key) - client.download(bucket, os.path.join(model_prefix, model_key), model_path) - model_download_end = datetime.datetime.now() - - # --- Load model (CPU), then move to GPU --- model_process_begin = datetime.datetime.now() model = resnet50(pretrained=False) - state = torch.load(model_path, map_location="cpu") # robust for CPU-saved checkpoints - # handle checkpoints that wrap state dict: + state = torch.load(weights_path, map_location="cpu") state = state.get("state_dict", state) model.load_state_dict(state) model.eval() - model.to(device) - # speed on cuDNN-convolutional nets - if device == "cuda": + model.to(_device) + if _device == "cuda": torch.backends.cudnn.benchmark = True + _model = model + _model_key = model_key model_process_end = datetime.datetime.now() - else: - # model already cached - model_download_begin = model_download_end = datetime.datetime.now() - model_process_begin = model_process_end = datetime.datetime.now() - - # --- Preprocess (CPU) --- - process_begin = datetime.datetime.now() - input_image = Image.open(image_path).convert("RGB") - preprocess = transforms.Compose( - [ - transforms.Resize(256), - transforms.CenterCrop(224), - transforms.ToTensor(), # [0,1], CHW - transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), - ] + + return ( + (model_download_end - model_download_begin) / datetime.timedelta(microseconds=1), + (model_process_end - model_process_begin) / datetime.timedelta(microseconds=1), ) - input_tensor = preprocess(input_image) # CPU tensor - input_batch = input_tensor.unsqueeze(0).to(device, non_blocking=True) # NCHW on GPU - # --- Inference (GPU) --- + +def _prepare_tensor(image_path: str) -> torch.Tensor: + image = Image.open(image_path).convert("RGB") + tensor = _preprocess(image).unsqueeze(0) + return tensor.to(_device, non_blocking=True) + + +def _run_inference(batch: torch.Tensor) -> Tuple[int, float, List[int], float]: + assert _model is not None + + gpu_time_ms = 0.0 + start_evt = end_evt = None + if _device == "cuda": + torch.cuda.synchronize() + start_evt = torch.cuda.Event(enable_timing=True) + end_evt = torch.cuda.Event(enable_timing=True) + start_evt.record() + with torch.no_grad(): - # Ensure wall-clock timing includes GPU work - if device == "cuda": - torch.cuda.synchronize() - # GPU event timing (kernel time) - start_evt = end_evt = None - if device == "cuda": - start_evt = torch.cuda.Event(enable_timing=True) - end_evt = torch.cuda.Event(enable_timing=True) - start_evt.record() - - output = model(input_batch) # logits [1,1000] - - if device == "cuda": - end_evt.record() - torch.cuda.synchronize() - - # compute top-1 / top-5 on CPU + output = _model(batch) + + if _device == "cuda" and start_evt and end_evt: + end_evt.record() + torch.cuda.synchronize() + gpu_time_ms = float(start_evt.elapsed_time(end_evt)) + probs = torch.nn.functional.softmax(output, dim=1) conf, index = torch.max(probs, 1) - # make Python types - top1_idx = index.item() - top1_conf = float(conf.item()) - # (optional) top-5 _, top5_idx = torch.topk(probs, k=5, dim=1) - top5_idx = top5_idx[0].tolist() - ret = idx2label[top1_idx] # <- use .item() result + return index.item(), float(conf.item()), top5_idx[0].tolist(), gpu_time_ms - process_end = datetime.datetime.now() - # timings - download_time = (image_download_end - image_download_begin) / datetime.timedelta(microseconds=1) - model_download_time = (model_download_end - model_download_begin) / datetime.timedelta( - microseconds=1 - ) - model_process_time = (model_process_end - model_process_begin) / datetime.timedelta( - microseconds=1 - ) - process_time = (process_end - process_begin) / datetime.timedelta(microseconds=1) +def handler(event): + bucket = event.get("bucket", {}).get("bucket") + input_prefix = event.get("bucket", {}).get("input") + model_prefix = event.get("bucket", {}).get("model") + key = event.get("object", {}).get("input") + model_key = event.get("object", {}).get("model") - # optional precise GPU kernel time (ms) - gpu_time_ms = 0.0 - if start_evt is not None and end_evt is not None: - gpu_time_ms = float(start_evt.elapsed_time(end_evt)) # milliseconds + download_path = os.path.join("/tmp", f"{uuid.uuid4()}-{os.path.basename(key)}") + image_download_begin = datetime.datetime.now() + client.download(bucket, os.path.join(input_prefix, key), download_path) + image_download_end = datetime.datetime.now() + + model_download_time, model_process_time = _ensure_model(bucket, model_prefix, model_key) + + inference_begin = datetime.datetime.now() + input_batch = _prepare_tensor(download_path) + top1_idx, top1_conf, top5_idx, gpu_time_ms = _run_inference(input_batch) + inference_end = datetime.datetime.now() + + os.remove(download_path) + + download_time = (image_download_end - image_download_begin) / datetime.timedelta(microseconds=1) + compute_time = (inference_end - inference_begin) / datetime.timedelta(microseconds=1) return { - "result": {"idx": top1_idx, "class": ret, "confidence": top1_conf, "top5_idx": top5_idx}, + "result": { + "idx": top1_idx, + "class": idx2label[top1_idx], + "confidence": top1_conf, + "top5_idx": top5_idx, + }, "measurement": { - "download_time": download_time + model_download_time, # µs - "compute_time": process_time + model_process_time, # µs (wall time, includes GPU) - "model_time": model_process_time, # µs - "model_download_time": model_download_time, # µs - "gpu_time_ms": round(gpu_time_ms, 3), # extra: CUDA kernel time + "download_time": download_time + model_download_time, + "compute_time": compute_time + model_process_time, + "model_time": model_process_time, + "model_download_time": model_download_time, + "gpu_time_ms": round(gpu_time_ms, 3), }, } diff --git a/config/local_deployment.tmp b/config/local_deployment.tmp new file mode 100644 index 000000000..e69de29bb From 8dd8a6e8fec20df291f0ddffe60f3473dce903f6 Mon Sep 17 00:00:00 2001 From: xipang Date: Wed, 12 Nov 2025 21:59:12 +0100 Subject: [PATCH 25/58] modify code and requirements --- .../413.image-classification/input.py | 2 +- .../python/function.py | 171 ++++++++++-------- .../python/requirements.txt | 7 +- .../python/requirements.txt.3.10 | 6 +- .../python/requirements.txt.3.11 | 6 +- .../python/requirements.txt.3.6 | 7 +- .../python/requirements.txt.3.7 | 7 +- .../python/requirements.txt.3.8 | 6 +- .../python/requirements.txt.3.9 | 6 +- "eval \"$(ssh-agent -s)\"" | 7 + "eval \"$(ssh-agent -s)\".pub" | 1 + 11 files changed, 125 insertions(+), 101 deletions(-) create mode 100644 "eval \"$(ssh-agent -s)\"" create mode 100644 "eval \"$(ssh-agent -s)\".pub" diff --git a/benchmarks/400.inference/413.image-classification/input.py b/benchmarks/400.inference/413.image-classification/input.py index e97d38057..6ee2fdd08 100644 --- a/benchmarks/400.inference/413.image-classification/input.py +++ b/benchmarks/400.inference/413.image-classification/input.py @@ -35,7 +35,7 @@ def generate_input( upload_func(0, model_name, os.path.join(data_dir, "model", model_name)) input_images = [] - resnet_path = os.path.join(data_dir, "fake-resnet") + resnet_path = os.path.join(data_dir, "data") with open(os.path.join(resnet_path, "val_map.txt"), "r") as f: for line in f: img, img_class = line.split() diff --git a/benchmarks/400.inference/413.image-classification/python/function.py b/benchmarks/400.inference/413.image-classification/python/function.py index 71a14fe79..48e837f70 100644 --- a/benchmarks/400.inference/413.image-classification/python/function.py +++ b/benchmarks/400.inference/413.image-classification/python/function.py @@ -1,22 +1,14 @@ import datetime import json import os +import shutil +import tarfile import uuid from typing import List, Optional, Tuple -# Extract zipped torch model - used in Python 3.8 and 3.9 -# if os.path.exists("function/torch.zip"): -# import zipfile, sys - -# zipfile.ZipFile("function/torch.zip").extractall("/tmp/") -# sys.path.append( -# os.path.join(os.path.dirname(__file__), "/tmp/.python_packages/lib/site-packages") -# ) - +import numpy as np +import onnxruntime as ort from PIL import Image -import torch -from torchvision import transforms -from torchvision.models import resnet50 from . import storage @@ -26,92 +18,122 @@ class_idx = json.load(open(os.path.join(SCRIPT_DIR, "imagenet_class_index.json"), "r")) idx2label = [class_idx[str(k)][1] for k in range(len(class_idx))] -MODEL_DIRECTORY = "resnet50.tar.gz" -_model: Optional[torch.nn.Module] = None -_model_key: Optional[str] = None -_device = "cuda" if torch.cuda.is_available() else "cpu" -_preprocess = transforms.Compose( - [ - transforms.Resize(256), - transforms.CenterCrop(224), - transforms.ToTensor(), - transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), - ] -) +MODEL_ARCHIVE = "resnet50.tar.gz" +MODEL_DIRECTORY = "/tmp/image_classification_model" +MODEL_SUBDIR = "resnet50" + +_session: Optional[ort.InferenceSession] = None +_session_input: Optional[str] = None +_session_output: Optional[str] = None +_cached_model_key: Optional[str] = None + +_MEAN = np.array([0.485, 0.456, 0.406], dtype=np.float32) +_STD = np.array([0.229, 0.224, 0.225], dtype=np.float32) def _ensure_model(bucket: str, model_prefix: str, model_key: str) -> Tuple[float, float]: """ - Lazily download and load the ResNet model so repeated invocations stay warm. + Lazily download, extract, and initialize the ONNX ResNet model. """ - global _model, _model_key + global _session, _session_input, _session_output, _cached_model_key + effective_model_key = model_key or MODEL_ARCHIVE model_download_begin = datetime.datetime.now() model_download_end = model_download_begin - model_process_begin = datetime.datetime.now() - model_process_end = model_process_begin - if _model is None or _model_key != model_key: + if _session is None or _cached_model_key != effective_model_key: + archive_basename = os.path.basename(effective_model_key) + archive_path = os.path.join("/tmp", f"{uuid.uuid4()}-{archive_basename}") + model_dir = os.path.join(MODEL_DIRECTORY, MODEL_SUBDIR) + + if os.path.exists(model_dir): + shutil.rmtree(model_dir) os.makedirs(MODEL_DIRECTORY, exist_ok=True) - weights_name = os.path.basename(model_key) - weights_path = os.path.join(MODEL_DIRECTORY, weights_name) - if not os.path.exists(weights_path): - client.download(bucket, os.path.join(model_prefix, model_key), weights_path) - model_download_end = datetime.datetime.now() - else: - model_download_begin = datetime.datetime.now() - model_download_end = model_download_begin + client.download(bucket, os.path.join(model_prefix, effective_model_key), archive_path) + model_download_end = datetime.datetime.now() + + with tarfile.open(archive_path, "r:gz") as tar: + tar.extractall(MODEL_DIRECTORY) + os.remove(archive_path) model_process_begin = datetime.datetime.now() - model = resnet50(pretrained=False) - state = torch.load(weights_path, map_location="cpu") - state = state.get("state_dict", state) - model.load_state_dict(state) - model.eval() - model.to(_device) - if _device == "cuda": - torch.backends.cudnn.benchmark = True - _model = model - _model_key = model_key + onnx_path = os.path.join(model_dir, "model.onnx") + if not os.path.exists(onnx_path): + raise FileNotFoundError(f"Expected ONNX model at {onnx_path}") + + available = ort.get_available_providers() + if "CUDAExecutionProvider" not in available: + raise RuntimeError(f"CUDAExecutionProvider unavailable (providers: {available})") + + _session = ort.InferenceSession(onnx_path, providers=["CUDAExecutionProvider"]) + _session_input = _session.get_inputs()[0].name + _session_output = _session.get_outputs()[0].name + _cached_model_key = effective_model_key model_process_end = datetime.datetime.now() + else: + model_process_begin = datetime.datetime.now() + model_process_end = model_process_begin - return ( - (model_download_end - model_download_begin) / datetime.timedelta(microseconds=1), - (model_process_end - model_process_begin) / datetime.timedelta(microseconds=1), + model_download_time = (model_download_end - model_download_begin) / datetime.timedelta( + microseconds=1 ) + model_process_time = (model_process_end - model_process_begin) / datetime.timedelta( + microseconds=1 + ) + + return model_download_time, model_process_time + + +def _resize_shorter_side(image: Image.Image, size: int) -> Image.Image: + width, height = image.size + if width < height: + new_width = size + new_height = int(round(size * height / width)) + else: + new_height = size + new_width = int(round(size * width / height)) + resample = getattr(Image, "Resampling", Image).BILINEAR + return image.resize((new_width, new_height), resample=resample) + + +def _center_crop(image: Image.Image, size: int) -> Image.Image: + width, height = image.size + left = max(0, int(round((width - size) / 2))) + top = max(0, int(round((height - size) / 2))) + right = left + size + bottom = top + size + return image.crop((left, top, right, bottom)) -def _prepare_tensor(image_path: str) -> torch.Tensor: +def _prepare_tensor(image_path: str) -> np.ndarray: image = Image.open(image_path).convert("RGB") - tensor = _preprocess(image).unsqueeze(0) - return tensor.to(_device, non_blocking=True) + image = _resize_shorter_side(image, 256) + image = _center_crop(image, 224) + np_image = np.asarray(image).astype(np.float32) / 255.0 + np_image = (np_image - _MEAN) / _STD + np_image = np.transpose(np_image, (2, 0, 1)) + return np_image[np.newaxis, :] -def _run_inference(batch: torch.Tensor) -> Tuple[int, float, List[int], float]: - assert _model is not None - gpu_time_ms = 0.0 - start_evt = end_evt = None - if _device == "cuda": - torch.cuda.synchronize() - start_evt = torch.cuda.Event(enable_timing=True) - end_evt = torch.cuda.Event(enable_timing=True) - start_evt.record() +def _softmax(logits: np.ndarray) -> np.ndarray: + shifted = logits - np.max(logits, axis=1, keepdims=True) + exp = np.exp(shifted) + return exp / np.sum(exp, axis=1, keepdims=True) - with torch.no_grad(): - output = _model(batch) - if _device == "cuda" and start_evt and end_evt: - end_evt.record() - torch.cuda.synchronize() - gpu_time_ms = float(start_evt.elapsed_time(end_evt)) +def _run_inference(batch: np.ndarray) -> Tuple[int, float, List[int]]: + assert _session is not None and _session_input is not None and _session_output is not None - probs = torch.nn.functional.softmax(output, dim=1) - conf, index = torch.max(probs, 1) - _, top5_idx = torch.topk(probs, k=5, dim=1) + outputs = _session.run([_session_output], {_session_input: batch}) + logits = outputs[0] + probs = _softmax(logits) + top1_idx = int(np.argmax(probs, axis=1)[0]) + top1_conf = float(probs[0, top1_idx]) + top5_idx = np.argsort(probs[0])[::-1][:5].tolist() - return index.item(), float(conf.item()), top5_idx[0].tolist(), gpu_time_ms + return top1_idx, top1_conf, top5_idx def handler(event): @@ -130,13 +152,14 @@ def handler(event): inference_begin = datetime.datetime.now() input_batch = _prepare_tensor(download_path) - top1_idx, top1_conf, top5_idx, gpu_time_ms = _run_inference(input_batch) + top1_idx, top1_conf, top5_idx = _run_inference(input_batch) inference_end = datetime.datetime.now() os.remove(download_path) download_time = (image_download_end - image_download_begin) / datetime.timedelta(microseconds=1) compute_time = (inference_end - inference_begin) / datetime.timedelta(microseconds=1) + #gpu_time_ms = 0.0 return { "result": { @@ -150,6 +173,6 @@ def handler(event): "compute_time": compute_time + model_process_time, "model_time": model_process_time, "model_download_time": model_download_time, - "gpu_time_ms": round(gpu_time_ms, 3), + #"gpu_time_ms": round(gpu_time_ms, 3), }, } diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt b/benchmarks/400.inference/413.image-classification/python/requirements.txt index d191dc6dd..cbbddaca6 100644 --- a/benchmarks/400.inference/413.image-classification/python/requirements.txt +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt @@ -1,4 +1,3 @@ -#torch==1.2.0+cpu -#torchvision==0.4.0+cpu -#https://download.pytorch.org/whl/cpu/torch-1.0.1.post2-cp37-cp37m-linux_x86_64.whl -#torch==1.0.1.post2+cpu +pillow==10.3.0 +numpy==1.24.4 +onnxruntime-gpu==1.16.3 diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.10 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.10 index ab734881f..cbbddaca6 100644 --- a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.10 +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.10 @@ -1,5 +1,3 @@ pillow==10.3.0 -https://download.pytorch.org/whl/cpu/torch-1.11.0%2Bcpu-cp310-cp310-linux_x86_64.whl -torchvision==0.12 -# prevent installing numpy 2.0 -numpy==1.22.0 +numpy==1.24.4 +onnxruntime-gpu==1.16.3 diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.11 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.11 index 3288171f8..cbbddaca6 100644 --- a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.11 +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.11 @@ -1,5 +1,3 @@ pillow==10.3.0 -https://download.pytorch.org/whl/cpu/torch-2.0.0%2Bcpu-cp311-cp311-linux_x86_64.whl -torchvision==0.15.1 -# prevent installing numpy 2.0 -numpy==1.24.0 +numpy==1.24.4 +onnxruntime-gpu==1.16.3 diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.6 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.6 index 63409acaa..cd198a130 100644 --- a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.6 +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.6 @@ -1,4 +1,3 @@ -Pillow==6.1 -numpy==1.16 -https://download.pytorch.org/whl/cpu/torch-1.0.1.post2-cp36-cp36m-linux_x86_64.whl -torchvision==0.2.1 +Pillow==6.1.0 +numpy==1.19.5 +onnxruntime-gpu==1.8.2 diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.7 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.7 index 54bddbd58..cd198a130 100644 --- a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.7 +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.7 @@ -1,4 +1,3 @@ -Pillow==6.1 -numpy==1.16 -https://download.pytorch.org/whl/cpu/torch-1.0.1.post2-cp37-cp37m-linux_x86_64.whl -torchvision==0.2.1 +Pillow==6.1.0 +numpy==1.19.5 +onnxruntime-gpu==1.8.2 diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.8 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.8 index 7b873eafa..cbbddaca6 100644 --- a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.8 +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.8 @@ -1,3 +1,3 @@ -numpy==1.18 -https://download.pytorch.org/whl/cpu/torch-1.4.0%2Bcpu-cp38-cp38-linux_x86_64.whl -torchvision==0.5 +pillow==10.3.0 +numpy==1.24.4 +onnxruntime-gpu==1.16.3 diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.9 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.9 index c7fc0663e..cbbddaca6 100644 --- a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.9 +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.9 @@ -1,3 +1,3 @@ -numpy==1.20 -https://download.pytorch.org/whl/cpu/torch-1.8.0%2Bcpu-cp39-cp39-linux_x86_64.whl -torchvision==0.9.0 +pillow==10.3.0 +numpy==1.24.4 +onnxruntime-gpu==1.16.3 diff --git "a/eval \"$(ssh-agent -s)\"" "b/eval \"$(ssh-agent -s)\"" new file mode 100644 index 000000000..892647ba0 --- /dev/null +++ "b/eval \"$(ssh-agent -s)\"" @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACB1mtWWL4bmQmqRMvbVqjz3ZUKX7NeYfMzA7Wf+31DqtAAAAKA7gCOkO4Aj +pAAAAAtzc2gtZWQyNTUxOQAAACB1mtWWL4bmQmqRMvbVqjz3ZUKX7NeYfMzA7Wf+31DqtA +AAAEBZdoiktY5L2ikHyUK4JfoeaTTX1KBHCtB+muQV2Y68SXWa1ZYvhuZCapEy9tWqPPdl +Qpfs15h8zMDtZ/7fUOq0AAAAGXJ1c3NlbGxwYW5nMDUwM0BnbWFpbC5jb20BAgME +-----END OPENSSH PRIVATE KEY----- diff --git "a/eval \"$(ssh-agent -s)\".pub" "b/eval \"$(ssh-agent -s)\".pub" new file mode 100644 index 000000000..c616a46e0 --- /dev/null +++ "b/eval \"$(ssh-agent -s)\".pub" @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHWa1ZYvhuZCapEy9tWqPPdlQpfs15h8zMDtZ/7fUOq0 russellpang0503@gmail.com From de15075aff66ae1d010d5e5fc3605bacdd7080c0 Mon Sep 17 00:00:00 2001 From: Russellpang Date: Wed, 12 Nov 2025 22:01:26 +0100 Subject: [PATCH 26/58] unfinished new fuc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sync: image-classification requirements + add 605.lu benchmark - Resolve conflicts in 413.image-classification/python/requirements* - Drop py3.6/py3.7 variants removed upstream; keep/update 3.8–3.11 - Add new 600.linearalgebra/605.lu benchmark (config, input, function, reqs) - Rename local_deployment.tmp -> 600.linearalgebra/605.lu/config.json - Update local_deployment.json; add out_benchmark*.json; update out_storage.json --- .../python/requirements.txt | 8 ++- .../python/requirements.txt.3.10 | 7 ++- .../python/requirements.txt.3.11 | 7 ++- .../python/requirements.txt.3.12 | 4 ++ .../python/requirements.txt.3.6 | 3 - .../python/requirements.txt.3.7 | 3 - .../python/requirements.txt.3.8 | 8 ++- .../python/requirements.txt.3.9 | 7 ++- .../python/requirements.txt.arm.3.8 | 5 ++ .../python/requirements.txt.arm.3.9 | 4 ++ .../600.linearalgebra/605.lu/config.json | 6 ++ benchmarks/600.linearalgebra/605.lu/input.py | 7 +++ .../605.lu/python/function.py | 60 +++++++++++++++++++ .../605.lu/python/requirements.txt | 1 + .../605.lu/python/requirements.txt.3.10 | 0 .../605.lu/python/requirements.txt.3.11 | 0 .../605.lu/python/requirements.txt.3.12 | 0 .../605.lu/python/requirements.txt.3.7 | 0 .../605.lu/python/requirements.txt.3.8 | 0 .../605.lu/python/requirements.txt.3.9 | 0 .../605.lu/python/requirements.txt.arm.3.8 | 0 .../605.lu/python/requirements.txt.arm.3.9 | 0 config/local_deployment.json | 18 +++--- out_benchmark.json | 40 +++++++++++++ out_benchmark_bert.json | 47 +++++++++++++++ out_storage.json | 8 +-- 26 files changed, 209 insertions(+), 34 deletions(-) mode change 100644 => 100755 benchmarks/400.inference/413.image-classification/python/requirements.txt create mode 100644 benchmarks/400.inference/413.image-classification/python/requirements.txt.3.12 delete mode 100644 benchmarks/400.inference/413.image-classification/python/requirements.txt.3.6 delete mode 100644 benchmarks/400.inference/413.image-classification/python/requirements.txt.3.7 mode change 100644 => 100755 benchmarks/400.inference/413.image-classification/python/requirements.txt.3.8 mode change 100644 => 100755 benchmarks/400.inference/413.image-classification/python/requirements.txt.3.9 create mode 100644 benchmarks/400.inference/413.image-classification/python/requirements.txt.arm.3.8 create mode 100644 benchmarks/400.inference/413.image-classification/python/requirements.txt.arm.3.9 create mode 100644 benchmarks/600.linearalgebra/605.lu/config.json create mode 100644 benchmarks/600.linearalgebra/605.lu/input.py create mode 100755 benchmarks/600.linearalgebra/605.lu/python/function.py create mode 100755 benchmarks/600.linearalgebra/605.lu/python/requirements.txt rename config/local_deployment.tmp => benchmarks/600.linearalgebra/605.lu/python/requirements.txt.3.10 (100%) create mode 100644 benchmarks/600.linearalgebra/605.lu/python/requirements.txt.3.11 create mode 100644 benchmarks/600.linearalgebra/605.lu/python/requirements.txt.3.12 create mode 100755 benchmarks/600.linearalgebra/605.lu/python/requirements.txt.3.7 create mode 100755 benchmarks/600.linearalgebra/605.lu/python/requirements.txt.3.8 create mode 100755 benchmarks/600.linearalgebra/605.lu/python/requirements.txt.3.9 create mode 100644 benchmarks/600.linearalgebra/605.lu/python/requirements.txt.arm.3.8 create mode 100644 benchmarks/600.linearalgebra/605.lu/python/requirements.txt.arm.3.9 create mode 100644 out_benchmark.json create mode 100644 out_benchmark_bert.json diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt b/benchmarks/400.inference/413.image-classification/python/requirements.txt old mode 100644 new mode 100755 index cbbddaca6..01d9a45b4 --- a/benchmarks/400.inference/413.image-classification/python/requirements.txt +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt @@ -1,3 +1,5 @@ -pillow==10.3.0 -numpy==1.24.4 -onnxruntime-gpu==1.16.3 +numpy>=1.22,<2.0 +pillow>=9.5,<10.0 +torch==2.4.1 +torchvision==0.19.1 +typing-extensions>=4.8 diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.10 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.10 index cbbddaca6..96299cb57 100644 --- a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.10 +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.10 @@ -1,3 +1,4 @@ -pillow==10.3.0 -numpy==1.24.4 -onnxruntime-gpu==1.16.3 +numpy>=2.0 +pillow>=10.0 +torch==2.5.1 +torchvision==0.20.1 diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.11 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.11 index cbbddaca6..96299cb57 100644 --- a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.11 +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.11 @@ -1,3 +1,4 @@ -pillow==10.3.0 -numpy==1.24.4 -onnxruntime-gpu==1.16.3 +numpy>=2.0 +pillow>=10.0 +torch==2.5.1 +torchvision==0.20.1 diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.12 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.12 new file mode 100644 index 000000000..96299cb57 --- /dev/null +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.12 @@ -0,0 +1,4 @@ +numpy>=2.0 +pillow>=10.0 +torch==2.5.1 +torchvision==0.20.1 diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.6 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.6 deleted file mode 100644 index cd198a130..000000000 --- a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.6 +++ /dev/null @@ -1,3 +0,0 @@ -Pillow==6.1.0 -numpy==1.19.5 -onnxruntime-gpu==1.8.2 diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.7 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.7 deleted file mode 100644 index cd198a130..000000000 --- a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.7 +++ /dev/null @@ -1,3 +0,0 @@ -Pillow==6.1.0 -numpy==1.19.5 -onnxruntime-gpu==1.8.2 diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.8 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.8 old mode 100644 new mode 100755 index cbbddaca6..01d9a45b4 --- a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.8 +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.8 @@ -1,3 +1,5 @@ -pillow==10.3.0 -numpy==1.24.4 -onnxruntime-gpu==1.16.3 +numpy>=1.22,<2.0 +pillow>=9.5,<10.0 +torch==2.4.1 +torchvision==0.19.1 +typing-extensions>=4.8 diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.9 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.9 old mode 100644 new mode 100755 index cbbddaca6..96299cb57 --- a/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.9 +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt.3.9 @@ -1,3 +1,4 @@ -pillow==10.3.0 -numpy==1.24.4 -onnxruntime-gpu==1.16.3 +numpy>=2.0 +pillow>=10.0 +torch==2.5.1 +torchvision==0.20.1 diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.arm.3.8 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.arm.3.8 new file mode 100644 index 000000000..01d9a45b4 --- /dev/null +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt.arm.3.8 @@ -0,0 +1,5 @@ +numpy>=1.22,<2.0 +pillow>=9.5,<10.0 +torch==2.4.1 +torchvision==0.19.1 +typing-extensions>=4.8 diff --git a/benchmarks/400.inference/413.image-classification/python/requirements.txt.arm.3.9 b/benchmarks/400.inference/413.image-classification/python/requirements.txt.arm.3.9 new file mode 100644 index 000000000..96299cb57 --- /dev/null +++ b/benchmarks/400.inference/413.image-classification/python/requirements.txt.arm.3.9 @@ -0,0 +1,4 @@ +numpy>=2.0 +pillow>=10.0 +torch==2.5.1 +torchvision==0.20.1 diff --git a/benchmarks/600.linearalgebra/605.lu/config.json b/benchmarks/600.linearalgebra/605.lu/config.json new file mode 100644 index 000000000..e80fb4351 --- /dev/null +++ b/benchmarks/600.linearalgebra/605.lu/config.json @@ -0,0 +1,6 @@ +{ + "timeout": 120, + "memory": 512, + "languages": ["python"], + "modules": [] +} diff --git a/benchmarks/600.linearalgebra/605.lu/input.py b/benchmarks/600.linearalgebra/605.lu/input.py new file mode 100644 index 000000000..79ff6f5cb --- /dev/null +++ b/benchmarks/600.linearalgebra/605.lu/input.py @@ -0,0 +1,7 @@ +size_generators = {"test": 10, "small": 100, "large": 1000} + + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): + return {"size": size_generators[size], "seed": 42} diff --git a/benchmarks/600.linearalgebra/605.lu/python/function.py b/benchmarks/600.linearalgebra/605.lu/python/function.py new file mode 100755 index 000000000..ea3de4d19 --- /dev/null +++ b/benchmarks/600.linearalgebra/605.lu/python/function.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +import sys, json, torch, datetime + + +def initialize_torch(N, dtype=torch.float32, device="cuda"): + col = torch.arange(N, device=device) + base = (torch.remainder(-col, N).to(dtype) / N) + 1 + + A = torch.tril(base.expand(N, N)).clone() + + A.fill_diagonal_(torch.tensor(1.0, dtype=dtype, device=device)) + + A = A @ A.T + return A + + +def kernel_cholesky(A): + torch.cuda.synchronize() + _ = torch.linalg.cholesky(A) # warmup + torch.cuda.synchronize() + + start_evt = torch.cuda.Event(enable_timing=True) + end_evt = torch.cuda.Event(enable_timing=True) + start_evt.record() + for _ in range(A.size(0)): + L = torch.linalg.cholesky(A) + end_evt.record() + torch.cuda.synchronize() + gpu_ms = float(start_evt.elapsed_time(end_evt)) + return L, gpu_ms + + +def handler(event): + size = event.get("size") + if "seed" in event: + import random + + random.seed(event["seed"]) + + seed = event.get("seed", 42) + seed = int(seed) + + gen_begin = datetime.datetime.now() + A = initialize_torch(size, dtype=torch.float32, device="cuda") + gen_end = datetime.datetime.now() + + comp_begin = datetime.datetime.now() + L, gpu_ms = kernel_cholesky(A) + comp_end = datetime.datetime.now() + + gen_us = (gen_end - gen_begin) / datetime.timedelta(microseconds=1) + comp_us = (comp_end - comp_begin) / datetime.timedelta(microseconds=1) + + return { + "measurement": { + "generating_time": gen_us, + "compute_time": comp_us, + "gpu_time": gpu_ms, + } + } diff --git a/benchmarks/600.linearalgebra/605.lu/python/requirements.txt b/benchmarks/600.linearalgebra/605.lu/python/requirements.txt new file mode 100755 index 000000000..d8d966118 --- /dev/null +++ b/benchmarks/600.linearalgebra/605.lu/python/requirements.txt @@ -0,0 +1 @@ +torch==2.4.1 diff --git a/config/local_deployment.tmp b/benchmarks/600.linearalgebra/605.lu/python/requirements.txt.3.10 similarity index 100% rename from config/local_deployment.tmp rename to benchmarks/600.linearalgebra/605.lu/python/requirements.txt.3.10 diff --git a/benchmarks/600.linearalgebra/605.lu/python/requirements.txt.3.11 b/benchmarks/600.linearalgebra/605.lu/python/requirements.txt.3.11 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/605.lu/python/requirements.txt.3.12 b/benchmarks/600.linearalgebra/605.lu/python/requirements.txt.3.12 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/605.lu/python/requirements.txt.3.7 b/benchmarks/600.linearalgebra/605.lu/python/requirements.txt.3.7 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/605.lu/python/requirements.txt.3.8 b/benchmarks/600.linearalgebra/605.lu/python/requirements.txt.3.8 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/605.lu/python/requirements.txt.3.9 b/benchmarks/600.linearalgebra/605.lu/python/requirements.txt.3.9 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/605.lu/python/requirements.txt.arm.3.8 b/benchmarks/600.linearalgebra/605.lu/python/requirements.txt.arm.3.8 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/605.lu/python/requirements.txt.arm.3.9 b/benchmarks/600.linearalgebra/605.lu/python/requirements.txt.arm.3.9 new file mode 100644 index 000000000..e69de29bb diff --git a/config/local_deployment.json b/config/local_deployment.json index d89b3a968..773b43943 100644 --- a/config/local_deployment.json +++ b/config/local_deployment.json @@ -1,18 +1,18 @@ { "experiments": { - "deployment": "local", + "deployment": "aws", "update_code": false, "update_storage": false, "download_results": false, - "architecture": "x64", + "architecture": "arm64", "container_deployment": true, "runtime": { "language": "python", - "version": "3.11" + "version": "3.8" }, "type": "invocation-overhead", "perf-cost": { - "benchmark": "601.matmul", + "benchmark": "110.dynamic-html", "experiments": [ "cold", "warm", @@ -51,7 +51,7 @@ } }, "deployment": { - "name": "local", + "name": "aws", "aws": { "region": "us-east-1", "lambda-role": "" @@ -71,9 +71,9 @@ "minio": { "address": "192.168.1.101:9011", "mapped_port": 9011, - "access_key": "Ux22nOcFoUaZAnmg-kULuIzvXmiFNVRiZkzcOaDawpU", - "secret_key": "9bb8b39326b0fde8bdfa5d013f743c03e57d146f10433fe2fe3ccce7225078d5", - "instance_id": "f337f509c0375ca4457f815cc0f67352088f6093053ba33c1e45aca0012e0a9f", + "access_key": "-5X8s-Wf3pQfjnc7kMAlr9HYX96jIMx3P7GSd55IBAY", + "secret_key": "c9e3b900a8d363f9907af7057fb5a8e35cb14ad24e9e474e75b8139323717fdc", + "instance_id": "26785ccd17e17e72255c255d00756a9eaa14b1aeb60a52527b97cfb33eece9e5", "output_buckets": [], "input_buckets": [], "version": "RELEASE.2024-07-16T23-46-41Z", @@ -89,7 +89,7 @@ "alternator_port": 8000, "access_key": "None", "secret_key": "None", - "instance_id": "c7be7d211bb211b92f41afb073f75635d9f5f2a222abeb6d9b17673b02d079ca", + "instance_id": "28fb7af28043b633b33b4b5999b48c14767f717ed76a73515ff8c68f253baeb1", "region": "None", "cpus": 1, "memory": "750", diff --git a/out_benchmark.json b/out_benchmark.json new file mode 100644 index 000000000..cf96b5c5d --- /dev/null +++ b/out_benchmark.json @@ -0,0 +1,40 @@ +{ + "functions": [ + { + "benchmark": "110.dynamic-html", + "config": { + "architecture": "x64", + "memory": 128, + "runtime": { + "language": "python", + "version": "3.8" + }, + "timeout": 10 + }, + "hash": "c9fbe3e5e85e119e20d6a72651ef23b0", + "instance_id": "be83782894ea459ea3328d4d3b4aeb7173acec54f2c1cebb354f97459b318eef", + "name": "sebs-local-f2033fb2-110.dynamic-html-python-3.8", + "port": 9000, + "triggers": [], + "url": "172.17.0.4:9000" + } + ], + "inputs": [ + { + "random_len": 10, + "username": "testname" + } + ], + "storage": { + "access_key": "FC95zkJKAUbfmXU3ci5lc0SFWhDWYrSgx0nRNycthcY", + "address": "172.17.0.2:9000", + "data_volume": "minio-volume", + "input_buckets": [], + "instance_id": "d14d6dc800ce2f976cc19dc4dd85d2010b65709266f5ae0f1a0c157d338134ec", + "mapped_port": 9011, + "output_buckets": [], + "secret_key": "65eb94d63b0191bf765864ffbd4ee58cc1eb852bdc3a5ca463bca2e7c5915aec", + "type": "minio", + "version": "RELEASE.2024-07-16T23-46-41Z" + } +} \ No newline at end of file diff --git a/out_benchmark_bert.json b/out_benchmark_bert.json new file mode 100644 index 000000000..c706062a2 --- /dev/null +++ b/out_benchmark_bert.json @@ -0,0 +1,47 @@ +{ + "functions": [ + { + "benchmark": "413.image-classification", + "config": { + "architecture": "x64", + "memory": 512, + "runtime": { + "language": "python", + "version": "3.8" + }, + "timeout": 60 + }, + "hash": "445383b434f036f9520743532c7bc0b1", + "instance_id": "a59d2b025927d6350363787bfbab3e7d44b90e0575cd72b939dd9cee291dd63c", + "name": "sebs-local-f2033fb2-413.image-classification-python-3.8", + "port": 9000, + "triggers": [], + "url": "172.17.0.4:9000" + } + ], + "inputs": [ + { + "bucket": { + "bucket": "sebs-benchmarks-local-f2033fb2", + "input": "413.image-classification-1-input", + "model": "413.image-classification-0-input" + }, + "object": { + "input": "800px-Porsche_991_silver_IAA.jpg", + "model": "resnet50.tar.gz" + } + } + ], + "storage": { + "access_key": "-5X8s-Wf3pQfjnc7kMAlr9HYX96jIMx3P7GSd55IBAY", + "address": "192.168.1.101:9011", + "data_volume": "minio-volume", + "input_buckets": [], + "instance_id": "26785ccd17e17e72255c255d00756a9eaa14b1aeb60a52527b97cfb33eece9e5", + "mapped_port": 9011, + "output_buckets": [], + "secret_key": "c9e3b900a8d363f9907af7057fb5a8e35cb14ad24e9e474e75b8139323717fdc", + "type": "minio", + "version": "RELEASE.2024-07-16T23-46-41Z" + } +} \ No newline at end of file diff --git a/out_storage.json b/out_storage.json index 16c13dba6..6c4a8e799 100644 --- a/out_storage.json +++ b/out_storage.json @@ -4,9 +4,9 @@ "minio": { "address": "172.17.0.2:9000", "mapped_port": 9011, - "access_key": "vTIGFqQKDU9CVlE_eFkJ7kZFt823CoiiG1GRgxLFczc", - "secret_key": "01872a84cd3ec4af4b897cc57fa515ca7a704a5e4557b5ecde5b98fe41ecc489", - "instance_id": "39a39aa73d44cee61a627a73fecd962f8fdcdbc415f70f702d850eff2afae3a3", + "access_key": "-5X8s-Wf3pQfjnc7kMAlr9HYX96jIMx3P7GSd55IBAY", + "secret_key": "c9e3b900a8d363f9907af7057fb5a8e35cb14ad24e9e474e75b8139323717fdc", + "instance_id": "26785ccd17e17e72255c255d00756a9eaa14b1aeb60a52527b97cfb33eece9e5", "output_buckets": [], "input_buckets": [], "version": "RELEASE.2024-07-16T23-46-41Z", @@ -22,7 +22,7 @@ "alternator_port": 8000, "access_key": "None", "secret_key": "None", - "instance_id": "b302608abce0d96e1518260ff38c366bbe0dfe279935c521ef682d740d84fe69", + "instance_id": "28fb7af28043b633b33b4b5999b48c14767f717ed76a73515ff8c68f253baeb1", "region": "None", "cpus": 1, "memory": "750", From 30068797db9ac4b32c8af80ce3b0cf6e2b7027e4 Mon Sep 17 00:00:00 2001 From: Russellpang Date: Wed, 12 Nov 2025 22:28:23 +0100 Subject: [PATCH 27/58] add new functions --- .../605.lu/python/function.py | 27 +++++-- .../600.linearalgebra/606.spmv/config.json | 6 ++ .../600.linearalgebra/606.spmv/input.py | 7 ++ .../606.spmv/python/function.py | 70 +++++++++++++++++++ .../606.spmv/python/requirements.txt | 1 + .../606.spmv/python/requirements.txt.3.10 | 0 .../606.spmv/python/requirements.txt.3.11 | 0 .../606.spmv/python/requirements.txt.3.12 | 0 .../606.spmv/python/requirements.txt.3.7 | 0 .../606.spmv/python/requirements.txt.3.8 | 0 .../606.spmv/python/requirements.txt.3.9 | 0 .../606.spmv/python/requirements.txt.arm.3.8 | 0 .../606.spmv/python/requirements.txt.arm.3.9 | 0 13 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 benchmarks/600.linearalgebra/606.spmv/config.json create mode 100644 benchmarks/600.linearalgebra/606.spmv/input.py create mode 100755 benchmarks/600.linearalgebra/606.spmv/python/function.py create mode 100755 benchmarks/600.linearalgebra/606.spmv/python/requirements.txt create mode 100644 benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.3.10 create mode 100644 benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.3.11 create mode 100644 benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.3.12 create mode 100755 benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.3.7 create mode 100755 benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.3.8 create mode 100755 benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.3.9 create mode 100644 benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.arm.3.8 create mode 100644 benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.arm.3.9 diff --git a/benchmarks/600.linearalgebra/605.lu/python/function.py b/benchmarks/600.linearalgebra/605.lu/python/function.py index ea3de4d19..492153bb7 100755 --- a/benchmarks/600.linearalgebra/605.lu/python/function.py +++ b/benchmarks/600.linearalgebra/605.lu/python/function.py @@ -14,20 +14,37 @@ def initialize_torch(N, dtype=torch.float32, device="cuda"): return A -def kernel_cholesky(A): +def _kernel_lu(B: torch.Tensor) -> torch.Tensor: + n = B.shape[0] + for i in range(n): + for j in range(i): + B[i, j] = B[i, j] - (B[i, :j] @ B[:j, j]) + B[i, j] = B[i, j] / B[j, j] + for j in range(i, n): + B[i, j] = B[i, j] - (B[i, :i] @ B[:i, j]) + return B + + +def kernel(A: torch.Tensor): torch.cuda.synchronize() - _ = torch.linalg.cholesky(A) # warmup + + _ = _kernel_lu(A.clone()) # Warm-up + torch.cuda.synchronize() start_evt = torch.cuda.Event(enable_timing=True) end_evt = torch.cuda.Event(enable_timing=True) + start_evt.record() + B = None for _ in range(A.size(0)): - L = torch.linalg.cholesky(A) + B = _kernel_lu(A.clone()) end_evt.record() + torch.cuda.synchronize() + gpu_ms = float(start_evt.elapsed_time(end_evt)) - return L, gpu_ms + return B, gpu_ms def handler(event): @@ -45,7 +62,7 @@ def handler(event): gen_end = datetime.datetime.now() comp_begin = datetime.datetime.now() - L, gpu_ms = kernel_cholesky(A) + B, gpu_ms = kernel(A) comp_end = datetime.datetime.now() gen_us = (gen_end - gen_begin) / datetime.timedelta(microseconds=1) diff --git a/benchmarks/600.linearalgebra/606.spmv/config.json b/benchmarks/600.linearalgebra/606.spmv/config.json new file mode 100644 index 000000000..e80fb4351 --- /dev/null +++ b/benchmarks/600.linearalgebra/606.spmv/config.json @@ -0,0 +1,6 @@ +{ + "timeout": 120, + "memory": 512, + "languages": ["python"], + "modules": [] +} diff --git a/benchmarks/600.linearalgebra/606.spmv/input.py b/benchmarks/600.linearalgebra/606.spmv/input.py new file mode 100644 index 000000000..79ff6f5cb --- /dev/null +++ b/benchmarks/600.linearalgebra/606.spmv/input.py @@ -0,0 +1,7 @@ +size_generators = {"test": 10, "small": 100, "large": 1000} + + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): + return {"size": size_generators[size], "seed": 42} diff --git a/benchmarks/600.linearalgebra/606.spmv/python/function.py b/benchmarks/600.linearalgebra/606.spmv/python/function.py new file mode 100755 index 000000000..16e8744d1 --- /dev/null +++ b/benchmarks/600.linearalgebra/606.spmv/python/function.py @@ -0,0 +1,70 @@ +import sys, json, math, torch +import datetime + + +def initialize_torch(N, density=0.01, dtype=torch.float32, device="cuda", seed=42): + if seed is not None: + torch.manual_seed(seed) + torch.cuda.manual_seed_all(seed) + + nnz = int(N * N * density) + row_indices = torch.randint(0, N, (nnz,), device=device) + col_indices = torch.randint(0, N, (nnz,), device=device) + values = torch.randn(nnz, dtype=dtype, device=device) + + indices = torch.stack([row_indices, col_indices]) + sparse_matrix = torch.sparse_coo_tensor(indices, values, (N, N), dtype=dtype, device=device) + + sparse_matrix_csr = sparse_matrix.to_sparse_csr() + + x = torch.randn(N, dtype=dtype, device=device) + + return sparse_matrix_csr, x + + +def kernel_spmv(A, x, reps=100): + torch.cuda.synchronize() + _ = torch.sparse.mm(A, x.unsqueeze(1)).squeeze() # warmup + torch.cuda.synchronize() + + start_evt = torch.cuda.Event(enable_timing=True) + end_evt = torch.cuda.Event(enable_timing=True) + start_evt.record() + for _ in range(reps): + y = torch.sparse.mm(A, x.unsqueeze(1)).squeeze() + end_evt.record() + torch.cuda.synchronize() + gpu_ms = float(start_evt.elapsed_time(end_evt)) + return y, gpu_ms + + +def handler(event): + size = event.get("size") + density = event.get("density", 0.01) # default 1% density + + if "seed" in event: + import random + random.seed(event["seed"]) + seed = event.get("seed", 42) + seed = int(seed) + else: + seed = 42 + + gen_begin = datetime.datetime.now() + A, x = initialize_torch(size, density=density, dtype=torch.float32, device="cuda", seed=seed) + gen_end = datetime.datetime.now() + + comp_begin = datetime.datetime.now() + y_out, gpu_ms = kernel_spmv(A, x, reps=100) + comp_end = datetime.datetime.now() + + gen_us = (gen_end - gen_begin) / datetime.timedelta(microseconds=1) + comp_us = (comp_end - comp_begin) / datetime.timedelta(microseconds=1) + + return { + "measurement": { + "generating_time": gen_us, + "compute_time": comp_us, + "gpu_time": gpu_ms, + } + } diff --git a/benchmarks/600.linearalgebra/606.spmv/python/requirements.txt b/benchmarks/600.linearalgebra/606.spmv/python/requirements.txt new file mode 100755 index 000000000..d8d966118 --- /dev/null +++ b/benchmarks/600.linearalgebra/606.spmv/python/requirements.txt @@ -0,0 +1 @@ +torch==2.4.1 diff --git a/benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.3.10 b/benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.3.10 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.3.11 b/benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.3.11 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.3.12 b/benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.3.12 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.3.7 b/benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.3.7 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.3.8 b/benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.3.8 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.3.9 b/benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.3.9 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.arm.3.8 b/benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.arm.3.8 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.arm.3.9 b/benchmarks/600.linearalgebra/606.spmv/python/requirements.txt.arm.3.9 new file mode 100644 index 000000000..e69de29bb From d224ddc7c08798dab46185758644bb6196123da0 Mon Sep 17 00:00:00 2001 From: Russellpang Date: Thu, 13 Nov 2025 01:57:44 +0100 Subject: [PATCH 28/58] add new functions --- .../600.linearalgebra/606.spmv/input.py | 2 +- .../600.linearalgebra/607.fw/config.json | 6 ++ benchmarks/600.linearalgebra/607.fw/input.py | 7 ++ .../607.fw/python/function.py | 71 +++++++++++++++++++ .../607.fw/python/requirements.txt | 1 + .../607.fw/python/requirements.txt.3.10 | 0 .../607.fw/python/requirements.txt.3.11 | 0 .../607.fw/python/requirements.txt.3.12 | 0 .../607.fw/python/requirements.txt.3.7 | 0 .../607.fw/python/requirements.txt.3.8 | 0 .../607.fw/python/requirements.txt.3.9 | 0 .../607.fw/python/requirements.txt.arm.3.8 | 0 .../607.fw/python/requirements.txt.arm.3.9 | 0 13 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 benchmarks/600.linearalgebra/607.fw/config.json create mode 100644 benchmarks/600.linearalgebra/607.fw/input.py create mode 100755 benchmarks/600.linearalgebra/607.fw/python/function.py create mode 100755 benchmarks/600.linearalgebra/607.fw/python/requirements.txt create mode 100644 benchmarks/600.linearalgebra/607.fw/python/requirements.txt.3.10 create mode 100644 benchmarks/600.linearalgebra/607.fw/python/requirements.txt.3.11 create mode 100644 benchmarks/600.linearalgebra/607.fw/python/requirements.txt.3.12 create mode 100755 benchmarks/600.linearalgebra/607.fw/python/requirements.txt.3.7 create mode 100755 benchmarks/600.linearalgebra/607.fw/python/requirements.txt.3.8 create mode 100755 benchmarks/600.linearalgebra/607.fw/python/requirements.txt.3.9 create mode 100644 benchmarks/600.linearalgebra/607.fw/python/requirements.txt.arm.3.8 create mode 100644 benchmarks/600.linearalgebra/607.fw/python/requirements.txt.arm.3.9 diff --git a/benchmarks/600.linearalgebra/606.spmv/input.py b/benchmarks/600.linearalgebra/606.spmv/input.py index 79ff6f5cb..e0f215890 100644 --- a/benchmarks/600.linearalgebra/606.spmv/input.py +++ b/benchmarks/600.linearalgebra/606.spmv/input.py @@ -4,4 +4,4 @@ def generate_input( data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func ): - return {"size": size_generators[size], "seed": 42} + return {"size": size_generators[size], "seed": 42, "density": 0.01} diff --git a/benchmarks/600.linearalgebra/607.fw/config.json b/benchmarks/600.linearalgebra/607.fw/config.json new file mode 100644 index 000000000..e80fb4351 --- /dev/null +++ b/benchmarks/600.linearalgebra/607.fw/config.json @@ -0,0 +1,6 @@ +{ + "timeout": 120, + "memory": 512, + "languages": ["python"], + "modules": [] +} diff --git a/benchmarks/600.linearalgebra/607.fw/input.py b/benchmarks/600.linearalgebra/607.fw/input.py new file mode 100644 index 000000000..79ff6f5cb --- /dev/null +++ b/benchmarks/600.linearalgebra/607.fw/input.py @@ -0,0 +1,7 @@ +size_generators = {"test": 10, "small": 100, "large": 1000} + + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): + return {"size": size_generators[size], "seed": 42} diff --git a/benchmarks/600.linearalgebra/607.fw/python/function.py b/benchmarks/600.linearalgebra/607.fw/python/function.py new file mode 100755 index 000000000..2db5e1f18 --- /dev/null +++ b/benchmarks/600.linearalgebra/607.fw/python/function.py @@ -0,0 +1,71 @@ +import sys, json, math, torch +import datetime + + +def initialize_torch(N, dtype=torch.int32, device="cuda", seed=42): + if seed is not None: + torch.manual_seed(seed) + torch.cuda.manual_seed_all(seed) + + i, j = torch.meshgrid( + torch.arange(N, device=device), torch.arange(N, device=device), indexing="ij" + ) + path = ((i * j) % 7 + 1).to(dtype) + + mask = ((i + j) % 13 == 0) | ((i + j) % 7 == 0) | ((i + j) % 11 == 0) + path = path.masked_fill(mask, torch.as_tensor(999, dtype=dtype, device=device)) + return path + + +def kernel_fw(path): + torch.cuda.synchronize() + path2 = path.clone() + n = path2.size(0) + for k in range(n): + for i in range(n): + path2[i, :] = torch.minimum(path2[i, :], path2[i, k] + path2[k, :]) # warmup + torch.cuda.synchronize() + + start_evt = torch.cuda.Event(enable_timing=True) + end_evt = torch.cuda.Event(enable_timing=True) + start_evt.record() + n = path.size(0) + for k in range(n): + for i in range(n): + path[i, :] = torch.minimum(path[i, :], path[i, k] + path[k, :]) + end_evt.record() + torch.cuda.synchronize() + gpu_ms = float(start_evt.elapsed_time(end_evt)) + return path, gpu_ms + + +def handler(event): + size = event.get("size") + + if "seed" in event: + import random + + random.seed(event["seed"]) + seed = event.get("seed", 42) + seed = int(seed) + else: + seed = 42 + + gen_begin = datetime.datetime.now() + path = initialize_torch(size, dtype=torch.float32, device="cuda", seed=seed) + gen_end = datetime.datetime.now() + + comp_begin = datetime.datetime.now() + path_out, gpu_ms = kernel_fw(path) + comp_end = datetime.datetime.now() + + gen_us = (gen_end - gen_begin) / datetime.timedelta(microseconds=1) + comp_us = (comp_end - comp_begin) / datetime.timedelta(microseconds=1) + + return { + "measurement": { + "generating_time": gen_us, + "compute_time": comp_us, + "gpu_time": gpu_ms, + } + } diff --git a/benchmarks/600.linearalgebra/607.fw/python/requirements.txt b/benchmarks/600.linearalgebra/607.fw/python/requirements.txt new file mode 100755 index 000000000..d8d966118 --- /dev/null +++ b/benchmarks/600.linearalgebra/607.fw/python/requirements.txt @@ -0,0 +1 @@ +torch==2.4.1 diff --git a/benchmarks/600.linearalgebra/607.fw/python/requirements.txt.3.10 b/benchmarks/600.linearalgebra/607.fw/python/requirements.txt.3.10 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/607.fw/python/requirements.txt.3.11 b/benchmarks/600.linearalgebra/607.fw/python/requirements.txt.3.11 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/607.fw/python/requirements.txt.3.12 b/benchmarks/600.linearalgebra/607.fw/python/requirements.txt.3.12 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/607.fw/python/requirements.txt.3.7 b/benchmarks/600.linearalgebra/607.fw/python/requirements.txt.3.7 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/607.fw/python/requirements.txt.3.8 b/benchmarks/600.linearalgebra/607.fw/python/requirements.txt.3.8 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/607.fw/python/requirements.txt.3.9 b/benchmarks/600.linearalgebra/607.fw/python/requirements.txt.3.9 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/607.fw/python/requirements.txt.arm.3.8 b/benchmarks/600.linearalgebra/607.fw/python/requirements.txt.arm.3.8 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/600.linearalgebra/607.fw/python/requirements.txt.arm.3.9 b/benchmarks/600.linearalgebra/607.fw/python/requirements.txt.arm.3.9 new file mode 100644 index 000000000..e69de29bb From 921f3217a65f041f53528ed415d4c34c2b27a5a5 Mon Sep 17 00:00:00 2001 From: McLavish Date: Thu, 13 Nov 2025 10:30:03 +0100 Subject: [PATCH 29/58] added recommender benchmark --- .../400.inference/413.recommendation/input.py | 30 ++++ .../413.recommendation/python/function.py | 144 ++++++++++++++++++ .../413.recommendation/python/init.sh | 3 + .../413.recommendation/python/package.sh | 4 + .../python/requirements.txt | 1 + .../python/requirements.txt.3.10 | 1 + .../python/requirements.txt.3.11 | 1 + .../python/requirements.txt.3.8 | 1 + .../python/requirements.txt.3.9 | 1 + docs/benchmarks.md | 5 + sebs/regression.py | 1 + 11 files changed, 192 insertions(+) create mode 100644 benchmarks/400.inference/413.recommendation/input.py create mode 100644 benchmarks/400.inference/413.recommendation/python/function.py create mode 100644 benchmarks/400.inference/413.recommendation/python/init.sh create mode 100644 benchmarks/400.inference/413.recommendation/python/package.sh create mode 100644 benchmarks/400.inference/413.recommendation/python/requirements.txt create mode 100644 benchmarks/400.inference/413.recommendation/python/requirements.txt.3.10 create mode 100644 benchmarks/400.inference/413.recommendation/python/requirements.txt.3.11 create mode 100644 benchmarks/400.inference/413.recommendation/python/requirements.txt.3.8 create mode 100644 benchmarks/400.inference/413.recommendation/python/requirements.txt.3.9 diff --git a/benchmarks/400.inference/413.recommendation/input.py b/benchmarks/400.inference/413.recommendation/input.py new file mode 100644 index 000000000..4e48cfa52 --- /dev/null +++ b/benchmarks/400.inference/413.recommendation/input.py @@ -0,0 +1,30 @@ +import os + + +def buckets_count(): + return (2, 0) + + +def upload_files(data_root, data_dir, upload_func): + for root, _, files in os.walk(data_dir): + prefix = os.path.relpath(root, data_root) + for file in files: + upload_func(0, os.path.join(prefix, file), os.path.join(root, file)) + + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): + model_file = "dlrm_tiny.pt" + upload_func(0, model_file, os.path.join(data_dir, "model", model_file)) + + requests_file = "requests.jsonl" + upload_func(1, requests_file, os.path.join(data_dir, "data", requests_file)) + + cfg = {"object": {}, "bucket": {}} + cfg["object"]["model"] = model_file + cfg["object"]["requests"] = requests_file + cfg["bucket"]["bucket"] = benchmarks_bucket + cfg["bucket"]["model"] = input_paths[0] + cfg["bucket"]["requests"] = input_paths[1] + return cfg diff --git a/benchmarks/400.inference/413.recommendation/python/function.py b/benchmarks/400.inference/413.recommendation/python/function.py new file mode 100644 index 000000000..e7b4ae73c --- /dev/null +++ b/benchmarks/400.inference/413.recommendation/python/function.py @@ -0,0 +1,144 @@ +import datetime +import json +import os +import uuid + +import torch +import torch.nn as nn + +from . import storage + +client = storage.storage.get_instance() + +MODEL_FILE = "dlrm_tiny.pt" +MODEL_CACHE = "/tmp/dlrm_gpu_model" + +_model = None +_device = torch.device("cpu") + + +class TinyDLRM(nn.Module): + def __init__(self, num_users, num_items, num_categories, embed_dim=8): + super().__init__() + self.user_emb = nn.Embedding(num_users, embed_dim) + self.item_emb = nn.Embedding(num_items, embed_dim) + self.category_emb = nn.Embedding(num_categories, embed_dim) + in_dim = embed_dim * 3 + 2 + hidden = 16 + self.mlp = nn.Sequential( + nn.Linear(in_dim, hidden), + nn.ReLU(), + nn.Linear(hidden, 1), + ) + + def forward(self, user_id, item_id, category_id, dense): + features = torch.cat( + [ + self.user_emb(user_id), + self.item_emb(item_id), + self.category_emb(category_id), + dense, + ], + dim=-1, + ) + return torch.sigmoid(self.mlp(features)) + + +def _select_device(): + if torch.cuda.is_available(): + return torch.device("cuda") + raise RuntimeError("CUDA is not available") + return torch.device("cpu") + + +def _load_model(bucket, prefix): + global _model, _device + + if _model is not None: + return 0.0, 0.0 + + download_begin = datetime.datetime.now() + os.makedirs(MODEL_CACHE, exist_ok=True) + tmp_path = os.path.join("/tmp", f"{uuid.uuid4()}-{MODEL_FILE}") + client.download(bucket, os.path.join(prefix, MODEL_FILE), tmp_path) + download_end = datetime.datetime.now() + + process_begin = datetime.datetime.now() + checkpoint = torch.load(tmp_path, map_location="cpu") + meta = checkpoint["meta"] + _device = _select_device() + model = TinyDLRM( + meta["num_users"], meta["num_items"], meta["num_categories"], meta["embed_dim"] + ) + model.load_state_dict(checkpoint["state_dict"]) + model.to(_device) + model.eval() + _model = model + os.remove(tmp_path) + process_end = datetime.datetime.now() + + download_time = (download_end - download_begin) / datetime.timedelta(microseconds=1) + process_time = (process_end - process_begin) / datetime.timedelta(microseconds=1) + return download_time, process_time + + +def _prepare_batch(requests): + user_ids = torch.tensor([req["user_id"] for req in requests], dtype=torch.long, device=_device) + item_ids = torch.tensor([req["item_id"] for req in requests], dtype=torch.long, device=_device) + category_ids = torch.tensor( + [req["category_id"] for req in requests], dtype=torch.long, device=_device + ) + dense = torch.tensor( + [req.get("dense", [0.0, 0.0]) for req in requests], dtype=torch.float32, device=_device + ) + return user_ids, item_ids, category_ids, dense + + +def handler(event): + bucket = event.get("bucket", {}).get("bucket") + model_prefix = event.get("bucket", {}).get("model") + requests_prefix = event.get("bucket", {}).get("requests") + requests_key = event.get("object", {}).get("requests") + + download_begin = datetime.datetime.now() + req_path = os.path.join("/tmp", f"{uuid.uuid4()}-{os.path.basename(requests_key)}") + client.download(bucket, os.path.join(requests_prefix, requests_key), req_path) + download_end = datetime.datetime.now() + + model_download_time, model_process_time = _load_model(bucket, model_prefix) + + with open(req_path, "r") as f: + payloads = [json.loads(line) for line in f if line.strip()] + os.remove(req_path) + + inference_begin = datetime.datetime.now() + user_ids, item_ids, category_ids, dense = _prepare_batch(payloads) + + with torch.no_grad(): + scores = _model(user_ids, item_ids, category_ids, dense).squeeze(-1).tolist() + inference_end = datetime.datetime.now() + + predictions = [] + for req, score in zip(payloads, scores): + predictions.append( + { + "user_id": req["user_id"], + "item_id": req["item_id"], + "category_id": req["category_id"], + "score": score, + "device": str(_device), + } + ) + + download_time = (download_end - download_begin) / datetime.timedelta(microseconds=1) + compute_time = (inference_end - inference_begin) / datetime.timedelta(microseconds=1) + + return { + "result": {"predictions": predictions}, + "measurement": { + "download_time": download_time + model_download_time, + "compute_time": compute_time + model_process_time, + "model_time": model_process_time, + "model_download_time": model_download_time, + }, + } diff --git a/benchmarks/400.inference/413.recommendation/python/init.sh b/benchmarks/400.inference/413.recommendation/python/init.sh new file mode 100644 index 000000000..f42329404 --- /dev/null +++ b/benchmarks/400.inference/413.recommendation/python/init.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +# No additional initialization required for GPU recommendation benchmark. diff --git a/benchmarks/400.inference/413.recommendation/python/package.sh b/benchmarks/400.inference/413.recommendation/python/package.sh new file mode 100644 index 000000000..64e9deacb --- /dev/null +++ b/benchmarks/400.inference/413.recommendation/python/package.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +PACKAGE_DIR=$1 +echo "DLRM GPU package size $(du -sh $1 | cut -f1)" diff --git a/benchmarks/400.inference/413.recommendation/python/requirements.txt b/benchmarks/400.inference/413.recommendation/python/requirements.txt new file mode 100644 index 000000000..c5ddafe5b --- /dev/null +++ b/benchmarks/400.inference/413.recommendation/python/requirements.txt @@ -0,0 +1 @@ +torch==2.2.2 diff --git a/benchmarks/400.inference/413.recommendation/python/requirements.txt.3.10 b/benchmarks/400.inference/413.recommendation/python/requirements.txt.3.10 new file mode 100644 index 000000000..c5ddafe5b --- /dev/null +++ b/benchmarks/400.inference/413.recommendation/python/requirements.txt.3.10 @@ -0,0 +1 @@ +torch==2.2.2 diff --git a/benchmarks/400.inference/413.recommendation/python/requirements.txt.3.11 b/benchmarks/400.inference/413.recommendation/python/requirements.txt.3.11 new file mode 100644 index 000000000..c5ddafe5b --- /dev/null +++ b/benchmarks/400.inference/413.recommendation/python/requirements.txt.3.11 @@ -0,0 +1 @@ +torch==2.2.2 diff --git a/benchmarks/400.inference/413.recommendation/python/requirements.txt.3.8 b/benchmarks/400.inference/413.recommendation/python/requirements.txt.3.8 new file mode 100644 index 000000000..c5ddafe5b --- /dev/null +++ b/benchmarks/400.inference/413.recommendation/python/requirements.txt.3.8 @@ -0,0 +1 @@ +torch==2.2.2 diff --git a/benchmarks/400.inference/413.recommendation/python/requirements.txt.3.9 b/benchmarks/400.inference/413.recommendation/python/requirements.txt.3.9 new file mode 100644 index 000000000..c5ddafe5b --- /dev/null +++ b/benchmarks/400.inference/413.recommendation/python/requirements.txt.3.9 @@ -0,0 +1 @@ +torch==2.2.2 diff --git a/docs/benchmarks.md b/docs/benchmarks.md index 73056c86c..6977672d6 100644 --- a/docs/benchmarks.md +++ b/docs/benchmarks.md @@ -11,6 +11,7 @@ | Utilities | 311.compression | Python | x64, arm64 | Create a .zip file for a group of files in storage and return to user to download. | | Inference | 411.image-recognition | Python | x64 | Image recognition with ResNet and pytorch. | | Inference | 412.language-bert | Python | x64 | Sentence classification with a compact BERT model served via ONNX Runtime. | +| Inference | 413.recommendation | Python | x64 | GPU DLRM-inspired recommender scoring implemented in PyTorch. | | Scientific | 501.graph-pagerank | Python | x64, arm64 | PageRank implementation with igraph. | | Scientific | 502.graph-mst | Python | x64, arm64 | Minimum spanning tree (MST) implementation with igraph. | | Scientific | 503.graph-bfs | Python | x64, arm64 | Breadth-first search (BFS) implementation with igraph. | @@ -75,6 +76,10 @@ The benchmark is inspired by MLPerf and implements image recognition with Resnet This benchmark runs sequence classification with a compact BERT model exported to ONNX. The function downloads the model archive and text samples from storage, tokenizes the sentences, executes the ONNX Runtime session, and returns the predicted labels together with confidences. +### Recommendation + +Inspired by MLPerf’s DLRM v2, this benchmark ships a tiny PyTorch DLRM model that optionally runs on CUDA when available. The function downloads the model and request batch, moves the network to GPU if possible, performs batched inference, and reports recommendation scores alongside timing measurements. + ## Scientific ### Graph PageRank, BFS, MST diff --git a/sebs/regression.py b/sebs/regression.py index e0eaf7f4f..01dc8d071 100644 --- a/sebs/regression.py +++ b/sebs/regression.py @@ -22,6 +22,7 @@ "311.compression", "411.image-recognition", "412.language-bert", + "413.recommendation", "501.graph-pagerank", "502.graph-mst", "503.graph-bfs", From 4fca4aa2526a7ae9402a4b52b242d169a815c0a4 Mon Sep 17 00:00:00 2001 From: McLavish Date: Thu, 13 Nov 2025 15:39:34 +0100 Subject: [PATCH 30/58] changed data submodule to use ssh and not https --- .gitmodules | 2 +- benchmarks-data | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index c33a17880..0969aa83a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,4 +3,4 @@ url = https://github.com/mcopik/pypapi.git [submodule "benchmarks-data"] path = benchmarks-data - url = https://github.com/McLavish/serverless-benchmarks-data-dphpc.git + url = git@github.com:McLavish/serverless-benchmarks-data-dphpc.git diff --git a/benchmarks-data b/benchmarks-data index 25c2bb40b..fbb693d2e 160000 --- a/benchmarks-data +++ b/benchmarks-data @@ -1 +1 @@ -Subproject commit 25c2bb40b8bde342395534b534ba62f8f0ff3549 +Subproject commit fbb693d2efc4538d4c3514c0e3567a516a53dd8c From 26dfcf4fc8bcc81e953ab6b3af1c41183f263631 Mon Sep 17 00:00:00 2001 From: jiahao luan Date: Sat, 15 Nov 2025 06:36:04 +0100 Subject: [PATCH 31/58] add channel_flow, compute, fft, and resnet of jax_npbench --- .pre-commit-config.yaml | 2 +- .../5xx.channel_flow_jax_npbench/config.json | 6 + .../5xx.channel_flow_jax_npbench/input.py | 17 ++ .../python/function.py | 279 ++++++++++++++++++ .../python/requirements.txt | 1 + .../5xx.compute_jax_npbench/config.json | 6 + .../5xx.compute_jax_npbench/input.py | 17 ++ .../python/function.py | 62 ++++ .../python/requirements.txt | 1 + .../config.json | 6 + .../input.py | 17 ++ .../python/function.py | 123 ++++++++ .../python/requirements.txt | 1 + 13 files changed, 537 insertions(+), 1 deletion(-) create mode 100644 benchmarks/500.scientific/5xx.channel_flow_jax_npbench/config.json create mode 100644 benchmarks/500.scientific/5xx.channel_flow_jax_npbench/input.py create mode 100644 benchmarks/500.scientific/5xx.channel_flow_jax_npbench/python/function.py create mode 100644 benchmarks/500.scientific/5xx.channel_flow_jax_npbench/python/requirements.txt create mode 100644 benchmarks/500.scientific/5xx.compute_jax_npbench/config.json create mode 100644 benchmarks/500.scientific/5xx.compute_jax_npbench/input.py create mode 100644 benchmarks/500.scientific/5xx.compute_jax_npbench/python/function.py create mode 100644 benchmarks/500.scientific/5xx.compute_jax_npbench/python/requirements.txt create mode 100644 benchmarks/500.scientific/5xx.deep_learning_resnet_jax_npbench/config.json create mode 100644 benchmarks/500.scientific/5xx.deep_learning_resnet_jax_npbench/input.py create mode 100644 benchmarks/500.scientific/5xx.deep_learning_resnet_jax_npbench/python/function.py create mode 100644 benchmarks/500.scientific/5xx.deep_learning_resnet_jax_npbench/python/requirements.txt diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 58f8adb8d..62798ad03 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: language: python additional_dependencies: ["black==22.8.0"] entry: black - args: ["--config=.black.toml", "--check", "--diff"] + args: ["--config=.black.toml"] types: [python] files: ^(sebs/|benchmarks/) # - repo: local diff --git a/benchmarks/500.scientific/5xx.channel_flow_jax_npbench/config.json b/benchmarks/500.scientific/5xx.channel_flow_jax_npbench/config.json new file mode 100644 index 000000000..ff297ac5b --- /dev/null +++ b/benchmarks/500.scientific/5xx.channel_flow_jax_npbench/config.json @@ -0,0 +1,6 @@ +{ + "timeout": 60, + "memory": 2048, + "languages": ["python"], + "modules": ["storage"] +} diff --git a/benchmarks/500.scientific/5xx.channel_flow_jax_npbench/input.py b/benchmarks/500.scientific/5xx.channel_flow_jax_npbench/input.py new file mode 100644 index 000000000..bb53694c9 --- /dev/null +++ b/benchmarks/500.scientific/5xx.channel_flow_jax_npbench/input.py @@ -0,0 +1,17 @@ +size_generators = { + "test": {"ny": 61, "nx": 61, "nit": 5, "rho": 1.0, "nu": 0.1, "F": 1.0}, + "small": {"ny": 121, "nx": 121, "nit": 10, "rho": 1.0, "nu": 0.1, "F": 1.0}, + "large": {"ny": 201, "nx": 201, "nit": 20, "rho": 1.0, "nu": 0.1, "F": 1.0}, +} + + +def generate_input( + data_dir, + size, + benchmarks_bucket, + input_paths, + output_paths, + upload_func, + nosql_func, +): + return {"size": size_generators[size]} diff --git a/benchmarks/500.scientific/5xx.channel_flow_jax_npbench/python/function.py b/benchmarks/500.scientific/5xx.channel_flow_jax_npbench/python/function.py new file mode 100644 index 000000000..5788880b2 --- /dev/null +++ b/benchmarks/500.scientific/5xx.channel_flow_jax_npbench/python/function.py @@ -0,0 +1,279 @@ +# Barba, Lorena A., and Forsyth, Gilbert F. (2018). +# CFD Python: the 12 steps to Navier-Stokes equations. +# Journal of Open Source Education, 1(9), 21, +# https://doi.org/10.21105/jose.00021 +# TODO: License +# (c) 2017 Lorena A. Barba, Gilbert F. Forsyth. +# All content is under Creative Commons Attribution CC-BY 4.0, +# and all code is under BSD-3 clause (previously under MIT, and changed on March 8, 2018). + +import datetime + +import jax.numpy as jnp +import jax +from jax import lax +from functools import partial + + +@partial(jax.jit, static_argnums=(0,)) +def build_up_b(rho, dt, dx, dy, u, v): + b = jnp.zeros_like(u) + b = b.at[1:-1, 1:-1].set( + ( + rho + * ( + 1 + / dt + * ( + (u[1:-1, 2:] - u[1:-1, 0:-2]) / (2 * dx) + + (v[2:, 1:-1] - v[0:-2, 1:-1]) / (2 * dy) + ) + - ((u[1:-1, 2:] - u[1:-1, 0:-2]) / (2 * dx)) ** 2 + - 2 + * ( + (u[2:, 1:-1] - u[0:-2, 1:-1]) + / (2 * dy) + * (v[1:-1, 2:] - v[1:-1, 0:-2]) + / (2 * dx) + ) + - ((v[2:, 1:-1] - v[0:-2, 1:-1]) / (2 * dy)) ** 2 + ) + ) + ) + + # Periodic BC Pressure @ x = 2 + b = b.at[1:-1, -1].set( + ( + rho + * ( + 1 + / dt + * ((u[1:-1, 0] - u[1:-1, -2]) / (2 * dx) + (v[2:, -1] - v[0:-2, -1]) / (2 * dy)) + - ((u[1:-1, 0] - u[1:-1, -2]) / (2 * dx)) ** 2 + - 2 * ((u[2:, -1] - u[0:-2, -1]) / (2 * dy) * (v[1:-1, 0] - v[1:-1, -2]) / (2 * dx)) + - ((v[2:, -1] - v[0:-2, -1]) / (2 * dy)) ** 2 + ) + ) + ) + + # Periodic BC Pressure @ x = 0 + b = b.at[1:-1, 0].set( + ( + rho + * ( + 1 + / dt + * ((u[1:-1, 1] - u[1:-1, -1]) / (2 * dx) + (v[2:, 0] - v[0:-2, 0]) / (2 * dy)) + - ((u[1:-1, 1] - u[1:-1, -1]) / (2 * dx)) ** 2 + - 2 * ((u[2:, 0] - u[0:-2, 0]) / (2 * dy) * (v[1:-1, 1] - v[1:-1, -1]) / (2 * dx)) + - ((v[2:, 0] - v[0:-2, 0]) / (2 * dy)) ** 2 + ) + ) + ) + + return b + + +@partial(jax.jit, static_argnums=(0,)) +def pressure_poisson_periodic(nit, p, dx, dy, b): + def body_func(p, q): + pn = p.copy() + p = p.at[1:-1, 1:-1].set( + ((pn[1:-1, 2:] + pn[1:-1, 0:-2]) * dy**2 + (pn[2:, 1:-1] + pn[0:-2, 1:-1]) * dx**2) + / (2 * (dx**2 + dy**2)) + - dx**2 * dy**2 / (2 * (dx**2 + dy**2)) * b[1:-1, 1:-1] + ) + + # Periodic BC Pressure @ x = 2 + p = p.at[1:-1, -1].set( + ((pn[1:-1, 0] + pn[1:-1, -2]) * dy**2 + (pn[2:, -1] + pn[0:-2, -1]) * dx**2) + / (2 * (dx**2 + dy**2)) + - dx**2 * dy**2 / (2 * (dx**2 + dy**2)) * b[1:-1, -1] + ) + + # Periodic BC Pressure @ x = 0 + p = p.at[1:-1, 0].set( + ( + ((pn[1:-1, 1] + pn[1:-1, -1]) * dy**2 + (pn[2:, 0] + pn[0:-2, 0]) * dx**2) + / (2 * (dx**2 + dy**2)) + - dx**2 * dy**2 / (2 * (dx**2 + dy**2)) * b[1:-1, 0] + ) + ) + + # Wall boundary conditions, pressure + p = p.at[-1, :].set(p[-2, :]) # dp/dy = 0 at y = 2 + p = p.at[0, :].set(p[1, :]) # dp/dy = 0 at y = 0 + + return p, None + + p, _ = lax.scan(body_func, p, jnp.arange(nit)) + + +@partial(jax.jit, static_argnums=(0, 7, 8, 9)) +def channel_flow(nit, u, v, dt, dx, dy, p, rho, nu, F): + udiff = 1 + stepcount = 0 + + array_vals = (udiff, stepcount, u, v, p) + + def conf_func(array_vals): + udiff, _, _, _, _ = array_vals + return udiff > 0.001 + + def body_func(array_vals): + _, stepcount, u, v, p = array_vals + + un = u.copy() + vn = v.copy() + + b = build_up_b(rho, dt, dx, dy, u, v) + pressure_poisson_periodic(nit, p, dx, dy, b) + + u = u.at[1:-1, 1:-1].set( + un[1:-1, 1:-1] + - un[1:-1, 1:-1] * dt / dx * (un[1:-1, 1:-1] - un[1:-1, 0:-2]) + - vn[1:-1, 1:-1] * dt / dy * (un[1:-1, 1:-1] - un[0:-2, 1:-1]) + - dt / (2 * rho * dx) * (p[1:-1, 2:] - p[1:-1, 0:-2]) + + nu + * ( + dt / dx**2 * (un[1:-1, 2:] - 2 * un[1:-1, 1:-1] + un[1:-1, 0:-2]) + + dt / dy**2 * (un[2:, 1:-1] - 2 * un[1:-1, 1:-1] + un[0:-2, 1:-1]) + ) + + F * dt + ) + + v = v.at[1:-1, 1:-1].set( + vn[1:-1, 1:-1] + - un[1:-1, 1:-1] * dt / dx * (vn[1:-1, 1:-1] - vn[1:-1, 0:-2]) + - vn[1:-1, 1:-1] * dt / dy * (vn[1:-1, 1:-1] - vn[0:-2, 1:-1]) + - dt / (2 * rho * dy) * (p[2:, 1:-1] - p[0:-2, 1:-1]) + + nu + * ( + dt / dx**2 * (vn[1:-1, 2:] - 2 * vn[1:-1, 1:-1] + vn[1:-1, 0:-2]) + + dt / dy**2 * (vn[2:, 1:-1] - 2 * vn[1:-1, 1:-1] + vn[0:-2, 1:-1]) + ) + ) + + # Periodic BC u @ x = 2 + u = u.at[1:-1, -1].set( + un[1:-1, -1] + - un[1:-1, -1] * dt / dx * (un[1:-1, -1] - un[1:-1, -2]) + - vn[1:-1, -1] * dt / dy * (un[1:-1, -1] - un[0:-2, -1]) + - dt / (2 * rho * dx) * (p[1:-1, 0] - p[1:-1, -2]) + + nu + * ( + dt / dx**2 * (un[1:-1, 0] - 2 * un[1:-1, -1] + un[1:-1, -2]) + + dt / dy**2 * (un[2:, -1] - 2 * un[1:-1, -1] + un[0:-2, -1]) + ) + + F * dt + ) + + # Periodic BC u @ x = 0 + u = u.at[1:-1, 0].set( + un[1:-1, 0] + - un[1:-1, 0] * dt / dx * (un[1:-1, 0] - un[1:-1, -1]) + - vn[1:-1, 0] * dt / dy * (un[1:-1, 0] - un[0:-2, 0]) + - dt / (2 * rho * dx) * (p[1:-1, 1] - p[1:-1, -1]) + + nu + * ( + dt / dx**2 * (un[1:-1, 1] - 2 * un[1:-1, 0] + un[1:-1, -1]) + + dt / dy**2 * (un[2:, 0] - 2 * un[1:-1, 0] + un[0:-2, 0]) + ) + + F * dt + ) + + # Periodic BC v @ x = 2 + v = v.at[1:-1, -1].set( + vn[1:-1, -1] + - un[1:-1, -1] * dt / dx * (vn[1:-1, -1] - vn[1:-1, -2]) + - vn[1:-1, -1] * dt / dy * (vn[1:-1, -1] - vn[0:-2, -1]) + - dt / (2 * rho * dy) * (p[2:, -1] - p[0:-2, -1]) + + nu + * ( + dt / dx**2 * (vn[1:-1, 0] - 2 * vn[1:-1, -1] + vn[1:-1, -2]) + + dt / dy**2 * (vn[2:, -1] - 2 * vn[1:-1, -1] + vn[0:-2, -1]) + ) + ) + + # Periodic BC v @ x = 0 + v = v.at[1:-1, 0].set( + vn[1:-1, 0] + - un[1:-1, 0] * dt / dx * (vn[1:-1, 0] - vn[1:-1, -1]) + - vn[1:-1, 0] * dt / dy * (vn[1:-1, 0] - vn[0:-2, 0]) + - dt / (2 * rho * dy) * (p[2:, 0] - p[0:-2, 0]) + + nu + * ( + dt / dx**2 * (vn[1:-1, 1] - 2 * vn[1:-1, 0] + vn[1:-1, -1]) + + dt / dy**2 * (vn[2:, 0] - 2 * vn[1:-1, 0] + vn[0:-2, 0]) + ) + ) + + # Wall BC: u,v = 0 @ y = 0,2 + u = u.at[0, :].set(0) + u = u.at[-1, :].set(0) + v = v.at[0, :].set(0) + v = v.at[-1, :].set(0) + + udiff = (jnp.sum(u) - jnp.sum(un)) / jnp.sum(u) + stepcount += 1 + + return (udiff, stepcount, u, v, p) + + _, stepcount, _, _, _ = lax.while_loop(conf_func, body_func, array_vals) + + return stepcount + + +def initialize(ny, nx): + u = jnp.zeros((ny, nx), dtype=jnp.float64) + v = jnp.zeros((ny, nx), dtype=jnp.float64) + p = jnp.ones((ny, nx), dtype=jnp.float64) + dx = 2 / (nx - 1) + dy = 2 / (ny - 1) + dt = 0.1 / ((nx - 1) * (ny - 1)) + return u, v, p, dx, dy, dt + + +def handler(event): + + if "size" in event: + size = event["size"] + ny = size["ny"] + nx = size["nx"] + nit = size["nit"] + rho = size["rho"] + nu = size["nu"] + F = size["F"] + + generate_begin = datetime.datetime.now() + + u, v, p, dx, dy, dt = initialize(ny, nx) + + generate_end = datetime.datetime.now() + + process_begin = datetime.datetime.now() + + results = channel_flow(nit, u, v, dt, dx, dy, p, rho, nu, F) + + process_end = datetime.datetime.now() + + # y_re_im = jnp.stack([jnp.real(result), jnp.imag(result)], axis=-1).tolist() + + process_time = (process_end - process_begin) / datetime.timedelta(milliseconds=1) + generate_time = (generate_end - generate_begin) / datetime.timedelta(milliseconds=1) + + try: + results = jax.device_get(results) + except Exception: + pass + + if hasattr(results, "item"): + results = results.item() + elif hasattr(results, "tolist"): + results = results.tolist() + + return { + "size": size, + "result": results, + "measurement": {"compute_time": process_time, "generate_time": generate_time}, + } diff --git a/benchmarks/500.scientific/5xx.channel_flow_jax_npbench/python/requirements.txt b/benchmarks/500.scientific/5xx.channel_flow_jax_npbench/python/requirements.txt new file mode 100644 index 000000000..f31e1afe0 --- /dev/null +++ b/benchmarks/500.scientific/5xx.channel_flow_jax_npbench/python/requirements.txt @@ -0,0 +1 @@ +jax[cuda12] \ No newline at end of file diff --git a/benchmarks/500.scientific/5xx.compute_jax_npbench/config.json b/benchmarks/500.scientific/5xx.compute_jax_npbench/config.json new file mode 100644 index 000000000..ff297ac5b --- /dev/null +++ b/benchmarks/500.scientific/5xx.compute_jax_npbench/config.json @@ -0,0 +1,6 @@ +{ + "timeout": 60, + "memory": 2048, + "languages": ["python"], + "modules": ["storage"] +} diff --git a/benchmarks/500.scientific/5xx.compute_jax_npbench/input.py b/benchmarks/500.scientific/5xx.compute_jax_npbench/input.py new file mode 100644 index 000000000..56f136720 --- /dev/null +++ b/benchmarks/500.scientific/5xx.compute_jax_npbench/input.py @@ -0,0 +1,17 @@ +size_generators = { + "test": {"M": 2000, "N": 2000}, + "small": {"M": 5000, "N": 5000}, + "large": {"M": 16000, "N": 16000}, +} + + +def generate_input( + data_dir, + size, + benchmarks_bucket, + input_paths, + output_paths, + upload_func, + nosql_func, +): + return {"size": size_generators[size]} diff --git a/benchmarks/500.scientific/5xx.compute_jax_npbench/python/function.py b/benchmarks/500.scientific/5xx.compute_jax_npbench/python/function.py new file mode 100644 index 000000000..2e16b320d --- /dev/null +++ b/benchmarks/500.scientific/5xx.compute_jax_npbench/python/function.py @@ -0,0 +1,62 @@ +import datetime + +import jax.numpy as jnp +import jax + + +@jax.jit +def compute(array_1, array_2, a, b, c): + return jnp.clip(array_1, 2, 10) * a + array_2 * b + c + + +def initialize(M, N): + from numpy.random import default_rng + + rng = default_rng(42) + array_1 = rng.uniform(0, 1000, size=(M, N)).astype(jnp.int64) + array_2 = rng.uniform(0, 1000, size=(M, N)).astype(jnp.int64) + a = jnp.int64(4) + b = jnp.int64(3) + c = jnp.int64(9) + return array_1, array_2, a, b, c + + +def handler(event): + + if "size" in event: + size = event["size"] + M = size["M"] + N = size["N"] + + generate_begin = datetime.datetime.now() + + array_1, array_2, a, b, c = initialize(M, N) + + generate_end = datetime.datetime.now() + + process_begin = datetime.datetime.now() + + results = compute(array_1, array_2, a, b, c) + + process_end = datetime.datetime.now() + + # y_re_im = jnp.stack([jnp.real(result), jnp.imag(result)], axis=-1).tolist() + + process_time = (process_end - process_begin) / datetime.timedelta(milliseconds=1) + generate_time = (generate_end - generate_begin) / datetime.timedelta(milliseconds=1) + + try: + results = jax.device_get(results) + except Exception: + pass + + if getattr(results, "ndim", 0) == 0 or getattr(results, "size", 0) == 1: + results = results.item() + else: + results = results.tolist() + + return { + "size": size, + "result": results, + "measurement": {"compute_time": process_time, "generate_time": generate_time}, + } diff --git a/benchmarks/500.scientific/5xx.compute_jax_npbench/python/requirements.txt b/benchmarks/500.scientific/5xx.compute_jax_npbench/python/requirements.txt new file mode 100644 index 000000000..f31e1afe0 --- /dev/null +++ b/benchmarks/500.scientific/5xx.compute_jax_npbench/python/requirements.txt @@ -0,0 +1 @@ +jax[cuda12] \ No newline at end of file diff --git a/benchmarks/500.scientific/5xx.deep_learning_resnet_jax_npbench/config.json b/benchmarks/500.scientific/5xx.deep_learning_resnet_jax_npbench/config.json new file mode 100644 index 000000000..ff297ac5b --- /dev/null +++ b/benchmarks/500.scientific/5xx.deep_learning_resnet_jax_npbench/config.json @@ -0,0 +1,6 @@ +{ + "timeout": 60, + "memory": 2048, + "languages": ["python"], + "modules": ["storage"] +} diff --git a/benchmarks/500.scientific/5xx.deep_learning_resnet_jax_npbench/input.py b/benchmarks/500.scientific/5xx.deep_learning_resnet_jax_npbench/input.py new file mode 100644 index 000000000..937e96e44 --- /dev/null +++ b/benchmarks/500.scientific/5xx.deep_learning_resnet_jax_npbench/input.py @@ -0,0 +1,17 @@ +size_generators = { + "test": {"N": 8, "W": 14, "H": 14, "C1": 32, "C2": 8}, + "small": {"N": 8, "W": 28, "H": 28, "C1": 64, "C2": 16}, + "large": {"N": 8, "W": 56, "H": 56, "C1": 128, "C2": 32}, +} + + +def generate_input( + data_dir, + size, + benchmarks_bucket, + input_paths, + output_paths, + upload_func, + nosql_func, +): + return {"size": size_generators[size]} diff --git a/benchmarks/500.scientific/5xx.deep_learning_resnet_jax_npbench/python/function.py b/benchmarks/500.scientific/5xx.deep_learning_resnet_jax_npbench/python/function.py new file mode 100644 index 000000000..f24b2cc71 --- /dev/null +++ b/benchmarks/500.scientific/5xx.deep_learning_resnet_jax_npbench/python/function.py @@ -0,0 +1,123 @@ +import datetime + +import jax.numpy as jnp +import jax +from jax import lax + + +@jax.jit +def relu(x): + return jnp.maximum(x, 0) + + +# Deep learning convolutional operator (stride = 1) +@jax.jit +def conv2d(input, weights): + K = weights.shape[0] # Assuming square kernel + N = input.shape[0] + H_out = input.shape[1] - K + 1 + W_out = input.shape[2] - K + 1 + C_out = weights.shape[3] + output = jnp.empty((N, H_out, W_out, C_out), dtype=jnp.float32) + + def row_update(output, i): + def col_update(output, j): + input_slice = lax.dynamic_slice(input, (0, i, j, 0), (N, K, K, input.shape[-1])) + conv_result = jnp.sum( + input_slice[:, :, :, :, None] * weights[None, :, :, :], axis=(1, 2, 3) + ) + output = lax.dynamic_update_slice(output, conv_result[:, None, None, :], (0, i, j, 0)) + return output, None + + output, _ = lax.scan(col_update, output, jnp.arange(W_out)) + return output, None + + output, _ = lax.scan(row_update, output, jnp.arange(H_out)) + return output + + +# Batch normalization operator, as used in ResNet +@jax.jit +def batchnorm2d(x, eps=1e-5): + mean = jnp.mean(x, axis=0, keepdims=True) + std = jnp.std(x, axis=0, keepdims=True) + return (x - mean) / jnp.sqrt(std + eps) + + +# Bottleneck residual block (after initial convolution, without downsampling) +# in the ResNet-50 CNN (inference) +@jax.jit +def resnet_basicblock(input, conv1, conv2, conv3): + # Pad output of first convolution for second convolution + padded = jnp.zeros( + (input.shape[0], input.shape[1] + 2, input.shape[2] + 2, conv1.shape[3]), + dtype=jnp.float32, + ) + padded = lax.dynamic_update_slice(padded, conv2d(input, conv1), (0, 1, 1, 0)) + x = batchnorm2d(padded) + x = relu(x) + + x = conv2d(x, conv2) + x = batchnorm2d(x) + x = relu(x) + x = conv2d(x, conv3) + x = batchnorm2d(x) + return relu(x + input) + + +def initialize(N, W, H, C1, C2): + from numpy.random import default_rng + + rng = default_rng(42) + + # Input + input = rng.random((N, H, W, C1), dtype=jnp.float32) + # Weights + conv1 = rng.random((1, 1, C1, C2), dtype=jnp.float32) + conv2 = rng.random((3, 3, C2, C2), dtype=jnp.float32) + conv3 = rng.random((1, 1, C2, C1), dtype=jnp.float32) + return (input, conv1, conv2, conv3) + + +def handler(event): + + if "size" in event: + size = event["size"] + N = size["N"] + W = size["W"] + H = size["H"] + C1 = size["C1"] + C2 = size["C2"] + + generate_begin = datetime.datetime.now() + + input, conv1, conv2, conv3 = initialize(N, W, H, C1, C2) + + generate_end = datetime.datetime.now() + + process_begin = datetime.datetime.now() + + results = resnet_basicblock(input, conv1, conv2, conv3) + + process_end = datetime.datetime.now() + + # y_re_im = jnp.stack([jnp.real(result), jnp.imag(result)], axis=-1).tolist() + + process_time = (process_end - process_begin) / datetime.timedelta(milliseconds=1) + generate_time = (generate_end - generate_begin) / datetime.timedelta(milliseconds=1) + + try: + results = jax.device_get(results) + except Exception: + pass + + if getattr(results, "ndim", 0) == 0 or getattr(results, "size", 0) == 1: + results = results.item() + else: + results = results.tolist() + + return { + "size": size, + "result": results, + "measurement": {"compute_time": process_time, "generate_time": generate_time}, + } diff --git a/benchmarks/500.scientific/5xx.deep_learning_resnet_jax_npbench/python/requirements.txt b/benchmarks/500.scientific/5xx.deep_learning_resnet_jax_npbench/python/requirements.txt new file mode 100644 index 000000000..f31e1afe0 --- /dev/null +++ b/benchmarks/500.scientific/5xx.deep_learning_resnet_jax_npbench/python/requirements.txt @@ -0,0 +1 @@ +jax[cuda12] \ No newline at end of file From fad77da51efa2090e38f0a46a06917060fc5e85c Mon Sep 17 00:00:00 2001 From: jiahao luan Date: Sat, 15 Nov 2025 06:42:12 +0100 Subject: [PATCH 32/58] reset the config --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 62798ad03..58f8adb8d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: language: python additional_dependencies: ["black==22.8.0"] entry: black - args: ["--config=.black.toml"] + args: ["--config=.black.toml", "--check", "--diff"] types: [python] files: ^(sebs/|benchmarks/) # - repo: local From 7e0d13f6bf987914fae423d05d8d8171b8ddd3a2 Mon Sep 17 00:00:00 2001 From: xipang Date: Sun, 16 Nov 2025 02:02:21 +0100 Subject: [PATCH 33/58] microbenchmark example --- .../050.matmul/config.json | 6 ++ .../000.microbenchmarks/050.matmul/input.py | 8 +++ .../050.matmul/python/function.py | 64 +++++++++++++++++++ .../050.matmul/python/requirements.txt | 1 + .../050.matmul/python/requirements.txt.3.10 | 0 .../050.matmul/python/requirements.txt.3.11 | 0 .../050.matmul/python/requirements.txt.3.12 | 0 .../050.matmul/python/requirements.txt.3.7 | 0 .../050.matmul/python/requirements.txt.3.8 | 0 .../050.matmul/python/requirements.txt.3.9 | 0 .../python/requirements.txt.arm.3.8 | 0 .../python/requirements.txt.arm.3.9 | 0 12 files changed, 79 insertions(+) create mode 100644 benchmarks/000.microbenchmarks/050.matmul/config.json create mode 100644 benchmarks/000.microbenchmarks/050.matmul/input.py create mode 100755 benchmarks/000.microbenchmarks/050.matmul/python/function.py create mode 100755 benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt create mode 100644 benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.10 create mode 100644 benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.11 create mode 100644 benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.12 create mode 100755 benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.7 create mode 100755 benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.8 create mode 100755 benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.9 create mode 100644 benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.arm.3.8 create mode 100644 benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.arm.3.9 diff --git a/benchmarks/000.microbenchmarks/050.matmul/config.json b/benchmarks/000.microbenchmarks/050.matmul/config.json new file mode 100644 index 000000000..e80fb4351 --- /dev/null +++ b/benchmarks/000.microbenchmarks/050.matmul/config.json @@ -0,0 +1,6 @@ +{ + "timeout": 120, + "memory": 512, + "languages": ["python"], + "modules": [] +} diff --git a/benchmarks/000.microbenchmarks/050.matmul/input.py b/benchmarks/000.microbenchmarks/050.matmul/input.py new file mode 100644 index 000000000..c1597dca2 --- /dev/null +++ b/benchmarks/000.microbenchmarks/050.matmul/input.py @@ -0,0 +1,8 @@ +size_generators = {"test": 10, "small": 1000, "large": 100000} +reps_generators = {"test": 10, "small": 100, "large": 1000} + + +def generate_input( + data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func +): + return {"size": size_generators[size], "seed": 42, "reps": reps_generators[size]} diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/function.py b/benchmarks/000.microbenchmarks/050.matmul/python/function.py new file mode 100755 index 000000000..f7a9c528e --- /dev/null +++ b/benchmarks/000.microbenchmarks/050.matmul/python/function.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +import sys, json, math, torch +import datetime + + +def initialize_torch(NI, NJ, NK, dtype=torch.float32, device="cuda"): + alpha = torch.tensor(1.5, dtype=dtype, device=device) + beta = torch.tensor(1.2, dtype=dtype, device=device) + i = torch.arange(NI, device=device) + j = torch.arange(NJ, device=device) + k = torch.arange(NK, device=device) + C = ((i[:, None] * j[None, :] + 1) % NI).to(dtype) / NI + A = ((i[:, None] * (k[None, :] + 1)) % NK).to(dtype) / NK + B = ((k[:, None] * (j[None, :] + 2)) % NJ).to(dtype) / NJ + return alpha, beta, C, A, B + + +def kernel_gemm(alpha, beta, C, A, B, reps): + torch.cuda.synchronize() + _ = alpha * (A @ B) + beta * C # warmup + torch.cuda.synchronize() + start = torch.cuda.Event(enable_timing=True) + end = torch.cuda.Event(enable_timing=True) + start.record() + for _ in range(reps): + C = alpha * (A @ B) + beta * C + end.record() + torch.cuda.synchronize() + return C, float(start.elapsed_time(end)) # ms for all reps + + +def handler(event): + + size = event.get("size") + reps = event.get("reps") + if "seed" in event: + import random + + random.seed(event["seed"]) + + seed = event.get("seed") + seed = int(seed) + + matrix_generating_begin = datetime.datetime.now() + alpha, beta, C, A, B = initialize_torch(size, size, size, dtype=torch.float32, device="cuda") + matrix_generating_end = datetime.datetime.now() + + matmul_begin = datetime.datetime.now() + C_out, gpu_ms = kernel_gemm(alpha, beta, C, A, B, reps=reps) + matmul_end = datetime.datetime.now() + + matrix_generating_time = (matrix_generating_end - matrix_generating_begin) / datetime.timedelta( + microseconds=1 + ) + matmul_time = (matmul_end - matmul_begin) / datetime.timedelta(microseconds=1) + + return { + "result": C_out, + "measurement": { + "generating_time": f"{matrix_generating_time} microseconds", + "compute_time": f"{gpu_ms} milliseconds", + "avg_compute_time": f"{gpu_ms / reps} milliseconds", + }, + } diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt b/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt new file mode 100755 index 000000000..d8d966118 --- /dev/null +++ b/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt @@ -0,0 +1 @@ +torch==2.4.1 diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.10 b/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.10 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.11 b/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.11 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.12 b/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.12 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.7 b/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.7 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.8 b/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.8 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.9 b/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.9 new file mode 100755 index 000000000..e69de29bb diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.arm.3.8 b/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.arm.3.8 new file mode 100644 index 000000000..e69de29bb diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.arm.3.9 b/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.arm.3.9 new file mode 100644 index 000000000..e69de29bb From 942f5a1f4e94e9f70d2e078fded39ebd622ed2d9 Mon Sep 17 00:00:00 2001 From: Russellpang <127130747+Russellpang@users.noreply.github.com> Date: Sun, 16 Nov 2025 02:13:21 +0100 Subject: [PATCH 34/58] Remove SSH public key from eval command --- "eval \"$(ssh-agent -s)\".pub" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/eval \"$(ssh-agent -s)\".pub" "b/eval \"$(ssh-agent -s)\".pub" index c616a46e0..8b1378917 100644 --- "a/eval \"$(ssh-agent -s)\".pub" +++ "b/eval \"$(ssh-agent -s)\".pub" @@ -1 +1 @@ -ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHWa1ZYvhuZCapEy9tWqPPdlQpfs15h8zMDtZ/7fUOq0 russellpang0503@gmail.com + From 6bc1dd7deb3a1abcf7efbcb48aba8277d20e0a1c Mon Sep 17 00:00:00 2001 From: Russellpang <127130747+Russellpang@users.noreply.github.com> Date: Sun, 16 Nov 2025 02:15:27 +0100 Subject: [PATCH 35/58] Remove local_deployment.json configuration --- config/local_deployment.json | 126 +---------------------------------- 1 file changed, 1 insertion(+), 125 deletions(-) diff --git a/config/local_deployment.json b/config/local_deployment.json index 773b43943..8b1378917 100644 --- a/config/local_deployment.json +++ b/config/local_deployment.json @@ -1,125 +1 @@ -{ - "experiments": { - "deployment": "aws", - "update_code": false, - "update_storage": false, - "download_results": false, - "architecture": "arm64", - "container_deployment": true, - "runtime": { - "language": "python", - "version": "3.8" - }, - "type": "invocation-overhead", - "perf-cost": { - "benchmark": "110.dynamic-html", - "experiments": [ - "cold", - "warm", - "burst", - "sequential" - ], - "input-size": "test", - "repetitions": 50, - "concurrent-invocations": 50, - "memory-sizes": [ - 128, - 256 - ] - }, - "network-ping-pong": { - "invocations": 50, - "repetitions": 1000, - "threads": 1 - }, - "invocation-overhead": { - "repetitions": 5, - "N": 20, - "type": "payload", - "payload_begin": 1024, - "payload_end": 6251000, - "payload_points": 20, - "code_begin": 1048576, - "code_end": 261619712, - "code_points": 20 - }, - "eviction-model": { - "invocations": 1, - "function_copy_idx": 0, - "repetitions": 5, - "sleep": 1 - } - }, - "deployment": { - "name": "aws", - "aws": { - "region": "us-east-1", - "lambda-role": "" - }, - "azure": { - "region": "westeurope" - }, - "gcp": { - "region": "europe-west1", - "project_name": "", - "credentials": "" - }, - "local": { - "storage": { - "object": { - "type": "minio", - "minio": { - "address": "192.168.1.101:9011", - "mapped_port": 9011, - "access_key": "-5X8s-Wf3pQfjnc7kMAlr9HYX96jIMx3P7GSd55IBAY", - "secret_key": "c9e3b900a8d363f9907af7057fb5a8e35cb14ad24e9e474e75b8139323717fdc", - "instance_id": "26785ccd17e17e72255c255d00756a9eaa14b1aeb60a52527b97cfb33eece9e5", - "output_buckets": [], - "input_buckets": [], - "version": "RELEASE.2024-07-16T23-46-41Z", - "data_volume": "minio-volume", - "type": "minio" - } - }, - "nosql": { - "type": "scylladb", - "scylladb": { - "address": "192.168.1.101:9012", - "mapped_port": 9012, - "alternator_port": 8000, - "access_key": "None", - "secret_key": "None", - "instance_id": "28fb7af28043b633b33b4b5999b48c14767f717ed76a73515ff8c68f253baeb1", - "region": "None", - "cpus": 1, - "memory": "750", - "version": "6.0", - "data_volume": "scylladb-volume" - } - } - } - }, - "openwhisk": { - "shutdownStorage": false, - "removeCluster": false, - "wskBypassSecurity": "true", - "wskExec": "wsk", - "experimentalManifest": false, - "docker_registry": { - "registry": "", - "username": "", - "password": "" - }, - "storage": { - "address": "", - "mapped_port": -1, - "access_key": "", - "secret_key": "", - "instance_id": "", - "input_buckets": [], - "output_buckets": [], - "type": "minio" - } - } - } -} + From 460ea1ff405458ad129a7861946d02a5c2676cea Mon Sep 17 00:00:00 2001 From: Russellpang <127130747+Russellpang@users.noreply.github.com> Date: Sun, 16 Nov 2025 02:16:30 +0100 Subject: [PATCH 36/58] Delete out_storage.json configuration file Removed configuration details for MinIO and ScyllaDB. --- out_storage.json | 34 +--------------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/out_storage.json b/out_storage.json index 6c4a8e799..8b1378917 100644 --- a/out_storage.json +++ b/out_storage.json @@ -1,33 +1 @@ -{ - "object": { - "type": "minio", - "minio": { - "address": "172.17.0.2:9000", - "mapped_port": 9011, - "access_key": "-5X8s-Wf3pQfjnc7kMAlr9HYX96jIMx3P7GSd55IBAY", - "secret_key": "c9e3b900a8d363f9907af7057fb5a8e35cb14ad24e9e474e75b8139323717fdc", - "instance_id": "26785ccd17e17e72255c255d00756a9eaa14b1aeb60a52527b97cfb33eece9e5", - "output_buckets": [], - "input_buckets": [], - "version": "RELEASE.2024-07-16T23-46-41Z", - "data_volume": "minio-volume", - "type": "minio" - } - }, - "nosql": { - "type": "scylladb", - "scylladb": { - "address": "172.17.0.3:8000", - "mapped_port": 9012, - "alternator_port": 8000, - "access_key": "None", - "secret_key": "None", - "instance_id": "28fb7af28043b633b33b4b5999b48c14767f717ed76a73515ff8c68f253baeb1", - "region": "None", - "cpus": 1, - "memory": "750", - "version": "6.0", - "data_volume": "scylladb-volume" - } - } -} \ No newline at end of file + From de41ab63b4d54ae5a718b12b8a220d7a8691a00d Mon Sep 17 00:00:00 2001 From: Russellpang <127130747+Russellpang@users.noreply.github.com> Date: Sun, 16 Nov 2025 02:18:14 +0100 Subject: [PATCH 37/58] Remove SSH private key from eval command Removed sensitive SSH private key from eval command. --- "eval \"$(ssh-agent -s)\"" | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git "a/eval \"$(ssh-agent -s)\"" "b/eval \"$(ssh-agent -s)\"" index 892647ba0..8b1378917 100644 --- "a/eval \"$(ssh-agent -s)\"" +++ "b/eval \"$(ssh-agent -s)\"" @@ -1,7 +1 @@ ------BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW -QyNTUxOQAAACB1mtWWL4bmQmqRMvbVqjz3ZUKX7NeYfMzA7Wf+31DqtAAAAKA7gCOkO4Aj -pAAAAAtzc2gtZWQyNTUxOQAAACB1mtWWL4bmQmqRMvbVqjz3ZUKX7NeYfMzA7Wf+31DqtA -AAAEBZdoiktY5L2ikHyUK4JfoeaTTX1KBHCtB+muQV2Y68SXWa1ZYvhuZCapEy9tWqPPdl -Qpfs15h8zMDtZ/7fUOq0AAAAGXJ1c3NlbGxwYW5nMDUwM0BnbWFpbC5jb20BAgME ------END OPENSSH PRIVATE KEY----- + From ded520f6177aece8481e547af5e45e5bf955c974 Mon Sep 17 00:00:00 2001 From: xipang Date: Sun, 16 Nov 2025 19:47:11 +0100 Subject: [PATCH 38/58] remove garbage --- "eval \"$(ssh-agent -s)\"" | 1 - "eval \"$(ssh-agent -s)\".pub" | 1 - out_benchmark.json | 40 ----------------------------- out_benchmark_bert.json | 47 ---------------------------------- out_storage.json | 1 - 5 files changed, 90 deletions(-) delete mode 100644 "eval \"$(ssh-agent -s)\"" delete mode 100644 "eval \"$(ssh-agent -s)\".pub" delete mode 100644 out_benchmark.json delete mode 100644 out_benchmark_bert.json delete mode 100644 out_storage.json diff --git "a/eval \"$(ssh-agent -s)\"" "b/eval \"$(ssh-agent -s)\"" deleted file mode 100644 index 8b1378917..000000000 --- "a/eval \"$(ssh-agent -s)\"" +++ /dev/null @@ -1 +0,0 @@ - diff --git "a/eval \"$(ssh-agent -s)\".pub" "b/eval \"$(ssh-agent -s)\".pub" deleted file mode 100644 index 8b1378917..000000000 --- "a/eval \"$(ssh-agent -s)\".pub" +++ /dev/null @@ -1 +0,0 @@ - diff --git a/out_benchmark.json b/out_benchmark.json deleted file mode 100644 index cf96b5c5d..000000000 --- a/out_benchmark.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "functions": [ - { - "benchmark": "110.dynamic-html", - "config": { - "architecture": "x64", - "memory": 128, - "runtime": { - "language": "python", - "version": "3.8" - }, - "timeout": 10 - }, - "hash": "c9fbe3e5e85e119e20d6a72651ef23b0", - "instance_id": "be83782894ea459ea3328d4d3b4aeb7173acec54f2c1cebb354f97459b318eef", - "name": "sebs-local-f2033fb2-110.dynamic-html-python-3.8", - "port": 9000, - "triggers": [], - "url": "172.17.0.4:9000" - } - ], - "inputs": [ - { - "random_len": 10, - "username": "testname" - } - ], - "storage": { - "access_key": "FC95zkJKAUbfmXU3ci5lc0SFWhDWYrSgx0nRNycthcY", - "address": "172.17.0.2:9000", - "data_volume": "minio-volume", - "input_buckets": [], - "instance_id": "d14d6dc800ce2f976cc19dc4dd85d2010b65709266f5ae0f1a0c157d338134ec", - "mapped_port": 9011, - "output_buckets": [], - "secret_key": "65eb94d63b0191bf765864ffbd4ee58cc1eb852bdc3a5ca463bca2e7c5915aec", - "type": "minio", - "version": "RELEASE.2024-07-16T23-46-41Z" - } -} \ No newline at end of file diff --git a/out_benchmark_bert.json b/out_benchmark_bert.json deleted file mode 100644 index c706062a2..000000000 --- a/out_benchmark_bert.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "functions": [ - { - "benchmark": "413.image-classification", - "config": { - "architecture": "x64", - "memory": 512, - "runtime": { - "language": "python", - "version": "3.8" - }, - "timeout": 60 - }, - "hash": "445383b434f036f9520743532c7bc0b1", - "instance_id": "a59d2b025927d6350363787bfbab3e7d44b90e0575cd72b939dd9cee291dd63c", - "name": "sebs-local-f2033fb2-413.image-classification-python-3.8", - "port": 9000, - "triggers": [], - "url": "172.17.0.4:9000" - } - ], - "inputs": [ - { - "bucket": { - "bucket": "sebs-benchmarks-local-f2033fb2", - "input": "413.image-classification-1-input", - "model": "413.image-classification-0-input" - }, - "object": { - "input": "800px-Porsche_991_silver_IAA.jpg", - "model": "resnet50.tar.gz" - } - } - ], - "storage": { - "access_key": "-5X8s-Wf3pQfjnc7kMAlr9HYX96jIMx3P7GSd55IBAY", - "address": "192.168.1.101:9011", - "data_volume": "minio-volume", - "input_buckets": [], - "instance_id": "26785ccd17e17e72255c255d00756a9eaa14b1aeb60a52527b97cfb33eece9e5", - "mapped_port": 9011, - "output_buckets": [], - "secret_key": "c9e3b900a8d363f9907af7057fb5a8e35cb14ad24e9e474e75b8139323717fdc", - "type": "minio", - "version": "RELEASE.2024-07-16T23-46-41Z" - } -} \ No newline at end of file diff --git a/out_storage.json b/out_storage.json deleted file mode 100644 index 8b1378917..000000000 --- a/out_storage.json +++ /dev/null @@ -1 +0,0 @@ - From 5c85980e1695a1afdd4ce54b9bea223320b9c54d Mon Sep 17 00:00:00 2001 From: Russellpang Date: Mon, 17 Nov 2025 17:18:32 +0100 Subject: [PATCH 39/58] test --- .../400.inference/413.image-classification/python/function.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmarks/400.inference/413.image-classification/python/function.py b/benchmarks/400.inference/413.image-classification/python/function.py index 48e837f70..64795612d 100644 --- a/benchmarks/400.inference/413.image-classification/python/function.py +++ b/benchmarks/400.inference/413.image-classification/python/function.py @@ -159,7 +159,7 @@ def handler(event): download_time = (image_download_end - image_download_begin) / datetime.timedelta(microseconds=1) compute_time = (inference_end - inference_begin) / datetime.timedelta(microseconds=1) - #gpu_time_ms = 0.0 + # gpu_time_ms = 0.0 return { "result": { @@ -173,6 +173,6 @@ def handler(event): "compute_time": compute_time + model_process_time, "model_time": model_process_time, "model_download_time": model_download_time, - #"gpu_time_ms": round(gpu_time_ms, 3), + # "gpu_time_ms": round(gpu_time_ms, 3), }, } From c5782dddcb367178543a8939ae31f1fe6a04c492 Mon Sep 17 00:00:00 2001 From: Russellpang Date: Mon, 17 Nov 2025 17:24:40 +0100 Subject: [PATCH 40/58] test --- .../606.spmv/python/function.py | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/benchmarks/600.linearalgebra/606.spmv/python/function.py b/benchmarks/600.linearalgebra/606.spmv/python/function.py index 16e8744d1..e2c4b0218 100755 --- a/benchmarks/600.linearalgebra/606.spmv/python/function.py +++ b/benchmarks/600.linearalgebra/606.spmv/python/function.py @@ -1,4 +1,4 @@ -import sys, json, math, torch +import torch import datetime @@ -6,19 +6,19 @@ def initialize_torch(N, density=0.01, dtype=torch.float32, device="cuda", seed=4 if seed is not None: torch.manual_seed(seed) torch.cuda.manual_seed_all(seed) - + nnz = int(N * N * density) row_indices = torch.randint(0, N, (nnz,), device=device) col_indices = torch.randint(0, N, (nnz,), device=device) values = torch.randn(nnz, dtype=dtype, device=device) - + indices = torch.stack([row_indices, col_indices]) sparse_matrix = torch.sparse_coo_tensor(indices, values, (N, N), dtype=dtype, device=device) - + sparse_matrix_csr = sparse_matrix.to_sparse_csr() - + x = torch.randn(N, dtype=dtype, device=device) - + return sparse_matrix_csr, x @@ -26,7 +26,7 @@ def kernel_spmv(A, x, reps=100): torch.cuda.synchronize() _ = torch.sparse.mm(A, x.unsqueeze(1)).squeeze() # warmup torch.cuda.synchronize() - + start_evt = torch.cuda.Event(enable_timing=True) end_evt = torch.cuda.Event(enable_timing=True) start_evt.record() @@ -41,26 +41,27 @@ def kernel_spmv(A, x, reps=100): def handler(event): size = event.get("size") density = event.get("density", 0.01) # default 1% density - + if "seed" in event: import random + random.seed(event["seed"]) seed = event.get("seed", 42) seed = int(seed) else: seed = 42 - + gen_begin = datetime.datetime.now() A, x = initialize_torch(size, density=density, dtype=torch.float32, device="cuda", seed=seed) gen_end = datetime.datetime.now() - + comp_begin = datetime.datetime.now() y_out, gpu_ms = kernel_spmv(A, x, reps=100) comp_end = datetime.datetime.now() - + gen_us = (gen_end - gen_begin) / datetime.timedelta(microseconds=1) comp_us = (comp_end - comp_begin) / datetime.timedelta(microseconds=1) - + return { "measurement": { "generating_time": gen_us, From 2b52cede914be87e97f751a74bf193e4f3252bfd Mon Sep 17 00:00:00 2001 From: Russellpang Date: Mon, 17 Nov 2025 17:35:28 +0100 Subject: [PATCH 41/58] test --- .../000.microbenchmarks/050.matmul/python/function.py | 8 ++++---- .../400.inference/413.image-classification/input.py | 2 +- .../600.linearalgebra/601.matmul/python/function.py | 2 +- benchmarks/600.linearalgebra/602.axpy/python/function.py | 3 ++- .../600.linearalgebra/603.jacobi2d/python/function.py | 2 +- .../600.linearalgebra/604.cholesky/python/function.py | 3 ++- benchmarks/600.linearalgebra/605.lu/python/function.py | 3 ++- benchmarks/600.linearalgebra/607.fw/python/function.py | 2 +- 8 files changed, 14 insertions(+), 11 deletions(-) diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/function.py b/benchmarks/000.microbenchmarks/050.matmul/python/function.py index f7a9c528e..cf1f5f1a0 100755 --- a/benchmarks/000.microbenchmarks/050.matmul/python/function.py +++ b/benchmarks/000.microbenchmarks/050.matmul/python/function.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -import sys, json, math, torch +import torch import datetime @@ -45,14 +45,14 @@ def handler(event): alpha, beta, C, A, B = initialize_torch(size, size, size, dtype=torch.float32, device="cuda") matrix_generating_end = datetime.datetime.now() - matmul_begin = datetime.datetime.now() + # matmul_begin = datetime.datetime.now() C_out, gpu_ms = kernel_gemm(alpha, beta, C, A, B, reps=reps) - matmul_end = datetime.datetime.now() + # matmul_end = datetime.datetime.now() matrix_generating_time = (matrix_generating_end - matrix_generating_begin) / datetime.timedelta( microseconds=1 ) - matmul_time = (matmul_end - matmul_begin) / datetime.timedelta(microseconds=1) + # matmul_time = (matmul_end - matmul_begin) / datetime.timedelta(microseconds=1) return { "result": C_out, diff --git a/benchmarks/400.inference/413.image-classification/input.py b/benchmarks/400.inference/413.image-classification/input.py index 6ee2fdd08..99e8bc4b3 100644 --- a/benchmarks/400.inference/413.image-classification/input.py +++ b/benchmarks/400.inference/413.image-classification/input.py @@ -1,4 +1,4 @@ -import glob, os +import os def buckets_count(): diff --git a/benchmarks/600.linearalgebra/601.matmul/python/function.py b/benchmarks/600.linearalgebra/601.matmul/python/function.py index ee1ceaff7..ee88b2e58 100755 --- a/benchmarks/600.linearalgebra/601.matmul/python/function.py +++ b/benchmarks/600.linearalgebra/601.matmul/python/function.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -import sys, json, math, torch +import torch import datetime diff --git a/benchmarks/600.linearalgebra/602.axpy/python/function.py b/benchmarks/600.linearalgebra/602.axpy/python/function.py index 9c31c05bd..79117fa1b 100755 --- a/benchmarks/600.linearalgebra/602.axpy/python/function.py +++ b/benchmarks/600.linearalgebra/602.axpy/python/function.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 -import sys, json, torch, datetime +import torch +import datetime def initialize_torch(N, dtype=torch.float32, device="cuda", seed=42): diff --git a/benchmarks/600.linearalgebra/603.jacobi2d/python/function.py b/benchmarks/600.linearalgebra/603.jacobi2d/python/function.py index b83230f04..ab3771dc7 100755 --- a/benchmarks/600.linearalgebra/603.jacobi2d/python/function.py +++ b/benchmarks/600.linearalgebra/603.jacobi2d/python/function.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -import sys, json, math, torch +import torch import datetime diff --git a/benchmarks/600.linearalgebra/604.cholesky/python/function.py b/benchmarks/600.linearalgebra/604.cholesky/python/function.py index 537015e56..5a7ac77d5 100755 --- a/benchmarks/600.linearalgebra/604.cholesky/python/function.py +++ b/benchmarks/600.linearalgebra/604.cholesky/python/function.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 -import sys, json, torch, datetime +import torch +import datetime def initialize_torch(N, dtype=torch.float32, device="cuda"): diff --git a/benchmarks/600.linearalgebra/605.lu/python/function.py b/benchmarks/600.linearalgebra/605.lu/python/function.py index 492153bb7..fc99a3ab9 100755 --- a/benchmarks/600.linearalgebra/605.lu/python/function.py +++ b/benchmarks/600.linearalgebra/605.lu/python/function.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 -import sys, json, torch, datetime +import torch +import datetime def initialize_torch(N, dtype=torch.float32, device="cuda"): diff --git a/benchmarks/600.linearalgebra/607.fw/python/function.py b/benchmarks/600.linearalgebra/607.fw/python/function.py index 2db5e1f18..bee06dd03 100755 --- a/benchmarks/600.linearalgebra/607.fw/python/function.py +++ b/benchmarks/600.linearalgebra/607.fw/python/function.py @@ -1,4 +1,4 @@ -import sys, json, math, torch +import torch import datetime From 6488d6d8ad9d6a035b3a46ec0f77957e42c1d9ac Mon Sep 17 00:00:00 2001 From: Russellpang Date: Mon, 17 Nov 2025 18:35:59 +0100 Subject: [PATCH 42/58] remove unnecessay files --- config/local_deployment.json | 1 - install.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 config/local_deployment.json diff --git a/config/local_deployment.json b/config/local_deployment.json deleted file mode 100644 index 8b1378917..000000000 --- a/config/local_deployment.json +++ /dev/null @@ -1 +0,0 @@ - diff --git a/install.py b/install.py index 78e98dddd..34040b23b 100755 --- a/install.py +++ b/install.py @@ -104,7 +104,7 @@ def execute(cmd, cwd=None): execute(f"git pull", cwd=data_dir) # clone else: - execute(f"git clone https://github.com/McLavish/serverless-benchmarks-data-dphpc.git {data_dir}") + execute(f"git clone https://github.com/spcl/serverless-benchmarks-data.git {data_dir}") else: raise error From 55c4ac44c1a8d37957bb2e17a3d9aad1f324d339 Mon Sep 17 00:00:00 2001 From: Russellpang Date: Mon, 17 Nov 2025 18:38:34 +0100 Subject: [PATCH 43/58] fuck you --- install.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/install.py b/install.py index 34040b23b..784b0ab28 100755 --- a/install.py +++ b/install.py @@ -104,7 +104,9 @@ def execute(cmd, cwd=None): execute(f"git pull", cwd=data_dir) # clone else: - execute(f"git clone https://github.com/spcl/serverless-benchmarks-data.git {data_dir}") + execute( + f"git clone https://github.com/McLavish/serverless-benchmarks-data-dphpc.git {data_dir}" + ) else: raise error From b97b7a56600fc610abadf6f20eb6a590cb5f7106 Mon Sep 17 00:00:00 2001 From: Russellpang <127130747+Russellpang@users.noreply.github.com> Date: Mon, 17 Nov 2025 18:50:48 +0100 Subject: [PATCH 44/58] Refactor argument parsing for cleaner syntax --- install.py | 40 ++++++++++------------------------------ 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/install.py b/install.py index 784b0ab28..b856e45b7 100755 --- a/install.py +++ b/install.py @@ -5,46 +5,28 @@ import subprocess parser = argparse.ArgumentParser(description="Install SeBS and dependencies.") -parser.add_argument( - "--venv", - metavar="DIR", - type=str, - default="python-venv", - help="destination of local Python virtual environment", -) -parser.add_argument( - "--python-path", - metavar="DIR", - type=str, - default="python3", - help="Path to local Python installation.", -) +parser.add_argument('--venv', metavar='DIR', type=str, default="python-venv", help='destination of local Python virtual environment') +parser.add_argument('--python-path', metavar='DIR', type=str, default="python3", help='Path to local Python installation.') for deployment in ["aws", "azure", "gcp", "openwhisk"]: - parser.add_argument( - f"--{deployment}", action="store_const", const=True, default=True, dest=deployment - ) - parser.add_argument( - f"--no-{deployment}", action="store_const", const=False, default=True, dest=deployment - ) + parser.add_argument(f"--{deployment}", action="store_const", const=True, default=True, dest=deployment) + parser.add_argument(f"--no-{deployment}", action="store_const", const=False, default=True, dest=deployment) for deployment in ["local"]: - parser.add_argument( - f"--{deployment}", action="store_const", default=True, const=True, dest=deployment - ) + parser.add_argument(f"--{deployment}", action="store_const", default=True, const=True, dest=deployment) parser.add_argument(f"--no-{deployment}", action="store_const", const=False, dest=deployment) parser.add_argument("--with-pypapi", action="store_true") args = parser.parse_args() - def execute(cmd, cwd=None): - ret = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, cwd=cwd) + ret = subprocess.run( + cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, cwd=cwd + ) if ret.returncode: raise RuntimeError( "Running {} failed!\n Output: {}".format(cmd, ret.stdout.decode("utf-8")) ) return ret.stdout.decode("utf-8") - -env_dir = args.venv +env_dir=args.venv if not os.path.exists(env_dir): print("Creating Python virtualenv at {}".format(env_dir)) @@ -104,9 +86,7 @@ def execute(cmd, cwd=None): execute(f"git pull", cwd=data_dir) # clone else: - execute( - f"git clone https://github.com/McLavish/serverless-benchmarks-data-dphpc.git {data_dir}" - ) + execute(f"git clone https://github.com/McLavish/serverless-benchmarks-data-dphpc.git {data_dir}") else: raise error From 1998b6b141e578fcc0a3fa42982bb5b94b34f84f Mon Sep 17 00:00:00 2001 From: Russellpang <127130747+Russellpang@users.noreply.github.com> Date: Mon, 17 Nov 2025 19:29:02 +0100 Subject: [PATCH 45/58] Change 'reps' to 'iters' in jacobi2d function --- benchmarks/600.linearalgebra/603.jacobi2d/python/function.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/600.linearalgebra/603.jacobi2d/python/function.py b/benchmarks/600.linearalgebra/603.jacobi2d/python/function.py index ab3771dc7..4dc37e2c6 100755 --- a/benchmarks/600.linearalgebra/603.jacobi2d/python/function.py +++ b/benchmarks/600.linearalgebra/603.jacobi2d/python/function.py @@ -54,7 +54,7 @@ def handler(event): matrix_generating_end = datetime.datetime.now() matmul_begin = datetime.datetime.now() - A_out, B_out, gpu_ms = kernel_jacobi2d(A, B, reps=50) + A_out, B_out, gpu_ms = kernel_jacobi2d(A, B, iters=50) matmul_end = datetime.datetime.now() matrix_generating_time = (matrix_generating_end - matrix_generating_begin) / datetime.timedelta( From 2cbd76855149eac137daf8ea021d494dfd20abc9 Mon Sep 17 00:00:00 2001 From: Russellpang <127130747+Russellpang@users.noreply.github.com> Date: Mon, 17 Nov 2025 19:48:19 +0100 Subject: [PATCH 46/58] Delete benchmarks/000.microbenchmarks/050.matmul directory --- .../050.matmul/config.json | 6 -- .../000.microbenchmarks/050.matmul/input.py | 8 --- .../050.matmul/python/function.py | 64 ------------------- .../050.matmul/python/requirements.txt | 1 - .../050.matmul/python/requirements.txt.3.10 | 0 .../050.matmul/python/requirements.txt.3.11 | 0 .../050.matmul/python/requirements.txt.3.12 | 0 .../050.matmul/python/requirements.txt.3.7 | 0 .../050.matmul/python/requirements.txt.3.8 | 0 .../050.matmul/python/requirements.txt.3.9 | 0 .../python/requirements.txt.arm.3.8 | 0 .../python/requirements.txt.arm.3.9 | 0 12 files changed, 79 deletions(-) delete mode 100644 benchmarks/000.microbenchmarks/050.matmul/config.json delete mode 100644 benchmarks/000.microbenchmarks/050.matmul/input.py delete mode 100755 benchmarks/000.microbenchmarks/050.matmul/python/function.py delete mode 100755 benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt delete mode 100644 benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.10 delete mode 100644 benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.11 delete mode 100644 benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.12 delete mode 100755 benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.7 delete mode 100755 benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.8 delete mode 100755 benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.9 delete mode 100644 benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.arm.3.8 delete mode 100644 benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.arm.3.9 diff --git a/benchmarks/000.microbenchmarks/050.matmul/config.json b/benchmarks/000.microbenchmarks/050.matmul/config.json deleted file mode 100644 index e80fb4351..000000000 --- a/benchmarks/000.microbenchmarks/050.matmul/config.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "timeout": 120, - "memory": 512, - "languages": ["python"], - "modules": [] -} diff --git a/benchmarks/000.microbenchmarks/050.matmul/input.py b/benchmarks/000.microbenchmarks/050.matmul/input.py deleted file mode 100644 index c1597dca2..000000000 --- a/benchmarks/000.microbenchmarks/050.matmul/input.py +++ /dev/null @@ -1,8 +0,0 @@ -size_generators = {"test": 10, "small": 1000, "large": 100000} -reps_generators = {"test": 10, "small": 100, "large": 1000} - - -def generate_input( - data_dir, size, benchmarks_bucket, input_paths, output_paths, upload_func, nosql_func -): - return {"size": size_generators[size], "seed": 42, "reps": reps_generators[size]} diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/function.py b/benchmarks/000.microbenchmarks/050.matmul/python/function.py deleted file mode 100755 index cf1f5f1a0..000000000 --- a/benchmarks/000.microbenchmarks/050.matmul/python/function.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python3 -import torch -import datetime - - -def initialize_torch(NI, NJ, NK, dtype=torch.float32, device="cuda"): - alpha = torch.tensor(1.5, dtype=dtype, device=device) - beta = torch.tensor(1.2, dtype=dtype, device=device) - i = torch.arange(NI, device=device) - j = torch.arange(NJ, device=device) - k = torch.arange(NK, device=device) - C = ((i[:, None] * j[None, :] + 1) % NI).to(dtype) / NI - A = ((i[:, None] * (k[None, :] + 1)) % NK).to(dtype) / NK - B = ((k[:, None] * (j[None, :] + 2)) % NJ).to(dtype) / NJ - return alpha, beta, C, A, B - - -def kernel_gemm(alpha, beta, C, A, B, reps): - torch.cuda.synchronize() - _ = alpha * (A @ B) + beta * C # warmup - torch.cuda.synchronize() - start = torch.cuda.Event(enable_timing=True) - end = torch.cuda.Event(enable_timing=True) - start.record() - for _ in range(reps): - C = alpha * (A @ B) + beta * C - end.record() - torch.cuda.synchronize() - return C, float(start.elapsed_time(end)) # ms for all reps - - -def handler(event): - - size = event.get("size") - reps = event.get("reps") - if "seed" in event: - import random - - random.seed(event["seed"]) - - seed = event.get("seed") - seed = int(seed) - - matrix_generating_begin = datetime.datetime.now() - alpha, beta, C, A, B = initialize_torch(size, size, size, dtype=torch.float32, device="cuda") - matrix_generating_end = datetime.datetime.now() - - # matmul_begin = datetime.datetime.now() - C_out, gpu_ms = kernel_gemm(alpha, beta, C, A, B, reps=reps) - # matmul_end = datetime.datetime.now() - - matrix_generating_time = (matrix_generating_end - matrix_generating_begin) / datetime.timedelta( - microseconds=1 - ) - # matmul_time = (matmul_end - matmul_begin) / datetime.timedelta(microseconds=1) - - return { - "result": C_out, - "measurement": { - "generating_time": f"{matrix_generating_time} microseconds", - "compute_time": f"{gpu_ms} milliseconds", - "avg_compute_time": f"{gpu_ms / reps} milliseconds", - }, - } diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt b/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt deleted file mode 100755 index d8d966118..000000000 --- a/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -torch==2.4.1 diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.10 b/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.10 deleted file mode 100644 index e69de29bb..000000000 diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.11 b/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.11 deleted file mode 100644 index e69de29bb..000000000 diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.12 b/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.12 deleted file mode 100644 index e69de29bb..000000000 diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.7 b/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.7 deleted file mode 100755 index e69de29bb..000000000 diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.8 b/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.8 deleted file mode 100755 index e69de29bb..000000000 diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.9 b/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.3.9 deleted file mode 100755 index e69de29bb..000000000 diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.arm.3.8 b/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.arm.3.8 deleted file mode 100644 index e69de29bb..000000000 diff --git a/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.arm.3.9 b/benchmarks/000.microbenchmarks/050.matmul/python/requirements.txt.arm.3.9 deleted file mode 100644 index e69de29bb..000000000 From efced9c61abbd1ae31dd9443552d258c6fab3a6c Mon Sep 17 00:00:00 2001 From: McLavish Date: Mon, 17 Nov 2025 21:50:59 +0100 Subject: [PATCH 47/58] Revert "changed data submodule to use ssh and not https" This reverts commit 4fca4aa2526a7ae9402a4b52b242d169a815c0a4. --- .gitmodules | 2 +- benchmarks-data | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 0969aa83a..c33a17880 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,4 +3,4 @@ url = https://github.com/mcopik/pypapi.git [submodule "benchmarks-data"] path = benchmarks-data - url = git@github.com:McLavish/serverless-benchmarks-data-dphpc.git + url = https://github.com/McLavish/serverless-benchmarks-data-dphpc.git diff --git a/benchmarks-data b/benchmarks-data index fbb693d2e..25c2bb40b 160000 --- a/benchmarks-data +++ b/benchmarks-data @@ -1 +1 @@ -Subproject commit fbb693d2efc4538d4c3514c0e3567a516a53dd8c +Subproject commit 25c2bb40b8bde342395534b534ba62f8f0ff3549 From bc48b5ed3806f1c0dc1d5314f69878c7d2e92294 Mon Sep 17 00:00:00 2001 From: McLavish Date: Mon, 17 Nov 2025 22:10:14 +0100 Subject: [PATCH 48/58] fix: missing config.json --- benchmarks/400.inference/413.recommendation/config.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 benchmarks/400.inference/413.recommendation/config.json diff --git a/benchmarks/400.inference/413.recommendation/config.json b/benchmarks/400.inference/413.recommendation/config.json new file mode 100644 index 000000000..649bb78d6 --- /dev/null +++ b/benchmarks/400.inference/413.recommendation/config.json @@ -0,0 +1,6 @@ +{ + "timeout": 60, + "memory": 1024, + "languages": ["python"], + "modules": ["storage"] +} From e1201670fbb4a89aa7f02729ff7b90c16b151f32 Mon Sep 17 00:00:00 2001 From: JessieeeLoki Date: Wed, 19 Nov 2025 18:39:26 +0100 Subject: [PATCH 49/58] add microbenchmark gpu latency --- .../050.gpu-cache-latency/Dockerfile | 18 ++++ .../050.gpu-cache-latency/configs.json | 8 ++ .../050.gpu-cache-latency/gpu_cache_bench.cu | 92 +++++++++++++++++++ .../050.gpu-cache-latency/handler.py | 31 +++++++ 4 files changed, 149 insertions(+) create mode 100644 benchmarks/000.microbenchmarks/050.gpu-cache-latency/Dockerfile create mode 100644 benchmarks/000.microbenchmarks/050.gpu-cache-latency/configs.json create mode 100644 benchmarks/000.microbenchmarks/050.gpu-cache-latency/gpu_cache_bench.cu create mode 100644 benchmarks/000.microbenchmarks/050.gpu-cache-latency/handler.py diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/Dockerfile b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/Dockerfile new file mode 100644 index 000000000..4fd7ea2cd --- /dev/null +++ b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/Dockerfile @@ -0,0 +1,18 @@ +FROM nvidia/cuda:12.4.1-runtime-ubuntu22.04 + +RUN apt-get update && \ + apt-get install -y python3 python3-pip build-essential && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /function + +# Copy benchmark code +COPY . /function/ + +# Compile CUDA microbenchmark +RUN nvcc -O3 -arch=sm_86 -o gpu_cache_bench gpu_cache_bench.cu + +# If you need Python deps, add: +# RUN pip3 install -r requirements.txt + +CMD ["python3", "handler.py"] \ No newline at end of file diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/configs.json b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/configs.json new file mode 100644 index 000000000..8505c8e74 --- /dev/null +++ b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/configs.json @@ -0,0 +1,8 @@ +{ + "name": "050.gpu-cache-latency", + "runtime": "python3", + "handler": "handler.handler", + "dockerfile": "Dockerfile", + "data_dir": "../../benchmarks-data/050.gpu-cache-latency", + "datasets": ["tiny", "small", "large"] +} diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/gpu_cache_bench.cu b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/gpu_cache_bench.cu new file mode 100644 index 000000000..77cdc3528 --- /dev/null +++ b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/gpu_cache_bench.cu @@ -0,0 +1,92 @@ +// gpu_cache_bench.cu +#include +#include +#include +#include +#include +#include + +__global__ void pointer_chase(int* next, int start, int iters, + unsigned long long* cycles_out) { + int cur = start; + unsigned long long t0 = clock64(); + for (int i = 0; i < iters; ++i) { + cur = next[cur]; + } + unsigned long long t1 = clock64(); + cycles_out[0] = t1 - t0; +} + +// very bare-bones error macro +#define CHECK(call) \ + do { \ + cudaError_t e = (call); \ + if (e != cudaSuccess) { \ + fprintf(stderr, "CUDA error: %s\n", cudaGetErrorString(e));\ + return 1; \ + } \ + } while (0) + +int main(int argc, char** argv) { + if (argc < 4) { + fprintf(stderr, + "Usage: %s \n", + argv[0]); + return 1; + } + + size_t ws_bytes = std::stoull(argv[1]); + std::string pattern = argv[2]; // "sequential", "stride_4", "random" + int iters = std::stoi(argv[3]); + + size_t n = ws_bytes / sizeof(int); + if (n == 0) n = 1; + + // host array of indices + std::vector h_next(n); + + if (pattern == "sequential") { + for (size_t i = 0; i < n; ++i) + h_next[i] = (i + 1) % n; + } else if (pattern.rfind("stride_", 0) == 0) { // starts with "stride_" + int stride = std::stoi(pattern.substr(strlen("stride_"))); + for (size_t i = 0; i < n; ++i) + h_next[i] = (i + stride) % n; + } else if (pattern == "random") { + std::vector perm(n); + for (size_t i = 0; i < n; ++i) perm[i] = i; + std::mt19937 rng(42); + std::shuffle(perm.begin(), perm.end(), rng); + for (size_t i = 0; i < n; ++i) + h_next[perm[i]] = perm[(i + 1) % n]; + } else { + fprintf(stderr, "Unknown pattern '%s'\n", pattern.c_str()); + return 1; + } + + int* d_next = nullptr; + unsigned long long* d_cycles = nullptr; + + CHECK(cudaMalloc(&d_next, n * sizeof(int))); + CHECK(cudaMalloc(&d_cycles, sizeof(unsigned long long))); + CHECK(cudaMemcpy(d_next, h_next.data(), n * sizeof(int), + cudaMemcpyHostToDevice)); + + dim3 grid(1), block(1); + pointer_chase<<>>(d_next, 0, iters, d_cycles); + CHECK(cudaDeviceSynchronize()); + + unsigned long long cycles; + CHECK(cudaMemcpy(&cycles, d_cycles, sizeof(unsigned long long), + cudaMemcpyDeviceToHost)); + + cudaDeviceReset(); + + // Print JSON for SeBS to parse + // (you can extend with more fields if you want) + printf("{\"working_set_bytes\": %zu, \"pattern\": \"%s\", " + "\"iterations\": %d, \"total_cycles\": %llu}\n", + ws_bytes, pattern.c_str(), iters, (unsigned long long)cycles); + + return 0; +} diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/handler.py b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/handler.py new file mode 100644 index 000000000..94c9400d7 --- /dev/null +++ b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/handler.py @@ -0,0 +1,31 @@ +# benchmarks/gpu_cache_latency/handler.py + +import json +import subprocess + +def handler(event, context=None): + working_set_kb = int(event["working_set_kb"]) + pattern = event["pattern"] + iterations = int(event["iterations"]) + + ws_bytes = working_set_kb * 1024 + + result = subprocess.check_output( + [ + "./gpu_cache_bench", + str(ws_bytes), + pattern, + str(iterations), + ], + text=True, + ) + + metrics = json.loads(result) + metrics.update( + { + "working_set_kb": working_set_kb, + "pattern": pattern, + "iterations": iterations, + } + ) + return metrics From cedcf1549526d83193fdfa70ba4ad5fd91d097ca Mon Sep 17 00:00:00 2001 From: Jessie Li Date: Wed, 19 Nov 2025 20:09:51 +0100 Subject: [PATCH 50/58] ran benchmark on gpu --- .../050.gpu-cache-latency/gpu_cache_bench | Bin 0 -> 1017904 bytes .../050.gpu-cache-latency/gpu_cache_bench.cu | 88 ++++++++++++------ .../050.gpu-cache-latency/run_sweep.py | 40 ++++++++ 3 files changed, 100 insertions(+), 28 deletions(-) create mode 100755 benchmarks/000.microbenchmarks/050.gpu-cache-latency/gpu_cache_bench create mode 100644 benchmarks/000.microbenchmarks/050.gpu-cache-latency/run_sweep.py diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/gpu_cache_bench b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/gpu_cache_bench new file mode 100755 index 0000000000000000000000000000000000000000..bd77e7514d0eb2759da7fac6ccd64c1f84e247de GIT binary patch literal 1017904 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 (!U|8DMKvKrc+56_Wk~+z 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�>B-d-FcaZO4dk}y7S~=m3sakB| zA={4N%!mbhnGlOWCQCNo5C-u87TB_tFT^|}0z!FxUFrI|j$HHo+}#@NadS$=DP^2h z=kiCHkHeip)IP(LF}(=eej(2xV5_*SYst6H-(x6i94dl-7%GKfJcmC7+E;6Y3Roh5 z4@_n;Z_ba|+aLE(ff+R%`lzA;XVkFqFiiz|JvMtmU`R?2%#+*H;_I|U1?|wLMpFSl zg9>=5%?xBQJwFoq1%IY|m+BPS+o#bZ_zg5sDlH%B zj0;Td6fQP}puV0S61EnQ1EE#T2S-pfAOG0XBoLA5j4U^2WUhR3L@LBA1%hl9NFbKP zwcyJ>U12+R=&y)J#?Q23ws5;ZnNkX^XV382>7b)Z2 zAQECk7$QZJ5T{z#3t0#4Oj4921xC8~6a>X{(>(;GPqe^-jm#COBf?e@0;m=|sZ96N z_Ru+tS%8hAw^zt zG>xp_C_;CNxI8O3II12_t>EyXFjfq4bZbOcG1~k7g2{Kkh-m)b-#zll^8X%G#O3n; z+Qg_oxb%9`i>fL5uei<3BLE7^FrYfXe@wm4OipPx_zmfgFT}?P`|L@yiIF+=K^*n6l3n$fn zjot_{PRN@bM)ChvhwdL3;=lKPC;-2GAMnBN(}M7ueci^z@4j7f@mm`SKeh_QZ+Gm5 z%)+lY__4z%_|4)@t$y)T^L)zC^F#jpHxGa*s%RvT2TxG|_TYD&AZ%Qu0aQ1+l;@GN zMJl!C`5`}cP-}ResTWyJ&w)lBEXoG?tWK1IkquKo-H`L?kPe&&Bx9K_do!i6YlfD zGrK9^c>oL!fVb_}*CxjE2TT_5GiU9xX_$j{g^meo!=lj`OpZnsfky` z_8IZ>b#6=+sH3u;4Qex|z$=qGwy$LQ?N}i%YvQ%f4(z&dh%S@Lae<4j>T?;qc^xi4 z`?F#=#oOU4r8}HpI8sx@MV}r>CXdjD)^#6jRnle3P;_UxQJ1K7?`9#E-t2X&2^PW7 z>B=>g%}0WNCISUcwQS=lTzX`6-e(xR+)tLU# zv`LC;T>jBFdNEg&{MesHTU4WAc2Z2z^%n_KpgU~m#9pnx7){a-^^e%fS47zUQ58@~ zT941}U7-7|zp#gT|K?!-D3U+C{O$m}XWi+8_p})6FYX?-3E{o>Ho15|90_l>3c>ru zo08+r?qlG6I))1Jha=&=c2WS|^KbXT`-vEM|MQAX2=7C-%EkMUNO-eV2;OynNsc$W zkAe4A7%DH`dF{Jx?(%?buD}1}HU+k8{rz29m?v9*KkM?=H1YaEn=0LHn|M4wIzWC? z%W4ykt$gv-DYhPs7PzrYJocN{#H+N{Uo5;4pyuvZ6mGBgydwb59dGr)6J@iqMNKk1 z*VMHpp4Ya`#q)wlc(PSKJUe5uwK9%{C;N?v=Zk;##dD$Fe=2PK{E&&Be22OJ)KRx6 zRLA2{tbE6r+OOtKe?#3~g3)uhC6YJx5)8lmScLtju5Y8$8SlcjWjZ6t5)A&s;)_T)R0Ex};75td+J|0x;ETz|3b4p2kxehP5h`c?3J*4Jz0eDrq2FW>t4-nV*~ z-CRGv?@fv*seHrkI_103=j-feWX;NdhXu`uR%N`gy$s z17yLdn9hgQsH50zKTb9&3tc}ycylEjnwvC{NX{$f`g#7=O(Y7nT4PNmHV#vJlVx89 zcv@P}-^)#;2CbiG_Ysz0=={4HO@^k!hzH2_A=%_zKmQu!$=kKY+*;!eX#LKLe&l(K z>3rCh1~8MEkf*naM=Hv;yTwCB@5>LDWS88i$cWihD++tImM(Hr?dG1!%w)e<*(JWJ zEnU92l+tB-mVR+sTqs5X_!V?5myB$1Ck>1SUMkZA+Qa{sJ83!UKBfLZj}WfBkS!9e zT{6?y+7LHhJMN&NSJJO^>pmn!I3j&0X#jkT3XKcf|K0<96Xiaxc*>g;k| zf`^-YEkiJLZrETxsu>{AL&>vZJb)+mB)9k{Or8o3MQ=QN0V!7Z`0Bav3@6qY%d_X; zIdb;+cgGKs(ck#LcF)wfe{xgNU%INJmjoyDA=rxMED9XZK8O5{ zXFlISY}mnp-_Wl3$V-ZgjD{3v45Vk$q@qAge%KeJoPRgo$e}=?C?gY-5QRoaXsOKA zI=OG6i=vU5Oz~AXC_xDEeJ3F*+A`@8^f`${$WWB;f<*q-O^Co45CiW@7E-y1@I+J^ zfjqP4*k#-C=ui(Akq*t_c@}|U0}M_Y#AA>Q-$z|{4jBf-vy#!{nm-57;~Ure(Bsh7 zqQ`&yeiNj}l|N{D{ICFe7=A9*@UkB%?>kV`@F94&!NQ_y&B7 z*?^bYuttB(UT}kl9>3G_@#yi29+x`h<48@9B1AKKHy;s@>>D~-Y_^Ox^#-(ubQB?# z7Q>nXl3$^p<&ya$1tdSBpbo-OH5G|T8QJLqDtMLXR6>#sARU`HmN7}GT#3J@jPIeJ zsW(*}6bfOaGjo$A$pgS9RFQu<&{N7hfPqCteutGgT1wWV5bJ03s@ObAfOOdQ&>oTZ|J@GL%+ zcy9eI{%DN#--d@UP5B;3F2 zvu`!6Ezz{5P>r_)oWFI`no8Tamw<0&hmuzdL9t@aNl+krUxH%yASklGA}A@fi?V;0 zUI*UDNMm0ABPRXa_@@B+88Xg?e#R6;Kj}f6GW|^XTGP)*1<((F8-af8)KfhAVfTg6 z4>M7D>E|8zuQ*>6*7R)nugq&f4~f1~CEWhiz^MjC$6nOCv;U{0{wnCh8e>&<&#{V( zF2?ujbi)|*mu{@rWHd~armm)~f@`U2xvkSisk$HyC>yZpx-#=K6d!W-s7o0I9y)rU zjG>R3+e@B;$CF|k-juO;eIIx&vg0qD7xE%>bE#amz4gnVr6^_b+2TKwqd5kOcc65| zFu=U;PUZ8e|qF;+NYMFJN>Q1Rp>E&JR(n)MLbPsf8cT9B`HoENtk@8Q%>2#k?F5FD$K z^Jg`E@O6#p$ld`b2^9HL$=>5URPtxwK`L2$wW5-%@!h5p9V{a$r8CmG5}m-oLn}If zr6X5{&*-YP{gPn<=Hk)0hK z6hlS_jqn1BQQ!0yh5bn}ywiM-q8MHRDCRvCj!LCvn$v2|m5-MF8UQ-ZER9Mx94!ys zpnkzIR<-e-s)_ z@(+{!dkhI^jutbYmekJxJgkwOag`#VsrX)!mFL{|p>+ToMYq6_!wr&nI>1PWknBJg`%KRU2;l)A4Y`76D~LX`C>BjhpB#LH(dR%sNI~=|_8&GE&$0g?Kb6eNV*u`Tg~tH=i^$Ja*)_uz zeU23=)G!9GoNl~Jljk_xG!G^YvH*1mLB|dd*rF&*YyuuBBWe?{t2|RA6Y!kR6y?2n zQeqR32T`|FHSyxBqhWxl9lf<#W?S==)!7@zC9(lITpk-x=~ZP1>H%#-P(4nz14dpk z2lCRXf8WA0x%F>B^z-i#0rWFtm=FCl{m;?QUY{uXxxH^<`k_Y#`r#!B{an+Kh<-R+ zf%H?1kwfW6pJx-cU-?tRJy9*QKDu$Jq7zqr^khvZQR<_&Jdwz3u=S%@X3XdYq!+ym z07fIwWx+Ai7_@)&S1^kBcU2oNCUf(0AYq2q9h}I7B>UFuN7*W%9_uT8{>=1AR&J*~ zewbSnFJ2PNM>FTGO)9QdXZNA?lL&n1p^nE;{`Hf3Jv!py5$kc9hk1}UVsCdh%7zB?YCupVb2VmFee{v2SiUP4UonDsdPt!4P=qAi|h zfhYtIBGL6Ycid%>%4!Jw==C`49{PlY895#OLYLKCOx3D4jt8`>w4g4#rM}h;HbQwG&W|Y&_B0Rfm*lYCmjBWV z4w1s<%g{V*1_wefCB;-B+4CHdBO9rOo}#li|? zhCJK;UeVVn_-=(fAJ+7Bn%tBqr=X@H;_fJC{J`cuLdx2z-B}Ic4uvbL*|S%8ar%8_ zmF#o8=spr11DkaB`59!)3)m4Jzq+A#0JSfmYu;&Ifq4RL@ZxKgq>T4!j2|kwd5;8F zv#if_#4^j!2_yuZ`O$dd;bjt9g_Zq<8=sN63Lcz-mn5<5-NP?N}MY8ZtYI zMSTnG__!mExg2!uW54>vzqS8kNZc+U{(Z5B7_9jB`HC2>b`rxhO$>~GYxgHDawa$a ztrdpW6x#b~_4qe}GN6fV+oTd3uPYUq@Zw7*a5|LuPpjytl{XRJ=dIgaG!r%c&C&AM zu8pp-Y_~@}NcJoY8X^9z)^ArBdOiMXzNl{{=+75=6w+ga9|~#VU_~SM3OQ&4X1=D8 zCb@|M!ZfN4)S7$*nGt!e>J0tU4PnL}&@JUuB%lt>wT>`1bP4rEwWt+mm=TJE`Uaw> z8!pJu^}$6k$VkqcxxZ2!IkE}C?%IY=YmC8DOX{oSkw!O38b#`CV5wGT`lEtuspQ>M zNlGT8B)7;A1Q&nxj-sNuRiq*nfW!|eYzQ)*o)<_O^-Tr!jnQ1$&pX^&>l-1Tsxep) z&W|lsPvCzLRBa=YZqx>Nf=c6ir%tdH(H9e`h_FK$lme&23~--}e8C_*zj{$7`%Bf1 zUQggXA<@;aPF3`g7CZxHtNKo_9^yR6He&KD?X$x%vQ|a*PnADC6qC+(SUxvL9)+(* zdH8$}MVaf1#tl*wS+JziP zXoEk1EN6_);54HUj<~0#6q@*3cPPubm11^Z)Dt8*0*c*&-uNg8gd&NoB?&`L4r+m3K(&mD zTG5*SCl)aKtUt8(-?aCS@!vS+odE&#@W^RC^iZTFL=<|s>Nl-M571Ca=;4Q#G(F4$ zc_*a@{x*jm?DM^E#fs!4^uTVT(Ste}7+wJBVLz@m&s~oiKmL7&$2hd&-=`?DaK*nn zw^52CS^WEq9-DOhyG6&px6(uctAw>o6w;T29UPUaNhCyxSbVP_HFo2l%Eb;l5 zAWXsHErc;j0WYirf{mg*8v6)ZsMv)w)rL@63V(BHB4pI%0T6DG3cbwnSpWCB4&x)V zk;-%*^P(oIt?~YpJRIMoCWqP~VF|sV_6{ZsTWd`OxH*WMsGN&gOcK?(mF+TCZiR1{ zOIxHkKCUMX*UT~XU@qDs2{;rJ_oq@kVJ>&(N(3V^q%V${fWGhqHhpc6!8Zzh%{VE5zHaQ}LthscN?#Wq{69ipvp`Rbm^FV8i@w-8 zA$=WqaYFjyn1#~UKQ4+)U-9;9IJK{bzCNb3g&lX$|0()fAktUs$Kjg3lj3&2yUO{-tSdnrJLlZSC;hlqwHcFVEiw=*&Fp<^S;qi})6a@@xa0?_8+&kw6@D>R3YdZ3tU0zds%$r&isHAGqU%W_`NSr}QFWuc^XxF&vN+p~m-59zEZi zPN8Fc1UE8cefq=`6j@HfcYA%rcukjg2(gMah6&IHMSHU@ondobm#)`7z$8++BfUg; zX1SPIk|JX9wO+I3GOnaT+_fm8s(o$4ENqZ~N_6JC#pL3Wn;LmW)U9JRv9%~d7KzoU zMG;scp`NM3m(Qr6(%J*KC_)M#)HudsCX9$KOhsPwk_f$Wf~5*DF!_h(kAPZhE%%ZLy()ogd;c_uxyKlbBGj;9iz1|M+_emYk7JJuJ54=Xwk;kYhsJW&Lp+W* z-hlLWVr>Aub*}cKw;TS~>22&&ir)UxB{{u)qUep60_bg*Au;Jq4ZGp!?bgA`=uPsK zVfCA9kN2oovwm}aFGW|b`prefDvA-MesjrwR&a~1C8UHY$|%ulGskhS1tr|nDnI2s zLVWOM4eQ>e#s#h?^1QEfezB^;(tVVcW=;ePUu)7A!NFCl+;Sa9)^D^y8Dy49BzQaRGSlc&rbepB98?X<2LH zc`ei@`5Adf#(v0;%_5on`PG3ZTjj&^0-IT5;mLj@;#us6XT*B?3#&Ykn)0~3!bcuw zW60z4_uioLxUhQqd;ekLYaj7>C1yBW9 zM7*y!HURHFNBiKtG6vq)lx{+JKlW%Y-lHPn%~m0J_y1jTyxDyWygxrG2=8hmlD%bA z1mJ!4Q9gLDj)C`WzuKU97iMq0@JKG+QeEpWza91#TLs~*ji48MCdZrIN5NYUbvlOf z=kJJk-+pue-a~)ugZG*kct5)PCWQBbhjQ^|iFLR^=tG4~Fq~-u>kt zKFR~OXyQn$s-h)uJaO$^vMtvoRo~-!en|+IzJf|v{NgQSn!NA zX*vI3WJ+;iR`%KB;yCB+u|vU4=Ei^B2;-=Y=-cKhcl7K8STm zEmcjt_y@&geUPKx^WB48YdsjI5IPH4AH)F!XC2oFT_1!Yvln5ki1nU!{Z`m{0z3Bz zsNed}p$d3Ds#VXojRu}K!|M5JI#?=r6Rqd_&17A_#ho4KNvkxBiby#!LXwFg8=z-lPpojf1oDV%{`#i6`w(d}miZ|`Gw+>R2;Ih|t z(v*n?|QAT{G>MF%QKUHOcT8qz5FjLS(KuTL z;A{7ai0J4DEeK-24zb5!YLwQMc?%a=C!S3aw?lR6)% z?#N0+?WG|f$(t%4Nyi9Y7ugB%@047o*T_xDRocFpUasrTN3tW?uD!#(cbNDJ|FXm8 zJ7g-VCUPDeb{Gp>m3$WdWh-BNaR{akO23E#1$}4_AJ~(!f{K;5^v_4Kd&R#pi~j2> z?V(P`Q2zW&ys;;U1vcG1{brmue#~Cg)dRN4zx_J<@bATL{$(!!+vQ@bv(eL|Mq(3= za{gV_B@_PnzlhGiz_t>nB_EliI;w3{hnC^H9`^}A)*kE?U z-wEc{?G%{&j(7<#h?l5uGkMYR5`MH%1a{;HwN(rM6c{hr;x-dLiI?zK&3DQB`m!hc z((w|u3V?4}cHKD&JBgR@T{Uj`wq0R|f}70E*f|6s7q?~ECiI;@UJ?@TTGcrKzqw^T z_;m(daj~--KNmAT(udRH8}I7ZR^i8q-5Bw%V<))qYmZ@?j}OLAQAHKk53rRlevC9KMXN64vTkjF{hjYA+9- zroYm-hr-hpZ|I@%j1q6?y}k_!(p81zf4zS4tBfgs?RdlgVY&nC*&^X=@mJW&SN_^X zjdhnze#z@uxmNw&CFuO4n}m{hl_z-sE@N-kQVt4UHeORRF(B{Av79i`kX`8qwZjzhU;4 zF52mYA#&`kDEWYuyLs?Dho%pVt=YRMJb8+UX>9fBNaLCLVWbKDB2QK@!p`^ejp@Ip z*S02@-N)yGiNJRRFxe^}n4>OD1}6K>3uZkUFm53v(*dJUXuI}%s=#{aDmmXqyF{rL z?7YF3I<6hBEyuOz#gM)4D%DPW#`N6*0IWFTz`tgH*cFI3%&JUFB}G~q58oOKyVB*U zacedk{_C{-q{>)bX)GrtT!;l`dbhEZvB>3!mm`UML)jQ~oBreO4c`r)1GAg@Y)Hu; z8aS>t#_?4K!wxO_uMQ~oMmUH!2MkWM%(H_ug3sAGN z;EkWL0AnbBVe-7ue@x04J-(Uq>^VacRyyxuYDeN1_+$!r>;s6&Qc6h|Ir2>irne4ezOD~>w&x- zYuAT89SH3tN4$)!0yG5TWg5*m^sL@Eo+251!u?#Gj|GY)w2DT$zjK%t&~$RbD)?{9Ic^vG|kyM#U3D_~034|7_y{ z)3SfsDKK63&zgelpPN5dU~V+~=L!=(+x~ej7(R#n!&U+CEz3TPmHWglj{U<91vjw` zgX`n_pznh1pRGI)TJ}#{AAVd{5I-);wkAIwbGZqqZT~a}1M0AU*eU=}v447;my93T zZ$y4v$fBBD`zM4S5BdebY?w8CkCf4pGG=E>iiu&}c2>NqO~Zn^J(z0lj#uzIu_M94 zm93U-T*kbz&cxAXOt|F%KBv<$VXFWfmt_yt6;g2+lO0-&x%^pp&yDVQLkK=MZmICu z8sO;Y(w;6^!3)b#P~8eSUy7MzWg_#87S8W6N8mrHJ$g{&W9;9>Y@ zPIP1;kzQ7$w{I+LS<$v1UY3gvghYOHYFTE%R)Oez>nxMuyXtg&zA_7TXruG6#DrY& zpeXedD~ki<;q1+Pu4C z>-b*12KOG`^xtST(}(<*mW@^!h(ofr2zSVMTYs#;<#&Ymcmd<7Z!>wR&76iPo$O(w zSrOqj{z1ihRqSjEClsN(`4YNwmT(|^r{a0C{>-KeMDS|NvqRO^s@0jk*jn`+eZGrq zt-5Wep^6xq_rl9DiN^tuIg{tp1cBT6_v__vtze#cULC?}p8a}l>fk%&?y0J_fz91h zmEG${QZc=qFc%P$?Qq{2(^LCynH#F&s5~>Y*LXIFChvZ|;qjplH}jB;X&*iQlOh>c ze($QnrYHcac3j+=c=o+G7thj2c(PSKJhKCn;mLj@;@N;965-kN z=XDUTv*o0QRKo`)^(KGr_=69gI4rGzddEH=wkDp}{yrDazLD@`t9*D~kPuJy8xhZ9 zKRmVl6}BJUh3hLwe!=)E%RuU>*eU>DbN$D+11y%MW1E{qlgy)k5{=!vl4w~N)((Yh z?nkFhv+FTbP(78%<1oCh_#puAKHvG^-6sa#k1pDT@P2GaF5Y51`0HB--fR_ucmD$L zX7@4h{`|}!ypd>E`Sz&iM_;qXgS=^vpZtwN-er%EFUTH$=$%d39-nZYB97+00Y*}L zoWBjX$A1s}v~?EG9%uIj+2gCv0OjPh$IbH%)c)Wsm9_U{rnl45@D2WlID(ZbXHxQG zw#RoKGWt$_xFlQhl_I01^5ojB8>t0|Y$Bdf+dQYMI-=%(?go$GXY?ZYB~Y*0r^OtS|3XqHSxD@n&Y0y)}aHn#@b3u z40`3{>8+G2`mV3*$bFnIHKo?LIcPGI?_vnTI@%*Ur}BYS2@ob2)%+L@V-_`YWc{>C zdJ(>ylcm$OrD_vr=L6uWa+HD@78|4KQ*Lg|^A)y#qfL<^i%YfWq)dvI`?h%^moCFBX6qod3C9N@22`;^=w|M25 znkdiKM9Ieh%rcxKaK@+LIwr?@AzNtjw{D`e1ZJM|749*qF)gCqJS*8=BVj(Nc{q`N ztY$qN1{FK6!1EP;iO0y<`#zw4E<7G{)fXPxGyV5|pDWsP#n)~qC>}HK)zefT5oP$>- z&xPnt;quto9`8%8*cZ7Pp z=haz9vtU_l_W4smQyb&Fx(l)a^mX*7KJ+!dQ2Kgl?*9mV4LwQI*SWFii>(vV*J41d zHBCJF;+Tcf*E!+zWyYJTQ13E!B@=@%*xHF%$7CT@Ck!wejQp4_S?VDyGv2iH--@tY z@unLzVco-S{RLN^{O_naimD`9&W%8KK5`pp06$m!1KNj zeDJ)hAUyj#*P3|lP?L-2ev$BGt9*FQ>z@oy_8Sq;!5G2^&zSOk)xSL8n)bom_k84g zQ$g~5)U%tid@nv;%Xh{QliCOTZMb~@%}Ew@#FOvrz99KNt6$;r{n-yZBxB0=o8R@3 z2a^kv2T!-AJlH&yD-XJG%0uNlTji4n9Wn1o;#cf9qCA-1*H<2d%lDP<1>iY*p%0$e z0Ih&}qVcF&Vm?u6=#8zf59yVQXGJ7D*(x8Ni%v|2C;N?vXB~zpT)vkq@_=i~_oZ+7 z$oHuQ$@j;f+?3^er%El~_Xh?^uYP6QeU{A!*SP7K<*Bc7e@%V0?2Qp2g%9{uTiMaM`b=c4cjtUDtUVY3e zIooLacfog~&yGZ93Kvi4M=BaIG!C5|-H0^?*kEHZ3Qg#KN$G!w{mb?KUEKVWtgq6B z@y-L`Z@sLK?KI#yFJ&U2S8cNWyVxyQo&md%^FXXBe-8I<4X7daJdoJ+Xsh1zFuSQA z=Dy~q9}0>OJ_M?w@@IGp&N?rf(E5<#-)a5udrc(sC6N$seF%T+B@)I~-0__|POzj! zJpI7#3(^mz7`f2+&a-cLNXFC;H^1Vi9}2P;$NarD^~2^pbM=E1S%>New#ug;Qpa0} z$I=h%H==&{tlC#UM6mx~3&3;sOFno`D+tdSFc(_U{{Kxbo)?paLh)p)e0Z)&CBu{b zM#OUhh6vL4G1mXR>H*i3?@L>JJ&<^vS zB)-FbBg%s*Rlf2dT)uBJF96R^X8YjzY(aRgzP~l`?0Z-)o|i_#ldbaMIioTep6oXw zp8YXI;qv{UxgKy$`QG*gANhWmKKUzIet)+qo3ebbIz-F&3@}J4-}&2c`TomeE$WCT z-`RaZ^1bPp!sYwA*&dQH<@;OBKJuW4CYfaWH?O|8HRZuE-E!r@pE>2B@|~^n$%A`^H%7vft@7bHvOF1{ z>^CBw9WaCso(tox7wkRD1Fk9G_kGq!zLysy-}~LYDa-f4UA25~1O`dvJAWH4-{1e8 zMIG_vJG(DPzMqYe3ysh0{+x$oO!@xxQ$F&bvM_ltsWs)nx%=nJgTHXfL*+YL<&y{F zkFpStCEwX^M0wB&L-@#paQR;IYyh77%<#c8RS=$M-`SdY-qbl4&zmCQ$yWLB?9nqB zp6oXwo(q5Li)T#ve(BR5a83E%>q#H^enUa>J$?J8EZ-aU)$;v5V31V4^S9yh{f^&Q z)Dcgf44mPx$d)nef@?2|vKc_lJ)I>+^)! z$`?K!)V%I6g`I3;%Xf{iQ7StW++=R@oF|OF^X)IK&-YgQJ1xQjEC2J{Z=dEt(cI5# z=)(#{*M4428bwJp`=6?1o#(#lMk%%-(VF{t$>*T++%@Xf5{MSP@g{Z?VEqO5^Wu!? zx*BXH&>r7h(XwZ4?3wAdFw$F2)8VoS|t}$dkFShap80RBmlP$trcc{gprTC#| zNd%;>nuDB0R5*;Incb@eR6J)*pIqfwJU!Kj?wfl-INF_u*gGQ1TQ+Ew4omd5R+~d40$@4tvT$R7Az z!u=Qb-o?b%-hc7HV0@_{w7h1k0DQmF`_q1Vpan4neXRW#*}dZ5GW-o@&nrCu z!v&sK8Z+OrzR5#BW_py)k}@TUiwu2l*60edWR0%Dne;)0U}A` ztNd+veD(9r7QMuaud@4s;;Tb3a)kJ5n7(=GuO6x~?Te;6eDn>r!HKMI&cE7{I{$tD zVDqh=vSR|VYCf0{_y_D9_61vo>6`s5B8crDuzQ!#$nPKguFx$MA0{OS6RsaFYBAv+c{}Q>6>|hG~?7aY!y-8bh1b%w!YygF4BphZ!lb-zL9#3 zFnMwN9UiJN<;BojedNWw81mw{D=n(|@5_q?ZJpRFd2vV}_LCg)f~`X2MW-?g^w{!( z-Mc`~FE5_nXM@R$yC-^(H|52MTYTh2Sqyp6f24){|FXRJYa1ucD0%TxAk8@C1zSav z7pL!Skxp!R!BJeK6D}`S?3G7ehi@ zF@xZfxZNQl*Syqb24X)pxnrjpt<(ONVA(#cPJPlJG(;&Lr=*J<8i6AoYBQ&_P;oBC&^xgu~)n_)Fh8-ltywA3@%H_m=>9^IFD7-pr37Z|3}QQ_LDbVqsW^lF8%*Y-n{)I zsmLR5ULky;@`kNq$(!-J6(DaoS^@HA8;l(+Z^F)h&Uox$vz}>)p$N%U&-AtyGwymO zITJpoo~g!|QZ9kD40Qw*+8LLqcpJYX-X^MJXZb6(NanY~4t_5FWGxQTsyv(=kE&amXz#SUKFG+BKfl~ zr9CK`{%q5q6p9ye8qBEsN_TxrXTlMbAAj^BOIiH){n^dem;l@PwP%6>F2alH{5V?$ z0Bq*hrgXHNlGy$%yLUMy`Tg17V5oxfYwsBWcu#Ba!FzlRyjw2Zgz(o$hFaJ{j-m}K};Qe+CyqBE63E{o>H@SFEkAyc{h2T9MAm}Y1 zV)Hks)-}inzxD|M__#E(_vukF&-Seo_`L8|sb*@dW zo%0L(*QGGPhw>uMf4xpIfY`lUg?yT30C}j+FEs5Ji>bca67g@^vE4jR8bt<>!~Jlm z3T<1o2J$Ez&?Ogp2+x1zPpl>2#Tyw}27{nHiKtVmR01`6eR`p3y{`{2^jdO&VVlzn zmq~$HA6uwMl4A?6ZhLH@Y4_{5MlnwVhc_B|p5`~Cotod%$Ru?%6?1FOff)?zmLm0bPr&L*@Sv!#>;~@=7n8;wNCOg!4m5RoUwpK9D6WG06wwO|tFyK!4 zMOduziS+p*aRhyk6*Y`yo1~S4Pq0Gm5@D{iCQ6_6pBl>vSRcbbAq}99(9&mL{ZE|r z_%UtIz9MlMVgp&H8dkMqB=u}QS+|v3FUW~`NJy1)4|uL+{z%wj=#&*UuBVL&a~@WaN&-_zmXjK)><O&*5ewCGdGddvy z-i=qL!MlGBc<+1Wc7*r-pSH#Oq^$5}t`6`%5Fq4>H;c~!?>W0{CEni$GvK{sTpGL| z$N}%8hi*rBAMtTpyv0(VR{AIQZ|3R%?{|03A8!_)1Kxi?Ra-S*?lL|D-m5N4gLh*N zc%OXQc7*q_E8F5d4o#hYv`@sFxjMkRwrl=)v-lkF-Vs%872bPZkpb^@m!!daK@NCd zaLRUs_o@GGi}w{-;muqf;N5+v{PAY-IpF>1j$4U$ugf#wU2t(4yaPG-FK#?}JHq?C zfcqDX284bqBM99$pP=b)NDt1U->~>yl>A6 zZ|3R%@1dpnu?cN{B=ol-a(QqVF3n*+n}~}1_Vv|T#`^7A%Geo@tTo}!0@nEt8}++N z(bvx~dH!9A+#EN~Zx1cQ8E&mZdLUAsWX5+;lRE5@mbZSS6KvVkHYfX zn#l{g9jw3V!HepFZ!wI-{Mj%Pl{NdG=Edmct84Z>$96G#)l6$00(a8tfVI)7@5Bx} zej-1@3bXA1Nf}HkAW?k_H##dfBf}9){v1j|^#0dUvP2m01?-%{me-MhBj@XVuB7+_ zQGD8Tpfe8dlA!4KFwTm9C~G{Q9GwBr@VRO5T%`j%|EqZJwM60h_HlXRN&0~&FB$Q? zy)Yj5cRA52N^Ef9A@k&QBUliD}SE?ryH+3YovlRDPH%pt&7(^ zcH7459{GkVZsYN~RcPJ}=8$qUhjxB2R|av5c-;auu;vo4%L22C*KOV0LA-7U@z(o} z%7EX7;c4)5whF)dtG6wF<6mow-*2{Klc|EaI&@n(v%- zP6~>y|EbT}3dN*&>rpxAzZ-wIE%c#0=R1FX#RWJX&vj>JfH{}a@z%_h7U1|KWcpUv zuULGC`cS;8Lr_(w`Hrmr^jL5BtY+v%Tuci8b`N|>`kC&zBT|re_a`}Om_j~jf0Cd^ zUhhwmF4Eo>B_u zj@nVqYK6yxRB#a6qn6W&>souMG5w{p*K55PK$fIgFhYx@9>(v$ZSA*DMGVh-@b#A> zCsa1m-nn+MVvdG;07k+hEqPBX%y=w5bknMtjZuthAP2M-OYh!a+ zE}J#u#xK&7bv!T2m2se*ePwkOpVR1-8qb>zo+E~3!1Kt{)8KjCR^eGt^-JP;--5Py z-b?1}5Krc656@+B<5o_1vfM23tff(_EuJFZvECLUUd#9Ng8k+*GOV{9d8$Hn3P_2q z@2}IS@?l5o`@KiUhV*T=z8`(L8vO)D)iu-PmG1m?k=GsRcUPaD(#2iN=e>@mgnp;)WQzu^->G&Fmm?eWJ9W2G@5F$(Mheu}4h>KAkz8W&!tkw> zz89h7Ds~{f@Os)zmRXzeCOK>34q1 zjeo7lEBYxEdruEUQ^xKVp-KBDSj(^n$6(sQ*)y9nRuX7V6 zkcxkOjct-v0wu=3GFRI8*P8a@U#Dv85XPaL<6l{45})E}tdF-GZFt_}865 zKu7Vf?an7Ys!3rgcRul~UolnEd}7m9>7Nh(CVTx8JII*mUvcbno=@yQ$K{6jeBz~y z+>p3Fkh#*1N7~u87;UTE%c2%{i(;!cJYnt8x5K9RU@6~8_bmfUsvDwT$>Hi+o(*oH4@0^EGp*E za`W8-tQY@3CA6DxKj{NM+Pgnes`eCQ1UHu`h9}Z!Yr=2Y%>W9pg zL4Oc?bN@~G>4z*gOa1WOjhXescJW-}$$;m4oLC)hG{Q-EezaBkzO(-?iRTedw#D;b zS>efC?cup;LwXh+*I;w`t+xZITRuk1Q?p=HHkn4D! zRRm8uGBzK+-!C@UYcFDazL%Y`dEn!Eu-_L(k9?IszMCq?6O=#e*!+|~7MsOjujctN zFCl$-d!WXacg4<>ynbK!0pq>$FP9QRODy2&S4_7KOzG_Ic>f+wNG4k(jrVthUUEi$ zl0-HJ{`&-t*m5K1uQ~i~Vs&Urbu$Hr})NT*rHH zZM*izXUr+cE$A zdT^fn!{WD!e`Xxt5&z`3f6c_I6gG1AuQ?f~CX|gVbUvq%^ zKd^sI?Sq=X%JKE&uczqQf6en|jNz8a1f>|0??i`*IAs!S zUAn3U)((EgC?xi-t=+$-5_Dv_e~r(26Iw0}=E?hqq#p)19hJg=^X0{r&YMRl{(F}9 zF8|fzbI5m>u79-i%t!SiARHCP&AR2q&&qo&QMM{(>?(~S8pI7 zjDwOm<@y!eubFN?d@`9%I4eEVkp#_j%pGSser2*yQ=6A#Zz7-dy_QGXY2myPXSJOC zB@L_-WwEk$eJ0bAD+C2GYMfJ0dCRM!Rb|>QBtQ9fXWtb5`h=_lJ?`>8iocff-sP_; zn!n_sl5Y_omLnu@(WO~Tw&{pTxRGUa@w4T?_HwaLh;7fMHsjK}bkQUH*Y3pymaN5~ zs~8N&H}no&U^Yq^_zbgU`5%ai}BfM1O51J2A=aqYI>kJGC7z| z_~n$=+A?h4<-8SVK7Lj9`*i8*0AeZX=DB?2 z9pBAe-hCWrzTD)UuI^`&cW37z?{eE8v&Uf>_;D=`grvMn8h>y9rTDROm+g=ryZ%-4 z{Fu-9tN5`$)i|wqSu?5EG>5;%U$h3i2C^3*e>zhRN#Vy0 z^5RP8+=CQ9uI9a~58jDaIR1(dwRLowD1hcS}Iz!=hW8P9?;I5%U#n; zXaTak$ZxR(;l$Z62~M{>gf(kw)f9#BnfCe15@WiiMQY0RKCTG_CjPU4PGLlMedl`zC`KHV$cWXQ6eD{0Ft$26+w)jX>!P$k%?G@I z5!Kz#aURQQw=3>IfE0Oy%-2BG!ksiEa08iy73=k#%$32t^Mx}P&CFP?T-FD&K=JEz za30Gj+SA%SkEH|r1|5_Ezuj@>AqTc3{HAObes^`=w)oxl=eGFWmlb}@l@Y(ab(hTr zKNgq`evKXAr`Pv%6pwdxMGA^;Jl>FUg+Vf6jQD=~MOCegr;} z@>`9fxyAqU-Q=+yQBrNl5C80vnGz=ZR7uS zyv-2Q+@Alx|Zr|^qJ^uv&N5Dxq!zdW2cUia7X{t-1^ zvy?#O(mvSHgk=XJ*H^=+C`wuc8`mqtZvf^oiV3z1{HxO4?I(sHKX^tSLTv=!sGlQy zLakIkYx`4uoLUHhqx42qg4msT(i${5sY>l|1%;C84K&Gel49LMeGnoV3MJq3x<+gf zG&R`pBt=)`($EchX{c#;Kl2t>w8+@cq8p}4+xe(Hvkga~0{-OK&niqyL<@7J6)jZ4 zyw(@3wbiY){ab7MwAS`)tu5Dj;6o>9778uEhb3DIuXRcDw4Mnik=wI~2ZYw=Xp$e&`$L?4 z7%j3;pD+8BQGXpcC}6F18gPId+3XVB`y=5xloy%y0RD17x{_=bv01D?;)BAZjKcPV z-&C24k@Y~l_R3`z9_p!}QutKH*^hJc1o7TuXjr!k69oJ8jJ$v>O zDwy;13h?g=*|bO2?t!n_sWCSa_Of?A>W^xZmkmD^p#@|P#X1l^39gli8QO*YUb|hu zt-Rwb0?f{z4ZZN0&Au7DfJ?`r_?W1v;aXz9wajaMkFafs2(|&{2W)8P;{7(a)$}MC_76rItxe_sBXv}XqX8HV$<+VD>! zKI;E3{%Hy;{`u49y!odOJ{tVPOJ4kQa9;ew>b91D4$6vuUO$Z|pIbjD`xzAfrKIyy5-JN5W#4;Ouj> zhU+pNis22XoV#BQZMnQAavdI6D}+L=5@FaY%^Vb>#R-HF34$bZ~#CeD8kYySIR!CV~| z<2s_RFH6IFnzu0gDHhZwREclY`V<>o>r^RYA=t=mep*k#;Wgn#7`(uAX9)p%JPZhp z!gPybOeabl!dPUUVC(+S{Xcbz>E8N|OeZX)nA=+6vK$n8a+YQ}&6!lSHOn;|f<^$- z@sgJ5sCLJKGLl(Na~y4-U*yVks#+b1l#%JU^G-^gASYfgI8D*!jLnMQp3TT_O5W-C z+-1lHd8fplv|oC+!700@@Y@@}j`FT2PQW0)y(C!HSJa_(Bh$F4B<0;4fm;V&NVEmH zfpHKJMNm7v=)0C|{~womB6KV@IaGT+c`ezy5&%;IYSBl&)TVtLa?}%d9dO}DY`?iY zAga9BuMjjQsyyYO@KV59p}Eksr;CWTZDl7{rT}~3#WyG}JZ(KkRk0Jun`FTy(vmhW zU_o^^Q(dkn3#y+h8V*C##Mo~J?~-+S$tU7c1<-*V2pA@Vo+02x2q9-# zj2*=uPdP}Mv4cnkIjH3y#UU%F9E`{-DHA*BUkq0fCQL&EBqGR22pu^YgrxBa2wx}2 z!N0S8GQ^Xp@i;Ge_)jB+KV5k^1v{d(m4}aO{`~(|9)5hSmWS)|mxqT6@6F&P#*my) z<4$Ik*~!EAV+@$(AgrqW`Q%}C#Phks^1+iuW`*Za6rVkwdjD#VwSo3aY@1|?{gMtc*bk_crr&nY=*$r# z!LWS+x+^V~tFawA;XPCI&~P0JicEVAe>q@qzNBrGG(ZNFMH>qeRY#HeSngKI15heG z7^45~uBu2jWh<+vJ+p#+!G2NIU2^ewh4;0N;9Z79S|!p*p6+7kRFGtd>H&DRm}qh+*SV@4!XC1t(N*LdAm>eFm;uuznh@!ETZVv`Z8$tHOj zulwSY!6v+e^$$p!_+b~*m7UQpW@oh34w?4ApDt5e z^go}Gi`0Z%D+@9?SBsh;Y1ExEs#@3cqzgWw&+}Fgrbd;g`7`;j3r=q!s=U_5M4xBe z(fU&#HR{mmsZPQmeUv>NorJ-ZY(M7I2Qm378V`fe=n#0`TnmHi6hUuTqZ3QW;G*GkBAGRn~IxLZu$}}sf zhY6};3gjJ}ak5Jy?1gfZa>fbi1Ky+wBACe;3b_-@r85T zBDL*_f|d143u`VV*M7o58`gaBjl(T%)Q{0H-oIJFn6y7epCUDC{UfH<|{qGno0W_ zIuhv)3)^23wmW{KxeR1xo=S=(36`91|r*S^y4 zJB4PFeP!?MVLtxq`D*OkZF$~f=VY`i#!g<+jh%9U*McTumaBb*MG9hGB~j@Uk10kn zAA=smtNVo+8ORAdp>DP!Q~lLkh~VaVhq?W9Wf83zPw zolXrz_+kW(-3W&g386zt>AmWUs4%5&F3N&cbgGcvX3`xm|Gt;dC08WQuS-xzn(?zE zJfHtA1D@0VlLpU#?xbz-Ox(BN7s7Mj^Aw&}y`MLpw~@_#GkD32r)WXXU`XSrnTRI> z7XdL8UKh|do5ix=4)K)oPvwx=0iKKp{nq696x<&}*~=tiGJQ{7xgN(Tq_daJTC0#v zvX^z!gK2`jtUowP+soi%?!!BE7_QjM(rrsYTUOf8&wTA=$Ba@K-}SCwOf@H0d)Y#T zF)tY~mbg!ACE`=q$(@I0ar@7aZpLWvRv{1PbU1oN`rs(_KE*F3jh1x&KrN){?NyH$qxSu^1`3x=Z^mmGdspV z8~eoiwJB2EwNJd#qOeY~PjvmS+9xg;p)h^_Ey0vhh68vmKCF;n`ZO=;bS&5>{^^Qq z9>AKVeS*b_e$~Ex;^}x%$C_!c~i^bwDLAWNTbcjRo)P{#?M9Q zBpU!>M63p^vGYIQB)6n($Xf_zSkOJ#fic?hFn4+FU=of#qXm09r1gm2gBuM8T!j7(>EB!+n5!+n86mq_rRY|;uB(l7}Lk$q0wt(o%7dsh4+m5{s0A2 zn&6QDh4U4H@(Dqiycy;FFw=hu@`iM(U^*~`0K=jS5tSoY5- z@1}$4@{)JG%eF?|i9K4$yUg~Hi&m%btZN^s{zUO?l6_>H=Gk`V)3I6CwzZGEd8*RO z&Rr~e8MOdcFO%O{*hlsjoM-ToR@aW7i*n_wu7Vb~k90hrX2I>vr{m@Cit;;}PfPrX zC+ql=TR+P%pBlSLA)7RxMp$V(@h5a+s3ghSH zEg$w!tiVfJR)}?0H$LrP%+(WOjk1*wtRQFk@B$|9S<8o9@n4Y%{}0pPKWh8L{{)5q zwT*e>PwNIm0WaC%fAmv%;m-v@H|7)HoF}X4A~Q@4o~CZHL+F{r}tz!ITRh(1@Kn zJOq=DiJWSy@ben`WQn&4SZ~19!@9Wvf!+O?>X^0AwSYG~$1hDEkI1rVkp?3$SBCgC z_dMQr&(k|{<#8S_i%&8Mr5LPrT$EeYA5c}w{(o7=vrS!^0<{~@cK#a*>i%pH*ZnrG zM9uuw!-OF4nQU@|{}00@9{%4!EcmWc^z~{9K#AO>#DbeB4!q=*iyI66!|zmoUjCf$ zl9(5A^tFyaWr%0vC7rKT0?sNf&u4uZiLy;0HaN zWPJW~zJ4PEo(o?|gXfw|c*-IT#IXGm{d4#+3eOY&nKz!tC_H&-izk)=GKRlc@MQEF z!y(vqddp0@r)w$jXF!IQr>xgtk?rHDi+?aDJoS1F>{Wqyws#QEruM6#+=lg0tb=;7 zk|n;|^a}tBUr*7t{tjwshF!K;fzAEwVrJMfZHB!K4`E-W1D9r4+Bf+d(pWBPaVVaO zHyCbWQlnkSVu;nQ7>u6fNNE!S2RAZ}c;Yq228gtxqHU*P2#sxmSVaolm7~3d#*`(2 zYQrFVrr0)ZwWiE2sjL!C*{9c2!YTR-7&W8a(KFSDVCATOAj<~1OSZAQd~m}8)P@0> zm$U=2+8&3FZGGxhM6VeWP@H=&;YpdXxHyuRMO++fQ*lx0ZM8ZsPI>87g`h*5iLpBh zRjC6}bLRc*TzQYB#O=$6H(tpgA0AwkMm}t5S3ZCdehK+-%+X3d9P>op@`1aEWBlf& zt$cu+hVtRFiF-NACI0joTx{_|UpRM_78 zh+x|T;xSkMxmU2A!Ash?bKJjuUJT(}{O2q-w~c~AU<^g z^f9%+U9vu=CiLPAPOpz$F+W8g`xj`VK4vy3oFBq{OdlJg?I4fgq1MN!b+MMXP9_=+ zw66pWO)G7p;b4mfro^-~^-!sBS`kZeo@=!Y%1-#b+R8U>(KETDiT=2yU`WYooqLVof^4tjZYe0 zM{Qs#UeXF8y=S7*x1s*4mT}d82SqT*`E}r%FasbgnPvbWPFMN>>J;9}uvx6yw==0m z*)mZ$LH20m`I?*toP_Grg#CGiF-CzFGDdV(27ZI$k=y#IdtXZ7FgKoK!W_k6X9|Sj zI@B7Oc1c@%et(b@=O<1K_4H9#r_JQCz0jU~*H8U$h+>^X|1R=~3`N$Vj8**I@qR;h z;VZ#9yrgBF*kUGhDE1)dp=2(pz_UzTqGLkIEG$3w^)ts%;^ea55akWF%!eIGk8d1u zuwZ~4Fa5xF=iC%FaO1r$pRL#+Dc);9#&|DEkT^F`tRx5dK-Q2&QiiPdm?GbJuhl&j zQ~b}pWQx4vz1~zz!An}E(EH-klpswD-e5yJkqeR}NR~DPR@2_-6yI+uskRsqPB&EB zalBW@`%T<3Cqt@`gh{{hYaP%rT6bpc<_7;2nOa#YfjRed(57oB7G6=#V(Nb z{vj+^W~0(z?d~5k6jj9cCy4DYm(~2_`PnIuy7SFx&nZZg=9?olr0M6I$wzE)c}Y^> zCTD~0V&T~KPWi8A-}gY(jW4(>@A(NwFhIyl+HQ>bpguQiX>C67+AO$(`H3$7N|fLJ z{3Pi-w#@U*=&THQHa?RE&oSE(o+lrm@Vxi0dE0 zdil%2RQuPND}(%Xo!&DMVWYSFq2PA+qtNRuwBE+)E>?)8Zb`x7lOQKl2_~Zy|N052 zD#gE^Z2yDi#hsvot9kUqu$l?X&jk}UcCwBrx)R8 zJVoG}^@((?M*W>24JYq8hdri%pMraTWO5x!h)f%%f#*Xk0VYqUhDb@!5_RO;{~QzH z{>b3AB76vs%jTpM>wncnwlRU7gm(e!eV9}DD}JJ3sXSM!gw=6|h?}Bjj>%dZ_6kI# za8xaB-WvNX?1#Ami_ys!bo$!eui5KIaLC|s4R_#k7&%3Aj4N@qY)?GZ5YliI-bG8q zJN*p48#4lqq!AG7w_$U`yqP26KgMvwl5-~lO_Hy~yG*$+09|S~P!aCfaHuA7xw~tL zkfce0;Kv~rnp22m5~lzx)P)+Qx}#AYm;A!+lDHn+V+lWGe}3wqCsKqx*Bp#Z zN9m#`-^`U(IndLp$T=~%$-7xkzFBU&%0WFc6cp%M4n!?f`jk9S{(Im!4LO>_r=wox zg=8D1e>&brQgHl{8Gz$n4=NnL;=SATAJ^N}e2s?~|3~rjv9($}cCrR;oN8=*#|;iR z$*!?4k<&+KzyyIFhCOlDcULWJ+B;8#H3^(RT407Db0(^SGKvlts- z)QQ-;ehPf;Z>`p zAZcTHY0?5Vm+ndKKF7`vMG`rYlr$}+|76kL?>v;Dy&t|Ed0X%U4)o^m2_1(j1NdQp z;s>%tuKe(aGR+U>R`3JgO~(&jrJ$}}mmfc{*j)HQS9cYvOREoyKBM;E%xvuDX*nb~Mau!C@|EfBTP$8Fw0-d^6k0-+pwP-Z2m7vSRcA+3mEOMP zv9_EBrDrx?PamFs@{AOuPu9xoL3b;p8BZBgdbs@syS;}GZGB{|ySk$qq~dIfA-rH4 zVRTSF(H=z3cODBV{k4xgmQC6Kwz`x3aBC0=4y5@cjvL4roB>Xj#TXaZJ(w#4oL@MBr~(ocB!#J8>(&l0pjM+K ztN_ZDR4cv;b7+TAG-y7uM!?^F;b`EQFgg!$Q*``7)F zQ^;MrxPZp(%O13Bh7MUK9a8+a%#{I9u`ic?5fiQyqbb4_yBWHU12w(T{c=MC%N1PP zm8(+4gR9XsQ|-$g%G1{WO##!Dr|;d7ra#h7k-t10f5W!zkEeBZ;fu@DV>82-AWxYq z1AJdNz0t6__D2?&O@CbS`Buu)L4VDF-|o}X;MaAl@O$C9ZHwP+C2jFLE-U<)D1ns6k*8%ELM=~Cj@R}~ zmJ36SQfXrGFmaWJLWe3%!L>Qb)8xr&&L+8eMJ}LmdFqv~_uZ*mVU%tVn(q_jDRX52 z^lLBH+ARAtMV_(&^m4q5q32|hrz}@+l?KbCr%DyIsG^NL<@pX+LCGa|YV-K?&YDN2 zr$8!bVcJ{wCk1IzJWMwYX`6VMCn%yYSKtgqPb{`|JdDvv`Q}zmj7@?$BLVN|;~XSB zvEB0>d}w3nsJuV}9tYZE(@Z(g89TJflE<~qd8>$G+w&c`pwc}KK<)R763|F+q5Raq za*1@@)v_2*5|q_=`JGUHhIkld?~9#(mw7$xirZ44G(iY07&C8GP$sQc@1dbgS>Fr{ zhbRnbF^$_?x6OL>6AKiE2V5l>%KSFR_3Fo?NnxwyCEfZc9#`iCR}#Hk&tGAYiISBq zA2ZnMI0z}eJBr6lq-}bFbvgPyY$=KML>&*K>;(=#Li};~L6J)-$e&J^Kc|4|+6z|M z3e+TfK|!(7da{X!`B!aXziI1C6?;Js(4n2F=+^AyF=uKs9A{;Gp!QPM`%QplVGevHCW1+D zPVq1-UfBz@x0FyNbYa(Cpraq>yo`Pf*GN6VOY)a$ykp}l)nw)Y*kpVDboQQ>0=7H8 zu8*V{UyC)^`OQ}v$7esjZvA<6=WTKEjgPN|nein|+U3PuY4O!9K6`Nt+??hsELVDW zJM$G?#ZXj{W_(Ss_hs(C{;4UDy8XBOk7@dEpB(yc=PS3P{(IAA7vFgQr3&A1|7EVU z_{!l&GGFvH#~{wR|FZZT`tOH0=rU9P6?+j!@aAwj<@nrNQjm7%r$(hwj&~cUIxp`L-@ps(edoYdLNzjAav-h#UL_L@Qq{?5GJq=~IXYcc? zconP%>BxU~#~(BJYc9Q60ZG?PEPko01~MCe&6vw#U3Oc?FJThQ(&>uZhPmy^pQy)A(z$j7PSnr1WZ6evhh8 zBfraXkl*KC5@QBvK0lZKrI(!Ls(;P<*6r|d`CZKRPVcWNkPa{Y8s^H-;a&afT{)U! zGy~RhmftMCL-`$F$NmSNPmxyt((!89^#7YP_5YjF^#5)-^#9-=VvujM{=aqp`#Im} z{$GN2&$s{c-Q@nC z!bL^DefPDCwg_{U*U*_?+8n+RnRF}l(LZU=WV!g7DR_i{IQ(UHz+Np6f;uPmCm4dC zJT+$0nsOFsOH-KE7t$KoTWGD*A19U4QU-&FWWmn=cn5)}_^VDN8qX-@1fn6{%f*=# zW<@AgjAx`k_(U~*(m`47{5pY*=Lu92Ay2(1RvATS((AGHqiO6hiRW8!#;+SIW{oey+mkG=Z3O#Odin*Ki^hyH)#s2DT+jQu}Pd+ak#+x~B`z0)fU z3H_hB()RzjJ*Rdn<^wFg!~P$yYR7iw17g4HNZwo5WWamWgfw_pgE~eXWMhB-%Q-(Q z-q8DLN6vTtx4JFfLpY*#h&OYk#XG*3ykFczoAdmS#dnBzysB4VD$FGB#lNlaUWQWB zFG>CD#0+?k3#P%_n~XOBNL_Uji_d&&gy2n0!tLMkJ5zk7c8RwWpGlv$UZ)1#kWHIp z?xBX5yuUZ=Q~s8vpC#eV{@ZX$X1rOp_O~!sJ9yLO{UD5}dVJ?hA|-?fB3rdVn?*iq*cipPCqLI%9+u1tfsnFHR;MZwC8LfD)0q>Q=wj;d1 zS=AQr)3U;wxjMkx7uVl&#+$|GfcJ+~)?#=^I)^rOGH#z|%$hf!k-Z+AmF{^F7!?dX z&9uIQZI9tDp*219xw(-d zdM!s$>^aACE}F|*fbR%YeP@JbqQy+CQ``7npm0NIb&*lO9_4zBSpyFD+9xmZ)P3K@ zn7j^|d{YdNG@A`&D7N8{0lmVUHWaMnQ7VXHl_^ighuA;D}YNJuF&ObQjcw^R> zgA09jph8o%6qS3YbnR@aI*@+)Af&q_gd`b-#gfMi>J)qZszLIqRCGZRDo_4^n`_aK z9{Uds)pb9X7?bZsS)S0BNBgF9>l{4?Nn@vZKuAN~_a(;7_aV_|dn@ks)NLxc>S<4C z&6(aQ6`fn|lXi|3a`PWqh<)X~)pb9i$V*s3=u2cpk;8DK`OYnO!ey~CjmhjPgY+i z&1esnk25A0A~Ce~OwW`-(XU}ABH!D7W}I+}&-Um{harVH*~Ab8=z){g zOeAZgw^MDDAH&=qqud`C@`v-EH>Gc(w@*CO1gyhM`}B$-=&Rqumv7nw3!=DK3!Oc; zw4x7stOZ8>RJ>dEQO>FS6}R>@ZriVBSSJxX{0`39rDH(ucCj-p`25Wjs=t4BI` z=;I>Oc*p9H#e`vI9QLOV6pSo4v|-_(+l>GPAi z^j=<5waBQS%#Si&xh}=h zrktg(OZ#G*3$$+-PmKCoDb4L02Ki@iBCoc#?kjJgC5i(3H9IrZ8_0f=WJlB@`Rviv zV8$_mHqkQbv5E@@=Rk!Sz$)i)CjMM#LePu~Sb+-Ior4uUIlS~SF;Mjn*oWPK_gj9g zG!qM`?eB44D)hhZ%|7T+F- z;0w%%x1u~ywb-aX4Uar^RRu=aFTbwe<1nNCclgQbdt%>=9rr2Z=wyBWQUSQr*$osA zp;G-MB-wMFEq74`Lc%M<#(*k_#lx_|V4O!k-a zL5FEAF^dF+4+8cLt>#AL`l4t+qmfhz~-xO^hU;1^f2nN?gh-%eMba8VbMJ|B5qo{L+Il{o|n+t z1^%~J*L3N-Ir=H2HpVG1KLqrOD+qXNdWJWvm{= zl7~wsCEmOGB!;rkn*Pq~H3bEA19w0Uh?i50J~w)8*3dYh(ds56Rs=qvUcJ zzr(Z!K8lNsxTe+pAM$ADr{vOaid;$_k;^`Rmdjxmt)$3SQ&bFLRLn5~4=-XlVAd zz8`K3p8W!IzQ{j7xuq9y4{h4L_BeCW4}2E0RCf<0nj0hYj)ns2rEs~jWrYX}Pz zWpewTjji2Z#V2Dv0Ac>`mbc>@0MMVc7;-RR9T-K9fIX(7yg|v=)y}@4hT@JJYc-er z=k%fira(H)_?VZ0b-X|o=|QBO-=i4yAx8bBc!TOj4`i-oE~~k+(Yf~xG}Heu@6hH= ztyZI1g?EjcKLenoqYtWM_u@;xQ#A~fce@`C(wst7J_r2fMd(WqJ9m(r=Hd$0PeM3; z$u~f$_&fkry9bAuG7KWm?NM0JQZaU#85vL^Qdk94I0HZkXHfgaz5`oF$tWNItaT0r z&G@RT7jc-G3S3!&GhIjxfK)|_2@RsF^iPc2X6Wlew9bAK3f1qX%R&3lvp`^^-vs;y zPhQ1GH~kKe?14XAir-_I99qynN%yIfkHJR5Xv+fUHV}$oz_`81XUuxbYjq!c8oC`F znWB%YX8mcQZb6SVUnI*jNLNXpBFUN;{kyzSE$zJoU*oS@6EKebJh}x!NBVbj$?Kqq z|D0*4va(ga%6Whv9B#ze{wR`zCt*M{SMme;jp4;=cAjC~R>^Jro-^z5sLE0~g*b?T4E}rx)qNfz2+y zHToszX(YJqw?H8V0uDj4&{wVKJ5JNLbiUBH8<>E_UgwR`h+22b#W5+@E&$ zYlo1qey=gNJ+MURdlEN=j)m8vhsNo9UBBd%CD2z9qwi593w={RlJ@%(FKE9b6n(cL z*?EtYX!@?f1J!;rm;>#n%g4|2+@E&$k(+ zxBcoBVr)Mo3w-J5v88OQu-v#Gd9x+CdkbE7;_Ipi6>I-xx~TTRxy{r&?gjM^e= z$$XCmbE#*)b+q$#4u0)nvIpt7HG(TW);!*R!`nTAOP~huc0F(R4K~G#3eHR}=O4-C z{H4Xx{B1@$n^u!)%`;I48pfzCMib2ULwU32`9Vg2WUTQ^9zXKn-Uxo=#|upVhWC2} zU-Q#SgZuTo-#0inxy<0>DdpXrQr<1mtElhoTU`*5_UMw@9$k{#1L=wF(IvS(x+J!T zD#~pSw;bIbZaL}N18HsA1Ft8w2l6Df2M9@O4^WcS9=gm}d${Gf?ctUeZx0XFPF6O; zH28cSx;&)gkACahIn>i(DrBs-X^(($qqySm-&{6f5hVj>jMj?v=3|gOzj_a9Uep7R zKD7KRpl5olg{Jjky;juNXOz@bePT@B7bW^bYhayP0W%?%f;#ui;Z)-jh-*IR z^^J4O3y>(27Ld{eYks`H`63Xv^NKz8BvRtp_?CCS#X^fAi&?#qUH$fuQjdL;N?z*S zZ;4Jm1svmx3@b%?SC1W1>2G`YTc*=1C4F31q?dWrhk7=?=hdHTgnxx}PsBtd;*f5t z_Kk1F>i!mLv?nsL8xniilckZ~-*1yH`F%+o*8_=rr?j9^KLd%;nfRl|Gi~+d(n*nb z9N(NhAd}E$bHw)8+zdimhew}5)4@IuGqB&{ung63-{Wc=yuNz}Y$PUmQSMjoUFcFDR8V=VQKwbms!t3saM{e8GoUKhUp)e4)*q zOyznqn~#&JT=Q|o{CM2)5jQ}(V9Qi%t@OP51JXN^r5Z$xuI7a6$Y@1ZrC%`l;yZQp#H zco##jOp<1t140U%eE~VVcMEIxsXL}%qAzkSGzv+Pcbx)B4jvY{wwOv%G3!W=<-GNkC$y?C^m!qqYtyQtrq7WqO&}i_ zdZRG3`U`KDMP0s=Z>^qksPn5??Y71@Gnt&w8ci>@ZH*`7SyF5Ckk)YZQ|Li<`e=f^ZPFS{stdv!XhZO*?&zs+GQv{Z(B6wY!OLa~QIsFksl5a~*9)Fpa z+9>|_tcmR5+0Y4P+y|z1%kWjLyWvDn)xz<|`y+>M@R7Vnm|V5cXP;C!zK=h0W9f#@ zc=|8()MH=PY5cGKk(0}$zGhVv+(^wm@XnQY`NC+d-gxSbpwHKg{_X^Oz;_@Jwib9Z zoKEQa;8F3XK!Y~wcL%|IXX?3-^CmnDm0~Zr8Rm&pLF(wek=?`_VPq7E*|T# z&Mfv=hZ|E5M}8l{pq&QtuMZ< zn#k`605#4t^JYvDBiBvSX6NcObOi+lzU~rS_;IUa)5IKW11)4xpH%#M56O5OnzK3!%2#qz7-V181%|24+ zv%Jly7+wbChV8M~nEI&@KVZITkAw67!cG!u5wNR^^k;Qje{!UvMSVf!Tvm9=ykg08 zVq^f6@xAAHBPR$Q-xSL$KCA0DK74gCN-Q2b*t+h^V)eE^(rx`Q)RhDsMqN9 zXIvu#|7VbzL+?UI+$iVJXJsN52*7%KZpbObD+A~Vs}4Ys#O4LiCczs0=`(|~3T^E? zB63gs$48<>N|yR}!4#-s>MC68uB$i^Zm}bf766Pr$P?voPHd>LFWsTVtK_^1Y)d^> zG_j_<7P!N2%Ch|K3 z1i)o83q5C57ep=;);0qOkkO-B7=cn$rsH(9T`^qg(RRYlm*l`dLlO#U%ga3hjSqG3Y@o}Q_2S9GQO|35q=bTLC7BH z#`}BfHt&yM7yzO4J=JhS(9}@7rr`Ai-4~H8KI>E8eaLO&E5;Tl*LNo1+dih9sI z$6I|P(f)YowLYF)(-nf!2%C}z0va)c%;UBCJ`+6>4}I9)W%8LQ2|^;wm)IwetA)A1 zB6md(kdjtUzM?DL;o(Ch53s=MGUoAEz5f*Lj)z)bbM|@ytx-_-*^i-3Xpj@oiV)xf zel#Yph6On?aLEASCZm2dKA#*l&iUYJIzz@(O!OW)rs6`_W6*4uRE#_Hl8RBvI8(Os z+1J4+<1r3-2UePeu+ns|;REBW#p{h>ZyCSoek^W{P=6G;K4A1lm%FYaP*b(Z2+hMI zirav%*Fvv#Nk#wYP%&f|K(5x0W_w#-MW>2#T~G93E!s)JGoE_*bY#|gIFPDeYD{?! zdBCveK4#Qkgv3doOv3{sJQBa7Tq*>X3*HY#to@tUKEBW#y-0~JF_P1AQZw2K^m0sS z45mGxh~}d5mVGcHd#k<#GtVQ(-i~<^8n*NmBYXxZ9D8i&y0tqL1pj?fq^m>j%v9%0i)y_u)sytWMFLz_JkgG6Y2T z5-VdJb8x;afi#$Pz=T*gs9@rC&{e#Xuj&e=CA=Yc6zy)Mph&eFbXO4x@CM<0Ch6kP zcY8VA9%VN`9|-r>T0@ILc&W8aCYN=fkoL<`>zm3APUtayyfHmtb}aUK&X2D`DQ(ge zKdAX}XiZOWJ%&}37~WugXVibjvSAl4L($Gt@|9{TV>xr)t~syF|NOJJzju(c({FyY z@e}hR=uHl$hfQDZ;J20pAe723`i2jBeRt81)yEp(vCqxIH%)7k-`eco81*-89%MFc z{&k?&(!fO@((dgqToM5L1bV@Cgbv)Yr^|27P7eXZ($M#p1usERNo_YqUBXfv1Wn-m zBiZ_B%>_M$apLVl4se_|{-HpFd1$5cA0UWH&F9QbdofrKxDH48C`ef5U(P-9!cMhM zNRbc(t(++)%!k?D&Y4nqN?WV;RQ8j11!h>vU?jT}oJ0%sl_(kx*5`?4t=F{YR@@|Q z-0!D(T-$};(1k6>qk9zA$9nWr)B4i+mh9(r@>RYJk?1l0(&X9r0mgO~?zI+cs|q-e z^;b3y#k$@fpWhiJBAQp!UeG4T8CXULR{N01XGBEcU z^^@d{>pMA(Y+T^7qjMCK`**7Sz4amR^jd3MyWa)>9l<>5r8?xtBc~GGnNJ2lm9GFE z6I~;}*kM9HU1D16uR2(0F)c2PBqamTPSGpynOdJ8X%2lZA~%tpJMaLL51d_~ z9I;6}$kw6 zts?o9Nl1Sm{7JA-fUBOzWDw>OeyV*20<^yaZx2JwW@G}~NKo4Yh_M@jjt0hh9#JFU z4FrQA!i~XpJp<4H`cSa;FTgv%YnUNzA$8AhFnsK55v~qunyFQEEad6TCHd}(fO61T1_W`;7=!9QF>IfDs@1j4Ok)nV-zRV0cWr)k{6xvjNV}*IA zX?KGInLH8h0rC)vN~3EvdR25dI1BID)hi<}Op_0Pj25VXJvYQ_Xchb|7~Y)wF<#VE zt!)l56WLK*n@0UuiYre37vs4}HLZSz`i05AbY&VO$0DUTcq0Cm1o82h_;>e2uII$5 z*zu!eh%P8s(6ro#ebYVMH{HV>(>?qSvY<_wtI|DuHQ^z?�dc>NOeV&J#?HT>lx$ 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
  • x+Iv^mmg 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 S^}qf*_27Q7^@6Rx?)_gsO#@B< literal 0 HcmV?d00001 diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/gpu_cache_bench.cu b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/gpu_cache_bench.cu index 77cdc3528..45015f77d 100644 --- a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/gpu_cache_bench.cu +++ b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/gpu_cache_bench.cu @@ -1,31 +1,50 @@ -// gpu_cache_bench.cu #include #include #include #include #include +#include #include -__global__ void pointer_chase(int* next, int start, int iters, - unsigned long long* cycles_out) { +// Simple error macro +#define CHECK(call) \ + do { \ + cudaError_t e = (call); \ + if (e != cudaSuccess) { \ + fprintf(stderr, "CUDA error: %s (%d)\n", \ + cudaGetErrorString(e), (int)e); \ + exit(1); \ + } \ + } while (0) + +// Kernel: pointer chasing with an accumulator "sink" to prevent optimization +__global__ void pointer_chase(const int* next, + int start, + int iters, + unsigned long long* cycles_out, + int* sink_out) { int cur = start; + int acc = 0; + + // Optional warmup + int warmup_iters = min(iters, 1024); + for (int i = 0; i < warmup_iters; ++i) { + cur = next[cur]; + acc += cur; + } + unsigned long long t0 = clock64(); for (int i = 0; i < iters; ++i) { cur = next[cur]; + acc += cur; } unsigned long long t1 = clock64(); - cycles_out[0] = t1 - t0; -} -// very bare-bones error macro -#define CHECK(call) \ - do { \ - cudaError_t e = (call); \ - if (e != cudaSuccess) { \ - fprintf(stderr, "CUDA error: %s\n", cudaGetErrorString(e));\ - return 1; \ - } \ - } while (0) + if (threadIdx.x == 0 && blockIdx.x == 0) { + cycles_out[0] = t1 - t0; + sink_out[0] = acc; // observable side effect + } +} int main(int argc, char** argv) { if (argc < 4) { @@ -35,26 +54,26 @@ int main(int argc, char** argv) { return 1; } - size_t ws_bytes = std::stoull(argv[1]); + size_t ws_bytes = std::strtoull(argv[1], nullptr, 10); std::string pattern = argv[2]; // "sequential", "stride_4", "random" - int iters = std::stoi(argv[3]); + int iters = std::atoi(argv[3]); size_t n = ws_bytes / sizeof(int); if (n == 0) n = 1; - // host array of indices + // Build index array on host std::vector h_next(n); if (pattern == "sequential") { for (size_t i = 0; i < n; ++i) - h_next[i] = (i + 1) % n; - } else if (pattern.rfind("stride_", 0) == 0) { // starts with "stride_" - int stride = std::stoi(pattern.substr(strlen("stride_"))); + h_next[i] = (int)((i + 1) % n); + } else if (pattern.rfind("stride_", 0) == 0) { + int stride = std::stoi(pattern.substr(std::string("stride_").size())); for (size_t i = 0; i < n; ++i) - h_next[i] = (i + stride) % n; + h_next[i] = (int)((i + stride) % n); } else if (pattern == "random") { std::vector perm(n); - for (size_t i = 0; i < n; ++i) perm[i] = i; + for (size_t i = 0; i < n; ++i) perm[i] = (int)i; std::mt19937 rng(42); std::shuffle(perm.begin(), perm.end(), rng); for (size_t i = 0; i < n; ++i) @@ -66,27 +85,40 @@ int main(int argc, char** argv) { int* d_next = nullptr; unsigned long long* d_cycles = nullptr; + int* d_sink = nullptr; CHECK(cudaMalloc(&d_next, n * sizeof(int))); CHECK(cudaMalloc(&d_cycles, sizeof(unsigned long long))); + CHECK(cudaMalloc(&d_sink, sizeof(int))); + CHECK(cudaMemcpy(d_next, h_next.data(), n * sizeof(int), cudaMemcpyHostToDevice)); dim3 grid(1), block(1); - pointer_chase<<>>(d_next, 0, iters, d_cycles); + pointer_chase<<>>(d_next, 0, iters, d_cycles, d_sink); CHECK(cudaDeviceSynchronize()); - unsigned long long cycles; + unsigned long long cycles = 0; + int sink_val = 0; + CHECK(cudaMemcpy(&cycles, d_cycles, sizeof(unsigned long long), cudaMemcpyDeviceToHost)); + CHECK(cudaMemcpy(&sink_val, d_sink, sizeof(int), + cudaMemcpyDeviceToHost)); + cudaFree(d_next); + cudaFree(d_cycles); + cudaFree(d_sink); cudaDeviceReset(); - // Print JSON for SeBS to parse - // (you can extend with more fields if you want) + double avg_cycles = (iters > 0) ? (double)cycles / (double)iters : 0.0; + + // Print JSON printf("{\"working_set_bytes\": %zu, \"pattern\": \"%s\", " - "\"iterations\": %d, \"total_cycles\": %llu}\n", - ws_bytes, pattern.c_str(), iters, (unsigned long long)cycles); + "\"iterations\": %d, \"total_cycles\": %llu, " + "\"avg_cycles\": %.3f, \"sink\": %d}\n", + ws_bytes, pattern.c_str(), iters, + (unsigned long long)cycles, avg_cycles, sink_val); return 0; } diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/run_sweep.py b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/run_sweep.py new file mode 100644 index 000000000..48d42bff3 --- /dev/null +++ b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/run_sweep.py @@ -0,0 +1,40 @@ +import json +import subprocess +import csv + +BINARY = "./gpu_cache_bench" + +working_sets = [ + 8 * 1024, + 32 * 1024, + 64 * 1024, + 256 * 1024, + 1 * 1024 * 1024, + 4 * 1024 * 1024, + 16 * 1024 * 1024, +] +patterns = ["sequential", "stride_4", "random"] +iters = 1_000_000 + +with open("cache_latency_results.csv", "w", newline="") as f: + writer = csv.writer(f) + writer.writerow(["working_set_bytes", "pattern", "iterations", + "total_cycles", "avg_cycles", "sink"]) + for ws in working_sets: + for pattern in patterns: + print(f"WS={ws} bytes, pattern={pattern} ...", flush=True) + out = subprocess.check_output( + [BINARY, str(ws), pattern, str(iters)], + text=True, + ) + data = json.loads(out) + writer.writerow( + [ + data["working_set_bytes"], + data["pattern"], + data["iterations"], + data["total_cycles"], + data["avg_cycles"], + data["sink"], + ] + ) From 6d28eefc61c588770c66e3df6a7816e0bf7aaa9c Mon Sep 17 00:00:00 2001 From: Jessie Li Date: Wed, 19 Nov 2025 20:20:13 +0100 Subject: [PATCH 51/58] Bump Black to support Python 3.12 --- requirements.local.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.local.txt b/requirements.local.txt index 7f8cde167..bb007e6d3 100644 --- a/requirements.local.txt +++ b/requirements.local.txt @@ -1 +1,2 @@ minio==5.0.10 +black>=24.4.0 From 55960b7a33c755f832e396cc20f22f167d0b98d6 Mon Sep 17 00:00:00 2001 From: JessieeeNotLi <146530955+JessieeeNotLi@users.noreply.github.com> Date: Wed, 19 Nov 2025 20:27:43 +0100 Subject: [PATCH 52/58] Add benchmark documentation for GPU Cache Latency This document provides detailed instructions for running the GPU Cache Latency benchmark, including system requirements, build steps, and example output. --- benchmarks/read.me | 118 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 benchmarks/read.me diff --git a/benchmarks/read.me b/benchmarks/read.me new file mode 100644 index 000000000..af17c1c31 --- /dev/null +++ b/benchmarks/read.me @@ -0,0 +1,118 @@ +# 📘 Benchmark: GPU Cache Latency (050.gpu-cache-latency) + +This benchmark measures **GPU memory access latency** as a function of: + +- **Working-set size** (bytes) +- **Access pattern** (`sequential`, `stride_k`, `random`) +- **Iteration count** + +It uses a CUDA kernel (`gpu_cache_bench`) to perform pointer-chasing and +reports: - total cycles - average cycles per access - sink value +(anti-optimization) - all returned as JSON + +The benchmark is integrated with **SeBS** and can be run as a **local +serverless workload** inside a GPU-enabled Docker container. + + +To run this benchmark WITH GPU support, you need a local Linux machine +with: + +### System + +- **NVIDIA GPU** +- **CUDA drivers installed** +- **Docker installed** +- **NVIDIA Container Toolkit installed** + +Check GPU + Docker availability: + +``` bash +nvidia-smi +docker run --gpus all nvidia/cuda:12.3.0-base nvidia-smi +``` + + +# Step 1 --- Build the CUDA binary (optional) + +``` bash +cd benchmarks/000.microbenchmarks/050.gpu-cache-latency + +nvcc gpu_cache_bench.cu -O3 -std=c++14 -gencode arch=compute_61,code=sm_61 -gencode arch=compute_61,code=compute_61 -o gpu_cache_bench +``` + + +# Step 2 --- Build the Docker image + +``` bash +cd + +docker build -t gpu-cache-latency benchmarks/000.microbenchmarks/050.gpu-cache-latency +``` + +Test: + +``` bash +docker run --gpus all gpu-cache-latency ./gpu_cache_bench 65536 sequential 1000000 +``` + + +# Step 3 --- Install SeBS + +``` bash +./install.py --local +source python-venv/bin/activate +``` + + +# Step 4 --- Deploy via SeBS + +``` bash +python3 sebs.py benchmark deploy 050.gpu-cache-latency local +``` + + +# ▶ Step 5 --- Run via SeBS + +``` bash +python3 sebs.py benchmark invoke 050.gpu-cache-latency local --dataset tiny +``` + +Example output: + +``` json +{ + "working_set_bytes": 65536, + "pattern": "sequential", + "iterations": 1000000, + "total_cycles": 46387045, + "avg_cycles": 46.387, + "sink": -401872096 +} +``` + + + +# Step 6 --- Run standalone sweep + +``` bash +cd benchmarks/000.microbenchmarks/050.gpu-cache-latency +python3 run_sweep.py +``` + +Outputs `cache_latency_results.csv`. + + +# Workflow Summary + +``` bash +./install.py --local +source python-venv/bin/activate +python3 sebs.py benchmark deploy 050.gpu-cache-latency local +python3 sebs.py benchmark invoke 050.gpu-cache-latency local --dataset tiny +``` + +Or run directly: + +``` bash +./gpu_cache_bench 65536 sequential 1000000 +``` From ba8f8002162a33255eb2c2b49d6a7c988cb0df1d Mon Sep 17 00:00:00 2001 From: JessieeeNotLi <146530955+JessieeeNotLi@users.noreply.github.com> Date: Wed, 19 Nov 2025 20:29:24 +0100 Subject: [PATCH 53/58] Add readme for GPU Cache Latency benchmark This readme provides detailed instructions for running the GPU Cache Latency benchmark, including system requirements, build steps, and example commands. --- .../050.gpu-cache-latency/read.me | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 benchmarks/000.microbenchmarks/050.gpu-cache-latency/read.me diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/read.me b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/read.me new file mode 100644 index 000000000..af17c1c31 --- /dev/null +++ b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/read.me @@ -0,0 +1,118 @@ +# 📘 Benchmark: GPU Cache Latency (050.gpu-cache-latency) + +This benchmark measures **GPU memory access latency** as a function of: + +- **Working-set size** (bytes) +- **Access pattern** (`sequential`, `stride_k`, `random`) +- **Iteration count** + +It uses a CUDA kernel (`gpu_cache_bench`) to perform pointer-chasing and +reports: - total cycles - average cycles per access - sink value +(anti-optimization) - all returned as JSON + +The benchmark is integrated with **SeBS** and can be run as a **local +serverless workload** inside a GPU-enabled Docker container. + + +To run this benchmark WITH GPU support, you need a local Linux machine +with: + +### System + +- **NVIDIA GPU** +- **CUDA drivers installed** +- **Docker installed** +- **NVIDIA Container Toolkit installed** + +Check GPU + Docker availability: + +``` bash +nvidia-smi +docker run --gpus all nvidia/cuda:12.3.0-base nvidia-smi +``` + + +# Step 1 --- Build the CUDA binary (optional) + +``` bash +cd benchmarks/000.microbenchmarks/050.gpu-cache-latency + +nvcc gpu_cache_bench.cu -O3 -std=c++14 -gencode arch=compute_61,code=sm_61 -gencode arch=compute_61,code=compute_61 -o gpu_cache_bench +``` + + +# Step 2 --- Build the Docker image + +``` bash +cd + +docker build -t gpu-cache-latency benchmarks/000.microbenchmarks/050.gpu-cache-latency +``` + +Test: + +``` bash +docker run --gpus all gpu-cache-latency ./gpu_cache_bench 65536 sequential 1000000 +``` + + +# Step 3 --- Install SeBS + +``` bash +./install.py --local +source python-venv/bin/activate +``` + + +# Step 4 --- Deploy via SeBS + +``` bash +python3 sebs.py benchmark deploy 050.gpu-cache-latency local +``` + + +# ▶ Step 5 --- Run via SeBS + +``` bash +python3 sebs.py benchmark invoke 050.gpu-cache-latency local --dataset tiny +``` + +Example output: + +``` json +{ + "working_set_bytes": 65536, + "pattern": "sequential", + "iterations": 1000000, + "total_cycles": 46387045, + "avg_cycles": 46.387, + "sink": -401872096 +} +``` + + + +# Step 6 --- Run standalone sweep + +``` bash +cd benchmarks/000.microbenchmarks/050.gpu-cache-latency +python3 run_sweep.py +``` + +Outputs `cache_latency_results.csv`. + + +# Workflow Summary + +``` bash +./install.py --local +source python-venv/bin/activate +python3 sebs.py benchmark deploy 050.gpu-cache-latency local +python3 sebs.py benchmark invoke 050.gpu-cache-latency local --dataset tiny +``` + +Or run directly: + +``` bash +./gpu_cache_bench 65536 sequential 1000000 +``` From 963286051f3cb7fc4897e8d3803233e8e8bb74e5 Mon Sep 17 00:00:00 2001 From: JessieeeLoki Date: Fri, 21 Nov 2025 18:28:13 +0100 Subject: [PATCH 54/58] changed to match repo structure --- .../050.gpu-cache-latency/Dockerfile | 18 --- .../{configs.json => config.json} | 6 +- .../050.gpu-cache-latency/gpu_cache_bench | Bin 1017904 -> 0 bytes .../050.gpu-cache-latency/gpu_cache_bench.cu | 124 ------------------ .../050.gpu-cache-latency/handler.py | 31 ----- .../050.gpu-cache-latency/input.py | 30 +++++ .../050.gpu-cache-latency/python/function.py | 115 ++++++++++++++++ .../python/requirements.txt | 2 + .../050.gpu-cache-latency/read.me | 118 ----------------- .../050.gpu-cache-latency/run_sweep.py | 40 ------ 10 files changed, 152 insertions(+), 332 deletions(-) delete mode 100644 benchmarks/000.microbenchmarks/050.gpu-cache-latency/Dockerfile rename benchmarks/000.microbenchmarks/050.gpu-cache-latency/{configs.json => config.json} (61%) delete mode 100755 benchmarks/000.microbenchmarks/050.gpu-cache-latency/gpu_cache_bench delete mode 100644 benchmarks/000.microbenchmarks/050.gpu-cache-latency/gpu_cache_bench.cu delete mode 100644 benchmarks/000.microbenchmarks/050.gpu-cache-latency/handler.py create mode 100644 benchmarks/000.microbenchmarks/050.gpu-cache-latency/input.py create mode 100644 benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/function.py create mode 100644 benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/requirements.txt delete mode 100644 benchmarks/000.microbenchmarks/050.gpu-cache-latency/read.me delete mode 100644 benchmarks/000.microbenchmarks/050.gpu-cache-latency/run_sweep.py diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/Dockerfile b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/Dockerfile deleted file mode 100644 index 4fd7ea2cd..000000000 --- a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM nvidia/cuda:12.4.1-runtime-ubuntu22.04 - -RUN apt-get update && \ - apt-get install -y python3 python3-pip build-essential && \ - rm -rf /var/lib/apt/lists/* - -WORKDIR /function - -# Copy benchmark code -COPY . /function/ - -# Compile CUDA microbenchmark -RUN nvcc -O3 -arch=sm_86 -o gpu_cache_bench gpu_cache_bench.cu - -# If you need Python deps, add: -# RUN pip3 install -r requirements.txt - -CMD ["python3", "handler.py"] \ No newline at end of file diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/configs.json b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/config.json similarity index 61% rename from benchmarks/000.microbenchmarks/050.gpu-cache-latency/configs.json rename to benchmarks/000.microbenchmarks/050.gpu-cache-latency/config.json index 8505c8e74..0ec4c3353 100644 --- a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/configs.json +++ b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/config.json @@ -1,7 +1,11 @@ { + "timeout": 300, + "memory": 1024, + "languages": ["python"], + "modules": [], "name": "050.gpu-cache-latency", "runtime": "python3", - "handler": "handler.handler", + "handler": "python/function.handler", "dockerfile": "Dockerfile", "data_dir": "../../benchmarks-data/050.gpu-cache-latency", "datasets": ["tiny", "small", "large"] diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/gpu_cache_bench b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/gpu_cache_bench deleted file mode 100755 index bd77e7514d0eb2759da7fac6ccd64c1f84e247de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1017904 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 (!U|8DMKvKrc+56_Wk~+z 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�>B-d-FcaZO4dk}y7S~=m3sakB| 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�dc>NOeV&J#?HT>lx$ zT1EPtyVV1TUEgQ&Afg_u!2?GgT%#VW!-F;Q;3DGaK`|s))|;7!4QGSWJvPo@zk`hj|pxwAnGLBM^PrG8dkrM3AtKe&luV=y%H4%#WTIUex zOfRri&=L4S)MhA(p{|nOA=j}d#Z~)~G9}i9t}!Sk$_ba28&IHI{)zkn`?(5oF!~h? z3T4lqf!|(?7ZTaXF%CnoY29A&Fh91rzT#N+R<4%Djpnk32B*>vAJ07>$e8CqEC+{fgq#}z4)dq~q(qy6Vfdv?Lx8%(*O zzT!?0S!9F<;En@v)JI;8*)zzm91ozUb2})&0L6ohh|yskE`iALWoBfSNGVKwAm#zb zr^F?^;rZQ}fe(0?8dw-X(PO~VV5gqM3At)7_iPByKx1JVI1pID=F2=i(OJ~^1o=XR zW`%Pk_!Q>PiT~rrXaUw@<*vdYtflfhFWfD1Hn>RV5m6iCz-a-y@60m1>Zk7Ow`a1E zK@V3g^2*h0NIPR4ZLZbM8}}l@4a31zqh$=nK&hz>4)#Z65b;H94j=)0NS}axcLk|x zu9nF~b9GlFfGG?1#-*m}ZPPl!Yn@PPgebB68$XKf3QPjMRw3pyO05DGsm=krUdr%e zygAV>?rXxi7^s?eRhYe;ffkWAm20?m9)Hx zUYWojr(=hZ&8Jl^7g=Un%h0y%fT$6d4zJBER*tz9j-`fvZTR5mHt&3KuoXc?C)aWfa)db{bdI znh&_z)T9OcQgRn$TOIPl|A&6E3H?Os;##{&Yj}DX`i0a8bGGPB@LyAP0@d6Dyub-= zkU3y@H{5ahIJbgb3a>#?ckm-J_a2c4ui@)V`!tBC+a-r_^DB}%T~eQv)bX7t!1%s# z^W%~#Z0<}$YQR1b0_ql>%Jn+OM&{b`@)eSN8U&Oodct@lsdCSdq~Q=ycgvd-h9OB2 zbc`e&w*zGttDG1O~V@Aw$4E4g*=EaWl2^7-W|wra z46|&)2&5`rF%nY2#2D0;O!%Gq>Ngbd?gt9jES|7mBE!6un4xN!F`15F3<;6B6@Abs z^f^`=vleb#1|L%eKwvWq!z9k{>CZ$5jZdRr*Buqxz`qY{7PrAhz)z1&!#Bi+o{R8N z07La#0tCgPMcQ3`_a3BNcUmSZy~6$Q?=i@jw(7JhmB+9}=BiG+9I0-nRjGeUgk!EG zt4_=02@_&i{9Te%r5&13d*$ zB-lXw1pmi}4c% zVRw{<2g5TL*tWKOIt}u)vQf>y6;f{hfk&B>QZ*l4q-!_oVdyW2?0^Z5RWB46^*8ZJ zCo}vNo{$EkzK&0zL}310j)x>fL=NUT`(B0F&OCVXN?Jx0D%}MK(^675twunTw=V@i zUnKybl&pZ%PUbXbE_IH&3(bV$OQTn6x#k>q2Nc{1xKr~0r|5RvbL||ZUVJ=Fv`4JE zr>#ArBYQ?i>0-EQ;2d2nT~GWKghGAC0<(eVK8=UgA_RvzV?i7r!wfKzsyB?1+MXs2 z)gmUkx9-%#V9Uxl{id}JakpmSBID2VSi-)>tXHtOp>_|c?rTFdc@*c4mr`DWJ-Ge% zPx@7d???Kb@;d}?L)q4 zHQqyvt#MqxG8RMlq7TgwQecVHM{ZyssRF8jN=L8e`g;) z?#jzYA3pwkMb`TOb;cS>J zy=0uRnHXRkKvH$fFJ^2MFvT!=CFc$`_O>T2T@?hyL+uLuw*|LQ5RhWPfJ`}7dg*V8oTI5G1#<7hw z3iYg98bBB;>+|!pJQ!|w{mw)Du(eS!=?>V9n^g@BD#G&%v z!JxnKFPmEJYIqly@jGAUcQSAU3iN|`$v?UV>PPo)h8Kc`(Oa>;>kCA?&BIHk^$8qR z%EY@XWB>=ZMYR`;C^KPZq!sEz$_8~duh&}Vww&9aonzR#cK6#+x;c7r<%UYQ(bl2( z(WD7R=F!VZQ@PJ zxe?;&OLVYtc;5OpxT6$%F^L`)6Icb#wSVSkHMhK@`k5Koxr-F@axj2mV1WpBlaeC+ zda;;~T|Q0Pq~a(RLV1poP+@Bodvr04);(HRNxyX07m!q0$>%&X4euyPmmuE}iFP&L z2DNy7O)2BBChn;7p?@o38@ErlSs#G)ka!=>t>(L`X$BtFAHt;?9R`ACPyEK(irsPH zKc|;^y!mK(yb%|9yel6!m#ozHLIUDLAz!c|5Csdi2O28p9ohY6HDH{x2foiDCavLQ znc_i|;XW*kf~3Ecy7z&&3k`gLr5g2EvJ6&38s~IfTJVnOBmlo$Ku)0)!_E}e9I@vD@ zD-$dJ7Yjng{W4X2RC2|C0V{|nxhA~)>Vc>*^h2o;E&-#Hx<2q9JM}`_h>9MSjb7_W z^e;BD+qoc?VtDg~$_?_79>%;CI2Q?X;xTtl8Gv#;p)IXG!}o2=lk^Yw`yPHvfcNX8 z03N>Ax%vRbW&>OM5hUeNbo(#zzpV0qiB!q&M}9#1GIP&nji%u%Ss;yg)E9oxp) zOBDdW#Os#C^T>+eizVw3kkgn z&AszbshW#%VS{?U6A~KMvbL`*;Y5Ilfa&2Imnlm`0v<|!^5gsc2Ub}SvMY-sA6%iT z|4=>t;Yd_}j;ekIeyi#!U{U>hc!0X$okYAyWuvP5idfzMkG(Siud=ur|3#rjMH9D{ z)}>bkg{tf-5f?%dxK|U5EJ|xFT#^e($>v=`aA{FMxlPkjYx~*HF0|FJwA$9%MOs@0 z7tmVkzAspp@}_a2)e1^A|KFMAedoRRCfE=AJpb=`$iv~j?<{9#&N*}D%*>g2MRzEN zZDk~e(AH0mq_uOC209+^YV*7j{s@;?XOFl-&rLCle;^s ziq-m1t-o+>b@z#TXv9bB@}_u~Yvg+f^3oOZnJ(n=Jx+O(_Hp*$A&~E15xXG|N@9*dx4P-aXkeol<(mdJ@Q>HvcP%8Qh6dxuCy{LBlL~;-y3cNxva^N?Yc}%KtHr4Q+{-mNyrLIzgRB4k0EkA9#R7XjL zVapi=+$O?cNW_so@Q*e?CXT@~A&mHKs{WZ&?HcT>0JcTF+VEWiJZd&Z25xmSAR zE5_8~Ube8Q+uz1fa;+};ex4(lM{X5T^!x+!#mvusYR(hf?}*u#boLv_B79~E%-c(0 zc@-0?2YLQH>;7WtVjHZ#onzGz?^x=LKGiH8=1Vd+NvZLuI`@D!blqZ(*2PqrVk&Zv z*5)>P-#J1kB_;h`_S(-wvkR@1@VrLlz29HaPf_X$C_VmRzMS|prZ!_>EcebFh9o^A zT=wcnks4W7EjTnTBVZW?C_z|)AgFPp19grrmuw+jK1H~F?GJS7rY<8kcV-?64(-Kr zTkMg&$4J;a%GxiuPdMl9q}*Xru6HxtLd@mU@=WZX;Nb*um)a<3H=#Ls7R8xTs!TY(Da7wO?JAaB8Tc?SnW$bMV!d*`U@0qI zaWN@my1`O>gIxV`iM}Fcip#BGGWT`b3n@CktQ5*hS(gupr_Q;w=q}xPsSpn<2IIjJ z->X1sA$a!p5;rAQ{$3h;U?NuCM%G`Mc$HrMRS?!d<661S=Z^S>zYLa3P0Hf3!jL<7 zcsw^Mo?D8)G_!-6^5^2EQ+s20tClR;r*vh5SiyTSelyj<_O0Q+^7~U43g_Z5T2;q8 zTQo4a%WArYb1OkCcX)P;T>3F$AwRIEF(h=$s0{>^DIpbRyZNs}yu)ca^virF_E3Wk zpQ32lQ%(6Y4~lh3J#po_V^Ewk3^jYIWlITbVa`!o((`!|>P3OCNab#XDC)K65+aN} zNk>8!#G>vx{E^XAO?K_KtJ<7!EAQhT)?1+5o+f${S@-v!V%>xHi9O_To=?bk=HyfN zExr6fa^mOAv9LSXc~3pdjYM2|#1%_}o~r3OpoY2piuHng(9^NW7vU`+dxJIQPn2FR zd+Ie^O(iwuuP?cT5a#ZBN<=^mPGlCbE!?mL2kuiRNwvIdNLNw`ZBhHuNHqmeh!p@ZZ_FM`!yI&#pzRRBpl3w^TTsl+N zeuwgI`4jJMqEk4_0jMz|Z2-j1x@M zHOc2g^z=>4T`op=+~%7sYbJP;#u0fflB z6dScU-d(|gvMjR9c~1HiBJv&wZDhtZiam!@*#X<^MMaT_W-XWc(R%jeA=8ktv`P^| zgjn^fO+D{Yfttw^N>_eO9&$(bsM$;Io!YMR)GU0|Q+(w!$|W+#ZH;YsXK-xPA8T`b zfkDLoTQa(b&*jk#?)((XbL&ACUjMA=I{X*JFi|R9QG#iM=HMo(StyRH2sWoH&g$zu z#>g+5q*_04HO|X}&zd~(=+evAA|$cy#z7n+u0d%&E1E;3vldUC$p@6KSS>;{=;`?6 zR7q{=v_HmRbbJtZsy$V@{4$jlDc^=u&o~w%SzQ_w8|1}~yr-sn_+B-fO1=C7$=-EN zi5yW~&e97C_rBP+M`{K=gGo4e`AZy~`5r8aFW*pBTYg{Z6>`Z{5oD7TGTHsp$Q~`d zLR}w@(|%?FhT9&Q(SkziP(CiGMy&g=NwM;$OE2f>t;$)$4NzA+W(w@L9MOS(IpQx; z+nu0#FO^;)dw}us3spg-l@(>WwWgRj@>Wprdo6x9@|i25XvR-|Ttd1P(*qaEjv zW~@mwHjL;~q#^Mm9VgJLDLr!CnOEn{pOeJppv3#hZD3#dnjARCwkTck2`DZDDyL7R zWx3bn#1Cm%QjB$fntuAXL2zF$OrR)6##pqA_Iw>GNquYO$cUT@jF+>VCeD&ItPnyM zTu?W~2d%F;nuS5xS6hkE#{3K)BR1j>*W+$&Icsg3)N2Hstl*4_p{lXD#L8xx*^tuG=L$76jt?f&u5a^XyO=vep z{BR)B*xDSu`cLs~n`?4AYL2{*tDtH|y_P*mPUS$&n&FdbyQ}u=JG*;gS?!VU*XB0Y zj@p*_1%o2aI^NNgV;+Z5``&Lclu`+`B&sg%^9HH*Nuc-k78wb}YXs}2r1!glJ%B!7 zKZx1n9 zb>F&-%(==k@23a{+xw`nH@shbQEIrwiwogUkALUg`c(S%h+ZFiTg#gqqs~2s(i_1^ zom;RPULEF5W;TzkF+VK#=(W#!`}~sWQg^m*`TKj8UfHcGeaPd}Fkib*yPcn|p*L4` zoq7wBHWY_PSlOppS(ST7xcKVjR0b}VuJ~`sD$BTB{kV~5Tq;JQr=F`hk}GrHh>zNo zt&f*Ko0=x>j+uQ~#uci!{FNEyH8+dO-kLXFXntdFE2mhNprQBBo{LPsr0lc0Po0R} z<26CJ-X9x%t4y3tHKTTTGYO98Uhn;q-j}%Suj(qXF@l9=aL`}3Aa*--;$L8G&8#kxE9FpFZ|XJFfM?_iErEO~a*kZZ_DhmZ6=sLNyia;YHa&)a%QaKFu9 zazR~+`V7(Pew)wXPsuDLAwS%|bD+piZb+rn z2iiyOf7**=-6#I*X!$v9$Z2xF&GWo){}b7Iyd`4q9U%P`A{--&;>^V^>*T%MOCNyK5@rM{W{cNN-_%}Ocj`&PTMA2nU+Ztv zpVa*RG2MJrxHKF2)CCGREFACYMk{{ZR)VN z9F=M1$e=vY)+l|}AGkjnn|`zRx0gUA{c4l$SNZCcmI(XnML_6?nHFhtW4xT?BHD5X zUD=XYta~E2H2yPnhRm&^HQj^vvLiwEc#T0-$$R!i(QGmi-$R<9RIR)HWJ>$z61u$X z_f@ZW8#i27Tt?4RS1?fZ&EAlAY^AfmQAcfSbC1*xdWl(N$068&sY%`seXRIS50V76EaxCIGlS{Cx{KYS1t2~*#K$1r|aY}@mkEtN)<@j6U#9Qzes!*Kcmjn?ZIGW`y*d&gfa8cUohzcRw6gdch(Ih+ z0--i25Qvf`=hbu{jQ7lAsTpeFKh9h1=-F5k#)mqcu0Crb%eEXQ2r4jh(i z@Rry7@?N@;dKQSsY9k+yW%K0&p?2is6>&^ZLY@7!OjeMdtu=#QfN>p%V7a8`ddtBt z@^Nh-A7vsRw^9uwA7Y)Ws&XGAOf_x)1POXBQ0fZ#6x*ZcITHHg1CBIzS^1$KQnt59 zvZS>994GDK+K?*`)$&uNdm%1$N_zGd>2d74{Qa+;y}!xIrn`TdpFTfc%jf$tp0k8F zXIAMgtk}wi<47!UF(9EFJ6)wK?vxSZ^c(v6x+~?pp&d6xaI}-18TXW!REdJYlG)}R zFJl6dqSTAn-Ed_}={InIe7hpY?DZjnrmSFie}o5wKQmD&l+r6@0hu9w2$Ng{RL_g$ z0Q>wI-Lp&j;@h68J@O&(&RQw^STb8+h@iwi@1o}!C9nU9lAe*_y>09`?P}hA$n4X_ z0y*(Ce!7NU&V~3_hy~JflI1J)%T`ug_OiYo)E(5NWzL{}mRMi9ftdqoTt(?O?oj$6WOwY@aj9r=-z*l*!CBdGs2pcf0BOh+Y_V|wc_XJ z07|Bkizl)t`CACE*n8|pqHh$czqJd;)Z^x7H095~pyw_UNKd!>?mm%!J03EklYXg2 z(1^mHDwh(5|4!^aksxnlNB$O)-M>@a*Rg-bJ=}Z0l%wpR-aA%H_LUE>ldnu2c5cRBY| zN_tHA99TM;=sv+oH?mc7ig!v(Cv}+E~I#;hu{T zMJK&oJy&u_W>#|FJ-LJX>))f`3KmPmJ@6Ip8;W_kJ2Rh@9`z$(Is6C)5V)xI!ML~4 zsLY#8ETJF^(#YCgXorOQdC>^hdABfU3^e=K9*tlMOgr2Mv|4&J#^fXrs^ zpH`mt(#ZKGF8i9{ITiZQsR@@dHSw1dOB%>FX+F=H7cWDgut?!PPBZ-gjr(xZfev(V%bxr;tera<|Lz)Q@G8v{!uLgu zZ-U<^Z&L~)dz3+WyVGtTrPfC--jMxg*BeCXM3=vd=_e*L{@ssQKVB3j4pc`Y$t&06 z6o6f@aydzIPyRa>8NAuFLuu%L=N1F)Eh!!PZD_T8d+TqpZ2B^LkGq$_`WqWqL`FyJ z!}~se-K}V~8Q1$;C86FUpy<6@*%#guNoh+_`4IW_wk#Yt{z^rQqWOESg$IuQ5`0jv zn$U4_qg`fyz8prq(RI3Bi>b@VZ;rwc?41mbSog*Fxt-tBg(`CDt8jIHvBcYxa7lwb zMR%mKT7MR-50`lNHjq-U5C05#WPO;Ous1gDImr7t@~Ut!F7{kSL)ov!(YCuyR~g1$ zN(SyGEL|zsSydj(s4N5H2x>@pw%xoRV&3PQ_aWxJ&b9yRfI zoA)yF{%if7S=M#FRNnh15}-#9)e8gtrWdA}D=|!~ZYW34L`Q1+-@b}=cqfxvjJ_1> zrj&@!GZV%6C7Y(G`wM<63&NY0E#rSS;P5S~VU=At!=m~)^#Sw$g7)&X#d{6y1O?eS zIb;E=`l3jl@;YfeBQeV{7syUGM+ekZ3`(Aq?&$6D`6a9UlRzTK9weU(6P>*4bQ@Mn zL%82lX5@Ge;PK01s9G{ooyYsBYRPMvk91X*$+=LyvhO|qKeDW!5x-h(m=JUENKf<~ z4|U!`DTz2rV=hrbc~*W@ag^iDLL4l*D>b@3@#j-`uC#cL&^124=Waq&`xLFoPoFvx zw6Z)9nC<9)!S8Jm+~t+S&Le{0{_YvpFJ6;{^dtWWy|H2S8e%!VmL){x+FI3Ky zdG{uyhaNz8S6W&q9*nP2AMc3;1M7=h)No%^UtoskI5;n8ek&wb=U}~)Xl{Xm^6Teq zp*-X(X!*7${rWRIk!J86QyRhVi{6iEF}8}n$U0V9CD$!586g&X%i32sPA-3StoKvW zqNVixHR9@1Htu1$au^5pc<$vmenIMQ*+N;lkxPpX^c|$+Au6%nli!!Qqp`Qv%NpiK z2u2XUs_2wSdL8rSQkw1y|GE6H?`4L_y);WiKyR0fqldgTCK5>>BllmekC#80W}A3( z%_!~!?Av?El%_s0`@L6?%ibTtZ|=<+au?}U>e_Ma8FG=6tzcy^~k4s@E2q!vXb)+nbT*P zgAi{r6itJ*zq^iYLDulGubu!;?vC7$^VOc@klFmKe7JKk)3Vj#JTL2A*55+oQ%0h~ z=j}iT{O&qmQmbocMz+_E246hBQxN6F}G0_?X6V;CMUPf zVIk?TSXVmQb@9kt7>8u zGhK}BtEqhW>=-Roc(ZGJ?+Wo#@6V|7NUW)dHF&=WhDgXIHC@NlbbX=3Yy1plbf5NK zmO*?YA4rrVG%tFoVbD*nfutZiev5pvi}S5sIUPj~w%wgM%G{<({RT@tv7EvesY-jR zVcLAw807TZMP=&hdg0S7NJ*hX2jg&C|AIIB+j{@1jovQusWJE7DDr~;teV#UiQ3CF zwoJ|+sdLFOjw*MZ%i0KM$xyMBqW;5)xcjs@G>3C@H+;-CL*LH_uhdZjoZ2^ft?x-w zXi4-Bl&c6mnI1_)+{+}TKJl)h!)0rlBEX&#FV_o8djBlvgPzS$LicG;^5Z?{%WLLS zYT;;uTKK+ARJnJP<|Q5|-rX?1V!3?(G)}pyaQWm1?N;aOjlcd|;*W)|(_^wGEf{W_ z%W@N&SS1x*;%#`^nUtB^NGtE=su-~tS9})XUN#9m#Tkl|MbP~o7o7N+`P+GC+EutJYJqGU$o30|JkWE#p|H7sY z%chor*z^t6ON3sqsYck81_5l6eiD~nX!sSwUnZ8DMR$3_dqD(H&rHJHLSq&1X~MY< zpFS$JvwZrNpn*?cdv?$>Cc!F~Uoyv^GfVe)Go2EJBL2^6JW|e} ze0C!Dub}tD#ijaj?=)&HSf#ev(grwf1|^`6YF2aPxdkwe5nKBr9X&W`DSjf+>*h$vrBU44RzDww=g@lX{wq5 z%;7;s1|;IKSv)i1%JU9=f!(I5azP7*iyVKd>N-Zg!OZ!{bCi9P{epCXugui;$c4rW z#F^OchI4ej3C*@*ngw_NVOmuqt+|R0JJ8HpcY}Z(={xAvdrh=gYL$AHTygrx{Ou48FC6Os%|N-&Hb}?n3OCIkF!bD9JJ|0iQy=EO^=-*mr=${m} zd~o`sD1;=z@`}Iz;axjJRjG7^oM`Y#tgmUIziEDPsswU-^H2`?=i?X~_>A6l!=n(H z>n3g+%&$z+wrs3AIEo#0$ZrAAThp#t`&Il+U(_jGaTr3u65l5CH6c0S zD%Zl(c0NNRM_hU0R1~^*1RJLiq?bmrQo$vxlxGDX@Xv{L?HTKuCB|2*>#Q=g?=U?p zF`pHx=J)_hhb+s>H!5(6nj#zaG4Fa>8$0cdQkm%8U3$g2)Jm-BNhl4i-@IQcQI&&$ z67)}z?llC7uV+l|K*EKn&-*TDDE0P-FTt?+?X8h<1W%Vp+=n)!!`(4*9${9J-W0kRg&AFwu`Q3 z>|8roE|mI6#cxHvt8#m--6OOAw9;D+-hbh=+`*-sHrZqCpv>OWN`G_M{?k?+R$9~j z`{8vooI9TOZv=DqAqU7$uIDy687f`bOjNy_7;w~DyRhueGub*S->N=SB43TD?f#LZ z2TM&tVYzQn7|WI#cHLV*LFd*h_RAa;Uj&6x5J(~lVh9XUuem)bjDWXll%z0;S6zsZ z7YPxWp<8rKW;;&0|JCbD?kHU;2aFU=Wg#Na1RKuM{Y374kz+=%Fo?X)iF{M>@irNF zyjQ8CbS}vxE{J5(5sx?#viK11ZoyBbfsZk8`eUNcU+q^d_rT611NxAmSGN&wW=HmbC*Y)Xj;p%== zGTyE3!}134+;hyobieY_8gJ=}Pa(*?_e;eOtN4S6m>$DU z^$roeL$>^_45>z(eo~G6OS$V*WxSKj>yKps8w@=wyDk|)-_(l{!e;L!p(i=6sO&oR zm{82UI;M0*BUFlGgEQ;kP^jYLE#^KB$jzwKyZ`FUD8{~+vSTvG85;&=<5h{q`aP4V%`(j?_( z_L7CmD(Lz#d>%6YkP9sqFAxQ@Blm=Ni*&7AWr^%ZvQ!yLf8Jop@OQ~@M!n5&h0cKE z4b8?s<%?>}nB~162T_+EGcNG9>NhiH{DX?BF{4K^=ZzV>7Y-M)eyqoX8@%DtEi~rr z{~-Tn{8;1dOGNLte0?F(FW)nem9g&AW~(N$Vyz}MTOk@ORv#I-9G>SkDgG-9pOX=o z0?!LE`QpGtrAkEW+$dHJJhyX1E1yE637R>gi*S-1p;;rD&O;f>Of~zIcS)7vcJ^l^ z$v($=_-jZ{pWH3E?YZ9X=I-wOfsDF={ob<}>NxwgJ-0$c_x(Pq=)T{88h76F*Prv( ztMlJwmU5gjt%Q*>^*e>iuUx;e>bSm$yMt@|@$%<;BKD$T_^9C?8~G+RA6XeB|Lr0F z?HS3OLEsX#_@#CXm;ZH8X0MHd2d857ci_as(*p0e^e@OMD>zrH&tI4RW&_SaT3!u@ zdN&%q&~q(JblNLb=28v$VrTAgmDuZnB2a&jTYHdc`$G3uYEAn4)y$98Puk!eEmFy0 zMtWE^gI=us&dkB0`)?pzd_EZ=w>`c5kMEtIdr)^-i_e^2+TndoFyuDp?)H}O#8l_# z(`yvTTL5&HDX=MVnI_(EEL zO@lnk{UpkT=0zL8`6w0ekPSH01gy99SVBLE?r~u5s^4H)! zHxDnrE2alKWO7PG@vHZ5zW$>B2FgI@=jbyg=dkIrSD&OxE9fVjN0RvjlM0T=iZkyN zIa3nLoLo8z^R{#phdN3}%^u!fI_lfQmyxG*)OEvGtKS=kuTj6hQuo@Ij{5!Z^}Nf8 zsHjZuv4vL*m*b6c&7L~tB$LzJi(+8OS^&R8$4UmuEb|6U75U>TlWSsf5g!uy^J+ty zyEBVo-CtIy)Ey^syM($@I}Z)V38gud!6}gEy`Mu$FdoWmOWGRqm2N;1Vb)p*YWp+S z`ak5_Kcdgh5~0@0?6fJuyH09%w|9W8-Gm|DH@MxGZDi;E`%oD<=MR4h!=2 zsmw<;PuPr5%15SWO1@WeQmHTVIq%*xl#MP$-X@RT%|n>wZH#jng4a#ejqu>ah{4AN zADg^eq~CR)dK?={Vgjz^b?U~!$C(Pbr$RU{2TEy?98W$Y!1gF4HrSeU_M;=cx6A(R z+Zh~6ws{l$e4D(zf_&fRo;r1Kag#Sr=bIeqy>i?$y~}m~kZbBX?|X+LPy55uSdiFO zxyNLoW5~_CcGbmVT~p?&kK<~6C|8rsykpE&swZNmcR972^o)bFAkE&kjqLVtCIuim)hdliUmP1g|bTCTI=QRZMT z^ITKDvEz$1U3)Cw!0hiLE*;p|(O%OvRXr@?ft&C*c6^S9Ve&AChp0T%@W7G#jUAOd zjFpE|c;K#qjUD57m?94&d5FowCwZt_zG0tO_jz^lUb_69k7c_8d99v2czBhZ4|;=o zRimy~97PSQ*jkki<(;sd*2}p%wx{lw6xhje?7TAdJ=NzWWZb=?C#txHwQJ}$uD&f@ zkt4XP0#7Awa@qD~?aGHMa*v$VeaUmsV6U1SvR;~*UqSP@#k6Z5E~a03Z|-p}4frRU zc9Y||Q)+VuWv1lifAFkszF=C@bwo{$GlctRqIvnB;26_;&|LwYN}gW*Az)7FU%%eGfj!+NIH{hYDmuGx2-8M zr*&~_+mhC3dm=-w*66V#(#P%-shm?)5lyC2ZK+eDBht~4BN|5S6UnxwlJ#wiTAMCP zHt5J`eOp5^QlFik%+#gY>MI%=Qpt3BUdQ-?FaoNQ9ZmH~lDf~8ZQ0gPz>GwTVAP3c zw`CH|waFHZ(MM2`p#=-FnINH5V0>LDJk`{ZOc8!=GL>#>YxQvwG<9iRWqfKj9dB?$ zi-pa}HignuB^M^L%^9jx*VfkT=bn`;2%?xE)wJepx^a5loT?@$n3-8sTX9~hDU(e5 z2C7vc6iQ0tjRGpOsTAU)--!*qS5fEsMnA5iy(u8NMy4y}r>JRaX)?IL?Ys$Q zP$etdS{F7g3QErplSVZrQppBr?536Q3{7dFk!_H8>C8myBB7aXMbSL7mbTV6rrJcT zbwWj!IuV<6rm1yN&3IKM9aq=ZZkq1Xst(?U!fM+ZvdzhwwuFdI@KTk?Btikx5}Bz@ zt+3q>ozvRv=At#zvaR(QExsBPVbh!279^T=`F`N+B%-s>$0UTvrWWP}Nu6jBnWU*T zO$$<#E`g?QPRO)WTg$YjW+$CrIg^Sa&O&1(r5gl6xdvYz{+)4klrp#v>JS6nK$PgH_e1B2D+yr3CNu+B4~koInv) zQONm;L*Y&)A&`^Se|3@wy4h&u*}_~JE$?~aVnXxU_#_Z#8{7T^rkla%safU~fklF}9w#yP%f zPHUpMX;Evk!L4pMI9$SbAC+I{ASjG|La4s#EsSeIA+8`OA6JOq6RPAjADho%ziK+2 zZhX-F(kO{ZeuM3sgG~jgTpCmG?$k;G$LHbE?|GOA%)@0vEH)V`X60KECa`e$mx#Rn zYtp(Z%A_*t-@LiXzao`NEOkvN6#!!TbA76*J=12?q79$bo=9Pxr`p<+sZ5hH1Z`AZ zbD~v7UG+YpssQVRs{Zgg%A={B&#kp58x)d2$%KMIQM#fY6?O9Dbr*w2oEQpm4teYZ7E^Hd5NZsP40)Mtq|tn^AnJvEeliIM*))!vzyeMPh0Ln@N*N*+2jP7 zMHYnF5>13mqY6?xfqBU-?vo}K;y!6&USc1Oo7xEsC!de4Gbq|WGYPV2HND>@~%v@YKzf~*l@GDHL;*MsfK53OA=bulr9L4 zx69C`*c3~&HmIo_VQ04|TMGh72&M9q4HTq%G59K*+tNul<@6dVq-9zsnqCucRnz_H zHI$=UCe)o?W9JN0vkMm{Q(EP#h}uNE8)oqo2174p=}xc7i&I>;`R25u&|QS8kb+Pv zDbs6$c}qbqxaEdXtnGBuQ;Zr-_35Bp@fK#ZQdU8XM&U$N7v>_!3SetmrnRhev@+h3 zs~`#is4tAgz-Y+U7tLs+LK$s6gXY^Y+o>rnwxNoPrfqJpmEr&&^e>i4vA~b8*{It> zmL5_fHY`}`g&7;jVpd8>5WKgE#yz*Hu40ZaUN#_K66p_WLN!}@3yIFIug|t8TI-kA zCORuvXz55+vQ&rBAT1N!(a_PP*4%imOC=X3(eYMF@`G&c{cKwL3X<9RaR?u2o&0L1 zPGekM0iJ?jMSt2P3$=&}OFLAXd@8`0tBMEyh@;-nz}iHZ!9tMfBf`ZX5FEx%^%ExA-G^%tmlZVQL6hmdAilGvl$wg$}3((kzVn`|* zo0=O`lU!8cP!OsVPBW@o+A|@7&@`ocwRPp-EgcuS;H3 z{~5ytL)2mz^MW00GnsC6Fc~VWMPZDS%@}Gf=i;sDOhR^j)LNrzh!f=GbwYjP-b&e= zcC#w2^6NLNtW=Pm$JpfhEtH_TGg)tHXHx~QdW@UOI$>*NqFtteq$v!v2#drhjaoFk z|4g&nRMq{Ws#~#C!=(p7VKniyPN~(cF4qYQCq`xrUb9fF(}#lx%A%Q6G*`z2OHCng zzxqoe=d?HY`#Y-PAzfe44TD%ZYe8&PazS=cRhvvr)D&P&+8S^EI1>c<8(MCV-O5r` z(J6vx+o+jIm8>vABwVzeGKFOltI(Lvn-`iV*m~TuS%flhB4ohPE!`euUY)LDN-xBe zAE8yD-NU3z9RStLULS3+Mf-*d$#@R7naq2z$3%d?>ErLBpl4}^kua;_C8bgJYJWh# zize4kxNW?Uc$MZ z#Zy0(St0e`CjK3ZVEYjH|cG)d>S0r(gsgX8chXwD> z90(i*lapd$w&_ZinMGKu7$I@y7|P6bg+(QYjX{qU*jNDTIHRG=)tqvmbR zO$+L?4T;g|w$bAVYe-ZTZml;YX0ngZG7d!rd%q0{Uy|%LofCusAFO^hBq|%*m`G~5 zQ^kh6*T~U*XV? zhya}+3-E;zv)g7ZZCRikHEfjxZ9$;zdp425 zlppL@DL*1mN*06P&cdYqVzIT&&k|HQ6q8oI8>&Da1G@8)pU$lxY}V~Jx?i!&51geZ z+YJdk6B^8_yh`D`o1&Z$m-2I37vyCHxxrK+8)VWa&tACDRzHZvSs{s&NxckDx&pGo zpQul|=%uDQG@P8Z5~dY3PB#k{RNVC%-Q4`uA`@D$BIJkLZR{ebDAx^jlr?H6zo39K zvdF}$h?_NtJkMDw({&JyUUY4VLJHzE(ojaKWk(dPacr*e5{$}Iu$I!0P(id*{W?Uh znou=v96aeaNEfD(kzG4LO{mICKDH1;5ENh-I{*f2nb=0EhDfnvi!Np{ib-4nRZI>T zV-Y#U+aRhz#y}^Msl1>CL5Po`yx;n(#L77=pEl+FHLSeLRL1kwkRs<<5Zt7jPf~_UqnByL)vPwGN=j`nF#ueu8Xq1 z@^@I!3o5+GHj9law%5{-kR6#&krI$sqy+hT!nLwAjU`%DEqE>oxcdH?xdJYK8Y}=n06nd99)$czN)m1D~s|;f| z`8#8RF)hA=g%LV~v5g8d6h>&Z5O)1gG9<(aIfPg@5k2t;$Eh5;uVYX;o4r;+>UxEB zoiADbtjR$WWN@~=EjH>_JTw@MO}l)LNt>0j!W+VBR_Jb(*y*009$Q-I$_Dtu>zm;` zb|KGB19(^4llFalRep%EZS#Z2+j&xcgg<-8j~HLoZ!LZ$%q2gQPoAQgY^@6;QH!Ap^Pa~NLW*W9sEC$%M;?PZ`cX<~ z^1~fvoF5f(V<;}SK^8UiYl9&OM1j!)90Xm#Qz3<|QX_dNVKBA_7GVOA z9>Bt$g;o}v5i67-v>mGY9#}$wq2&I~tfOS}j(`L+qavH@7+C#puRD>9U3pvRsv!ki zv9`tq5qf~qN~4&om$CG;)|1X4_0m4i{?HOulVN8ysHA<{{IS8ht2r^@EUuecL9TG5 zuD6&^#u3fxI~x=*MNKGmGqmdLe-YAfruZ_XiOgTq41%?EnMHaN9E3@a6u*2;cU7q% za#mp^{LI#HzTJKfbC!S(bJuLn_b>&}u4g z7tyLvH#iVjoyFO?Q*|l`&Cd{Q3p(k8z#zG*qh)*%L4g%Q9!F3Kv0K!(>I8-N4~s_x zrRw@qTwt+;gMy?!W%cf$W(gT_Ii0%HStMn@LCq+Nor$v52|LL-lnF-!h3iVuys&aB z49?F&(~4zrgM%!piT(z*5$Nz1b|B?}o*1WBv8}0J#9cec<&48&X{X<)IP1Nkh~lIU z+r-5pf_C^8bHNEjh9fnZtbD$K{Auq89q#i+sFNRr-@Uo^(o^9n&Qp4$$t2@q{ua9JM&xw5yWVwfNCaEp4uOI|e~aBsX?D+b zeWb`D+w4Y&i*2-uaN9dP;@cXQ55i(TxMmp>S%4#2hmkZHI

  • x+Iv^mmg zh@og}f-P|y)PiZ0<0Kqr*8A@&wN5spjfM95WGlx!AY3N7hyxT$qa5+BU!0CEq)@j7 zhIzV^S?6g}9gU6y!It_8p{h{SQ~?iYwj13Nj>YjO=3?TAB@%AaQG3rl2AaOIM;It*Txubue)eyOxY-Zs;8#|iVu3^Iy=jD`Aj2} z1+j8=3f&bTlMMoGe^IhKHY${iqi1ubL_FP5J?4C}X)MPJr2E9v#^#cqse`1`Fj0|( zXScgnq;dSqn1-E@=28)aQ-Y%SqAyy+X1>GC*==o{VpnI4okqkGsfHz7f@rfk0;qa~M7i34sT5aWh+a2`|L8d) z8HlY3cT>-@9W^ht-+=?%THbx3ODpkLsFx-)QCE5T1?Vi=kcEUTa*!=RSlgaPFy!0` zy<1x8GL^`g?e(_pK1PCPB~u-$Q)}UOqd03(+1!K|2tICdv4-qKV$TREX^Pyu;Wp4@vwhuPxKa7cMLh_ZzOW}Lx+o};mZwp7 zu!@UQvZDLcoj0bXYR^Qg6U(e7V;dQ@w9r&5z-Sv$9HWUY@edu&8P4kYvl|QYCRn z6lEB=jG7u4MRN8+c!27{@zCZnsz>Zg6snH%h1V25O^z0s?xl_yMHey`joPX#%wN0H#yyclCSW*B;lgVBs^1E(Rx)8zH9*4veiBx@~{1Q5;Inv%< zf6_#b8CJ}!?U)o9BTP(XMyDHFMvv%J|C*aSBdG-uVaOO%c56dhOE}rsNhBGe{-?6@ zxEGB7Wd!1fnlEvyoJph?j~UT02AOS%Ea6iX{MDna=zsN4Jd?zpYB=ST4hHhJ6s8G% zEfvk6&zOaD&J!w)9Hlbx-<&jrQ#Zezx}+_&7$qV6nzvvncb1(VJ=NS5#}lXT^-z;O zeIJ{dUu3bVejXMYIZx3#&lqc3tF>mEo5iM-%BdNg$$Rlp1;rhucz1mCC{rl!M~z4y zMLntb90u^M8_g0Z1jYMgfUbuR=F-!)wV}7SjRBxVO$j# zGbIx#Y?bqx8Zvx?N&ftsfXpeRo^6<)87L~OT1RY1^cT8N5Ap4T;|uL zacepkci8pU$9(=4Y#y7{fN4w-WDF~aH*2f~@yx>1{xa)yX|!s;@vPovQ>{80{Az{G zIVIwAvU*XoNu=moP!Eg~vE_rsT+?n@d3EqH{v#RMe}P3qzumUnS=j|vy!@i|l0|WR zexf`{(ufCWk1^$BrBL{6%U6EL*5B@2W}a=<76_LgO2^b-Ka>;8Qttu{h2A zOv#3fpv=kJQXzsl2gfVy!dcZ)Rsx#pXVEdqtgujD7k^z_1`cze-JKUG0+@C=TR<}S zKrvK$9);tvKnr`M?umjgz*ErSfs9~7VNjvoM@-B_^Y`}8g1`(co}@{z2kJK>ci z6n1!Q`wM&`KCSoBi^qpuE1Wd>{1%&5dsCUhOy4S&&JhJCmGDvfDr3-NSS?~z3(Kp; zEi5ybT4t9kGhW7ptj@XP^a+^qib=xY1%flP+ZtEhO& zHggDVh+CFw3tTr$@jow}$)u8*c*DYh@q~`yPo8Dx(~D_FSB3RsRoMo@3ETy9+Gk(9K9i z;zJg{Zg5dNA^qzLeI*8Zh_U2XIbUp3DQA(e?_4f9?XkyyiYHqxQneA`Fv(Z6g1x+PjL7ciVt*~ zuC0?UK;m0d0k(nDxmf*r6~Tw=W6=J7_~w==b@cJ|lin@+gQS-_*mU8J4V#LrkcG+* z_bH!F7N3^Ku(c1?JUia>PZiqVtiWxz;Ip%W09#NmH=Zh)(t>!Iafa&@q;ku#>1X3B%cPrRCXfRiGyQ^E`Ng1>5%J~ zMy5xxGdYGqGrAy~UW!|5H0yZBYKq}@TqLXZlFP8WLec6^qr~MmnQlEc6Kza%B=vr0 zbUL5l!W~yR#ya$w)wVDr?r^w7G_j<|x@V@Et@{PdO=2$5UrD3|$5&wsjwlP%mCMmKb%TF_(`LcdG!}zyS5~eP84#0B=ksSqo3^x- zPj7H_2XxGDi|>exM`sF=GOi|3{Npl>mPs0Wq(ArAcHdlN>vWJr7Q z8AdhB_o(cKwC_}>%Y?qNt=4GisN-d zliY2Mc}V@m^Fi|abP1d_9dF!7q#Ym5sQ6)|VXodL4{Eg_nOTxdDsoUpW=WeVUG0OK zerEi9lx}4W74@2-clv%Zc*nL*uMyeS7xK)NJ$jWwY8T0)+l+JNBSnUE4Scpp1U%Z1 zmEC>C6rW2vcO(+_3#Ki`@my{AYfoL3)Te{fdOVAL?IavWH*~PS*Pxt@m*D)Yos9`t z!j1V+{1*~dwe`jJ!Ps>VLVuD zx=?+6szj|vO93x!zGC^$&GReoWa=qAT#$YbDc zDMLZPSJnOL3TMxfe11EOoZB@m>xCio3NRTjm<7mEGKE$VH%@w}CaT(X7guB4z9R`d za=Efu#pCQOp1iV45?#`kZElEyAkCLS*uoV`FO72XeR`=>CxQ?*Y5#F^fW&rQ5vF`) zLwbfqylz^T;;5z6n5lA){L~B zZQ5h)ESqo()ilJx7E6e~U+2ghO29h8E2#)cThIpzdeb8H5y3I0rzW&>d^D}R z-~;|U4mDb|d^b(S0AG$5D5nYGQho3>8!N@=6YYgABH$`()NFe*M{{hMnRDI|=SWgXVh#=>Jre-;8B%LMb*~-zr)ln_6^CGo% zC?e%|ZY&|;0y+3NU|Ka9Z&9&;rX?nZS${ zv2sRlg;Hl!o!a6G)kI;GvQ0u`4u~bORLP3+){M3$m*^VmRv4+3JwN#q%>J>8pr1%8 zuG>;FXM6-5N+@ep_tt*<6aM<*&F`NN@ICrJaJfdsTMNn%UG^)rxm>gYd6W{lQt1Mf zD7KfR3iAcx>8XnPzOC`tiOMPu+8Z0Y<#_C3G1QWXB1fh$+Neg4{@V!E5cXiC6ep<*CEl9Rz&7N$|=9J}BYA?G|bja{4r*84m@uDeKYLm9y{+E}Sp zYsFAUJwZBwu|#Q0bsN7g4cc=!VF(q>r39tV2Q}dl%UrLwh&jq3gou!4k?fa6v+5pv zH6)m(8iQ~_vL2fOLqo)q*_|{}JMpB&CgDU2at>Q1Sk7>yFuyZt226F>t6rKSL$UeT zLPMxHu@4hz40+Q_M4H<8@{Fin`hvf10-0sJ!ogder8BC5_9g5z*%)xTv-xNQkLi&z zFGUMRIrtXRT$=Dg2Yb*5^(rSI?VLo8D}zR93>m0IK&W;_T^zO~g!5{wU?j!vRY@%( zQ1i_W84OwI6obi{wC!>jP_e4gs5C)E7dBpLzCurK^nlEmul| z7yjW9sak7W>j~Itas))ydWw`O6q+|rn?>{H1!PjAwi$ITNsYND`o5pTe!|yw`37}h z1cBd|Q`0VOy4Vw8kw}v{lV!`%6DI%kdO?0|+$Y5aL|ORSjQ4rEK#m3(J#Cjnq?rYH zDvLE0aN1+T?roI!$5z3FA*#fKC97N#dYEzsoE;nrz9M!_P8%Qns9p@z<|Z zOfVB|k>gYmW82H&3lUPYZYAABjjwG8j|`INmW4_$MJJ4pQk&4}eq%`p2}43JjaQaM zO5e;MH3@|Rz8qH4(`TBVJtMg!nbM~~4Vfa+`(61DNQ-!jGEpiI+o?epr44xpzkjak z+(fELdY(F16=|@Cv7)-a(PABqZfRQ#wrsl?aA;Y@RB@?Se?dMgJs&iE+MEmZNbnbrPw{Kdb+REV(jo| z@);w`4oPN-RL$BQ3-fr9`{W7ed8VJXJEfx|Eot=9uB={S2HEM7KH{?r=es3PXsKPIyTLa$(pz(kER(GD+tu(1Yj{=m=H{g+R!VH4|Ujo2#osH z1TMJxOkMwUEykrH1sbe1YDq?a$AWQQj_3Jj@8}JZF>1P6zsKx2ZZ?L~YOEMYtr*ws zv>OGG-dj#AWuK4f#{Y_}HEp(_Y^+Mync*vW=bCdCG{f zP)G0^9-I09*}R3M>TbfJwlSz&^lR z&ur^^4%h_z0=O1f3A6&|0aJicz(K%{r?>UJ4BQXg0;~bP1Z05E0Wn}4@Cjf~;MJ$L z^*s*U2K)$E4O|4&1GT`(z>&bdz*|pJ4`3tkbKqORF+eG>9ooET_;4S;>wxQltAORi zHv@Bk(}6D#HVG(sk#v9A*4N2z9T4UD8bE#pIt`38ansEEBzQTWuxnnTTwvJC@CKLy z%mvzkYk;k!Sw{R?p4akRviJ7BWq|zFnO}LfAYqLr?pc0k@3Xy6eutZ1dA1;7rvmaj zcHixN5kP)dn|FD(AYoep`F)x2Ujg!4Wq#$^f`naX;u=4?z3&Ae^0DoGQD6!%ABYjQ zjNdiD#7~eO_&x9_@G3C)(CvMP0Tbny_Zog1fHzMd9(Wk|=;-Zzr9cTV2zZyUzkOwU z-#ft1fIk4Yyz~0bq7;r4G5E^8G z6~Nbl9{|4qghuQ6eE@hKcn$a$urGD^1TYGi1WX5R`U&`M*xt9DUwMu>&+;zetMkIz z&HHsXBGbT)yvy@!=ULt*{L6V^8S_5ue&_&90%E{ipb_W5Lhkte{hzn@ z{S^2v@Ks}`^tc~}bEs3W2Ww_VwH{hh-GEo``c z|Mqic{%F}*o8K5Uy7Jy1JbB5W(@vWG{a3es~#a z^G<#5(HB0tXlmQAFMaHl18w|I?P+xBb_ieIFnD%h>h5e&~tMUG=FO&;7~9v)4^}_?y>V z`kRh_Eq?LanZbXr{!aU+8!o&udd2w#HC+C2`PKjNo9yXm)YAI8GY#3^4WoiqK1 zM?ZJY&riAYv+w-*cX$8onB!;d*Sd1#ioGA%eE(Y&m(|Yv{Ie(D)4bt^cZdJw;*z0% z_{Eu>tG?0oQoYyGbKhg{PmUa3{*O0q*?-~O2Vef5C8_Pb*|YW;S5^0`ufF!lPdxLj z?g`&JVEMt1mPF_L;jisybx-`=fu}C~%Ri<*`I*a(e*3=ZmtXVtmM@+1>a%OEUi#(H znbDcA|Dz-l9lFoL#gFZ1KL4#PXXdVas{FwBzVnWi!voC2$IS01&F>iVJKg-6WyQ#M z%zKady}%eu`x?XOpgncOcZ}imcVi$W%pv@5l3>kQU5+ML;qHE=-=co z^zQ-t=z~lS$-{}ttKPo#u}I6iU)cEd39Sblx%q&#cQ(E` z=gDt;-83umf0aLne{@IRH6P#6w+v_mPX4*T6ksG!25d*J zUjXg_ZUWW-tAUZgTH*ynZrAfG@-J<&AhfVx!{pb7$*&te(DPVu3)nQ@{^X9nOMou} z#{=^2!a#A7PV%|w|J~5@1pET{!4ZdM-BNu z3p6{whwZW+3%yfn15&ZcgGj!+lNV) zSK;B{D18Q)2-E-#z$L)dz>UCNz_Y+xz|bS9lR%!V{cqk+-9M?0h6dU&`NSPgUn^MM#J78nLZ z0Bv7Cefc3yy zU^UPQ%m-q?SYR0NVbmwGi+DW7fd_$gz#3o`&<@N6rT`;>GGIG>{z>G06y=qSp^c+? z2jty_^@ObjRu_qrbe;W#yEq1Vp1+Iv2g1EOF3ijS6g^__a4awkhyWh?_d#GCum)HK zv;%X2DZofTbo7T&AJOx>f=9*(cT5odFFL%K4w!_zOS{&OqfY><0eN?!ld$ZW z+3!8On15&ZcgGj!+lNV)o8aL!!bhMHr~@VeQJ@6aIv(2vSP!fPRs)^Dhf#<5yND-7 z{;|L?AOd)zzkzkY8ekRB4$PHj`o>6U*U7XC*m{zFmoN)Y61E;#TO>}>tnMe==HJyKoI*%YeoragwgCpKuq)K+ltQ zG54A1Y-d&hW*c4!7kvK_L)=#*LW1#2l zlf&f=ly-OA|DUva0Uq8Xd<3ommH~}G9WV)q0wuuKQ|M2?dSET^VeoVHF5>AV|9l_@ zj0J`P5x}GWKM1S?)&Q&I8F^nzJ7N{21%?6g?m~nxZwh$nGgC@9cNYF6Q4E z{@wA#`SxMbWfeSZ2j&7(fRR8Mu>A~lGjI=Z6L1Z%3}^)EfDfY%lXekLl>8;Y*3;?B zzd6nVLf4Mfz?IgBwc4e;VzDWp6Bmk{(*4s zjtlehKShriJRA!Q10sM|g?n81Q*l^XJufz_NCy z4e|EFqE!SQdU5&)unt%QtODABxxf@)Bv1xyk1^%|_W&P8`8Vw%o@>az3}^)EfJs0U zC;_%kXAA+>18ads#uaH_-PxoAqJX@+P(s+&8RP@paQnQzpKu$$v){G5n15&ZcgGj! z+lNV))$p(rm=DB&vA{4O0(iCbBVZk{23Q5O19O27qYhJc5zk2SmjT;r=*Pf4z)iq4 zz%rl_r~@Ve+tCZ#NgJhI(#}qvp9G$rjo%yad*HLcB|!9C@Xdh+{9eQFdf>C?krt5O z>wsn;_Gt}I@_P+1A2_%He>LE(`W=0*FCY&PX{H}81}8A|^VFk>Fz2uA{^yVU5=0+LjXC>vlmbT90kZ_mJNU$uKwg7S@>O^1x zus1Li*bgWJ~OJqSjX^aECEBGiA8)+D~QUQ(Tdls^)IGrRsx51@}AK z4E?0H(ds^hTCQVgtCue}$Y%u9tzoeUNUJx_gRy(Sy%r_!*>p9Z#zU zj4%4x4j+$w2=EPbzqUH3eCuUG2(D*X0W>Px`le7e})uiamM zl{u6@p4QpbwLdmm@k8UUZf!95{m4-MBKNZQ8y{eh`l&0n^ko>TJoP@OT`q+R-s8bl zSn`=A`yGVALKg_`T6Yo&hocs(ihpZ#eR2^U(<7-FWve#=NH3n_&s3$fomxB z(;sQ5F8ByTeqWRtNP6yQ;!9ELswI`gtzxlwx8@SBSt}Qq%Dq%>tj2HeK{3~LbtLu8 z-YQ{`Uk6rqik1uh^5cUT{Uq^5e{jo7BlpH}F^ZEYh(~!O>Kkcmhzw4A1M=V8ydY6; z&(sQ12}MiFfd!59;K)FYa%1Fb3rjAJ_fE@BixKx=vyq zgY@TQlc}YapWKT(p(@l+lTFe?1LDW;Bwpt>>A9F|LY2DOS8mmEs^G>CP#*d7zt5(T z1o>tBP+!0Zp$X#0SIur4D85*%rVs5^<%bZ5=|Oz(#UVFcP`>?wksIsc*Wo6;qQ4Xo zypNZm+j*Ba|J|pr4h@IfuyA_#mr5m;nr7QHL4AwGx_BLa{6F^IKEA2D?*Bi%fo5$f zVRR$g>c}?cGOesYfo$t$fC6Fbwr*ov+&WhVNN@!zlr7V$)p2c^c3Lm-Yt*WpqDHM+ z6*VeqE=8?gReLFyMy*=soKdURi6lVV^LxI}T~0!K+WEb%-(TN89`MY`>-BlRKX>Oo z$uSGVTzP9eY^q(i#$yIOzhb$#dOw(ja_{H*-_(RT-Ryr|&Ap#nW{t6JS@PbO4b%EZ z_1`Vmg&F>rxWv(a!E2i1BXhrN7N5aiXfy3vd$j!@zYaG26Id;)_CkwqKDSMtRdQ$U z8AD>Q^l7v_o#zUP#lCHyPM7!We^z|snS^)o^SJtt!0RrXE{s%Usx{B&-yXVAy8fs%RlY;#5t>H zZoU-w%{-YlEP9$&g3 zcV$F3S-R0bTXR1Fs~Ph2P5g@Pmc1L=_%UNMg{2$s%Chl$mNP#0P1k9#HWB0uWxD6a znc~*{yZ4ycZ2d(sx!z(_+d6%=>cjl8S*!q-E@|a5PC)=m*UMWLD?q^u%l|LzdnD8x z%F|I+^9r)t%2VH&t8h*+>kWtev+nyO$ehYMw7@DqZT)jqFe_~NwUbQS?p<59*T=pu zmX%9Cm9@%CKD)(CP(aJCnP+~^X+be-ai;RQ8d+BDh2=NvmrHrB&VzWgy=i`kyd^7M z{;>h+we>4Ee&oxy=wYn#GaM_NqZf>|r4!!_VXvU2vp#YXDQjci5&txLUIt4ielA2V zgQX)*ckJP$&vtAfS)9sGcWmM0pCO)8dyOW|d=zEn)BDHp&)l-<{kfJ*ujl%^@RjAy zJNC(K@TbvfucPjG;d`2R)6b_|eP-<6oF&&PE531RCdyEZ@clj~_^ zeg5#oX8p&v^)t;ojOPPzh-JU@q(zl{#-UeU88fBmdex?tO`AonJq6D_HS^!Sd*>t5 z)xj#vi|NX5-6@aC+Nl+tPB-IE7hC*B`;0L5vu{10-o9yNtv{?3CBo)bd5YL!-i zJ)+VqWE}X}bsABi=I1VqXPQ}|D5{?^*yH7%v}!u_`sl}d#v=uD&r8#iNqJq@&-4pq ztv$NFVcXty+VdX8VpUYi8{NRLSlbQjFjsUo{c@vDe~x!SpV{<{k@kK2J7(4$p95}H zsNlsp@!6D4_q=hlnC3tC{-SjvXNza7CT2;UHeFv0@@1_*jsB4S(mK>`v6W|-9d&zu zTOkU{=ML-*hfS9Q`>p$|lKKnLt^24}t8*r;yw*S3_2+XOMtt^jvX9GMKR1mz-G2St zRQ36)A1c_dC!_Dsr&O-I6+b6Z&75w;&r>b^4tYeLy#vh&Ym`4nH+#U)*X?+C_W}FG z&Aj(bbFMyx_q(hH8|CtK+buWIsi%G=`Of@%O_C;0=NMx@4`j8aH~Zs&b$`anthac{sX!X3qX6`fWUTt$o|x?T_-*o^{&8WjE;0 zOv~G{>!k|)%{J%dn@@>U(a!^>pGx2by>8zlDb(?lzuiyKnzFpEl6@ z$tu6@VV-6u&rmX+TY0A(>FnIEMa#>YTPUo*-rgDVQ%wAFbM;QPBHAOMNx`j69)PLG z6g~g*A^9tm=#*{TcaUms+PB{vZ?i^)x;{xwHJ6|Htz8t%U)%F^?Lktu`dSCaxoCNQ zOSccRt^5W)PO{V9R*56}44-$=#;&mb_T00S&+j;+U@o72cFyN#@_dDQo@mt9IB-7a za%o}R%=$Th{;DuTeiW&X&6*@|Pn5WoIl zR32BxGZ=U6)LUaTg@>A0x1!7B%a=%Gv;(Qm$uK>nU0*UO+@o;t4=xH zHi2!foX*LV`T4wQb?ftaHq|~})2~3e`0RzOEq*RUPG`Iw_591QW&|m}p(DZtAa+o4 zHS|CSAHZ!|sqH-Ig}nG%c9_Mc=^yfIM{xO;yz=Jf32l~~o?Br}nQ=>! z7ot-$eYa*WXwzl?u08g0X8mrSsmc9qc{ZlLx6O-d*3*n*EXz}T3iqc{ZbNwAz5`rt zm1ssaEQqcv)Vg_Pvo)lKBTv8e;XAkQmU(Hp?1utci9A1>cDb--CF4a-rxzS`truUl zjRQQpEmt1hszxq@=vM#d&fu(%dFAQ)qX=__jrvi3qdbe7ElK`|!wYo%Nt}7bwf1oy z^w7GFCZ6`Jg~>A*`KK3+`1D1Rz&z(_eS0ZlR*RlImJit+&{%$6lhPn9W8P^LbZJ&>uIEM*u zZoW%@Ht!vcx2(H|&mtFoAVTtOY2VJL84m1ZUIw)%K-=nN=(q97l<8!x|0z#rOe>qZ zl-CY(3KJOdWs1sCPNA%o&#liJwyZyRfKN^5{&M|Ai1m*)7dmqK^z$zlNq?2|%lK+v zTroGN+BHf?|1|U0(Qn++S<%>}J++wA&wF<7=m^`(ljvwOyFj z-)v^&IkIdo_8CtlHQoCB%IQ4wG$(1VB;MvG?M{q-ysY2O(k8JObe#k8X;o8atn9jV z_r=t6>z3V?i+@gjt!_EJAit%W@y&IwFuJKzzs*g0x7*5E@s0auo160E%&c$O!=(u= zlHNbeJw5ug`y*{l(RcT95p(0_CfSGS717GibpLMSuC`74tw$&81q%L`@)FRP`TKSp z+`e=F9Xq+dxp%grR{hT@&(-z=tlV=6Fl~NrrETBG&-(`s z?veVp?c8=?=L^nnmS4ABd(!>CTz;ndoAHhMpL4P`Q+o`*bhv%I=@)atKm@<3y2eYowet?M`3u~GZZg_O{i@7k2N9NgH{lpjt1?yP+0@-qHiu6?6Z z|DJ7$VQl`(U0*5U{kZW)u~JkNKnt4&!&k-=i*GPq3*>vD)BU}1W7DSMqM}u0hFGk8 zU3r7enB{w}@)zOzv+{Styc?8&;^+In0lxFgo68S`4|MGB*!Cc=Og_3tU)K1*f$-iP z5oP(_hnMe`3*_=b9-zHTwgTD`UD&Ztdq}-#`**f2-^Nu=ISlz<4X!t6hX3W;k0sVq zo^z&KwfE=c-mtwgo-?gX>Cc;1CJjzNYho}IS1R+?*oys2FJ(9ihFpsiFrwXW(1bC3 z=Au%;tLe&{&vBfs{9?)*Q^Sg>y)Y65jd#T(dE|TH@+aRxmOtrVtmo{%gGPC;nD{g6 zSgJ2tabz55!#U-{MtS)zwEfS_Z&JRmE~9A9Z@X7sn}JQ5W{r%H#DfUtPYOr@rsn z+2K8~=YcgV%9n4`?*~6{fcwVYHTC5y6!pcs5A5d3w|6=Fzx|JTAGmkLs`h<+gM~Xw zT;AcP+|9dp?{0pydAF~8Id|!{?eQ)@xTfBxxE4L|Vr9((b+vWMHLF(EDGQgbs8edL zSy|hoT(Wc(FaL2~efibpuPbML-sN51zJKQq@0INhD^}ik{bJ?+Jh*D5_sabZ{P^ns5cmMU*Dn;9sYu2v5R#|lEifff? z>iKWc4J+@z{*%hmdR{JFb*-W-{G@XJ$&&i}uP@*JaL2ag9s8E=YTNhVwziim-W9d; zmE@Z1%Ma}AXkXsevHZaIlvV93YJaF~UvYi;o_!DhMtR=tCtuz5<$){PS9l-Xzs z>468nXD>a zO1bF%e=1j8OJe19%8RaVQ|2vI%G;EyR@CiLF1>b-a`|drT)m=hud-_OidrV#Yn7_K z$^|RDO2s~<=%J#LeabZ}RxraCuWVN?=HC^o#MP-R=+QL*N7U91$37qJ((;$`*0;>CNPP?oi?x&u@|E?B*+wEUkX7x+EOf>R||tgZDci&lL=xp?gZ%0+e0 zl`LC(?Pf)}Qz`ojz4p_RYgYI>i%N?cmD0|lOL=+4>NTB37hT&~v}*NQx~I6asB)}m z*~&VvQr@mywUYk3W@R1SQnID=C9=eTSe;nCQtL$z{dXz-yLe4g>D4P)ShYqQ551?W z>va?Tdnx^^cQgyGp<>^f6?F1*(#cgLCDndK z&x&6tH7kEt^3s+5-<1^AC`BJt+-n{zj%?>^a66Vq?ktm~^E)n7uGqK#nUeZ7^|hBM zH|$@t@`%j-WlG5rrD9X*ydRX6yi2+A+S*=z)}nObbFO)dR-IMcJ6>Gu>9|B$bYG2f z`Tey`%EB9!`NdBcU9|c}Z4Z&a48xc~8@`8N~|*I!q@e`g14#p}z<*{A5oGimd| zy~cL#f9iN9V8l&U>w(SVnG&|X<^S68Ovlbh$MTssoYs-gY@P$!{ma>0+c{_G*tWN$ z&e13bQF5F$C-eX60onhLz4L+_{Xg704s*bm#pgml&Xiwq$^ZL4izU|4PEPxW_P+7( z?A+VRLJmwyv|r${y~)cV{0jXK>pMJ{zs0l&0znJFRTYnm3gO><4f6+KB07##hQwh zwey7Yl&dtJEbE(8PRg$iWft;&%fjL%N>|CAH4Bv|`BqurnNwxS2_=PITo&jmxy)bA zFBf%{UFKKHGfaVnHNP$EnpBcYndxgO*T#929;bo>DE>+(%aT*d(WS~l#kEc1m6v~s zw->dPmE$YfecyOlpDMapZlMxw7T=Qc?-FnK8uUrg%i7CEyGnYR7b2WLP>%PC2eM`%KUZw7LRqDR; z&eMHgF!C>S>Hd<1y03U)e*TgY-S0N*>CVqz>el^cJr^1EH1n4&(*5%n<=4~9f4))Q z^UgQwd47I=v%ZVXdM?h-U%XiNoAsS^XLt=9dXYTb8HX@2`J@aXL?y+HR}d_jKx zOAP;o7wf)x7v|?Ly-@d??O#&R{*ooSzj#T0Jzk7Gulj<`Map@}7IVF*Ub3r5DNnYXDpRJs zC(+BUQe;_~_c87Lg-Y=c)rEm){vzww@ujXM<(swjiS_3qS%1v+MVsG4mnwzpjoDvT z{f&MrHTuo0zuCX$d@P)Y=K5v!Z{a*N*DsebAI<(f&*)z>f5~}&(AMk9^Ys2(V5~1@ z{sooB`em%&RR!z!Lc?EGW%%stH{)xq--d6#F%M1}>#wqi{$+ei=Iiw+ov+v9nKJJw z-~P_qrNx)+qT+q%KDL+a zZ3EAk+c#Ii_U$~|_RY)o&Fn9;pNfrsGW*|LZ_RNnHO5oxe`&ulu4Tr0SlIsZ^6zT( zoi|L{+WN!#S5_?hqgTtga0!j_B}<5>)Mz^EUs=i8Qucp0v;WfKFI3LsXQO2Q z>75F&elIZgyTuFi`Yl+nR?3&=;_LfQ%C}0n@&#+D$N5c~ew6se{?gn(E}U`y_~f+v z$Et$)v(PqwWdB&WUKAVqyTbXi#N0m_+go$}Ej6~g<~+EtVEbHVY|rN#+i`PyV6MLx z80*`4#{R)ouzxVO3)SZS$=KhR`HPMHjyca47wn(r8T+$RV?Sor)69RqQQtCS|2V&3 z|7g~Ckx@^VvA;F*Uu^7mFL4?BabrJbZoi6+{khB7kDphZzki(T@qx$ee~-Q$GV_;u z^7ktj754u{x_|yfy3cHn*?x01 z%91}Y-IFaBT(C>qE-qfYxu}c%mDxY@X4t*CIFDNsg0C?DJdp59V>@O#8>hS83z>f4zTPq|cN8w|~sr zKf1~mnES^l`-OtzH^!%Mzi93cPs#aHa%t%TW4~j@QH=eec7De8-`p?GGxm$-{!rUL zvi~VH_KPLPezB}r_E)dI&vt&N?HAduG7prRvU&RcaI(z%jM7;{e0{%ItlWcdaD1M! zMB`r;YR9LF%6h4+46uLJ{(e_lu~|{N&S(3;`RkDEpEqmgtMipz8q1VNH2z)A&*b={ zlKrXc{FV~s9_@XOQ<=xV`s+W+MkkeHoL_3&?UBEl#}y`@D;rgn33TIlW1)V{=64Gf zj?Xww(5v&W|IfzGx@TsO5-=9zdXW9EU~$I#g0D1;*A^5gSk!)Zn2tW@FJ`>iV<@u7 z#Imk%nfC>+*7bJ7WSS^k#ku-a(cJ~Q5x%lO(~d%$`}f6-)=j~egGqFfa#EHBsB zXwy0QPZ;IB=<;VQTIJ3AgK`~iy8Dt@qkvm4ZvAhTGx>fL>C^R=Lx15iD%xu6@agI= z*AvB3c!jV_I-9?MG2x{;yjA0sH*J4XPORp2a+{>Rj2my5H0v!nwec+MP{W@v8g8<% z+zZZkNy+tF>-p_$Dx6xBQKP&L)ns_KA)keSAy&^pc=V-3N*adw!R*kBGHMO)N0w#O z;WzU8+*fAQ*017+?Na{58J>^GG8}=ft1_yaavonsZGgV3Ginb^!%=zvB^mW3j6iPj zDe0GH)Bp@GwdvofQ0k|{6 z?#ie`a1c(w=-ssEdg^r#^@8D0Mm+=vVL$Y}BBP#wDX26M|K1GGwIe=khOYaF4+mi! zMq7vvgZC3(^jFf38;A>oF#Q1iFU#99Y7EBUF*pcEp?^E$a3ke*WK_R!C*ujDum^@- zg&!t%Wz;d~31`&mmlGE@z{Kv1x&wM%&A7k_JSsXIfx(9|YH5J_!&>NSqn}^|cES|w zgTXz_514@C(6=|kv&*P23_#aD>IEaP2c}^HhT3Td9E2`bZ2xN*4;Y6b;eP5RJdjb7 zFxtWR!SF%ay@7JD9{L`}52LUXX5kSSeuVyo!AM5ULf@nGZzJ(wGxWU{zbwPJEWeKN zgHf1;uFj0=-AKJ*5T;=}485N5fP*jzeQ%&%Fbdt9@WFZ*dn4_JkvGw9=zBBc0sW8R z7adlzdky^?ei(*ZVFY%-EbNoz$7u(Q!Z8?wl|jbs3C119;0~CDQCW^Mj?n)k{R`u7 zp0qn1;uo=VQc&QCNK&?Tu&D zMmPvNVD#hE9|k|cyntD#G}E7-WPO0)e&!wYeTwY>Ouzvc{50zi9E8g4=%1l~U=%jP zG>pjmpJ(2|I6MJkN7)X*EL?U6^WqC^&tL*}K+hN1F2M*q4pVRp`oBc|*}*4ZBlIWm z!$EiihQ3UE82bwK*-HMeQh(_A8uf?4uTy{M{|5CJCaFIR{RiWF7xn%o^Am=@#eM+> zk24=&8Xgn<+tdU4zQcaxZt}t=82&En7jzA>eS~p10)yXU{@z1**Z`y7XZ)e>KWQHv zghMbqM1Mfn52$a5@~{O4e@K3qhR0y^N92dTVe-F%@~{bp|BL+4^<(nGI2?h&pOF7v ze6St{PY@TT;2{|PZ~QRyvy7S&{pV~4@1tLS$$9~OzrqjWFe=NxW_^PR_$&=!tmdyKTN}M7#yd)+sJ>K`3KXm9mdbFeSry>gwaX-Fg(Tj{2=*Z00vdoPndu` z(4%D4qc93bU>25cr(981t%YeAf}!H9+65CZ4hKuJ>IvvC&8ibH4wvnq-Se_)5Jq7; z%)%H9&(Eq!I0)0ST$WWmJMp`+Y7_LqHW-J8Vd^~m&|jWapM_cIeiikp$f^x6QHdW$ z77!n%;4v7hB0kJQ_b%GIFss(V7~BedZrUNsFfRI{tU3%+FbkuLX-Am2)zk|PUXWEI z(0^f8?Ss)Jv|HZyWL0H1)?G)Bz)qWVclzxQ?ZYOq|iq_9-BCPnd>1F!qwHnt-mCW_b<|?Se`h^?|i8 z3!7lHHmi0(&&#rEFO0!K=vtmt$3=%VdnkVm;|AlfU6$+US2zfd!{CanIws4odN1`| znNvkQ@L5@2O}qCI7y6-ZO;&A{W!NptYngvA3P)fX@@X$6=%*bp z0k=Zmwe&0WTt~fO_ID<8pk6S3FMi>D%zt4Ee&PMZe=U3^@uBa5tlA>WFe=Nf%mZ15qtLT0tGZrC zy`c}L;Z_)WkaoiaJOVx2v+59xz>_cqYdR^ngY^c6b~2w~^i|A%;V$|~7{(7hyBUYq zlNUBa&#Q?K!|(`G;D@h*bZH}1f zU^|S$9vFiIFb;=d0*=E$=zg61unwkSGt9zv=sG}o=z#;!2Zx~_j>8~yKS6$22g9%# zMqoRP!X6ld127JUVFHfBLFkT>AJ)M%Y=&9b4qY9ThaNZpeQ+51;W!LJ_mkv@bubK@ zVFb3rDC~hTH~`~t7$)F29E9$-kRR5;G;D@h*bZF>DGxnx0Q%rC^uuu&gzmSJAJ)Mz zY=#lo4x_LK#^3;q!(o_$2qMqn3=!af*-Nf?KtFaedf(QfF4DHwoh*b1|-3%Z`9JoLaM^ubZ+hsxW@54|u1 z127C*VFY%;DC~nVn1pdS3KLN2AwTrO6b!&LY=v3a1zm5UJoLaM^ubZ+hsrz154|u1 z127C*VFY%;DC~nVn1pdS3KLNIck)9oOu+z5!&aDuUC{Mb%0mxKLLVH3eyF^Y{Ll+S zFaX1_6-HnejKV$`gGm^Nqc8!L!{movn1TVAhOICQyP&I^^3Vg5&<97MA1d!6KlH*7 z48SmKg%Q{Vqp%OgU=qgRC`>@*|BxSgVG0Id8n(hL?1HYRC=Wd_34L%B`l0e}@29q!jM_~dg?29q!jM_~dgA0R*U!W0a^G;D=g*acnhpgi=zB=o^i=!eP&$q&6S z1OqS(TVVut!6@v5F_?sLI0_R`=_5b%!W0a^G;D=g*acnxPI>5oN$7*4&<~ZT$q&6S z1OqS(TVVut!6@v5F_?sLI0_R``4IV`7p7nUreQ10!Y=4~C*`3BCZP|GLO)bKOn&Hv zAsB#R*a{=C3r1ldjKL&~!%>)k$`SHIFHFGzOv6@~gUYLRbn1-z|3%j7}U6h9&n1nt!3jI*|82Oei z48Z^l!&Vr9T`&s!U<@W<9FD>SR6ap|=!Gd5fN9tYv#<-g-c5Pvfl26tqtFkPPm&*c zVF(6b7`DO)?1E9)2V*b^<8Txvpwdr%=!Gd5fN9tYv#<-gVw8s-n1nt!3jI*|6#1bS zhF}1OVJnQlE*OPOz$Em+QRs)tXUGq| zFa!fI3|nCYcEKp@gE5$daX1PSP#GXU^uiPjz%*=yS=a?#@1;ESz$Em+QRs)tXUPw} zFa!fI3|nCYcEKp@gE5$daX1PSQ28ABp%qro7LLQv z2TrTLFX4j`n1(SJ{LpFjIE;S;AM}6pv|61Y@25|zjnMO%(`p!IVXwSDa9SOP(a)Y% z-Cw5s=T5637=fKI3VUG|4#Du}PpcF1KCJl);{h9C_~>c14FX0m7dq$lQeLeBMN!|^_gW-+%U}Do5H3@y2&!}TC zy5)>o^DW+o4KQ^RabfzFGincv+<8VFfw8;Ef1GwgAI!og=)3of+5toNpHX|E>s8bP zCiYPedH>NfYVEga*Xz!xtuXdR^25Zxol&ze`Z)S`i2DTfgps$NQM+Lj_QP=Z8Fdtf z4xdpgzf1ggol$o{--l=q^n8qXFx`Jf9T)v`v}cgzFHt`@__Z@?CyalKcrf-o+5@9M zBHs7N_cPiJ!@oJBw!z>ZXa{utjds8|oDlu*)bsn4gUv7vBQW^<8MO~a;Bgp(X_$rX z|K$CDFkUbQTcGcsXVd|hICVxX9U@QmjM@%Er>PfALH7^P&rp9jc=n8X2&N{^sDscm zMY$gm7uLfp+yO%+JRcqUU1!xHm~x+0Ctz?9&x-#M@!$>^JfCO8!xTILLmr;ZK1@4n z&Z9U@FEq{hIjiJF5m@ z;{Eu9AH)Y!PoGs&F!tfIs_Qq@>mz4XKlFd>tl9=$A7?(n!A~%sV6>n41cRSuK8@lV zU_L?D=a^40`+4RQOn-s-1mj;~KK+*ZeVO?r{3`QF_%-Ge^nZhTLf1EG&oi{=IQ@`7HjQQ%@NE zCG~`{Ur|q(`VIAjgTJMozbDV{s3(m7p8PQK2lB(hv{+h z!`SoWhoO_?7yT6Z|3JI4i!dPE|^dQ(6?klZHHOU zgxUuOFP>0`VX9_ARsKx*r4wo$j9oUN?ts2!6KV`5UOb@=!O+$C#?W7i52ju=p|-;8 zH4|zN^sk&ylQ2;~p=M!dExx~?Upt|Op}&E6FmmIBItar7d@#O#LiPO>U*m+@BHT2g zc0>P`3H2C^-aMg>!_X}gs`qcy>$VBCS$I3`hQT{&Hw@iHyJ7eq+C5I(SI}v`oj}y2lTyqLOlYr4^5~iMBjt&dD^vaLam4K*U&#O zc3?t145J4p)Z;Mp$b@QU%=(}emg%)WU-tv*To zLlbHvOgv707>$x22H!${=;|i_Kk4tM$PeRhCqIn5gZwc3PV&q0yT}iN?k%pN8GY1;Kg^20=e{4o9%^278o^26vin8#-*_f6(8OdMxCVe~tUCkzcT zp7Q?p8PBui`vKz#LqB3XVeG#cPZ<6Q;|cx$&HS98{y$^h!QjuCpV0G5<|hpOiunnB zzhOQ>|8JR3llXtfe1gH>lOKBiKzD^W*9ACLy?9dXfrB-Z zY7(X{om9u6|1$EIkmm~W!}yithvBQp4?|azU-XxfzZCz=$PZoDkRN92$Pd#i$q&P; zC)LtsRm*6wn?=UhHj^x&~qpCgsH96(}n+T>Iq%1pq?;wFZG1+ z7U~HTucV*OW4V=ng6Rk8Cm7mEKSAFv`U!e=(@(Pe5dBn6{rAvMFtU$+g2C62A9@au zANmfGzk+^vg#0l6DEXnUb5cD5qi>j0Pe9L`CRJA@aUP?epzHBTwGGCi)D!yOiVtSH z>CXk!_idAEJ&gBEsykr%-zU|>(El#_6NcVRf5O;%=+7$J`#$;;hCV=h;9ws<82&Kr z=7YPbkB}Ee;?xfYKSBMVr+-pS2|rE!_>Gd#06rN19QA|Yqmybc^nYHQw=o-U!A@%wT{SD)Pqrai&dHNehPttDTDcUW1mUb^8{+UU&1qLT3)o$pSnpBTL z7r&4-22({-YK;e$OsP#UJ#R|wgg)1l+7GkmO{pU=Trs6qUWBi5N^OAYswuS%X5CY2 zuPmQGr4GS(^^`gR!xv7ewHH%=&y?B%vlmUN-7s;_3=Zlph8_NFOy z5V~%rKcEMWLmw>l(oX1sL0AjJcTTAh7=_(14f~;QEBRp%j=<1e^yg*dfm>k=w!s8E z1XHjVrr`k0!sF0&_mrA~9ykVlP`R9Xz-kzTJ{W=xFan!l7Vd!2d#E3Dg{U8l!9Ezi zcS?O$bf{cG{QD>m{ctM`!8VwNM_{al@qv;1r&QN6>itUk9S-iI{xBY9bkLBEDP@1#C3_%7xx48d_(emCo59peMrpzl4z6~32#gb6qyI&`mK{NG1AV78Zf zL;nYv$1n)TUpLs7>DlF_@ED_ zU;_-r*{;blJPJJ@C$GE@Pr@jyTti;C3=Tp+Ou;6YhON-`3EBaD@Gy+R6EFo`YiZ{v z$p?M?Y#(6|MqwEC!6;0?7#xBrI0n;D@zZax8U{bb_78?(6O6-%EPtBy4*EaCe3$oO z^|h3T_0TndANpVz`e7#w!X6lbaTtS1n1CsmhU3unS=wic!- z3lrZUjw~ms*Nx~f0ON2g9E4#Q{3iVZ)5qz@movWKrypSSKY1Uf;0W{$(O&`D1?ylG zHbKu1Sbty&#$g&BgIPEXT|Z>I3_UOleXw#J?SNhwg!M2ATVWO+g03G;sWIq>1ERwb zn1a>oDL2eKgAv#Yqp$;}{tG`$!{gBN6WX-_AFPGp6Rd|vInNP(iSr29^KJN3+IuPf zpE1v%9}d9~9EA~h62_owDg6s;Ujn0{i}ON_EK_ z#-9Y~;9vCbr&KK#JPrDij~KWBePZOqDd{=Bk0B;xASuif*n-7Hxy;c;nu3F^f0NzZ1`&QY$R)=cn~b z`>OFosP|4@E5R!FtyP|ztGsts`8HP7-Baamu5u|#6B1Kc>G{Vg^{DtZRk@!k-dN@7 zE?HOQeY|vCmG7~6ja2-h@+u$iPCtvW`Wwgz4)do z&)Z7YS9zZ*-B{)8mij(Ezp={ySXpCLp!iGWReoAbOK_|=>)%)*AN^JQ#5j>Tr9NH4 z!fg_(Nn$lwvDQhfbrNfHRdey5iN!kwu{KqdTvKAmtS3^Tw=~uKbkf#pF5@2l<^(M?UhB!#wz#Y#TypPZ+Uyk+e)9B*FFES zvXWHsa(8i{oGDKHyO&E$Dc8zB*Y8iMGG9w~Qnqrw`?0dei@WDPHScYuZ1c`N=jeh$HM z{>^VId8)K~-edE(>CWP(g`1_WUj9WX^X!Eg^%h>|ay(X2yg{#rc>3|Um(1*0hG!U0 z1De2*SWd|7;l=HTxHBc<->{vW?mJSjjzl>vqc+iZ6t(`bEw@sb?3yCVU^W$Gh2F zSBkev*o`zwV)o-5#yi{GK7r43sdH|LH-WEt7N55MvmuD$ll`qVw&r#uBsJVzQGBPg zTwj;B^1`z;qkh5e*XQ`B#HEcto}+l?5>x6L$KUA9sNb;1H0$t%T<&3fBlu=oza-X4 zso!N8_0b|0*uQJr@sidey|05>F!9x#$NGA?v(JmK5#Qhy8TF;Sw)*D|iFQ-PP5dvO zFrE_*9_f>AJfnEFNxjVNthElw9Dl6@-6V5d>URvk_sWd=U0z#$vrirpYh#7PeHPy! zJ}$}Ud|Qld;=SVAQqif~wYb$B*Tr6(QD0~Gn{n^cjXtyneB=1OZ};Wq?(O0XQdy}( z81Lb$GU|QywwZObei{U@+<9mtr*sN!*x@R9w&6mVCfiJHPo3-uf-9|Xg zm&SMG>e+p6>f7{^+1DLEzC-x#wd!|kZac8C!rBhB;yZ@#)t0YW^KI8FXZfP|N?$sA z-T{0K_;PvKuF)^Alz8iNc~kg0<`7SQs_zk8JBjZVcAvgZ z-)@dY6P~)-*|$#}_#*fovd6NH4~ic!(`C1eGa~(_!4vQjo?$Ran38pYo%3e2Jvx=FSmWjjfb{r*ixY#>1pRG zQpQi2>bkj?k#)L_GNY9Fg*}hC4bWEX4He=$j4!sr+2_S~3}5rgnYZ=g8O75*i>H+1 z=|KmN)X9gZbk*#0mLE`6nr89Iwljk7FuuILxFvTiU#x9CH)-dtNAL#g=jI*8JAwBg zIjntxwGX+SeTaS#EOnT`+q`;iUZ0!oC*J+`xZ3*PAzO-#6|a%CRzLRIiZ?q4uNQw8 z-ljFq+m$1DqIe#$=Qj68+J>}In>R!FM)A$IT{(%*w{~`4%_7!Ee6t;IHR4Om!PkaQ z@t?a-)3)7P^lhy+|MB_pIUQq4-yM_s;hX7Lrw-33o_;(ZD+=0HZ>V;@s%+qIQ# z*B6Y)`Z47({5|XD?jOTHygsAuwBp~gV7?VUMEu`LeC?Wq)TibG`lE5~{wDm*8#C%I zD?Z0kR{V48--*9x)7<_2_=h)V)OX1BJ98bf;>-ELKB>R9kCwh4!5_GZb>Hr{?_*ve z_D$M3g6l$#x0^ER-zax(?7N6<9QY$kY(M@(w`A0h+x_M?d9TFXQW55V>Bk*-UAOWZ z7Itr5y|sM^SC91TY=`kj@w+U4?s}B0J4ewYGw8ByIDsBUpKU)dfp1_IpR{$^682~K zp0Mh}xaPK@LA|y5wzC;;%WVbwDs#KEL7YKtUlqZ36yFYeOtb&)6knsZ@9)Dmfv?T( z%N?6(BPbmw?H`D*C*3 zUqnCRJ8P}O>@SRcU&#&HB?8%{Y3o1(-oC9F^`rKf_V#G!)_Qxwc$eLkQQvF#=Gt?M zKH_@Z!+2wO_t?F9U9}$CT+u}9b#D^yNMT%i9gIGeJ{ZH>e7E!bka4QMnEd!=%P%nl zct`MVv)9#}$Hw(m*#?C1ExU)`pRxLtbtpHFf31(_0j*sUHzxj&b6q8F5?>p>K3-ef zE&cpoJE+-Gp{-1E2~E2WF^+%a1^B&}aD4g-ejn@H_}T@>O%>YpY-^v_@5$-P-y*Gk!_x?1Mut;5@k_wDw$ zxpCZSUzb{BV}1YZUN5#N-W_-k*yHMR{vnwZGAH`+B=Ou~_e^u`^#s1`9DEb_>R#y_ zPv+RN7cqbFt+wvdaLvWO|0?;Sb)QDYbSwVIwv753dp)(bM5KGxRkUlngrsiI?YN-)Z*Irrh+0^YIg8@VD|pA#zxL}wM*#M`Z6IV|?vs*NWeazhoh;9uN>V~u)Vdd|Hh%8wjV3?ay}K#sC;xQSBDwAb$E~M&ZvLFYHe?A zUSnQpaa-_qy*i^lKL>9V@79Mh>cw-Y!%@7!wv2lD9K54=oA&TKXmhATi!mER$;^|x!1VWiX`4cc;&Zv=i(i}+wcZ{kJBF4I{qwqK#R;BQi(f) zSLvFY*L4;B|0aH)lOk4qt+>V7LB6c)61N_&=gl*Ewf>ihBlD&eZyVl2_PBZb3GH(c z);#OMKQu?bjBgTu?PJs4YyX(c1DRmrOXE9^?`!sY=<`Lp@+t=~QeQU>Y&qmqU*m=` zUhxO;A9M8IFV)cQS&P3Nf6c$~JFmR9`Z=#Zc8TBGuJ+;YoTFdbIgEb<|F`Y&&3QZ^ zp*L&uIE(Ml<1_d^uUA3hd9S9OPuP!>&prMnloG_Z1K&Y=-n@3@?z?p0P0Z2Thqp31 zx41)iTj%J_;ysEt?>x?`uUzljLtp9hec4Nx?@!L|mHukR+lhC!bF>J)qqF#AzVzW6 z!*|HuueNK=jWSdlDz-~y#XpR{=`C~jD=+1I1pm+N@vVN~_`CRxlEL~+T^;_Gw-y}# zn)A!JXD9s-!ndqDqdsGgtFLdyJr{kw?7}yO?;*P{x81Ssg~##LKjnO#Me+{g>%`|2 z&xIiEYk)P

    Lag?n&Mt-mQ3@^2&PBj<0tPF}-+u@s8u2sg6>;B>&aEJ){1H zxvFnZ?C0ikP5)*YzndzMCI2}7k#}?7h}YKkCwCpr8XJjS^D^oivwud3b7X67+)Hfj z=A(9PiAxDe6Mp4A+~WdzY(8&k`y6E(`Z)2vUu^1ZORRV|6YmMBt9DEvecFq^=Y8CV zv*O{`=g^zQDBEoD9mf~!&8U0N^;zu^-nk!r|{K(U~Y4_^ct=| z;dPq3(l536hVeOV+a&i^e6A1LKQGIiY?S+_K|XlfCqt)wPElfZ;T^*}Tkbf%`aWl$ zmw3bYI`Pf4&PdLacoKN>u1}d`vMV5t8CWj)y_eW)EXVO5UvU+_Z({@i@kK3%q{Li$UrPX}m{1l2LzP_gdQ?=~HbxsqN<^wr3^d`q6^z zWUe0CQ~j~o+a>eqFy1)cR$g0uz%@+mNb)BAa}u(>J%(=- z-v;sBZhVe&?{~C8^zzmSx;sAe=f$O7$||;Fc%GEk)_Dq_J2yVps@-U!!=+xec>D0q zwk_L=FO9F?9#h|zX%kltZY5qPzV?q7<~BZO@kV_vN*#~jOX2(YOmj>-WZtM9*AC-t z`DDTIi8*hzH9^0xn8mlOKclX*$FyC?D>g3VNj;a^`a$MK3h$ADjQT2G zE6p-DS{BTIRPR&S#$?e?qHEs=GRNIoALL%Twmw+*jeM)Qp7Pm@IwkSW@pJ99Si22u z`9t`Rd@iG2GVQ)z{MvfMgN z_bc@KwCz0C--o~R7|**P*SY;JpQ-q)R9(CNF5^Cozv*ikl~v#HbN^QVNVk6chu((% zCrhWk_Ia%jMVdpv7C%Jp#VR7TtGb>JPu>(n0-vlpNHKW0CM6Yn729eCeu&u{M=V_c=} zC-J86K4SM4v`Kt5*E0U!boNQ^Mtt%tow?+0$2&1gOvxR?xAj}I=T745$2XVUV|cyC zonuPw>g%{3H;Yf&-GFZx-&}Hs@iu;Y_S`-AdS~%T?gYM*_~w%PS-j!zIOmp_mDjU> z!8eyV?8jUEUFVq6m#z5P@ZG^{Yx`y1j}7MT$42oTnS*Zt-^d(%DXHI}^ExK=ljqsB z;Bz|vXvZecyE}sKw^Byi|FK=wE?sV}&^|!(KZA7@oAiCO)UB7C-tY0OBKtmWn)UQJ zzTo$r+aU4A@b%2%lX*~m1KS6D2YGFcS>CoRcP%e~xAs5hHfP%KcHwpEYsr5YpFAsT zw*1njB;J~#*<+^h?Z7u%Os)MlvVP6c8^BxngW20Jaog~=;+;z!Vt9|vA+DFW$ML#; zIP>|3^ivv7BOa%|7oYp(?1yLZ$#IV#-wAy0;`Q`%MB5o_*PSG87=PoBX3yUv`RCwE zNPc`y`%tOpD88EEjLOd;OjA!e@6(Q3wd?aTM(zOf`M(OTIoXe~ZReB?ct`P0f6RLB zv0NMe@t^QLxj7#D^@{($Gb%svGELpjJ;ogp|4$3PbGGA!C8D>LXF|;!FLa@ zt@`Qb<<@tv<@uvS4j!q$Je$-tGJCyR@HNlkllgTBUku;B+3S_JztJzsiFW|+#2ma* z&k?+>znZ)OPAbdFwm z2CnD#bKB>);%%FQSH`y+ZxXN5KDq|qQGD{u%*9rJaqZUlod|9G4gFJ=&N+T={H@Pg zOHO4od5N{x?#*4ZdQc{*_Re9|}L z_{Q)pE@HvFj%DA!8`sdpTN7mep3bOO%;eQRo2-8qEQt5nKNei4nc@0U2j0Y=3cU6@ z7{?e=hd#XBe=gYXS=&bLQyX7Pkz<`9yyJKu=e5Fd4V26mpnb_ zBj{@jbnV*rt@_!K)IEXkB)-?#eOAB7u~%-N@hslpUuO48em4#5#mgmqW7XFiB)0gx%224tghgvxDA?9&pf)q1QR+Bj{cSeFEL>px4|&Cp+l! z%<^&O>rCU*fA1 zLGMIwcF=p#0}lEz^g0K91l{YPPoTRU^qSike+Rt*eVpyuO#Rz}KI))%q7OUhz352? z{TTXygFb@Z=b%rZ_c-V^&5XZ;-hkfjptqp6I_RC~%?^4mdcZ+HhF<5OkDz-U^a*sg zgI;qxY#U`4?F0+=t&3t82W&NK7!uopiiLpIOsKZGyV>G z1A4oI-h$rhpm(A-JLtXW0SEmUdYywlg6?(DC(zvvdW~G@a?l&l$2sSnas1Io9rRB0 zVf2@gMn7M@cfow^*R=F=tX`x1SMBHD*11^mH|2~-z5piY0)u!vn5)l=*ZNJn=ZfTH zBEVZ|^sVg6?xcKE~fcuSFj}?J)l6qYio-`mlrEjh=MS`_Ts+^da;<2Yn2^$3d@bVf-ER zTJ&}Yy$QY5L2pBEcF?=g0}gsWdYywlgzk0F$I#sldgc9$zk^6z*4*C$f z*FhgccRT2n4>0}?dM)~R#$o)?M;-Jw^kE0R8$Icu_oELu=tJmz4*D2+kAq&>%J@6z zwdm~*dJ}r9gWiVT?4Wm}2ORW%^g0K92;J+TkDQC=#>vL{tkLAdb@+(gx>0)x1l#X=-uc62fZJ?&OskS z_d4if=xztSay#Sipx2_0|I=ao(MKKhHuPZ!y&FC0p!cH>IOs#@eGd8_H=(yW=xylD4th6wz(MavuXE6c z(7g`&7`od*uap~v4tg#6_&*%RAAQt8Z$lq;(7Vx-4thWOfP+4S-shl?q4zlGm0`x; zL9az`chH;ATOIT^^kxUW8$IBl_oLT2=tJmU2Yn3P?Vwl6&1?s~7JdAAhw(=rbzTUgw|> zp?e+lF?6?sUilE?@1WPBkN@3a{Lx1p^fvTi2fZ6T>7e(c4>;&U=zR|Q7!6RJyB+k(J&eDDUW-0H?lAu7qYio- z`mlrEjh=MS`_Ts+^da;<2Yn2^$3d^$%lJF!{~vqrA0F43{_&qC{ShXOv1-LC#wvnh zPz1H6nl@>hw$o}WUB#d(R;@u*P}`wZvC=hG5!4#12x5&@#Huw`RjgQJ6|riKRm6%l zR*|%c`M#g?yk|0Vcb?hfx<21OzSmc-tG(yE?)P&)KhJZXbLN~gqu~!0@Ylj0DBxcR zzrTRL34UJze=Gdn0{#y8Jq7&T@Vg86OD{zK7x0gUKUv^@kXrZ?1^f%)j~DPa!5=H& zZ-qZvz~2FXq=3I0{%`?*X%PKiz&{%PU;%$E{DA`gh4A|e_?zJO74Wyh?=9f(fZtQV z-wnUJfWP!2^nU^WX!w%_?gy!bKT*KH5dL@pe-r$%0{&L`qXqmO@J9;xyWtNP@RweU z{x9Gk4S%qJzZU*L0slhy{RR9@@cRn*TjBQ>@OQxPDd6vh-(A38dI|c!fPXan$pZI- z)WV-A;9m%Tynw$6{#XHjEBw&{{toyf1^nIchYR>i7oqz0fdc-8@cRq+o8b2q@VCP6E#U8f-&4Tf4Zpj9zw~nSe*yn!_>%?h2dRZW zQNX_t{&)d@6a29P{#N*-1^gZGM+*46;SU$^mtKMXFW?^yf3SeR7XCm1|3div1^i9$ z`wIA5;rABscfju{;O~atUBF*@CHlXBe>D7s?)RyMztH_Y3*lGy`?!#ezTYSJe*Px- zV+H)J@J9>yJK&EL@OQ%>F5oX+g8nby9}R!7fWH?0Kmq?k`27X^P4N2)_*>!k7Vvk# z?eQ@0{+sa=>G!# z(eNkn?3}58YvE56@GpcvUclc3f6U;oK+#&^kHUZO;Pm`~-zv-84_G{Su(}}-Z^iS# z-3jel9LtjUoOu=w&pZ|VOWhHu?-}fa#_jnobwEZlWBAZn1OAaA^e5IsJ7@fOk73rc zP-Fjxe;)m~?7}k49zK-6KR6m_3H(vSA2KNISI^Yx_n+Bs$DZgax>MB&Z`HEv4}BQx z^C^&L>U2_5an-WH_V132bN$>dyo%ikt$IEUyZnF_&*9l|C%f#IZ;f~97yhZ(C0FD9 z;W+op`Ry@2J6N@BXz}Uxos{J*h#Z>6qDN#{1NYD~nZZ^};g`Bn{Bd`g>36 zHGIzWCEB3qWxETlF~F;#vEJxO%^s1ZnKbYlnZ*gW3OU79e1si4{T$&&q^tO(C+j(N zvQsM?T88(1Al_m4tjmh`!0JaK?QvNJe+~RIi_?DW zm&NzluOc7kD!!E;Y;6$QCI9~4S`R|4hBo?nPu4rxGyQahY9-a~F=$5qrziD0wNs~` z=go{2yi>M#{7}_Ms%=!vB=k++^rVi(=Zs$OL-u=Jy}%=uWBft$R<5_K&2Inl z2?mu)Q-d_KzAccZS*59VrPGW>nk7hM_4Mf9&zh|6Nv_TOMte1WqkSIlN4D=q{(0$8 z_p+fYikgP39Q>PNs|rciA$<_(pTuX&PLKA<)Lp&9@8aA$nom(Nh9Sn#l|z0r_{L%+ z^Wfj$YccI3j;e=l6TGv)e*fV~F7;vvH3ll6*#gZD*&5D;_V|Z?GyM39mG7d|WA4%& zU$Bcm*)>6bfLrMspdZ!SV|dox-fzdb?7eZk{Vuu|=;uT4L0Vl#?2A*?DA3Q&w$p!f z#*h6E`xAei#-8X#!Iy+?3F6$9(Wx~k_Pc9T|5Ulu>*myaSiS=Fh3@@~4)N@F*iOJZ zY<)^>|MrM#n<{8qw)UjdKC8=y-?+A)oY!@o4}UxSuAij+Xq)VQDqd;NXX*KAm5Mi_ zSN|SO`aO8XJKMWa4POxDL8x`mMR$b`pLM>7YrijIqCK;#dL*D(2TjgB^!8j=yv7bV z!8KX6qN+#fb=aTI`zCcnCLY?D@1s)w(eQhB>rI`W@fTGMAF7_*#@Gj|g+B=YF@v!& zDgFMw^n8V9e~Yg!7WddsaZS!0qEp2XRdrZ{xOIE<=KgM8=D2V7u>C$^HGbpJu7mbz zeAaD}JrCo3KlUrD$Ghyu=5btA^%~rW{dZ(E8+if#(#3oI-rXF zeCgF#pAUZp(yz~?N162T=4v&NYFzds*!J_k;*ALq1x4_>F|KyB+=J275?QXRFBd$mO@K@S-)3rsxK20bClX|KTs`L?V5uBRo-#vR`1=L^H(#MPJW9lJ1Tuif**z@D4U!(u_?@evZm-~)P7_YTU6 zn|bF(ak0Ix;UJ{uh(*vgR`jM$%`QV`KA434WC_pYftFoTxX^~sxe-JG@FrTN3|2=Yu9qSO7{DemA(P`^*`%PeS*&! zeWot<+a7AtudG((Z-IXKiM^>i^SAGmbo;9EZ-lnT*PHq{zxESh_?!9N}8}< zKB+f#o(miH^FbJ2S;ze1kwt|kDkM|&@*~csslBPY)xp(nhwOLet99T|yCKv%P?a?V zeeDdP&$Pn=HO3~mif5*Wft|-%q-mSgn>wN-ok#W@r=DdhDNza4f?JhoGxY8AdQ$kf5^f9U65)|=X3(x0zuZ1+F3C86HbnC$+~l)vb6 zT^{>DV85?e)uZG$824BArv9bU*lVfmHmXHE9v+lC05B&&>O;DYYcQW==f(4;8m!^$ zSpprQvBtPk-e{H+7;y~ny;#1 z&p&G3YlnXRir&<|nb;V=`p~TRfA|-{U!Gk~JMU_hcTtauhNGxDW{kKI@9Vn`$HUBc zQNN9-&r9tSM-1K?=*B|l|8;NbnjzS*=W(=|9dn|JSzJ0KeYCe{j43YlN*4Qhy74)S zS=Ba;h_&j*-qdcHJQ0g|7QbMRxJ+HwLfiP;?Bg}c$F-;ju{Ofr0KXrfGwrO8xAxnF zRULbvSp&_!+4*J0NbzpPD5}zV!kBk&DXdfdRRi7H=0fB7Z}v%XdY^27e#|{MUhI%n z#!UaJefWwU^oZ8up+&`i2=ku3^MxH7=PP=@{I62ixa{8s zwb$}0_G;*pn|o6uvh^zVLrRSwLQn=fl#1OB?dDH=Qya6jnf6xa9(swO79dLB1O2Km z3hAe@x>{ec3hn*1Nw4;eNjdsD=(lV|yJX6PcFC0IRJAYV=o_J5Yi%u{pKR;X#XegwldfV1ua@5<~S%s00%4=jZuD2h&Rj=*x<{VndJWR89kVs{W+okuZCT$H6j$3zr_B1K z0s8sJZcY7G4K{oJMn2j4|JbK|nd@3D&~F^KHS68NSo89`Wyk;@n=Z4c7Us@$pp-Di~1kJcioPqNybxBUe8H|hJZO|N( z(O{ppmty+MqLJVg&}@WeAElYD>Vvk{Umx1X^BVX!!+*{o`0er{pUnGDi;uC}v)W~U zyJ{c*p&vEVxxNMZ`6q8py_y|Ab9_>L9kH`eJD7^!3H{*N&h;g~!}?;*)>K#C`1t*n z;wN(AS3*C(Zfoj~dG+eL#|=69dg!;zbzYuk=vSTUJbpX$qfT=kzX$sDr#r82#of66 z7H}3{%>{MPk2-5>YD(Vg7pi^w?Dm=9y4aozRG&2=jc>m5Jk~*udcU>x0Xk z>%Gu-Tw$#57`t;P56p7`=u4M4*N366y=rS}<{)ce9?i^i*l&vL??&zG0BXF&pkMN< zLVEkyr7kzy^I{VE)}>oh51HZ@H`-N5U#Ifii*#2zZ+}1Z9oIOYS3=M?Eq5M2s>-v% zxjv!FbDeX&dkx0t_0G%hgMRc4Tg|`cR{Vk8p6T=IAoQgx3zg?CTdx*=s(&NUxBkX? zdE%=4Vdwp8-G}}CCg*xD^b2oxUj6{|rMEbbABMi^R_FU;4EmAH&h<&?TW>E^{@ith z=YF-Wb>9Ad=u7W%9zO(q>+hWFqpCa+=lTTn-S-&hpY7IV?gudL?sXpD2YtsH=j{`O zzUhAF`Uv#3En8Eu?D;Bvjd`iPtJL6x8^`x4_BHG{^qU^snu=%ZGxMif$Ne^EezRII ze?Gi5WfkR{Z`JYoDO;ajS9+nZeZ+Zr0?=>zgL8ct`h`(vPL0|GbuD2P>^@iQP z>I+w;Uk-iGU!1kC(yxWSalNyBRJHA9=qomSzqT!Z80QBsi8KZFqZ;VvzwEpY4bX4- zt8;w|^vgS(>pP(z@i*u5Oi3%wZ(noPrm7DrpO zIWKM85?)SH*%JZgE^ZjPK9_oBc<&%Vd(+A%_pNc=Azc)MYzdGp0d|aqMa@To{ z&~N<2xxP)6=Tqn9=~CtStWf;ibx%3ISlrm{d|g`u{o4OH>+jL%hX&}YlFs!lsytsh zpN~4BU-Xsp`j$j7UwrMnzLn5#`Np}v9{P1#ubZ?%Uo~V~>L6o# z{>N_5^!JTjNzO5wqdacs<*9^z){mT*rylyjBb!9}@=v?0oeexjZ`jJoK`{vPw>YIDatcBixsB`@i z=#z&Pn)7n69koIqKYW{`V~FbGP0%Nf+?EO%+kYQ>Y*)MV&DkoA`ziGE(c4nj8Pgod zH2Q{dm8J@58Y{nFng*oVeB8EF#F)OEddjE7JH+a8`dc{x(4$IMKPjv<>5L z+&05`n_3gc?eUsEZyO7JVEndJW!^d{eV46Q$DlDN&q5V{f~h~$T(gT^=gF>t^G}s- z4brt$Z%Z}j%}1rveNyGpH_)lYu}ZfI={%FaUpm!pBc4Wo)^1Dr^5&=N)os@+eNCha z`sQiQ^^2fy@jKrS*FaxC(^)^N@wgHChFRNERe8&=jvacfg&WK>W2@v(_`Yq9>3FmK z`A{YF^Xr`Ty(&{Z^oxGJE%%zsz#RRJ-JqE}CiHcI)kqVb=X^ftfZlt$bA2E5@iUy) zdGs^59(|_s{bL^V;j^93Z%xn#&vC9_2fhDXXX8SR>u%@+=WR3GQ>~6i!#U^Z_8++p zFP&;L z&$GDBw%GZ;>W6+wgYz*Mf_~%`&h=4Mo-3V~C!xx7m2op4`Xx6wuWuOokt?0IXAJsH zzi}Qvsmc>}9^Vtgc=)aJ_pd^vSonx@y&w9HKRB;% z2>N+Z=kcS^_dT{Pb@w34aDRmTWuX16keUw@&@X&^Tk0;O-hSpJ^Iea7J;w7|=jHK1 zzvM~hYmgxHO>NHON1z}5C+GS&^c~MQ*IO^5eV%o`|9YVx{hV`s0Q&Bjv-VMIqA>J* ze{p_ZsM4%Qn)(;NUz#4I+4z$4wU-)8qc>oE{a5F0I}iH!E6(*z&<9_2wtiIQSqFXO zHRt+nRi4+K^@WN*@+Is)Z#dW2LZ5uod3~2aAAZ}pz7=}!JI>3q33}hV&f}N1qrRJ* z>&HSL`ls{qEQCIsa2|g(^xl6tKUQ`?@80aZJblo6K6YN7(J$lt<`d`odC&(wbzYt( z=!2g*kG~Fj_vg;_-Oxw>G@8B@`oNEzmuD07o)ON=Q~Ec|w?B3se=PLL-JHi?2)*@_z5?HI=3eh#4Siyd zzSNu|q)R_jkvVr$*LwD}ul1;#dsX{%K=0nmdHgYAN?BI^QX@DuX)f%_jTT$ zP0$DTbFN`!P(7x~W{Y(^T=6Ri` zQR8AW(zG1WmpUi!I8xU=celq;`k90guj73&W1Q7P#jk?C#{yWNlf^+>C=<82(uAdKm#W?5sRnT{xs3sSK~a58W;1BCNjzSe9;8GcZzfUI_P7y&g!ko(+z!Sn)Bn$$c@wKOV3w`WV=k;9(ec&|byuS0G4=-@8Z-U-iU#R@K_du&1PJ?>A8U@mi!Qxzu?co1w3~%y}NFT;-kk zKKSzQm!=kJl2`V9uX`FoNHgzO&gZ-+^xaFH>l4r~x!UVd9N%ZL2Ku_|`yAhouu;Xo!I^#x`g-s`aKFGx(>OQZmoXOUVmJ1E@9$z4 zAzjZ+ec$_jj#i`#tor`>ZAQB0Tfbj^_Wu7a8s~QB$9$E>k2I_AaGpl(&&!dfa&@2K zUcc?{y;uu<$?y6c-FKtPv>E#HNZdR6C6=-0G-zkVov59jX>i8Pt>&F!C^8Vh~mVdwgV(1#u|^|RW~a-X$Y4ZZ(S z=lTxlJ&!r-GqvCMK_C5N-}ipzV9Y=9zPBg(96xg~ANtCtzJETekuLtU^Y-n4KKP8O zy|&+v`k?nc>wF#_{XW(M&pD4j4|?l)=lUk-<9~6kUk80;y>opx^uZ0z^&=B#pLXZ^ zTIk(>b#|;(`{)wr{zwzp=sb-oR}^Xb-V|vv<=TFZN- zg+Az)yjw`0|Cz!Dq+9!*X>4sj7q&pZ{C(5Ds`R`-Un{vno%Q^YXW=@_cG)&+X^F9_W{UR_I(S_gZYlW*o0SceXB8 z<*$Q&(HDivpL-ulBlIJ_#JTq%Bu-!JE%5%FHt1*l*SWq6`c+>!uW$KBDF4^a^)=AX z`qp{>Hb6h3*ZFx&3-oKYI@fnXKc=rx`{#c5Qt~nG2k3VmzY_ZSDd+ln=(kw?j=u|P zhJIC1f9^Fp!#tNwV#}YM0`;aC+q~H1XU!UN5#xUn~mbUvgo9;@}}bIGS7;^ z6s#R=RTis3zMH^e`}C(SEye~)d84YwZ;DSU^Q;_vQdvdQkg788ilO7mDwhqLT;?xY zv13^!2xw76&!f&qzORW8*Yix8{g z;DI(*tPyOKV5`AAft#h#$~;AQarC&dk`X|4@Q*pNU;oC{^fJ%f zvJy-2Aox7+T~s>!w#zi|dHC1}J|BFrI{puocT%Q(YclOyRTe0EG;eXIxK1gn9KT(w zt9-iuJiC2PJC83NUOQik91=z`%`OFI+U@gsJg6tMe*!1&$7Wvjg3#fE*a z?kLEckT#06xLlc?C+b)9T3PvcJD&=;)|?}ZA0ytfq18A* zOhp%umt8zV!|_=Y?08p0nRjAYMK;rO%xdHnMP4&hUTB2{JC@<4Gy!`&sQqgl{7LxL zl&t=|_!kH3276oqyZzBND~fTXS~j>E4dmak%roBZG_*Xv@KWgx) zMPQRuoPqwwd~|ubh3#?WgKjl+YED$+XC}v09rzk>HKr9;^W0c`41%|UkIL;k)nG9_ zJTREli{R6_OmNLhk2f`rqbk1%xpCFFYghS!i(~e{zA?2dR$O#iSp`Vun2mJmSTXp& zm>-eW%l(%76*`3b)vU6}AXPloN14P`t|es^6SIKbmVU(QnAo4%4RO_%`}*{z68}22Vz#+=>1|mKf7^f1PS?AqKYW@f}0@CDr|@U*sO+ zQA-||G3W3YKcg(Xk9rYnz5}!Ue1i`~aDRpNo!pwCMHi z2Y8jM4#{RAM#)qh<8ou5t+bN1itve3}tOI81Eze=;`Cwu=_<(t)?!sVas#?#EQ#E_z!^nlVsXuN&Q z8T>W&AEc4vQ_T$?_&VTAk7vckfOTduH7D1AZ3dfz&sp>I5559}iiV;O!wvhvGIfq}QKr4s zfmOBZW@u}m{W(5c3(Gv`u)X`h!{Bzia*kH>_=sxJiS{_R`yc)` z_|+Vy{!|_{U~9pqDS%j53ft@80C?$_U+eQBaA0d8Bn{vjq5qp{++&P$+}D+bii`YZ zjm4A7!o_o8$0=|MK2!soo(7lZo!HcSG*$V!kl&b}_ooh2<(paNRx_~TRuA@D@WaVZ z2Uq(+Irt**;}o~&?6c7d zgih@nS^M89&|v|l*K1z5lF*Hu*PpsD&m1+gEKocQW7mV?==ouiOC6&|_2PWywEol? zDmKcy-MX``%v)PlSySda-9ElzeF2p^LZNN(Z$8pDApI|ye!Dp?yRUuI%W7)M{Abv+ z9M(_S=b}hogMVuguNm=%<&K?!bEScJ)5;P>m*pK8IO5s;zZK^xr}w8ks%#jar=rxV z%;n(o!S~`ZjAb6!=ci=GCk|wTiZ9H6T(#f3tIAxDcw++nsoQhQoNpakRpu`)%^$AH z6-KPJh}C#zf9jgtvYBF4=8vUbo0)GZFb=QU&(E=b&vQ;c&K@H*+i*SoY@A=JGGYJ9 zJ}wvIRZK5nSZ~0f=uk`8aoEDF?4E!v$km+Ei1hQ%8CZj=K3EMF0JDF`Z(!aXI5rOS zb2ZLri+!r1VB1}EK&%S<>qb25+vF`Jk688f{ra~nF~)v@$v`b=)P5U+ulBtD)Czpg+HWV71&bQe=T@qH zTA*7C-Hu9!KUJS~U{SDf3Jlc8UJG5Qj{?{U$GKE}x}e<%?OXr5K9kXwMO}HDa-2)` z%b0%D=luTEnB4J~uWhEPei@a&U+guVs@rnJtGl2-rIxVjPqAjOS%S5K`2~xC)q<&_ zs6Ulh0WE1N-E_Se=Mv zJ&x;nMk;0t)vv1%t0LH+It`!oZ&BKF{^T+b4i4CN+}L+Y;8OEf4BC0nPFGs|2A?|5 zQoK`@2Yj^R7<2Q%)mTh|w}S7cxP4rkVaHOw(iFy19-oR=0pD8qeyq|Vp2|nHwGVt9 zc=|exD*r67HZV+6*<)H=7sOo5^K-PDiW`Eq>7xGBeoBjxtIlri{s&(JuIj1&6l(>G zWHGz`V5`CQP$HB|)kf91lj*Nf9GB&qif~lod2kgv0LvgWsy@njAt}LPZ1BbXsesap zeF>*f>a;ndSNF-QdX7aJFVfVhGzi6GGfuN1&$=$6wDr)=hxXL}p;h%<1#L65={8lY z1#DFoQ*~bl76#i(#YElJHAbb~DAN1Dx|n_`KCAlWziu(9%(pP#8JRwh8a-%`6-Rzo zGDh|sKdsEWIJ=G13CT$40!TCRlK#wZi!3WbCkO3IIkrCp|5$@x)iDD9Joxufd7_T< zP)Ehvz!wRw>K+Gg0?!^do530d>j7Jy#q9B4G{_2p?Wyvz_YJig(EC{hd`ho$svK(k zkHtqHxXN#i;@gj#U+UGAK7Frpq3#pYqfWPJ2+VGDE1J&LtxRY+IVE~AS=2kx6X=>0dLF0 zYr$iJt3H_z-VUA~&uUyWfUO6!&oR)RSc~AqOkI8C{15-;tTZZ4D_A0nslJGTZ33Hs z&+0c5mla)U$56ga@VPJDey&sdV-I{I;QN_MH_&hPS|FHi2e_1W6fVkFK>NpBEsl3s zuirl)u7uwY?K)^*qjtNs@^oB;TOzK};yV^E^i4?XU%cHKezLu5aX!IsTa}fgy>L2h z?>{l5X+oOgRetuEJ@VCNmk7?D;NT=GS2YfB~u9KVkbbqO~ zuK-i}^tF674#t8-!46O{5c@1dP<$46JGjaxy{{;~5ImlTF9+`gx6jS++so>Tx6-c$ zPl9J(n^t@+cn|oY_>5~akwFW}N@n3>2e|t(eD}s3iGALKv~HYK z^IazdS3A8gr|`!eI9G32ZAC1zVlPs=(HRwSb*nu;1;=`^RA^ zD!+KKzkjGfoYE4E&n5k-7(S~xp}={nnlk6+UBlsJmOdn}L#(Q+`cvJEWxB@W!|yn6 z_dNm5P1W&WHDV+YqlNVes5h2G&wIr^j_2PI&6KK*zwn z7TU^d`co5?*8Z*b^!j)fv>2%N0{JA@~tfYAL-OMR)1?&0+98;QbF$-%)ocm+GzgJ~pU)`AKDpFrl=tHJ@flM9bexzN!tUq-d&yBX5 zgK!?OZ0Pi|gs*rPH5SDzG{sf?Q-yKiBYSev=Wwlvowyd?ov4XaxvE6s@Gt0tf z76sAX=mK#%T;o!6S`T8a|8;*VXxeA&a!$c8|NZu*tii83Z#P+1*}w7Zcj0(^1J6h7 z%m3|wgk*0SQu=iU~9n2!LrYf+rUPEWuNzU zfVs1nTDv5`O2LlCXZ?GQ>3!v7bjHBBqzCTO;krEMDXrZmxSU*6yJMLf^E3vys+$*@ zg@~748;k&}0;>m8`KjZ*x`wJg&jSyE*C;+P7BH}v4Zc$LKeTJ0ot)94oGa9K=gS6T z9CMem$BiCB(0TALhIH$Y?p&1)*PWIX)uaCxs1K-JiG7V_Gc+Z?;d)_UZkb%>`FVP| zY}c){4DAP9x^8MN@PL(qRdYYdUe8TX_X1Vp?vZ`4%jVn+G{L@aWFFFbZXD=06)y-j z5^PkSc-T=@yiie5H{zk{XaY1F#{Crgnt!V*U${SYvZ^auA#=XzxfoOAKwql%?u51q zTHFGZJy#6O%>&mX)ah^_@39P5XjGq%+6nXFs)6IV3Ykg`I_~;GXsOOYLzb6W&lJ5k zI9z7^V+W8Mb{v9_kM206XSnrh>52HUs#`j}Ep!C28GJy{*nq)n7ntN4OnHr0D}|MAWF+xb8P|CxbL zGw^c^{8t7ZHt+`xe7%8hGVpHG$ zYTy?c_%(vBWxeh)@IM*&+k!XpCcZBWJS>hQX?>f4m;5fb-O_rGfp;3>9Ba_eH1G=y z-0Cot$H12x;@n~2enXtK2E9B^{fX`WiqNNdmw|t0;0>ZY={P&zo!bsU`#}@j$1n70 zzOO+)R`A~&;-vXhp|7(a2(hfw4g4YlzuLfWGw=rt{AmM^8~CRNUKGh~&vd=^H1J~$ z{1gMf(7>-Z@ZTBupA5Xyz`ro?xELqt`VPM*e>)@%`hyJm;|#pkz|S=B1_Qs@z#lg7 z4F>+Mf%h7C+3)kWkH^4|G4M$S9x(9B4Sbb>KV;zUSM!(uMWOfYt=C=uFz_t~UUYA6 z{B)d=f~UvZu?AjaC}+KahYfs=A%2@d-)Z31-*W4fE`NoAUn25Nw?mVG`wemK7y62Q zb-y$SeVYHpppO{z?-}&}72ItVc;Ja_%{YV?1B94vzLJ%XW)JV zKi|MZ27ZTuKVjf68TdPb|Ah0^e+|4x^lw`4iRZRYn%4+Eit&SjcapnXa^s}=z6Kr< zankYI4LoV!$BX#sIMW61IY=Kz&NguO>$&Am>njbs&cLrW#J|J9+YJ0Q1OLpxiyq8h z{svLbqJwoi>?QQ+TBTj2HtGoF#}H;xaY0><*769u;4%Dez8QfXPU1v@W%|i-N4%n`6dj! z;x`!hdm_#l zmj7!5Zx(UV`Zfa}{zz^+r}g_7ctXVa8Ou}BnHwj~j}vifsIL(EH1`XhuwR;h=MW8i zwuqnBpKsuo8~7>%Ut{3%yd$0O(*}LJ;9FR)cMLpf;I2R9wsShpNCO{Z;4=jOj^#Pi zz?((;r}Z%dUuuZcWzd(rlUuKJ{8ffHUV}br(62XezadV8fkzBHE_jLkfH$7oHt>Wf zPg?K!M{Ya(h;eERT(7$S|M&mbY`;N|>h@BPC#%05x$U7%KW~0Gx2MpipG}|3?ZveE zE^Ry%%4$%x=5~<%k$#tT3%A>8hw0*2*1NiVZ!lfDcRl3YE=^Ei@bsS9P$O^SJ5sYU&ZYR_2-hebNf;H+sR+zc9Q;=$v-5w9@FK0mE65a zZ+mI~M(*c!1MO?%yD|Ntv~lvEaeFrH>*NupkJ0{}`~vD$(7ut@bNg}HjpQ$J`vclH z$-m>a^`5TBTjW3aqu%zAzfC@dyoS7!d>VNJ`8(uoX&vo9$bUiouV~*TcmI>^NxO;s zPU`B&-%H0QZzlgId5qf$+V{yl@9X$J+5~w$x5Km_khgQYi*_`3yf>L|dYl|W-c4Tg zxX$NLa&JO!*U=tE-oWiPo=(we1Gx=@@Db_$ZsU?BCjBS zh`i!s9sj^|9BxNw49pXfNF$-g5HlP@PvaJ!^S>#rsEal4*&1^G{& z(z*!wb?G?Vwm#MVM)FE-*U?^29^!U{_SfW{-0q>hf&6IZTk~%nzll7|?Kaw#o&vX)bKH!W|| zv7X`f+qCL^OzQ7TZnrRw{cb<-9si`u(MkRjTaEV)l3QPBKX2=?CX!c@t9Lr7zq80g z#^0A^%S>b)bC5ak-Ud|6nSM*mm@&CA9<4cl4rD^r{z{Nb#1hxssAZ; zN%BL;edL}mbsYP>^ziw)eLDT)sBa)|rag)L3hLtII$ul%o$Uq$`|d4zldx%HLS zRnXe+kA*KzeFJ&=dx!>~AX(O}&S|6>4)}l@Roatzzv|-vHt)JFI zo0zN9MQ8)GURpP;MVqYC`UGv9wvD!hwwX3WTTkn!_0qa&lc(soowPC92yKWqKJQp!LyuXf4{rEFC9C8=(!+`f0ti9$Jew zaWd1>MrcE{0a_oeht{I)n#uapMrp&eL0Uhpm)1?2oWb<8QQ9zVkk(J@rFGLL{Y+0A zr47;gXg#zRZDKm>O&g&N(FSOJv~JquG^V2s(fVlJwDGB07o`o+253FB$y%15HbNVs z4bb{&y|ixHjTC|Bt%!f8Y8=?)+`e;407HzzS z`O$`GeY9@cWVP1CX(O}&S`TevqSi%d1GHXRH*InPlTD0-;I$e}DOdF*2(|T#$w270Ljy6Q=qqS&b!WqkCVbi-p$*V_ zXcH$gAKEZ&kk(J@rFGLLf2PyLX`{4Z+90i;)=TTAO`gE?v{Bj+t)JFIn;fh4owV(= zQQ9zV18soTN9&=rXcNclcrn@*+AwX1Hb@(w_0xK3-L%Q$SRdLbZJ0Jl>!NlVhG>Jdep)ZBn>Ja=IJ8mPFl~_5PwS<1(wy}Mrp&eL0TWJMH?TZ(?w~+v?1DhT0gCq)}l=usnf^K(>6jIq7Bgc zXg#zRZK9s(X(O~D+T{7#AE%AbhG>1X7H#4ej7J-y_0d|i3FaSNsP$pm0Ii2MefkkP zTg_k3(Z}jO1eg#AS4bfpU+q;PEJ-MAePq!jEUHbfd%mN)S zeg0}O|MdB(N6W4Bd8~*2^m%IfeE#e2QWq*|C$B>cVY+&rkf*;7vG_$w`fWDvv3xG- z)92Ue^L1j2VXa7oR`T+l)v}XTq|f`)->;<4->sF}pXOa2z0GE{$`|Tw7Q_Bc0Y&WJ zB7sfowxx9a(C#++j@vCfF;8)u)w7b^p2$GG+`b|$(AoZ<{U6#t-GaFxkB;c=iL`TQ z7tk)IT|s**?ftY*(r%!Ai}qvMZ)k_!W7&T{rrn?RXxfRib7&XPE~Z^Udn@hzv`^A* zpnZ$>W7=7DT_DR|ev~SUVO#2P(&^64Tc7NKVX(!UopgMEA9QXPttCneT(*E+HYuw-p~AL z_oqFYb|UQ@+6ABJCX71+RyOqWzfm8`_}{F@M_qX^*CzNIQpi0qtVi z6|}d~>S#aw|3eGpwm^wD|8e#ov46xK3XHnpohv6rZf&{u-oHQf;=k0IYbgFr#lIr_ z!x|wK<2o-gT*rBA{8DeY`pLHcN88nBHh7V>lNDL31EklDi?KNftF18GwM4tE zF!fRDe@CtgsN#4Z*5DlSy-KWX7*sw40>2v+eZ_xE`kTcdHq zLB4vqs1L-n&_n$M@(}rWw$oDb_zPNiGx^ix!Iv}-a{c-hd4e~VyfIk&4?(&?*3On^ z8(T(o6#mX7x5(4qpWOql>Xm*kC8uZWU0XlW^00k8b`;Cn)y`*U>zBcF%WKDU^2C;0 zem!`;_PG;Wl9~Jy$@|fT&$>V~*M4k|Q5V}K^KPmX}ZS zzREWs_(kMF!5=0M3H}jzSn$2ebo_|mbIGHE-%K78{8jR};KMMLsPZQSA4i@P{7Q0r zV$W*-C&=Au!q4Jgkb49_5Ca-ArA?DEqPe* z=g1?1_mW2iKN2@msC;9BUqBug`~mWW;2)4D1>XY;0u|pX%5CS_)C#1izX*DflzwR&j3oe@*Td{4iV~Q~7!XKaboi_`T#l!QUhI3%(l`U@Cq<@EPPm z!EYcB3H~B^Sa9{DoGN}q@MCcyQ}L+amypKV}=BToo^6t2J8{U!K?%Vq?34RK>Pw<<_ z{er(j9uRzpN5>Beej<5D@XN`=fiAZ9Zu?IncMHCZ+#~q2+P%n9f9dt=r{r$I_uXIT>k<4kai``;Aov9Gpx{f%LxMj|9v1v7@`&JvROo!8f}cws6Z{_XxZv-SCj{U1 zKpj6R_;hmXC%Nr^J-J)(7sx$=_mg`CKjt8vuTSuc$o+ypOdb&YBl4i&dmpUhhXkKX z9v1v&@`&KCl1Bv}Hd@Dz2|kWIF8Gz?3BjKrPYV78xwS`b`yYq{x|+}3f}c(95&SN4 zui$T!`vl+lP#xbd_!RPh;MbA|1%Hk_BzP}*Snwkc)A>dOzkoa{_ygoI!9O663%-X} z$4>}8n>;D_jpWwI-1dK&+%0(V;X1xY@Ds?rf?r1N6Z|o9zu=#d2L#{m2%T?G@H5Cm zg5ORa7W@tJh~UGI)bXQ&SChvCznVNQ_%q}Q!M`R?3Vzraov*cLZu_4{?iT!Ba*yEe zk$VN-?I<1JC-@9vuaE}>A98|@9~AsV@{r({lZOR=oIE1<=j2hr5BQnRHzxR* z__O3*!M`Q<34XXw=j#{zeDZ+c_mKw$ zf1f-g`0nF${IK9BlSc$!NgfsaCGwcygHF=%(MDRl<=zODs zpGzJS{2ubS;O~+r1mAU{j-M2KI=S`J-1fho+%5PE1<9u$1<8XZ3*_+0X^;5U;;1b>x0D)_KTI(|&>apZBquOv?h{seha@Gr=%eRJFY zz{xsax8P@!dj!9W+$;Fo4-0-|ti7x4XOkxdzmeP;mD~O=le+~ko~Gk_1V4e?EBIyPKEWR&_Y3|R zc|h>}rt5rzf}cSi68v`Zu;6cyM+6`4*YTr*SChvCznVNQ_%q}Q!M`R?3VzrOov*cD zZu_4{?iT!Ba*yEek$VN-ZKjUz6MP1_U+^2q1A@Ou9uz!99uoZ6lXbpf!7m|?2>u9p zRPay8V}kE9OUI83ekyrF@LR}}g1<&??VsEJJIvPc-GYxN_XvI!xmWO~$bEu;N$wZ? z;5jIJS6x#gIYq~h2tJiOD)@EeF~OfFj|;wyJR$f|bvoaq;1`lx z2jsT@gXC_(KP2}EzUN#W-z)ejvLxph#HrTz{cY#Zx(aP>WJgx}{@Xl%Ve zeS|My!E|T;^;6#{z85}bzW&}h*k5An+|*xW^S!Lb$u65{uVp<<-Yob>f=jwbb1wWhIEBIaH z6@tG_?h$oUMKi7t%Un7qRzQe^jew*Oq$)kc_McyL#Q{)lBza(!K{NPJ;zG1=7 zA#W7?Zt{@e?~peLzRMyVKPdQA@_NCqBM%7vJb9hq+sOTbA9bnDw?^;_$$f%9NM0%U zhvZ(t_gt*wR|tLzxkvDu$jb$Ph1@Opkjr%Z62VU-w*-aIjCy}=azKlF7__O3Kf`3aM5&ZBgbiU1kpHChZ z{66wV!QUqj3BLQ4I(~!TCzA&SUrAms_)Fvg!3QnT@#_RXp4>0^rQ|h&KT7Ts{8REu z!S}sN=j#>xH1Z0;ZzJ~z{yKTN;I3ck_-?@`ke3L)l-v^hY4V+2A!`@ z@bkzk1;3ZvEBJfl6@u^9q~m)8pFv(O_zmQ4!CxdV5j;h134ZKKoo`Q-%Tj+O_Wzc3 z33*cRN65Pb|Aagt_&&eU@jC@Sl{_x^E#&QjzeXMte1{u#{5HYIlSc)=io8Yer^q9M ze@Wgf_`zYFZ&>hi$QuQ}n>-}=JLC<5?{brl9~68ldA;D*kp~2Sp1e-*ZRCEzkNU07 zw?^;_$$f%9NM0%UhvZ(t_q5&T>7 zh~S6crt@tU{Cx7T;P;U?3jRKMNbud8b^HdwPbLovzLLCN@R!H~f)Bb~$FCFocyhns zmy*{A{wTRm@K4Dr1>g4$ov&B$)5t3Xzm41@`0M25g1he2@!f(?ATJSoDY+&1)8suT z<&OWa$diH}vRdccCHT4I3Bm6n?-cx9^0?r;-lgNW3qGAZCiwN_ZGyi*9u>TwyhZS1 zey8(|2!0WHv)~VthXwzLyixGI@7D1{g3l#y5d3EHpy02P*9$%@qT>eyA4gs%_?6^- z!Jiv#?NAR70uj7{sK84&Z__gFEfjZy> z+%NdoaWE9-?APjPYV7yd6(b^{88td5d2K?PQmXaj|=`LdAr~{J+9-&1fN9S zCipV)sNm0%w+Q|%c|`ET*Xn$m1wWrWEckuoje@^V9uj=_Cv^MvL!Pw-F4D+S;8DV?uZ@YBdE1iy{kBlzp&<$}A~bbPnq z6Ua*hUrKHX{xo^d&vM8ASL8{-4|!VW+a>t93mk9nGxg~fnd5?G>$dNIfZ&L6J$h!o8fIK1i2jrcC@A15j9~XQ!dAr~@+I(j# zEbdQxnLH$T@n2MYyhlaw6UaS$zlzV&f0vO*s7JBwzsGDo((>^=c!SA516R*|2XWj` ze@AFz?e~JNR|CsGh&=t?ycLG`=G6&)2IAn?3a!(_=_9fZbUXPSLjMN&!-5ZAuj4!= zcr|&u;8&BcUYVQkGvwVu|26rbi*ogcy{PluUGVeBM+<&0`ALGmM?OdJ-8Sg>HP7Yd zJA-_I(BD8F68uH-n*~pi-!J&FFX?=r7yJ_Pe+d2v`6Hq|KOz6o#ku9*r(MTCMDSC| z+eMsP$Y%-tYvgAMzQfBp{>6fiC%;DUtH^&N_*3Nf2>vB`RPclUs`LG`;OCHc2!1zt zLhyIUw+Oz=D>{DZB_--Z=5H!_h2Ynb`viZUe1_oL$Ty1iKdM7zwX?NZ@C(UTi8v3E z-y`^kQ$dfpI^`!Oth3D)@cm^96sOe39V0|6RwwUhtF2Zxwtc`5M7rBLAb{gWk~bpBMai z@?pQpZHG(A-xvBv$wvtNr{sGJzVAkz?_q+UMt-c|w~-&SIJZ2nlTQ%b^`?$LO~jc% zev!~GC9fCyr^%az{wwlU!4G*$=ld7I&n16H@O#L=6Z~EBBQMLX@2+p__;UoGPQF0! z>&cf0{sQ@L1@9-nPw-Iv9se`Ir;u+G{95v%H|Dn6bL59yk;{9@{emC)p3e8jBF+WmzZ3cg$oCQY56HWO zevg0Z_&Z;jTb|kE`wM;}`H6zROg>Za;`ep@a|Azu{1U-0BR^D>|1t8hf`3N-sED&) zLg)Ke!OtL{A>!Olex~4WkPlmu+djiT(D8pPcs2PUf?rJ@6Z_*cYQaw>ZxC^AAwN^-Un5^C_zoYlUqqboU?_zzmU9QX^9eK{vITsE%=Az%LU)_-zw?O)}w--LjGsLZz6w3 z@K?x(hH}d@`q>jH%@Z-tv6Y(!4e_HTI$ww{AZJ$rcj}v^~ zFLl1N1wV~EDEMvUO@hBpe!t+Z|LXY93qFB-li*9qzZLvx@`mSg>-80Rv*3q(rSsi& zd9MCka4zUvkpzen)tkNH~X`*+dr z7m)`=z7LZ(3;t1B-=15}y}!}%-xT@ICI7eJH{}f_Dat=C%|$t{ zBrkvA|Do$l;HI9pKmJSHN@9{IaZN}i={NffVnQm3NhFeI_Db7mQ7*2@R`zj8Wx0(# z*V3pPk!7-GZOBsANg_gHyCTc~eCK@5|MmP%^UUks=J9^c^Eu~xzUOH?0auxzq1riffp6O1N<1J|33KHig)~#^~Whb6nw4XSAc)5__N?UUFjU} zui%{&_x;9x4^(^-c&ma_=YH_L72g2vQM}uB*1ufopANoI@f*PZtN1J6YZPz&JL`Y0 zcz^J}6rTyc?;Pj29tH2K_!jUJ6z}l|`)yLZ34E5~3&C$ud@cBY6z}jS>#tUIH3)pO z;@Lv`0_ZRzZ`+_q+!7oz0`%bKXqvE5%A5nZB_-l%< z0bi$hyVk6~Rq^A%ce=_s-iyKaRQz%9LlplWe2C(Gc4ohqDxLvfr1&E6isI|R+g$C8 zv(qlDzpvuMz>iaW4tSH|tHAS$ZwJ3q@xb5M?|&7a0{*<>4}kZ)#u@)c@Z%KUzYXh8 zR{RX`+Z4YMyzNU){nx-3takEU+OqySWq%C#HpMRh-|1SX&NA>WFFX0S;8DeUwqw8J z6iUFX9d$4|9@qyr56u$&~je1?<3GnX~ z{}KEz#rwM0@1E*@{#ft>6u%SvG{rvzzfAGY9a;Y?#ZLj>TiqwW3jA2bp9goT``&+m zAEtO{PxgC~;^%?q6n_wWj^dlZ=PQ0dC)R&R@iW0!DSi|9hl;-ezD4mid$GQCfwSHQ zfOl5>LhycyF9$zH@vY#eDc-v?`yH=%3j8v~?*PA5@%Ou_{EBE0KZ1@Ze3Xa5yejje_rt$z}G7N3ixk| zx9-aNSE~E){lVueJ`?-{#UBO#R`D(13(C%V>#;BUEi2vx{(!n)x)8jry53(4zFFCK z=*IecsQZ(Hzy~Nk8+?M|E5Ywq{Acj0;{Enxzq_mZkmJFRQv7c4a~1y>e7@rQ?9ck& zDn1W;^HoOYlC5cRzsj&ry6d z_zjBB1Aj*GHQ?hfb^2}RX8oHKKMwp|#V-c`M)AkN+g|3>{~kQH%E|k5XTO(T?&KNp z#}!`$KKMDO{d(}#ig!AY_4ifxF@}L(sQ4W4n-pIKewX6g!B;3AIEek)>i)nK@WF~d z0G?HRBY03<@9cjt>!%ez13dqtGe0+iKc?(o1OHm_U3##7Uv-^w4EQ9)F95$@@nzua z6#o|d2gQ3H!hUyE*Dne1q8it2;3Jj&yWp29zDG~iU#j>J@HZ8|41Bfn`!x7wW&ewC zW$)?5erU@4A@kW2gc~}cv-cK9wysH&GqiPKi$-V{Udez zj#gRnwiDZL7M%{9xA<<%5A4_2?*QWU`W)A;ZYcA0A-D@%DquNyuMFGo!SdEtu?H9X z-Zthv&GsE(p8}78?*)DbxUKBp2X}#Yf_+C1^b@TAckrR$wPDO9o-4qsKIUCu|17xW zXD;*gE4U3V_C7EBjVV3}d>r`h(7zu%4=#D$0A2v!2lm~3tY1?6bnpszSJ>YGZUs30 zp5U*5N5KyUZ|z6k!1n|14_;7wCU^;4^86@x1zh6U0$u}`{Pzg3UssUh>hV zz$HJ&fmf9M#o$%&JuxqjgIh=NxP*TX?gp1Q`y7S&0+&2wz+*~h5qJ)~8~m;ZFMvya zI`zl66dwj&0hjeM2fPL@@vj1R9m(U`7k;;c+u%}%fuk{B;4vC_E_ybLb+c@4Y@E_v7`%KFw(&iXtC+zl@Ec>#D-@nzs~ zaLMPl;IqIb4?PE9T;Q^P6W}Fqsn6TMSA$D_-UVL=F8j+K$FhD6T;d-B?(WayJp}V| z8F&nQfAFWl^Wd@%{sLYCm-_S^$9^l|lIIEFHE@aNUU1jZ9FNTJr{FfY=yyGy^<&^t zpCiC?;Ih81122F}o?iwpDc))z;s=-bj|8uQOPn*nUB__zqQ3;(R{SgQnBoVWzIp zpY|Qhexu-0KV!l3;NtgA@G^KG#Q7n(bu8=m2Jbus`rx8}3V2@etH4X(QYX)YSHb06 z^ar@>IQA>&kkEn_=Dg%aLLam@B+B(%Lfc){gUEmf>*$$zug3G9nW#f z`QZ(48(jRhIf?b-;BMq|0C*l;`oM+YMQ|DKa_};^^u4X%RdC63?_uoM8pv^qeG1$S zF8X(XN5N&h?}Nv|<+`Ke$*i9Pm+=k-FDQNmcnMtA`?KH`aGCdC!E4~M9(|{elY2rhna1TTY29$o{lf=fKRjA4B%=8W?gaJS+YfJeb456i&w;Bub%7Q6&5 zb=&hC%on)KO9H$GF8kwc;I82ur_|@W;I`s>G_igRT=FmkJg4|&;018;`!sk7T;lu% zyaF!qc;f801}^*N1aQ}>9KX!tz2LUupMuB0Wxl#5SU(3Y>wN@x0bKT@>%dD&=VkB; zxSZ!(C0TznxLi*i32u$x_+=hvfV;uP?-KARxa9LI@Hn{S?VuF<&4bIh#()9+@rV|^Q3@_Z(E9K09$_D$dgaG9?+z)Ro~XPfb? zUjdi;9{|1?T;jhF+&Y8fl>96QcZ173ZUv8m%RbxtT=p9Wmv~a(d8K~`coAIk|2}wG z>2#dH`s={ue#=ns8n}%23UJpb9+&7p3vPo;-}@Cj1}-|jiR^bAxb%%l;CXP#&;8&F zl>G+q#o!Wuw@IwO0-U3@tkc0O;8IsNfL9fN1-u3>^V@nd>sx2CvfN+l5AFh&`I-rC zgG;?V3LXcS{c#I;5j=#t?J2PiZvuCp#qk^tz7RYHE_JvTJO?i8y+e-m3*gdk z2Z5KsWnN~3SCsuq@EW+}`DbuzG{-6W{mx^*Zg8pp@!(N#@q0IT9Q^;!|KLS%IS1}D zmGvv&Qn$mwYvAJd8gSRy9H;b?7r~?8(og;Z&x6anM5eLd61eQ+)4(g>(uW@gx5ltv z(fJZQ3jY7+|LLrs1DA1)1}}h1p67v=z-2wI0k0_gb~9LiGq}|Map2ZD9H;CH7lXUO z#qZ4_P&f6LAGI(#)`66(uiQ|!ZUk@HtywgnN4P4g6Fz^Dn z%*!0`GPvCDS_N*!*{_^qw}ac@GVg&|>^BB3d7A>B1DCu#0A2u>I5&cq6yN^>)~|p| zp3eZUflFVy5!{vF_$AKQz-`5M`3K?$m-vqXFMvz@7l4<*rOzw_uYk+Az6Gy=%ew1% zA^UYDIZm0E1h@?@^?Vz63|#i3cfoUt?{N|97r^BlH3WPyxa?Dxfv-^fY4FwHvR-}x zuYyaQo{QP9m2!@20=OGo>iJ&q7`Wv5Q}CSPUH^%3fy?}k055?{U%d{z0xt9NGI$MK z^4aPV=%+b;skbA+ON!3`uYilr67ZVhUx7z6tS|L&P@et96(0kh2bc5VeDE^3tlzi5 ztt{)y`fWd(^=)w37Y2gIz$O2efak!aex3j?fJ>f#1TQK5zL&D!isECzYv8hu?gV#@ zb>{y=@F=*{Pv^^6Kd0*7Y@jdYg4J`a1Thp)hk;8M2-UBQ0K;L@+gfLE2yd~j<#$0>P!3)~GZ_0axG){laV z-+|z9a2f9<;CXO~{|WFSxUAD3!OP&1pT2V%=jSBi=KV-j*h@TDf?MbExMW?F!K2_( zC%=K`!R5T+pNo8gyRrXH2Cst4xE6z36WFilde7~z$KMyYYBf*Q{5`O`_0xo`E z1+OW-^VN;>)`Pgon|mV1Dd)*1@Hn{mT?k$PmpWMsUILf((&3uMe!I26dlNVB$BV9M zQ_t{>)|}`Rc=>JSGylf?4&vtT*sfE5$N7EmisBuwW&72N4+XC(eg(MeB)-z&cVk-C zv*2wN{}sG6)M@X#j{O!Cp9G#${C@D5;v2wi#k*b4`Yy#!2d}Ad-2m=}y_`Q^0go!) z`Uci7D&8O5QhX+OS@B1~^NMc)k1O7zz<#UXlK&>~&5ADs-=_Fl@O6rJxRLcOHIIY9 zYs!8$ct!D*;9Zo?&vm|^b-en#+)~ zzVV5Q%jX-Pu6VmwIL~d>@2jps{&!aVIN0y5=H+7W{S<#3+^6{W;9%m=zFh3jio#t_Wv(evV ze;EeuR(wvK|J{nJajgQ6fs2mx`EkmAJM81&(%%BNaNj#h@hRY8#UB8-mA>RzuOsP` zdL2ohoT=tr`s785OP`#rxb(@nic6ooL2+5X^A(r%`)|diKisFd^as6Or2jmm?4@6= zRb2Yg^NLH~dr5KWpWi4h{qqOKrEhOlT>A5`ic3GA_PBGM%KoDFLD^saQaZA~w0g#= zBl}BN#Wzx2HCpdKw7~x$Zq{ja85SI#{sMRX*U9&s&-O9Jdl5JL{#=|xuuLs~op-U^ z^7|u@8x5U;(ivN~-^XgJ?5`x=Xj~`O_4c%)Snm>TOXDrn_4l&gd23fO{r~4i`u~B(GXXU_$kpVC$~>;wCgz>68S-+%;N30_t9W$|X^hKg9gVo%kC&--h_lV17I7j|MLeV(#N7YZiF5GlMf=zZBf{C4*DJ zzX5k2!}+`q{E*u*UuUt7j5iKm+0ChcD|i)oz6v_;fajiI`z7GJlbu;#*6Yk?fDZ=G z*~l9hpN;{Cd9sApPW@#4W3nHTe2=P~fKN>u1L>b5!0lDc#qV|C)@J6L;P++l${6O-S6eM+{c4^Y&q&xG30}-_Vy*|D z0iOSy>ytWK{jmhRw2bXfXwUpB;n%X?$*@0&25$Oc1%3E2@G;;P5}W{^4_?~9e&zM4 zx4>;Qs)N~$)&4)MU)at9(l-Wz+gNuJ&n4jbTR0E@!oqt3+}(}A-?2|M_1vi*e{2ND z^9uNnu&<1A=DF{K98dmxj^|~JYbNjVL9u3a2NG;^GLwH1YR4?`f{H9TJ%q1`>$bt z@G|zB|Csq4@N>X(Z!(wtVuA2)o&0TZ>k9Teh`(*^_FvYI_Tz;v_dibnw{vWGE&S%e zt!H_>kD#ACDfS<-z0~th;I$1bAo)L>=GF8`7Y4c<`s2WD59`SOau;}U4#zL+{Uh+w zzRbVnwq@=880*)zu+AUQkAYi7wx11tHMk3jxg7ij@Yt1Xe+tW4e~Qlk*f0+J@Z-oQ zomA)jVDo;yD)F{)G)+h5bd~v5{;jeeW^w+AYkxL#GDr zKAgeX&^h!;_FMduK>|DtUigje$Ae!e_FJ5FxE#DTm+jlbek-{9Y-c`uuY}*X+5Q-Q zvQpp`)ZrxP+yP#t>ml=q*Z;Mw_rc?+2gy&zr&vFC4%^=j`=Q`@Kga)XtfTKDy#MBh z@r=vYt7Qs;ZqIlg}0qw68_kiH!Q z&jpzm>)*AktHDcOFp&N01>r}qeHr$Df*1bD{8Q9Pn9j$>Zw%*u8Shl^=w56ud434o z{R4CH`vth`U(98G-OsUp4tW!uv%o7juS))J29IrIohuOko8Yc_%q4GapJ)9t3OND$ zW5Fx*bLJuWzX&`Qcj`O_Ub>mNjH?E2Z(w1G^H4gkn7p~OoX9=-+m;7Bem(0Xz$bv` zHZgw#{9fTz2BQBdcj|-6!XNmh`zyV((>p$=e^`@$Z?-x(L07`SLMOAkOo^E5~u+ zw8w?$gTk+2`?q1g3EZvDjR(BW`YzmmlladBFFndSQa?9=yVs*{qi){-w{e{)@wcIV zWa_OjgX?o85;{Qm77p-P#Caij?so<<-sRxYFE}1q*IU8uu^h+?(CJO*Y~!~QV*3@~ zDR5U$=J$Z#0UlHR?S1glp=>Yn)sglyqwhM4x%A1Q;BoBBNRM@e*ze5t(jT4$FQWjz zMLfTP=h0xq-dBO&!&pb^a1wa61M|1}$+{mrb`t}+uf9QarZB%8e!J2BZN^pV#9Ur~ zJYD!_Y!WYT^=5zY-1%%T^)nOPK9Tvs{A4`} zUPj+@Lw^f+WenHb7Svmhwd}Xtiv{Muz6rcU`?h&VJ{N*pIH#Qh`?cWi%?uLY9o}L6 z3f32fXAJ_6O=ErOSF^$Mk8qqZ=&Tf-4%|0Zg8wY`w9d>!>agFt?AL~U5ccE2Yp@r; zcZ0{NkDA9x{A7JBI=3>A^|jA?tY5YHz&I58!@(;bvc2T<8nN%ld@1x_1katxK+e^F zf#*+VzAx+}@3UX`ot&Rb&_JhwSH|Qg1JS*RXy?|4;DBPi+4a;t7AuexvF-bSikk<~o%7_74$nW$kO_@p+7pv6jO= zcLUpF8?&~G&SC6V?r-=0g#G5nGyj~QtQ2^4FoQwhcYs^i2ls~K_rYUNv7z*Vj-Rr= z8}&RN_Cvw*|6+TY_bb3FD8Q#+|17vG#P+h!{t8~2$6WSDAJw<1llYCChw<%MXcBm3 zFSeI`=YH@q5+Lht19)i?_lFPB=eyBpT5me-(K3cLoXY=fR6N^0?mRC+iRJ_%9sK zm9P(O#CVTnF6;3;;q9283Ht}ZT^BN!`P~F=$9ZMRK6?P=-Q=^37YxsZ&Y9qG@Uy^g z0C+k`8__Z9T%;T@%)nnOE`k0UUtnq9Alexq>2|TCo7lFs{Ik%F} z4d9jYo%-FrVtp6h2htPcIvw1)isRe`@!tR*#rb(6>|X(|@f*yn7q}f*t-ogd3SNKd z1N;8qQMK>P1h;S=I2iVig6FWmNPf16em4#b6GD7!DA?7 z$@5xp_gv1yM~J7xH>_VB!vpOJzk|RFYCoC{UK`DZ(mz*%7x9Y%qw#);pTToGv%SRA z?_2g;Y{T(93%}!qtMmWe;BLI2ltBC+gIB1pn}_gyzGM9uuJ9>20 z^~=App{%>n;DsdH%edx&M@!7_hyEJy3ie-FU+um}{Is8#M*{Z8ftOz9I+2h6z8Kub z{ZiS#9tSU@KTLzp_rh;ueW`~&Kd|3iTjo7yJ%`{&w(EYqpnh1?b#n{JQXZ=pC@10v=W8 z+Xuj7y_|kGg6G;Wm-Ev8R8K~~g8kwE{O2RY054}a zez}gm4LtWH8%mwO3tqX7>lS5a?LpT?^}Jore&u}*L%{8s%rA%E%fO>c*{}5Hg`!hs zLz(xr;MKqLx#d!vA3FTXeqE=tzVy#Q;PH!?i_UCtcONHTDfas^mw0{#kKVvMf%yCV z#(rxN=4J5l;IUhncLl#&?5V$+hxE6P!EN<^n0>ZGexQ2u0Phc+jyav3Y`rC`( zE*ghFN4Spr_^%{+}bzXC7z=K}G8AM_{tjULT)`yTih@bX*C z>G)lL%m;Vl{X7ZSzXe|Vhz(_5X#W@VujBYn<0osN@Cw^Y-Yx+zwr4K-Pk`rK%<*mO zNASuB=28!RY1P%&^+Ozg4}P-7g1d2@D6d1^2_FA|bza4|J_NVb^>61^tna#??a_{{ zQ^4~VGEYF~D&bgPlAq_nW8bi$tj9mV<4PFVbei8QTz)Kf1m-E1$ZCO8t@g`t@5_qw| z_A>8Rg6EEQ_P4U|9&EoAI=_ME?_oZOpXkpnuwPei))@f%$>4G7ujV1=+pECs6L!+x&3nJ+yow*%=S-%zX4wS4|7>xZFXb*{4nM}zo*}+(hQ$ zcR6^xGjoY^D|mDh*SWl(t#=3ZTkOR4avn~BTURlE6?wY@yz)5*_$}gmA3XOo+snG> zxcg34E32DT?A0EY{M3`U>HqfIY@fh)6T<&wApAD)DBV{x58>~E=WuQjzkBR~`P!T9 z<-W%d@XCwKrT#AiuTA6r`38U6x*pv6l!5e<)!^|~ZR+vRwALSM!DFM@UiP~VE{-Rz z_TNF^g|pdS`uS{d>wV^ZpubY=k76#@Q$K^}CNQ7Q;aL4TvR@15+cUw(gIDnS&M)A1 zgI8CwP6GU6@S3{r*k@1HFEz2fjCVMAbuII^p>qwmOWD5&p8JgR*$MW4iTz2={t)TJ zehcb-chkV_4(wO@!^7ak`&j2hezLvolhp*C`;LLcxe&a%k>fcP_74eH zuM>R%URuV6Qn&8C*>44Z=SZ$2Z1DUN9v6Q7#yXdH$DRIe*+=oZ=5B9U_YmI`V`={M zwBbALVHL;l4IwY;`JEQ*zkq!n_szl(bMMnwKWaGXNBeLje(3*$xQTOh$QkE^tMEpSNhvgM) zh-GXY(UtucJWjvU!NUP3e}s5Fp5&SS|1uw+dem?SWkLYycJji&LgXagaeHr=LYB;`b{AH= z3+Gend92~h1@QG%b)Ak@!NUs_ZNPdS`U||yJp4i2%uDGh7Pym_fwgu&_FG!W|+(@JYEG}UCUhZd7t4JWAmpcq2I;t z9M@0KDY~3-y66`-OgvSU=M#xH(m&g9%70-4>&Upy6|U|t-2-lo=RD9Mp#FG;cs&oQ zpR_&zc^ks^Qn&ko$8lY7A_mK@IjrUU6SK4qsMgLZCcUN97O&ISx&{?4R((c_^ ze}T_A?}LfgyNhJ{NZ8=MUIdm$1h< z$p7AlAf5xczb(PIV&L&>Szr2UoVbZ6s_OPu*ymp61Z;rLJK%*^d0e9NBY4%vdEkF7 zt8Y(^$3C9plzux1Jl>OaXdA6R#()>-ex7;kTL0Iwa>VO(rS|dv5I5^3o?(wN*PlZt zdX+Q(t$VRfCFsm&f8z49a9Mvk+i=p4?ZtVUgE*&w=liqYarmK!!QFU&sno-l!p~v* zv9RynoAs^3*^=5({V|NV8L!>n8Rs1Es_Fx)z)NcVZil}8o^!rB9m;-P4>Ff}I}E&n z-{Y1zv*7v5IZm1PnTBI5&7ZC&ZsITD^BH*5mh}SoT-6W%gueYX=lLFph5N8hTeV)M zf>%`Ec!+qt4|rH7hkU*W`@zcZU*ILB6FCg=EBk50jec$)?hk7a=fmKxKX~2Y_Jmc2 zPFU6LZ?Lc8{>eko@%Lr@!k(PxGWyR6#9h|@Ru1`;Tn{t$@*mBf-Ubn`uU{3nA6mjF%QvLIMaF^PrO3;b*bLyM-eVTcXZgS4=M(Au- zdE4J+zoXRpJp+8T@_Qrky8bgf?_tD$FL?Y>o-Y~ibHvTL+Q#)xcTB*C(4VXF+}Q*D z-&kLCdVL$B3_>_oj2GQk8$SbCh*$dIZinz6rqz-{ptf_FGbVr`8(K`)Oznl zg7y61^`n9KnIw1#=LEShWIWJqli;I{`oPU7V_T+Ve+b&j!F4#?+71giK z17D%?`5^InKJRz>eamo3R*Vk;zqx8kF##4z&@_dt1Ir? z$#Pr!S(fT=4?rh=1nXE>7f*nfJ2IDjc@6Z(sXVj`ay;%$+)(9u=Q!}FpU?ugH#gR~-q@S|`K)u@Edh7^#`%}~ za$nW;>D+}EI(ElCxO0ScD)00Ddl2$}Gb9To8P0WmG;tH>Hgz7G1^fIrTv4(wTnGEIs{fb42dnc;tD`uc+$|iZ=yV0o zx97}%hWQ!+?!JiaB@gEjH*wBV_52`sP5IpfopNW^zXbXR^yher-8c`DxBlSOC)uy$ z?JVN;{HXozW@8V{=1=#Dz1nB1(9i#i{Yu~74qiB!<2(UkfulLj*d@-oN`prSvprr; zv;GZk-^uYypD7Wq=S|h&*RXf*?aae2$FThh)t8O|FR1=-0r3NyCjejHOuSKk?uX85 zrLzG%rs}F&w6V_NhEw0DMR~k(9zGh}!t11Roj8lQ$-`i!zqAGY7od|rhV#59`oN#i z>80v0Jb?AfDsNMXn>bw&&a=$R9Pru~&h>Q{csb*o_ou}^!#c8#)`1tEV0)>n-wkgt zFMAwo;@r=Qsr5dDcsGkEDPXCC$($Z@*YIr*XBu7OT|B5@OEQT4sc!FwtG40MVi zUSHiY=xyNEMZAwcfH=J;u>N8-u8H7L)&K7!Ua#jZ=)=)&tZKx;@{&$jwd&O$0hyYFybbk zQMJCZ;5l_2R|L0JANT;gi>mXzhO*zvgU)r@4?KPcuSdy$6uj^&=S}VxoeXa6&pOiQ z&m?Z*AE)-Co5X$s+gr%PW8k&P&Ujve&SJGMSSNA(R%@>FPS805yu3Ga`TgSQ;QDhN zA2Gba{H`Ki?;ENN@eFI;Xy*_Wj4e=c;|7 z2K}7+yoEzg<~R$g4%5UNjcX?CUCRDZV^8BMov-o_UYp9}!rQVf>lF6eOI@!W0lrzy z`*h-s;<*y`gH@i(;OkU=errKz_ZY{Yd(+tueZ=c^sN$Rid#kf^-OV+;K|S0Koq}3l z??K1D!l~1GIQy-sarGx|@?80t?PY&F72Kt+`>qAA;sZIpL~JiXe}U4sPG$Y#S3Hl` z!2Ss0rf$osZl}Y(iu>5|ezQlwqnlVq-p8_8^zk_o^7}Ohj$ps`8P4-bgt*DSTkQ+e zV6Q*_;bGXjRQ-Pmd;Pf(-A`lvit6*DiJLsYw)MtRL;d>*930q2ye{k@MzH7q`G4ByRE(Rq=0vzCD!dq=@);9?5?5eVz5zLwIlI z(zp8)H~OPg-Ohx)`zPnVJQwz1Raeh}$JM<24xLzt=Uw*A_GfUMwO=`(a-Vac;ms3+ zuSdf^-;et?-UesQYr%d6aWk&A>U{MBbm9+lJbB66D2}Jx-5F;u;zp;S#+3x$toZHV z3sgSe11~D>I+OMDs^6YSyip#`fqhu@s|CiM>e<5k%3ea=9)SHg)h9Q?-aVV^!HYcX zdRAk6WpZ9=|Qg!l43;N$f-^TqexgXnSH2bZt<~ot{!*SrQ z(afb!jwEj4nWf?>z&^i??di^J{qd^d_`3PiM=kIg@$R%=yVQAOx3f9U+Fh(Kb>5S> ziN~$xD*^jld#*RRZoLG&a0=_l`DX#Rd$4o7i=iJ=dHzgv`to|=E@WBzjln!BK9abJ zGphFG0=TW}=T+#qmpjM%HF)d^zOaz@(H(pa>laj?KZkg|58v!ucRBFrc4z;&96Br1 zI(i1Yq~hNO9k=b&Z`*|V!s{-wmDeW{zL#_Q@9P z-++Ay@f;2PHgS$K_NB9*?*|?~it`^voQH$EUtqs4&7PM+r}{ash~4nLZ@>$^dEUn%&JIcT8*k6{t?&bbz-^qjr60}) zx6Wi8xn7%3+{C#;jq5FA-z+})@^k3K+wieW&r*HheehoD{MIqUe%%jp{IcJS+;&-LPZyAnCN8TPh{^G)!Wn%}lr z_G{sF#-Y$TmUyGryGIi@@r+Y>n+KiBV$NF#_3$`&3?C#c^HKq~{=@Ykb@(0hH>-Z$ zYb>AttLprpBwp{&_d4tO67W3Ue<;5v`viEc!uH1_&U?RLox)!nzr^zz?5&l~KK~7P zX&=u26x8h@v@lJ6VrstP#7&&>va{cw5Bt2@cS^9YKH;o~R}F8r9^}i9p%YW{zR!4$ zr=rf8!@(_;=WB?YIIGvNUs=}+3>Rn3o*#nFEEWG3&?&9uzH|!m<35-53%5AeR|LE= zjCm3Bau#uuPq&KmX3;r{;VO!tVg$#&2G&(+iD# zv+>K9*FndP&wG*c%*(>}<8ev-S4Cg-hkYkD*6&N)#IsuEVXUz?=U$8RAm_SS;Kc_x z@%Z&5YiSGmFF}8tx-VxSXuH z?AP@^&x@Qt4+hV_&*P=r7xl-H#7#U^RsS=<*QxX865(oHd<7m>^K#G>)Pow=81T7D zXFl;pb+WPrzQ%B~?mF;z58!lL?dX7K#>W{6k53Bj=eICctR;~9G_+nL`cMvym#;$kv`3J${2C!4=bHju&?dKb>)HI?XVxL@*kMN`?Y?b@D$?4Z}mjydVhepiGP;zyAk&JGRK)m zf_{U&TdiyV`Hk~G%y9A>|Ap&t8RDNq-1x1j^|cCog<98t3}~#sy#>Gf&4k|sk9P$8 zjs&+*pS{5g;P&^<^>`0>@k7pooKGGDcU|MG!#53wX7i^{VIRMY?L}v|S)7M;>bmI! z;wEqU_uBG?Hy6g&H$kVO`tTdz<5WJ|T)_IV$GPvxK7JVSdOfTCH*4%0`28nwbAPy+ z?M9`9?F_o4mJf==syG}hnSaMI7={`N@35F>8l9IVEBHSDWrbG^wqY7y+a zsP(cQe1*z?rwid1?|ly;zTF@ccTCN9t-Oaid>R`@*BJkK%Q%X&BcQ@Z#gnINM#!eyu;* zuf*S-xX~{u{ip6Dd-Hp6Sm=j9e>8LoxX`=`d>(Xas{gEked$f-csB@tmB%aRu3x}i zKQM2P{B-;$$6p@8I#Lf2!x2OCr;~`AakW)-awT-))48r<(7&ezoyS_>A48`+$Qe(Y zOW3ca*69G^rv8gZJN=FTudHVsnfGyqHy;qbz6kb(Y0mz02Y77->&yH;3!Z!3Sy!Kd zyS%*K4}<=Gv_UlT>oMHKe*wpNDDpM{JPw_GpmQPdMz1$5hkfN=&iZ_ZxS6kYY8~x9 z8~IfG)L`(cx{kh-c)j0V%yG)=)HlF>v$B81*f+>?*Gt*&DAhkl5I6cUbzkT@*w@s# z?q%4Q@p=1lAF0)4tW!FQ^Dn=baU^*3SdL%jF(dZ4&mb``0ZE%owU82 z{T6m-zxcQi>sWC8do&jjH}eu#=by)neS^Hc0{e9;&#kX$Y`-^gqaRcDF=J18u6E@- z$oVP*`?#8yMX)b!WP9lwCBqxU`6BGguRHVnF7#chAMSA_$K&?%`dWbcKh$vQlkvyc ziM($%4*PgJ&cDQS8S#2wQsaFZ_O**yU(UDdVV_g^?=**XY}Idvfv-^ZbBLRK)~;lI z=`%&}e1z*^D{}P#crniTk^cNW^xf*b*JrMYr>m96-=$?W`g_)OPJj1St=~o9vs9kf z6E|_@E^yZEHt+&opX!M?y;re)G0GnI#C69+@chvnzl`?^@aSsphgrCd9Y%lj2 zmK)xneqI*+|2gaDBjRR$qv}4u-d8iPsQoBLypjF{!zm9Xysul%U02pQol1(%pst1f zVzuwQ1fANK9OrP1w+j2Rn#X;w;W!7Yx;l-xiN~7i9B&rf#=OYyi4+ZYhFJfvWw4Ll z?(F}sfR~{o*WInJWxp|8ckoYHR)69q&kIz)oeBFW{%+s|#PBHWSEzNj1w5zDpFOT) z{ne^&n~2x*a2V&oLO$n$$Hs6S_JZH%z)ODSaq!>k`ukg>a9#zr+FsB4<+;30r4A1O zw?5(w2=@~=dDyJxaWd><2XUQu#RvT?hJ97l;b*Wf4{)xd{cd3WlFGwK;wBF<`dmQs z2x9;fVc$jN`9APbYQ0y*Ugdw^0{iWy&I6|rH-4kYGiJfM9=vc4llGXGyA4Nd&7WRu zfo~yh^4Uej+2cm`>%NWWMf8Kjjr}N9hdJ1nHgP<1&c6ygj`!!#Z~E0A&l}!6Kz#ik z?5)4Cj`Xqb!OOVOCFg{_|J7KhR}1_E!%d%A<~$#s30~Zv{Yt&f056~C?9aEfpnpGc z^ZvKN>bh)0ol~DwdG2--$7ADtsz)FXr-N5EbN=Um-vC~1t3 zn0ryr+rcaCc%3f6eixXBID^i487X{$lTQG*&SX9u`u`$s#W264UxoiaY3 zN3K)a&*wN}CvZK;`sz;H=ylF&|0? z%SQ2EOx(mXSJlc^E|8#98gh`H!Lw6W}r2r}aVSHt<@6 z^M428e-yl^-uJSFxQRcf=CQ|Z?6<7!o4_s9TQ~S!NZjajQTx$a*vD`m@^BgN?QFkI z?F)m5oADMO=e)_fZUWDJj0#5{E-)OL&7ZD@efeh2gVgOp;wH}3D$i@dD=MB2cd&gy z?bm~dn>h9R8)p+Y*Y#2LI`T^BtWb6Mv(afDxa8;GtY13Tx$fNHw)))Nv&3HA=f4@; zTF!YZB5zBeRrb9du$9YfsYr-b|JJ)v^} zaZ@K%HQr@L$Hcje>p{)~t6`s0es{WubS!$EUB%zoaMEw9>gN>Vjq)Fdy`|>sR&bX( zpT7ehQ}(;x%YJLBPYxztpGRDm1(AnK4ae8bpBBO1^*h(6%-7@K?p?SZ+M)k{FZ%dg z=CcZ5cQyEZ|L36-Rdx6WxJ#V}Lick# zCETx*bI5tbO*}3Y&x7ELmHsB;E}Hk;NxUyh?!Gqq@*mBg7qfmBwJweTkE;2dPTb6w zjrY?Ifz~77RvSK7oXy7tYcqINUB4gr0Q+67>fvnSjpBTy1zt9s;wcPs_P6(-Z>zky z{=%1oCOmG)IUuzx4`wX~!2iwba-v`ilsrujRLDtU|IX{c=MwXKe zZ$2ORI!@fo`(~wctLVhI4(Ff`FN1wljrUvF*Y;<7xn67g5XV#c+If9x4cN!kxY|6-@t1?_SH{(qxY3`h&MhNgAMeKr zllQG%2m6?+|CeE3dy4g?-+l>Rc*dExzrdq--`Y6jF!Bh;S^b#pMdwuE9_PM)^3uln zp8)$ZJ_l7^FSwVu8Si4%|38Jj`zy|;oGX3?uc^;B>$imCEWXQe%KL(jHoQSSj3aLR zT54YIf{y!8&YPSQ{tF&`!kLFRTF~DF{hHdp4k&S)){Cq!{r?EV8^k$`xQVl<*87|~ z?`p+yUt0c-+o~3Hs)kd4C~x3}i;vB+_I(r_??d<+F`P!+_}#4P>Uv|}AkJmbac$*# zkafML1^b_1A0N#-*HUO6-a`EhYk@ZrH*taN0VwffN1&+CbsI2Wt>Tn&5I)tm?EZ|h<2R_ndfc zyji~F%hAM5JcCu<=7HDLxqS`v%YQoS>ND`_FU;lj=o)lv)i(}Z!SUw~;P_+6&oJWk z>+Tfyfgey0b6_9CxvMhXjs`EQdY%W~ zMe#L8pZbY?3y(|o$4%hHjU12MZ#m#ewl5s%tj~Ui%Oo{>j>5j$li6POqg__AeNpA-7;sCy4tN1^lZQeVj#Kim09=25$lJpG zPWvt3xgvAv8`e{ZU*-P@;`RDb*Xh%Vn|Lbf^DZ6%FW_^oY~*b-^h@g8b>P#D=f&Rw zKizQh8(qxvE_s*=Uh;9C<-9is+>O`KE|oe5&*S|kavya&cyTr7N9Jq4XE;Ay)Vz!& zZsIAw&hd!-#o)21bKVyj-mL!Q%cr5=R_XsD`nZq5YL?}BmgCv1&OZ}~n|P{Nzw&y- zz2Lfv1C#&2Ob=Rw|gkq56_%3S*PJ;cp= zu~of&0{c>TjZm;LrZ!g79CT{ZM z_HiPo?#ct3Yq%6&v*$aYvsvxS@3&xIgML}{;X_|&tberO6i*K4CAmL83%vXoPly*W zEp0*PHR2}E+tfL5mls*Tg3lk2`>w|r-fW!mb&tS zxLfs^o-el$4{_7~^J=|cM%=_{t2%$$=#YJ7H(u{^5a(OqdAxotzZcMcHFVUzFp#*> ziS6sG{|vbKJ7ea7KR;tF0(U*Yd62%b1Uw&LF8jh8;Ds>9DSRVwGp?NKd;7n_@sxI9 zd)YU=;Pxe~FXyx`9BmTLt-=_NBbKrATzxo|IarL@ha4qYXj^{kc z?=|PZYxuoj{CP0zKj6iY9RF~PYYlNXVr%}ig}BL^t?IMKJD4y0edJD{0EO$_UjuAZ=hd< zePukyDfR!V=-O6BAcrTT=>xtLb-Aw0r{|#PwmHo=PcmceK*V$#C`qS_R`5eBE_2YTg z8HakCWOxJnJnXGGoM$iW7ZNvh6;}JyTJX5y9oDm7H`d)L@HGfL`VQ;MxMqRJ@wu<> zp`R=TujV;FGViYtH}T|D-)sE=`>j3B0$%v-4_=t+>`SK+H##M?e_e0v8{}s(?8m9~ z@)`84NzVCd^&#S!&+$t?>|%HW{XWD^JZ;suGSDgG_ab}aXBWY~qWa!?@WHCiJAK6Q zl(BCfj64qm&n@LRS3;Vc-8_yWnyaZmk-TAtn^)ZjDruxzm;87L-bnt>& zkB@-QRr~m6;$|J`>(&E5VP4tW**A_RZt~nq)$J_U=YDq9=S{G$s`dMZv2T!{PhsCy z?Y~_=<#^mrah}~+Ux$O24`RR4C(kmxf&N6|CjPkE7w&^j^mNvj_4Nk0HOM)xZ=qwU zdFfeY{cUPpB#4{qBmH-*ZX@0(&PNR=d)EnEC-OO~TUxOH6ZWOuo$>FxfprRazmvQl z;56ZQT|?e4aXoR9pP1UmSHr$~9qR{?{|~@pc)j~t*gXd0VPM5Lu z$FanXP8XGji(qf1I37#p1>B9_XBmswmVp;%I{U-h;IZeN*TtI+Z!oTQUvfMp)yIw_ zUhkiHzpLD*x)}E3R3CU8e6`BY_t43&bjI0cGwbK?cIK_0;SJ(Embl5=I@RBf_-AAL zi|Y1WtthT*+|YasehZIsJR_0kcfnov@IHm|viA6j<20Z5Zyxt^xYiKjCZ4z&?`5!$ zsq3S8;L+7A5QX2R;Q8Zu-lfk!2mP{|m*0sux*rw%n&YXeb4U)nms-F7A#Uc^{jf6+ zFM$_7<@%A=x!wma;6A*(U$^6y#`*7MIO&&=NcsHRBzV4qvmP!aZt}T8?T^b_(Ekwj zwi<8eZyLvA8&2^=k8}DxmALUcO4akV#LeeW#aD3QjNm70J#=#IS*Jbb@lWWqRp*fK zx9r!#^@6-VYASK#cdqJh)`-;9>7K)^WD=Y zPtA-SKW%zu>apV|C#GI-`t?q z)Wjj=*f%LNby{ZfjZy*@* zhkZd$fd0c{h~FFWM}i@5#1LcW4f=u+Z#d|;jftUt+v^Sa>`=f+dcyU8Xy$xAZ@@Q@ z9+OTzt?AUECy%h3Ja#TIH8H7a`USbnK*_+Q#Q4dFr>0CyTNB48O#-G)r*tHyQ`#ee zK-$iP1OABDllDh4Sqe3iPA0Nh`oG7U@g%aztT*J{@h20(Y{Z{P22*w-X$Sp&e=?Mg z_-ub9l}aQ%p{zfYNqPdo;Eq4(^UzQt*=*XM_NRh&)($6W9O-lp@ctcdy}DH zc*mc#)8xnJvHbxWITfYPpUL>_fH#o#P!Qp8GUAP70{#Z$Ok~5pP&k#zCOpA#Cgt<` z!W5y$mn5Hd(iipx0(LNvYVebhVA4x*r2-*O))VqX5_ZB9_Itg-bSN3jdVPMs?MbA) zi5;WOdXm{h(C_tRX)gUizc1nm`+Ui4I*<)TB1w;(P9_uSv~S0sOpuj7k_r<|nef8JCgNTPvAaz~$(7~31prqli)1!hOm z0e?1}@+339Oe&lWC4#{aO;y-$q4dU1oRUmTtT&V$>e0?5eUVf;6HbJZ{&b2)9`Faf zl&OrzLo=I9czl7Z-)=BZb~a6JLg_%nAFwG))Yr19P=tyw)dTd%g z9&a#{@OXmW5OoS4%~d4pr_~hpMd&9(!9><>FwS5&l%gM|qDavC%7(HYe=6k9`ZIRe zpUDO(V}2U7x4~KuduVg!&3V6fRCW7g7#up4lZ0Z}SY$Vj6HZqX_Eg!GX zmri=TS${g4Ooqb2U@Dak20}jS{a$}I?Ttis%uv9Wv;(PZDjZB^k^w59RMwM@m>&xS zypgn*)mO zE+aH8K7TkIiqJYwrIIGxNFtmFBoox&{0(L$lp;@5D!x=OoeU)d-h`d?)9UvmB8dpO zPEc764 zK)OM+UfOm7WJJjfdZ-veb}((zgpk)Tt+!yBQk6*g8+1dPdS9A0nIv_Dluhl7<}nfs zdy>gihFqqpo--M0Av;D(38(GA_M6}$v^gdtK_9jGG^LFew8tN&b!Ugd4XQ7YPWWgw z1~NWsAp!c?M9A!GRH_kwI^aoXDZg3jm^=DR*}hOZ6|ge_ua_2Piq=ddnfCeZP@1Zl z7EvbaO?a~nqD}b%o`{FO>G#pOoAub)P&h#P*`&{(%6dJi5H%j!S?#PZ5l+%Pg=xcR z&^3eEv@hgKo9KKA+L5XICjHq=f_AJ3wY9X@Z&UxvHu%Xj4J{GMM5qVSHj#=Xf+UcP zgi;>rqjV^st-_n2%HMIEq)u6+HWW#xytD;U)p?S3GVP~xNZ6Z6gi>_)p=G<{PbO)T z_J$&1I%v?UNYg~7sY_Fji1;F5YEPkTnga1P@agy16cBZGItQdP*-Sd@@dc@fJ)Uef zL`SQzO~=lpr$MLo1^j`e**znvP&SoJMm$u;nUsfGkS9cq+U!;lI$Z1+ZNg96xa|$m z*(5`~-sg>YQd!#8ywvl}&g`Xfr>bnw!BV~~H9tC&`69MA<)td1_DtnSRhbDS5}qV& zss2=>N(ctSwCe_`Qt5xbjE8pqP$=uAz0{MYcAur)CK0Aax?{A#Y?u}U9ZZ7WtS=ez zQSnn+(}}P@ouu=UH$p3ja^I+HhD`!IS=zm5KMPa!(P@r$e_A*JKOG1XA#XMk2{h8OwlCurxT%`X*9cr!jD|Tj=me>&_SPQyYuWDJSdorW;&`_=Aa5CQRKfLD|T7BPmJ`bss-%s_6(_PI>9j zld-c6e$rfP&~WHr8}XUu>b_q$(f~5kOCXj5H{JeBYHMj|~=a>#Oe* z7P<&U6T-Oo45zmkrdCtLoSwFhW%L7V-U<(}^ZI;Uw&9+;tbW-<+Ret4MWK@S<*GrkGeEFOe#J6WK;5@vc>+gQLz^K=&kagOi z@bl$iH6?e8f9Z4br2!s`7xK{SewqS{?Wyk2>~ zz29GZ>}(JJR5V}VG!LBPCP z2|w%hIm85&BPg+3K94V8Dp#B!r@xoiU5N*BDzPq)0pAMj55Vtndw+!np$N+Ry*`ia z1K(UQG~%twcBrm4_3ZWg1-=1|9R$BgBsYwXMX#o~y*|C4k%Rf2z7JsQ`nm4j)AI{v z7Fafa36=8tUVhOB!>>gRv?*SHcIe|O1HQn&?Rv3tACDajy(sY&XzN#by3*H!etv)7 zrz-OHeBMFLmv!a)-n{UWif;Ix%IFI+;d1wCTy#1iB;fI<{G_J1dF?9w+cvCQS!es5 z-0M56KE%##x2&-xSi;-Orba(*Cm`xBQEeA{1}+;S*ySkViZpV)m1{8w z_74FJ<^_*%vx?K-5aWT#-QNZ@{`S{Rl-;(=?mzjs``uGWfHvO59X|d5X8-cpW>$cm zrR*~-6q%y7!V@SWp4(-3POoEsy--0LwnFtUgneEQ1jJ^wTUUb96$dhW6-Dk3_5HPC zUfz>{d&h@Z;$qMKgf5gFik~41Zcn!XG0=Rl*9rR!(pI;?3Bcmx+PAU%rDkKpCG=k0)Nki>$RtSNoa2S>j^ls$|xG#0X%ipDgF^M>#uDqoRFC4EMMTX`G#k2w%CC6ejbat(6nBO?v2m{ zEMbyOYC#ZHxJtg@!Rvdvd+6Vk1-}yJ!{QWtPVnU!M&4|<^J&K{gijp~3j)<}OQ?TvBul3bG1Os%JXtHA}TS*Af8!YIP;8T&TP{#T_x98cG!i-zrNOg(} z{b3UkuD8blieyh~d3a6*E~)GJQEoq>ec+2af)=w2ekg7#6{PJaulH2d5EuY0Z{NDb zi2oFX2siP_)|G5XSxS)gN_1%jI<@j)>78H%FAC!q=c``Yl`Eu<*YJk!abBoX3kNok zzuyRW%nzjFrvrnCBEfU`Di@{c?JimF`xHIxg zy80kUU=qoR?x+BPQ$Hk6Zvk^TAPl_i31Cz%D2nCVkMAmh;r-*Bl%HULSU%iyCu@*> zA_U|CdM_^aZD+#esw-O@o$td8@0OZ_5`^5bkgZijBPmpc1~Lj>(jzA0x(!##TqpAR zx6)TJ1xoMx9U*{o{+yAW7#lHd#9$RTh;#1~mnrf|z^9*oTbXowe7=AN2IVolAp-Re zfsGLd7p*_s6_y)tP}M)AB^BWvmp@!7sl&7=aFW&eCB#abxG51ytn{QOFzI>PhyD4z zDG>x}MJggqk@1D66a+We$YOk|T?nVY0Vmx4QmKT?uY|Ctj!9j(;+GQkgmrpc(P1*% zy0do@&K;!~Tc&zVSXX=gR9g@#rU6AE+D{w?ICIBbNcxBfggWd8FcAL0#W`|?MKgda6K;HMtNHmM*U z;^w4h53pmY$9;1geSA0ikG3%>fx7zn``6QamcXG=msq8oAV zhfo-jO6zg#B8#+m1Y_JeZTl+B`C~%wj8BZvebZwEO9ikb+cpbAHOI{<+G3nyWu8L zb`sl&!DyH_8`6tJx|YbGaFA7;wB$)9A7BWrH|$T3^rtTJ-7wYm=7*wV*)SS_75H@c zN* z9LX(yIupTqPuVX0hkj0(-tI7$A6mhQ=KT4h95_2dc8Eg{5i8q>LIp5T2q?Ejd3cy) z@rI(_{;co1-cvN8j+CUoLVcRH`p)84g8kx9e&51_ewd^@k*Vd&3+Q zUivw%N={KYkeb$e0xuYkOho|ERlWvlh={T@kvi1_-^VpH?3KSKwm=k%L;^DisE8!w zz}=gohho!iz~AIDpf)JqJeksrDuX~J2Fl`xBkF^v`2t1TW4Nc}g{viu{G`7dv4Ch` z#id{TDkY%>DfBmd&vb5fu9Fmo)pW#Yd468zf61tujgwNxL zC8)Z2RR0#;`p5&mr52`m`EF{9j9QnI{J+~+=@DppAI!zWb4t`dJkGndBBdy^E(+BL z@`dIhU~dObm?AX}><%lUOl(AwneRxER6tV(4lCTB#jBuRSHd4*?*o=x6tC_K$BCL3 zp(_K?S)jF4e4Jqo*^a0NRts#;E|ok5-Y*gBs<5OWK${Bi`)gS7v{{uSV(!N+f>Ts< zU|*prp9qNenLm6T-{HzER2P9<$zgrQ`G4@4iF3VflATA!j}7lu(Rdec&?;}6SYE-- zQ05fbC?bkm2^HZr+*4gEG(tg&Mwtm35x036fWD7<;P3Cd(@&oR-}eAsBOnk;(v!&b9iGFGaX z@{y;-fyfWM;eX}vD zJCTld3XG0GvDHzjB$$B_6o-<0=3?2i+Fyyi;aR5xaxQy!Q zm7M%ga*b?^T;n3c7ukVBMk1kPn>lCKKpEbYIn_3pA%uXOB)N#46Ps0H#+)moWI$SVysrSzGUE>k0;^U5=%X_$+@L z`s0hdp+MRQtEFk!MtuW7!Gn}1x+#EU)2;7z$18E$o!BzBZ709O zduOHtZVt4n9Rx=CJpc#XU8zkS)5swg+rB#XfAh(42n^Z5A#^*xlKNpeXuLw%Y8bldHR$;?)j4W2iw4 zl`G0e2op=NOdNtLJ*i^-wO2fsg(I{}c{1M{eE1loYzD{u-b~Z9HIcNh*Z;CK=T&Bwt6zGp-R{B_5kj?sQ??2>R1}%S)$yE0C@h1>E!p&XXO$9h?>}!txu|kgP1533Mm# zp9CorOWU76-<1OoGnXjtN!NRd9T=TA{H`M7Clr?LDr_3Ryt0F4W)-P})+?7RV#UGAj?F}qcZzAa=Fr+_^~YFST2 zC&WNBFMSe>t%^G}o{ECR^7JR|()+N>vSCm!5gGQO-^frS7vL%X$VC3RW+A2bcffsY z05aVjTEw$}Gk`R_CiO$AS7a2It;jglpMVH;Pey;aH9HmHhQ`$zBU=cdBs=I%4p`q1 zft6kXEX0_w(lZGhTn6G5Huu|MRy$#cw`7I0b_StZ4i*w5f-mDXWMjSl?iQcQXY^)) z=mMY5{ie3xpHMmTnfizzcoT(`By7J_`SsVrb@s{)ll82%gBRJCV9e)5+|&gK4ZxW2 zvtDTl`JkLNaCD{7&e@M#N7|7wm_bm03WJGDB}o5vU!CA?af>=hLLOJtZkPC_zX$nt zSn<}a#+JrHH{F+3!;lKlXKH)*aPh7!RMs73}T%9O0Tz6uqY&6gEQc_82n zF+qVXUx5R{H8RQ@mZ$;V>N{5B!dq=;^nuL&g8-@KrFfy`%rNgMCWPVL z`TqNhff4YiN6>P230B?tTAMV zo-1$t<&JdF{{%_ z0&h~-K$l!FJF=xHhDY^%Ib(T`UqJ6`*x4j!JX!4xwBuI_1XE;XxP;r@a^6|dZnH{u?t@;0xv1phUL~HJIJJVgYs%} zjR=$cm}CG}jt`-LdautX19o+Gyhv!_HDtlP9x2tu@nsmeptFv)++_ehm;OC=3>By{)7gFr=}Os8lU3#BHo8x z#urJPSBDZ$X=XoM_pq}c3Pl-K>ngL`>HN`kgUm<0KG_8%BgH$% z>SsW2jEYnMAd^)ETaqb$Q$Rn|6to&3(6cih4>3VkruAka)iJ|GuOf?tO??+=aDIeH z?{;|3C)1!eQG3o=7OrThiK{I`)v5o9MNg5mt|6)w!QOiX@ov>}KtoT~dgW%lKPk|fm)c=mAZ)j^LiyS*7a^E5 z)V2c#BRngnQ8TfcGLp4peKWPF&pf%uwA-=Q>pg!ISLT0-TKK@AFkJE1ANw?cPm&QX z*ksl#xid6dvHlTO1hAA6(O0tAkv<%baDeB&5BQb>Wf9bJ^YCt2g)|M+`HX5OCJB8= zcROzQwJ1o@(w8G5QSsaapobS>X^Jx#&NK&%4(~RPUV8;CnG>0M5JohKC&dgG&2-_~7d5m-?q(Rxb&zmkiD&ww&K z=ijpuo{q>1OKxL3W2f-PRCT&xSmgN*(A>jU!JS!t`Z0ZW>W+Jo+Ur0%qu?woD;G;X zD#Y@Z;Ebr_&pOdAP+15FjEOG;xWWP2ufsvJMD-3}=$kc6V zebN9_)G!wyB*|(t%vHe?sR)P;qg=rq(EZf^d9==6GJkM>J!C!b2o&-6Bu)7cw~8X2 z92|PjwE)25;v*|VMl_7Y(H%=@@Ih?W-$<6P5}qmW|6@>}4zq48$JfKQV36 z5Y~Izkbu6|V)iecuw|dZp!MhJxV1|At%<+QaTh?z{uaei=%- zc@EJ8!Kl{ZPU0rib^<5znAQ@KAdv1?fzD>L-c!G_d#0EAb+}qhTXHW?1HKX@(nli% z;~Um1p$`E>z3iiuYEgYJBF&#IeUPI4jv&N(r5-uk#CPzMEqt5C>eCU)72k?glyF08 zXIihUwxU>pHVW)gX}+<%)pjX6_Kq*-EqxDH%3cDNoR2W{(E-QjiCg5bWDo&FUSfxz zKHO8aDg-s70F(BWvo&@TM(!A24c|y$CIEu%dL@CreU#CJLB+R`8iXy#Ku+RVcv^bu zi{ahsut#XgVx)3}g=bZiTXO^tQV=c&ucc2~jz4(RdqId_edl`Mo^76lwq_Hvky*7MTrqcB9G zu}7>|O3Ajo`%=wognZCP6sjz5jC#P8I-lCO4SWJ*X8rLR(G&^HzFiF1J13Erk|3`7 z90$1G(|b za_c=M+G>tudnE?h+>fQ>Q`N;$O8-TG_sxf2dnJ_fr4yGK`RXIi^<<6by7HmvjTo^} zM^c5^kdh7ukhMd6&mR`Ck31Gnh1^(_;j2&#Y-1gXbrD&siWZ$Y_zT^fh}>L6zWBr$ zgG*dKbp!P=K6bS!C5Eh2E2SqQ>&4UwgZY4r+XtXg3E9?|K|Ub(q5WJwjYrJ+Qjka9IIv#G3U=Z`}$42qYyu6uOADD;%{Gy6fT3oi$H;pf%bl zy+!e_hG+U3`U~#YqNzo)9%escy{7_|%M91%!^jP^e-Nr6M5!!XF2Hvmy(gW`00Tl3x!!JsNb!6!TNDoinS0v<{?~dXU5pVK zROE0{8?gyOCT>k)-to7o{}|!Pvt(;XmX?h;M)LULK}c-1D|2|6^dR<$GOyu#+P7Fb ziC*w)ctZsb9Z=h;Kl0Qy@k)G~X5<7xggsEeD|8cxhaVM^=E=8)R2V~U8r((FY4YlKNWb5}-Sv62a zMFPj_Gmu7w%@j1hfpBmi3-k0a_lu z9*%VjJQPjZuN8*<`^l+7s5`G$8gyev;d^CREiaI%N}Y)|lNFALjZ;2W2d!7Km55+^Mw&LjQCR->123SY*2uUZmIz=*{+gAhLi> z9}{8BRiNNxWJG-+lC4b3(2`o8Q?;y#03l=vLL$$I%6k+cCzDi)j>;c1^;k%JmK$4? zf{v*j+oLH5voHPOyLl&l9m4p)et4ArDrbC2*2JrVndl)7u}26l%$iWc@NTiDm7LIl zM5rg|g><9a!eROmsP{Djs*#5884_nxL}DVZEF}J zL@$NF!Q4wkVlI0WtVS*^(^KZ<+5#E%FX970ACRp4&3dOAA+abuEekdO`c+F&7en-q}TCI3nKCij{;?;t~7!0Z-|;)?z}}D z955;|QpAH2Zl)3>ihE9<2)>`xcf2-mN5KXdY)>4sT@I*nJ$m05b?pbf)ll1$X3-`F zSb%zDE6sjTs@x=O9-eu$^YQc7=j5MIEN@akE$5OvZax2osEe;z8CXHwVZ0B)auY_v;a8Qak z42ajF0qUTze3C8*_EH5Wj*-rkmLDuJ7A7E%wKoI;_=|a%b4|`k1T*PkSn*B%QMD2r6sZ)7 zh7fN8#X8 zGuh{mae$bZigR9{GfM;e zt*iVM@Iq}mx?0vNHv~Uf!Q&Yve8LPHN2>k+tt{o`gIZ@{dnN?hko8z-!I~?*SxuW4gcdI&&xt$$A zB}VX)=rN-t;8Q7!>#r5c74~Y}Y8=v_f0aAW|Dl3uYu9OyS%pK_D|JV-jl1*jMX=Q{ zEWua^*&BtwOsSlOLoTaUc2m<=lS|EHR6Z+V@E(S3`jD1`pEcz&{XGJRyJ%%nkkvbC zgac5n7G*Du7hzGGlr{^9*~F|5k7HH|SA#t#lZ3P>W@IQ8sA#`Frv;DnWQic&G_Eqo zP&>80qzy{FbEMbWxn7CghENgx1iomZhOg+2wOXwxOI?_TnC9Lff7J>z(TnLLx4S#q zIf@_jhW@xX4pXJpdn!F)eeuKo^e!=@l7;pwu7nV>x4?TxvstgS-s?oF?ExM#gp)=> z)??n&d9Mo6F)4IUN;rR{ua8pjJe%50kxU6ZVG7iF`bc3rh-`8w%hJi~KobeF)*0HB z_SP&Pq)F72j6wK7AEX1|sz!q#3YS)o4hp zhD8>EtSCCTJcNa~-qQ?Elxgk0eD1YK^7DY=W+@O|J!%uRt?S{+)c&L&bfDhR`mL!4 z;5fxZzgS(YK8f|Y-V?sfG0S~M`^1~DY!Kivc!c2#a~6aF>rMy*TQ9Rh+?s;aA6|^9 zj>&rsTFRcMIz#aeQIoKDfDk++I2-YSAmASHl5_4^2I>}=X#KUCLxpiTTmgX!<&$Yu z)K81jKs?uEX6Dy~#)%#DPErZ%RiSOP0Ear~nXG*U)J;$lkcW7yQAP6NH&+5O?ojJ< zRw=TeRjRT#jOg-jtiRSDt$hkvR`;@B%LCK|RTEQqi2vzN+WLk%n^TRmiZRK^f(P$K{i;A5(hkp3KGV3eg`&HF?A0^o2tRrP^{A!|7KrZ zY?0AQdl2+Wxz+4rZpiR%Emcn9<3%XtF<`k_sT7QR7;3eH{Qz+e>(-p0ey_x9NyvQo zK6)}10VMO!Y7>LBMz5V;N<^2KDq+oTkPyWXwk};4C&PXUFTTtARXAwSRZ2OahJzL9 z#eabX#W16z$TapU(s{U&Swge~^Kg;!kD-O;K}k+bM)F>4=V&(2!06H+r&u;u26KHY?(2jXAHSuMqyEwq9Nou_smOE#W@};!C*y;`Ss6k-8Cprd+6Gvp!S3TYU zybKO8G9UYs7(9XdG3*s|l%_-_Kw}&&dXQCHBmW2%;?1VzO3dhOxYFk31TgLhPmOZc z&yPG48=C2dgW%0oJZN5Ae=SS1-0VBRX(}QfXxt7X1a%GVqxM9i^*`&CCuC~U_mndtvX*=6Pp4q(63h_6H?TO9F5&*wIP?hTvUXWKt2QLm<9$^W5PlebruT# zc5Uu#T=ExdqjIf|L*Pn9F`!gKTDY7}`rQp~R5w1sK2Y3GIp#Y>XMs}Nu;SG<&0#dj zMO7|t8KI6-^xifd$cetFBi@h!VW3Df#TbZ*YGx;{BMeLi8-<8GzzsMjUJY3gLjete z2pd>qE-*|=0l<7v9P-}jv%scK^TF~e{)7SiF7g~Y(XGt`1WV(d^}4CDa#asC5=esR zjrXVSdggy)c3dNEHt?QR$E~N8VEvFFbqt`S89e}G5I2L2O^)m#m0|eNv%^ZLSq{VE z21*owDB@n&j9y0t`=fdzA-~~DaZR{UYcSCoW}?RngA1-8#*J9A3L(02;+CJ%7-^KI zZ+LWL!$u5GkSf)WEkADvS!lhd@>(~M9w}vmm2XOnU&yM}JU+#;24-dl$KPQ`VR_d6lD`~lNG~i3PoRgNEjR13nfl^o+&IV;EFtcZ>YGz!yO!Y%y~hF4yP8_9`BT%Kmj; z4u%*!u_j^-xh-c>R88?yH1Tf%+$7TS0uI7wDB>c_O{XI>5~(GDssEEz2-c#LaJSIN zFr&&lXc~E|AoDx(s>3Y9uT|E=hjdmZQSvuRixb*kf{s~m$q_X(PpC#Iqh84lA;$vs zyVKbC`)yr&k-g}%HId{Mo=N@)P#M}#fg2u`8DtgkTwzlzGZf3uGRWgOrPbeB2`5Q zW{?NN^vdFRAdKc$nl_Aq95NC_n-$cJbhvi#4bY~?%P(f+5mbay^uTT4QdNC$I-`oE z#;_q3=$6r$2vpHL=>YAHoJ&0ppKPZ%WXp(DjzUF!qCS@6-ykRl9iSDqff&L1vX5Ie^Ww?TTm#x zL1BCio*cttMOa&4xr*JQn4*bE#`I`bBYYn>s?W~wc}yV9G0$ls-6xr?-;>#lIto+d zg^)2--7-u(ZY`l9WDp5tU$4ZftJ=~xgdU(#-??($%fjG6Sh}F72z=J-m52stJKJs3 zc>)!kC4zm0l=*4+KCJm&27wQ{+wcszVhD}mtxX~r31 z7Mo{I1%PvpNw3o z_VA8`vINaqbj>KV4B*>|6#($K{mpAoq|~Q?(bUV%n+Pn3Ub=dj!K9Y;o;bmJM%7~i zh&6+ovO}>cRehu9sxAa|zBctc)O1EPZfnnL^qY|L;^(O;3k+`&=C z;U$D>@5)6j2BMEeeVf5pzV+8C0Y&&Ugf2h)eK2{pGv+FNbjR0~bJi=(dNyhV`^r6| zm(CrD7nYF?1wIROQI zdMF06QvG@3$VMPAw*(Kzuo9Bd;+*6ob({#&Iw$#R5b-&Uo~Mw!^!=^Rsa`{Z*>@GfWn()kK;9p&86C8(7+$qBUFF*kd93*!0PcU=g&y zs1^MJ(#gaO4pDkm@PHEnuWX9#q*eo~-O(hd<4>MPpU7i^{WOme_2|3wuPJaEf~7~B zpAWuOIR_xQQOG?59%A+dpXeM|Y>XCPgHP$-^ij<|unjO(j;9z_ymF|~m=>H=2qR-4 zbR0Cjl8D>r&7+fM(ghhp_&1<5+zMhy!x#owsFf%32f@C)twv0&>z3|KL@u zS7*o(^mvG!!lt2!iU3!yS8Ap}BI*m%u3}*~`yoWmLg#osc6GQ!*U@RXvYCorJ9JxF z${zN?m-Ha*3o|4HJOl>}a$n0(0tMM-v+~q!AMo zhQbW@w4Y&cGc+U!BfjK*VR-nppdAperwmeT)DnJ5OOslHqsI4%LvB*~@NUfxX1o-b zX?0?VB!iFF#ZY&EI7>S| zH&=SZx=GlYJm5|k8MlzD2!dPhndw$GqM@s%6E65Bnb{aNQ>Eq-S$= zI7Q0656Y8T-drcOw+GetfqR}@BdS1R9N-U@G`lg5k$6P|;yxCJz^QA;nXUIsO_R3B zV|a|(*+FnZ1nfy3$xlW>;My9#r_;-H>|rC7sc>2bLB`M?k204fA9|yIP5Bd(FG^bI zh-MLh^5z$E$y48t<^$RX*gNn;j#^;I@?PutvZH`bfL4U18T(HDTg#n-u|6k3SbP>4 z@%^x^ejbHVgV<2pcmeK7))P2my;9aiBS2~rp*>R>2r5(H-->0g%YIXTO_-XKSgD~p z?;s^^Xw`V#L>9T_s~1=z$Bm3Dr7@RcZ!D~J#qqlrfSQi=^F zbmHq+IG|L#lCneEWkiPWhFx~3vIJ0b-e}17w~&Amqkf?R9;bvTY{KMd6_vF)Ax$N9 zPVrB(Dx>gq-hqIqK93<*4OOJ}MCRRE@~PN9T`NA@yASNRBfbHlzV4aztMF$t*X7y4 z2ymilZahvEAfoE$=+s@%)6W^Mv{P854&Af)0$_u>u4co$D+)BGWjSK_wZ}*rl~>a( z7{MA@gu`HsG8!8%$&QO{x6#&n0%jgYts-?2|4ou2C#HSjk%2jbjm&aGD6dx@W-v9$ zhaOI3Qz1iT1P;5lLZzL`gg35RY89lfwaD+{FGonw%rWWCj%4jo-UHma4Ay(r9$K4w+);t`d#J{*LChF54#x%wI7N6?*c2pQfX8V(B;xg+5kh_@ z_EW>JPiuEc2#jxDRn#5pn;!US#XHCqLPN{|(Lh{HJ~B5`gIdQ~SQkGz#4%K^P`YJ6 zI;9E&r-Xlzx+ZP9ooAJ6Gy}t+>#r49Rh+gN`(?+{HS0k*J1B7t^PGF)G%L}1r5&X- zi+oV9_^DZptvwAw%r#ztIHf&%IzdVuC~QdT*1U?NLh`Uo`Iog{`6K?AY%#<>%f?=U zo=7@SG(rGV2?DVYSdp-mQq)@r~{^j9(&{NHXhl>SeWg ztF8z}bJ&T#LXH)gUv5A$Ont5eD_=#h zhAY$`4HQdbISxX!yIl&GPcy7E7)aLwJ9+@++Ho^X>UzaG7zZz|y6Sx4A)3e<{9F>R zv0g=G#T36SS*99K;SB}oKA%e+3o=`QG z*1!VkUlsJUX?s0>rV^7=7B{lqvngjjSI4xG95Uyynqvhd3iLPupn;b<1J)}YrrpF_ zq&uF&r?c>Qr5r7B4EeG8k3Rhg$5X-`w@^!B+!F|hl}@RU6B=g>+?a|*$Xf5|-@qAQ z>?u0PFS)PgXEZyS(7vuyjg4u-@mf@KIW}9>@{Vd_v#)`wS@hf|;RdAW5H&TuS$3Ts zgbI?EbfyUoO7Bg*8jnMLm&1ohjgpkWmA|UyI08 zQ!L7j)t8l*yyC5OguNNg{+p>!M`dd#%h0N6-Od(0F($sd6SBk;)GQD%&55uxkPjp$ z>WWVkspX9!Y?FtxvL%}gL*;NiHSgyD6eI$ zqp^(DsuQey*MuZ3;#{)2d_2wYRoGNemqNW#HAWpRu7N>|uR6F%jFvs(a@e08pM=gi zCVMi+!9Zd*0knyeEOU%#2F;nnu--FGOQFc$&ge+I?2uIaLeP?3*5}0brX(sBJO6+q%ZfpWSRICl5a$SuGTP|i2!PmK zo~k1gSTXWQOZDPFtrIp78e}?y-Nt<*Kzs#V=AFQc~1Sbjs z&l=KD4FZ3oJ3yos0;GX0n0!+BVK!t|xkmokF!EBKeD4jdrm7&oHD7dC31X~*x3}MX z9jRZeR0~*#(9VW5+OI>T#?@Aku|QBt z(X~7SYOTg#q%fM0j59<74$sN*l|fi~?ksk%kwZiZyu)z}1XdCD1y?np)Mkbn!J{Oi zeRfV(Aybh8FLdHB2-jIe!&iY%vu{z^aYBYx@fk7sG2KashA}E&81!Y;^{a54k&t;S z0R=^1-6xL2p)0fZSn{3jWGKP(oK~|oOi>oMLxMQcr4L2#ie+~>afvr|sF4(LGGuaT zhl~iBCdKf$itJK7sZIG}n@;Cg=!>wqghe0@Ih2uuI!S!cCQ|>i)!7uf;W?W~*>Fjn z6q+>=CXUqgQ|aws2Sxl)UsV?C8&bw7kDB7y8GUsfqo<``h*}I)jdn*x-g+fbP_f`8 zRoh zMF_YEP52wlB68xe*b*Dtj6Yw0t(-#-VSHw;1iP9)B@&9BT-6E+-&a2lR&Bk~yEO66 z;GH6o1~v8{K7N&cO=Z>U47k|X;j4f>4h=HBnM%=+9RF?-HZ`JaV1RfY9>evX9GPfF zES;dk62r8qq@)O#awjJE)j~EXI_zwBL|TCYw9Yz`SYV+%#I+It2vA`%jT?Wo-ZLqq zI+JDA1_3i|b-1yC4EAjEUDWW3^z}-Rk~R}-Of0};)jN$&7vv$a55fp(Ae;>Kik4F! z#Dieq!TH27>7S}?CY8e3?@!X2`UQE{yuixpqlecm1RekEPy!VC?3fDYsgJJ48i1Os z>i7W4^kxasHeo#gfH%J#GgXlZT)GnQIRKE=O+gn(#NJjs)t+@OchK;hym2i%iwvwi zX4Ev|RR!EM#=w|WA=C`OKk97@+|Ax3>#tvhwoE_Z7r=kf z&2?j2x(w8oY)9MMK^bKxuN^}se+cK9;u@GnfMCk4Q!_S|!61ZgYvu5;`UH>E_3oq5 zK0yE&vdn8m(z~O^@p|}i*I!%TPlH8HO+~TJ$=KX>s4t8b0p0q*sDQESl}Dpfht`^L z1G^K6E4fKYX39G9p>A7iZ}Lgi_*+N0qnVJP!hs%HBstxqq4n5#O+uKPA@;coPO_FX zF-s8$(D(+2D#K{6bFfLPh>Z2u=HN%mHSd;X(I}4&`=AV!KWpoj$?|0n-xIFGen`p{ zgLMZ%sB#2gqX+>|+?WbAo$JNC1KEj|g1fbydd}-n+Y|PS&(tR)f=pUR5UfiWw%LMJ z=yZB;vjhf2v1ChdbzZH{srteW>J&_I_ih=vd|!?bDJe#e$6kb=>QCFVv*Q@!mCC5! zI!A$Hhyl%xY2dVnSEv3Ju#cQ=lX9Qd&7U`m)s*?j>?$}EG*dfG+_+S)Ayu*Aqyk_A z;R`?`#3XqAUyu;4o#ktY)LM%*>sRu+r`i+pv`npa&PIQwA??Mm;YwAP0x&pC-N1A( z8Ebp?d?X?XiPjGS`oHVD6%%}aWTL2mPOZfVOsJ8WJy1py3$ytRk(wVtV;SJqX(}ux z`lqaU96r`oO7!X-Lgc-#_he5);~}=&C@kZLK(Sp~Q zZ$#5mrx;-6;2YHgMRd|4xpr_J;05AdoafFLAnMtsKM54-D#sY`l&o(E>BPubwb|&v zBYIeS{sI18&A}*@UvYBB=nkNRNIFM6=sQ;N+7fj7 zCU#2(GAFXUu41KZxMBUZM)xEl3$GaI4t7@VO11~{=r}t~ocgH!ne|Hf$K=2CDJ>ut zeEdK*Rn%=RU>Fi3fkRubMD=U5mqED{w7A1*@?geT%`_di#n4p0#!#=IEj*OoO`Sw_ zt}9M>?K2H9)z=wpLM(&iu(MU)TzVFoL`b^l6!rC00RoG%o-k^=$t}aXEfjZjvH!Z$ zX2|d+|1{V~GEW`ITx&q`u(RFC`XP7-?RX$PPxffGREbLQD1!gNqEl_}*lK{bkHFa*W!QP4*y_R&>Aa!nn>mWFkUHSj^9iBctM zS-A8icoO==NJdnXusUT2j&G3?8rG(hZCL4R%TnR-SsfuRJK&$EDVfR2bXG4mYYf2w zAKs9geDzX}^V=C6@MObtDvGRX{fh`c(@kvv-@;BubrV2);Wg|IS02+GI_H2atV0Ot z2I_VGrdrIJ&`Hm1Ads*3Z2XI!Tn`2-9WO|>S}(BI7{WKSE`t#{`YWEk#9 zUN>p_3h$)md^Dv$V_CEv*5_>8hO&)L=4laEhDwlBxa@sf#cqsK!`#!QCa2?n8K&rqPS8XOy847=%AH5I^`H5*7@+#?%|T*6M(4M(}voCIDk0AV2E;n zehEGk5c(xIZ+Gz)bt5+EyM+tea81R6<#9vB!T%dP4&lO%beDUR!k0R zAwqQEPvGXy4J&ce*2nAsCSr!N_9{$FJb;BjD4^dyuOm1o0UPfShwzJ33Z@7o3nY{X zBuubE6D=f2ECv_}+^x^4#~AE4*Vpp%A^{3z5-FdTP%}-w5u84mbG=d#1t;NF8fk&B zHF}=q(hxWw6-6Xq5)>#Y>y?Zuu&90$oB>ZF!x}~@?C3jD!~7{r+CZuGN_CshQa7b+ zCKXCW!Nk-+ULK1Oj)U%pU8X^u(^xK2%3+?7pV}`a2=bDo?-Eml7ln1M{@7~VtbXKfdLF)tNx)b>GOG=uKqE-Yy4WnU9Q3&5i)7Vi+FIW&1f;;s z-lhlFnOsf0ssvUY3KM-xMHW$Dy^?JUfuO2I@D``-I8wSOLRv(Epi}AD_~`XYG!AZ3 z54wdzuwsw_-0VnGEOi&r-Q;wH^ALv+$^f{q*NDxAylSD8DR}WA=#dv;`< zy_}8A9QfLb>LzeB1NV?6rAeYGwc{HigTt`>q$*JJ0IdG3@i(X6V!A{#iF;UmkduO% zs!~Tk^2)3%Eei_3-S5Pc5?Z*C{-)TM{HqNB#R!)ub!}tQ32Wr4U}-2Mk!V6S%`=XL zg)0m!iU@n-)SPN9ijoTZzqZPx3pURLSQI^w33NzdP#x$To{r}-mZEMfeU(GhL|t^K zmg-Z^L#|s=&}Jtl;L~~U2wOVbCRSZR<9l?{nYu=YZVnUt0PLkHR8y_1ps~xaLK}rBe^xV~auGGg8q>8QKQ;h=Xmo$`hgP#z zh9%Asm38J@>K0LZwm6|{V~8f=qMZE{1UED2XmT$$8F2BphrPmTL8Ifp zx2>{3DytzjGKNw|pCX<|`rn6)#4)6{GQ%~~p_nWDiV}hyp08~S3UGanGqLfH=u5?k zplgPZvfd5>Gj)@u2x3OCjF;g#8;Ziy(ui}bMdDSb&=@UV)pt{*Sx4Z|;Y#I`o9xFG#~+RoM;hgMuIE)*5|Zw4Ojw= z8(yqzU@TPO@!)`9=tG@bHFr*v9Kkv%*9+l?5iqsrdzI2DCwVn3;2`2F`G$LPs>6uF z`QduCv1xjwR2kKJre@Q{LCJw}AwBETQ3NU7s;r2;(Wsi-Snfp&L%jTf$pL9w0C|U# z5fbm%jf`%*tkF&QlH){VQo{Oc(H0u6)VbaiOLGRzIAp*$R-FomcEQ9A8Oao6G>vyy z|F&7&*gK#3fEsqiX$S)MYb^IMLaG<19(+Cluc zt3fw*GMb77<$A9`+}FO{@#O2f#q(O2$VF^D!=n+OO(&4A9sP+NWwe%5xmwpNNo&+( zF+&`yOeegx&rmk7sa3#9z#ugB0T^%IP=;7h#U~&{XN5}8lBjCN47FD$xC}9&{H{th z3IX``8AY(pxzRiSXDp0u>&7L~_1EgY3xziL1M${hHv|D`&3#E;R9cZtyuRU{SfRvE zz}ugQc`>b3smsL^d7+=(gbq1**x7<*11$8J{Bbt{$)cbBIL5UOTVpt(rb1amjQ4E( zMm*_}m>j0kftw=7jtLiyDX2Ys;%XX<2!lh-J}Vq<(QVkf#@uPo#23&G*a3#v$C5$? zdfJtVQ0{DNsdXA=#&EAW9L1n&8un*g0)^LluujRtC>|p<$bwqFK|;HoMNdv%zX}@0 z3(Qko<)O_$a1Vc>xfMQy0E7>qF#K8uh?-$(%CJp@jY8Kf1t}L^r3u<-TK`_dN@xU> z=)-g&hgyD^1a4>mu5qx+20R*b>x9N-O=o>H``Bv2UP<4{Jel!Tk=kaU04*CsE$Fl1 z=Fr9XFkx5zCI^{RBi$n3?A(qM8>d>REgB+432s&};*EXU@I6>VJqBWsv)EQ9_nHy~ zNb@i#0rI;j(6tQjjkqz#i>O+o+YtMJMT`==Kl0YFImUI%NsUg`6t~f&B`5XP`aKD0 zwIdPj(Ir*@sN%%WI5lWbkZ(AyvAV+>0)Lot8vo+oMO}b+d}UeRR91yDJCr;yCc-g;{cyV3v{i$^WSB*&C^*t&EksXS(6?5m*Y zoK4bxbGM{3aGeeLzvcFG?T zinNe15PuBu3lKJYhp;eN^XQ|8hI^{AQ2<^F*;5Oq&%ttxdp-I^IYNL!d3(ANX@_yA zV5#L*RcaHoDx~N=8Q##;9_1A)w ziW&}lt?G1eojsff5QSJEwYjrt1BSi^Qho*SF7QPh%CU6I9_K7&Ef4&6gr*6?mU z4OF1b*ljaO8TrCdWmv0@6fnR@JU4YLusvPNYrXGu;6UC~@Rpe(AH~?K9!E90(L&dKZUti67 zPq%X&)Fe&Xoq6Q^1b<5>LWf@&^M#X`=BnGB3{}=2v6E*d%Po0PI;;^@;~+Z*h%rX$ zOg@^?IQ}~={7@k3SK;epfF#?Xe>?Vc{k7&WsWYtyJ5&fT`-3}2Wz*r0BG{oCs~?6H z&qv%C_FCj69u%f(fZ+pjs2z}I{h*wwfYy83^Xf178)ou3yd`y|ZY%J!mTg*x5?=ey zdSyqw*6`c#bK$q_;AgXfnYJ3~hgCqF z^-3SXrqdFsdf@3U*S7BrrOIYB|03W6+ zJ8j6D^m|a~%uyPA{HwgN{+ueyf1x)@^|HPpoR#9XforOZqrZmeV8{fHF>4y!s<9RV zSg+(Ar0ZppOwEyNl|?cMj)geV*)jGBQ`zvG$qQsAwVYZT78A1=WR$?^_SI&#`X4H2 zy(bE)m7sZ-8?0&Q+Icl1K)c~K4qjGBiqh~^^0zRY9=?EYiTSlOrP+se$2@VBt(C}T7Bhy#XcUz>9? z%`@gvGG(u`pjqYwbb<%j)6!7*LPz3t6J4eW-o8jOfq_%j0hS2r>Zl?vhb(MG7Nr>x zetkooZ`+Ir6fA;-rH~1OT2M!Fm0UCH&-Be<#j|T`L1zK85_ElWn8+}|7|$QF2$q+Y zgtuYE<9yk5s88w9uIY4Wt-QX7|IjHu4Rr?g*I(PvjLICeF_N2mqE;->g!8S3>I$dBkgA=6_Da~tN_)2#wif>z)yc$- z`*5Je`fITV>8qG@iiI0^KT@b*hv(+#G3P-=XREJQI`9)e(xI^mzeav@vua=RZt`$8 zC&Ic=Wv*A+8jh!t4C*1U1~qZuC*?Dp+DahRgp!}NVZ9QMDgk2jI>V9hgrlig(t&A~ zZPC5~XQKIfB^!(i2~X2oVS03LYL|9m7z*txK(G+t6xJ(C4&W@2EVjAK$yTKnXm%?@ zn!Xul$4R~Gl}gm+uJF@nwXk-Nc|y`W8)v`-!NZPCN?NbP@8XojfmS+Rs&h+GJ+v}4 zs2bKRBv^ThLo8exFEN4)fZ99}$dD!?QxDhSnrfa0%k{u4aj?rcXiSsIGSzeWrNn6F zYk+9{pH=Lwt-n^L0wDaG!~!)e;7R5~Kt%0Wv_duBhaqXb63ePXCg|ox0*bhKlj>;* zQZZ|^36w+^f<6#vY6dA=j`m3a@5};=d&&kjVwI@(jmuPZ8?U)l> z_dP8Wvm}@KNW=GRK2v8A8hDCCB9FvJvGSO3ES5CIAp_ggrvnl?vO#(YnY6z?Cne6-Wv7Z{u}eiR%8uCdvQzwXBv`ROZ8URHR6x_l(M^a+r#T&SzgOPYPghsr7isDcUEpQzK^AU;A(FUkz+cbk$yZqW*L#|+nX^x#lX?JC$BIdd zdTwZm*mhIFr8J|U*DI6Eb)V4k1U>Au6mHRzc{AS%r(#h7ZMY}8019m#Amr8dmXr9! z|3uS7$~JH5?QmUo2A4_2Fr)c-&AKJ)32?Zezzn;N~r`bZBZx1(F+ z6K+IbyVKHBfF8kFi9ZC!UF(uBx{ zp;Z2$YO=fjA8ew0(@Er1)*^ze)-);q3{$16#Nx+NDg%a<0KNFXoT+suDp-634l9?W z>yZ&8Bj0=4pR6<<2A(l3OUO|*>n$^Nf^oT?Cn@N?WI`KL)oYB*g; z#qeM#DeBKhVQP#edKCxR#^_qT$c(CZ?B1i$CBJTqe$i^b_ajf9TcCl;=6NCUPo4mpD&Sappf zW~-3kW zj7~_cVx=WSKgGBMc7GF+(h4i=fPc)}4BwV`Jt#*z8?&^ckle#eyWUgNly~SC+gylO z&9pv#1B^^mB)HVT3@c2Eg>qLwpwHMQrpr;lC3mLCW8{~gVGHTIom|nK6UzLhl=bI1u0pf!*`I>$Qgftm!8Rlfx|Riau^%adL@0Lp#-^zAYB(C z?$xWdn>5Cb!3EGH(czxT8kUHI4=0EmY7hWpHXdk zIzX>!s{KszD}a zzxt&*?-=~J3TYTvEAHRntJq@@8z)SoUl=P)g(C<7ZUu19;UTa&14>09Wr|_fBm|;u z8zfJiR;@daB@PcVhad)2qxj?CY6xEgO*n=4Aa#Ix-OhKiTXn_RdXt~JQ9r7|paF_6 zla>N0I})}?$Yx^VALUkEpHnR^uJ&S_TFqS}x3H&jrHX@kwn7l%$>f+rKKVa6dDK&U z5E(sj#i1{~NDd@nLy37@?@2Y}46%)T2TQhO1};+BJiMj^>_iRt6R(LJYd!!n(a(dY zn}=cTT6|XJA;J>#ZI<<(k~9iR6-ve=$q0fC|E$z$(jp7CqXiJNLrfr7f(B6DVVsjf z)l}w?>Y$FlV29wGQ)&;fj~~L1MNZb;W_nuM+TAfw9|SULID{9gCG!Um$xYGH7j_1&TL?gE0gfj zPSq%Gn17R+h;Ome^IuuN>y@lLAgyK>EbUPZ7?4Ah1jFQ$Gw^^M;vOBYq`4cI(L5Gb z0d=mjo)uAlTKHH(wDdUcCyxs#6Y=B+;t(8ojqWq7s@9VDU#DnQ7X8N3J>CnpVs0F!0DNX%HW6f-P*mF9K;HJOj=Qa+2&pnWY5P2@OnKaDGcA!JSSCRa}^t= zZum<>8L1>}I<7vij5gS|&55DGb4IC1gSg(bgu_ zD{>(M42s1^-QyWV;i50Onua%I?xHA!wx~m>a+_mC-<`ry)~It!H9XHL^j}KP*atxi z8KtVig=p2sgE9};L{^EvIABfYW8$*X522`}W9X?jQlE%jb9`P6fd0;q%XpcxKMUks zKQf=9N7p(^OgidRLl(3swt??cWP3*HN_ot9d(ISxF(RfV7b8+oH`by~mG!Ie!>jCJ zer_1Twz;*Cm%f#%b?XQy#xTJw>y=GBD`Yen8%3jN7Tqb3hzPG0DMf=yMp>_n;FCWs zGYN=dD+elec-Ev*<|7mba6CFV)Czj3BfL=IyN7HUshW*Wbwm>FR=|gPhI<0NcT`RT zDye$bK1vk_szy`qJ0v)FxQ{&`sl*^e1QsJUsQzKap}J9KY^1TW6~x6~4$oOar?FN5 z>SDuYxif=iOcsp=EzUm))UQ`+Pf^Fk+tCaB3GoaJ_l45+R2-;QRm(PE6Rq(Av${>o zaDz!OVAyR;4dPB9VnWGcHeeHYiIa*BgK>t8qx^UU6)%Q(Q2m{8;b=XS`}%8PQ8*l8 zR0wn|&2bo4{XG&!hl7drj$WHO*b(;n?Z6rt-xi+cdQa=&`8(>k?aRXefS0YJ>k=TDLKaxcIi8N&C9Xg4%DP-UshiorrP$_Z> za~{zc5Cl3wSX6*dF&?6lvLT%Hp16nh6%jtqp*@`28*|*`7~BPdj6H~pYQ54|XUHu1 z2wd^wnwT4absR`{G#yGDzR`N6D3Yt`m;%WGNCy;saRj!E=>o@GEU06gf6L}(lktz1 zTQuazCn`z8l16%Ru@#|+m^vkF3R%`K)#=3IWI6DZvUS8_bW*kG08CD`pau#u90I&U zkPpoPkAfG%RkQGLX+V@2m)GY+O6%ShR}u3p{c0LY_Ti4;q;LqkIIJan^3`yvdnI~I zHJmopf!YBu5&~s1J%B7%h(D&v^`5yOHCHL=55pY(vq?tQjcQl#gzZX95|f52`JRbz zCWmTDQi6Cz)O)k(Xp<-#_P;Nkcyf)9{h%H6kR`8ii$T8;CGt4X0UmXjDF$TfA%<^J z?v4B}dQqUYzWI&2Q7G}PHuPaU+Npy@E;JpG+cs`Q~Qg1X8yQpVI1E^69C z7ePn@QH`q{r11_&Cso&0>th1C!}pXoxb{D_nj?7Jj`GHYWQ&0t5`-Y`=Z{=!M{p{K zI1_}G#5VD(vyi1E^N@7r8Zt~?Sig#9P0e$7tlI0*nK%nxdGVJ%Eb;=qUJqorUTIl! z(%Ga6SlgNajg>^#;MRp&^^roaKCtylgNCZ31!?aQJK9_mHjYknm2?gAGNV8tGyK|S z4I-gjm^TC}%_4w>b4H|+Ue4}^gI4Q3b)v#qP1voOnI4Dd8uWLhYpM^*KG6VbrYAbfk{rY32tM@5?o02TVvUo=HJnIR|ovxPk z*ZOMp&T8|NX{lJ1JD@2qnV(DqV>d0*4{s=^Pk}mqP_=P*>-&ZRXRIHV0`{QQtoLka zuC$4JmrU$Xo215bc5pl&^^|te5X>QJ;?T_o;c2S1Pi&^5I~Yl48>@sGP_8DIRis`%F5D_$61zr-}W-U7K!xr;SYiYJ)hDdGeV?7z>4A1iAscxza#~bSZWFSUW ziu)>=VfA@=dJi0-DB?<&3>~q+C__`&wT3d)V6M^8>vQsi9N-qX5EY|4~ERV zHMPh1J$3$+2~9j@OqTQw)*xb{%bBa7I0X{v|2^z%1hbfB6kOaHh@rj_hx}9}pt`O} zorxDiMzS;&uFm?#5_Sx>j^k{!9T&$HqiSHLz#|TrTILCe$ne>t>Kq366#>K#{&<8I zvmrTSxF;cp{hr1VkjA_PDBh>-xD7cxxQcsW@RPi)&&lJWwIg~98H}}%=$w}Q?%W?L zbt`|Wv)Ry7t+Krd%P^|10j*fD4I9LfY19lcufH}7%#tZQXAe+b$nZ91PJDQk2qC9) z&QI)zKw?&?K?YPu+6v8-n?`@@h>X~^B8A1VoZQ_n91Nz zp1&a`_;(cOm~au@|K=I0+T@&y@2$~dML&J-3m)Jq|psfW3DjsNVv_h_9JP5LM_$rtkXw4V*QmmVdzqQrTNGgCZ3G%1! zH0&~+(Y$G91=^pr40}H~_K0e(8B8uJAKx%lI^dEbN`2rORzM=NsE}CCbR;Mqqr=fP zL+pdJv}HkUcmYju`d$6tymIsi-!oUY1vu46crFPtiA_c!Bg(-YsMDF<6`;EEWJzmz zT?y7WXtK)Ha| z@5#5pp3Hc`W2)qn{`!J2K2}X%lm13h#`Bl zTZ=?s8jutR8i^hEVIzxncxU0vSe9&)HV(>BJC$X;-jjwbrMnq-C$?AV$%qP*+h}M& zJ}G<)W6}_Z%*T>`{L29bf-7#>G6hZTbPOe?5P>Elt@i|9;t>$3CgJ%$nio_8oC)?0 z5XLSFnzLoES2jpH1_+|0_=f%IiTwEmJZ+&S$(wbibAP>3*g%Am#4>joK0rN^0HX}e ziNNIfvyQ8rI+^sgYGcv`X-E=xG#soV1nC5P(hdtkwXDRm-czZO@?)8(;PmqvIN@5| zV%SWhM~LYRcVO;%Wrx97KR%A34Z2b}$Gj)OSI3^hNk<)q4LVt`JnBCxI?0tU5C!LC z5qk?w(_~0$4f;%H$FLG4gM&AS;MGyW|CQwzoysDHPG?3EK>hsno@Sf)rL=xQM9+O( zmPDZ=Ud66GO&aw_{DJk#Clwimpr%n9$$AedfRkaD!knHZ zjtKWKR!&}(F^<#LK(fcM;vpBE1$K!A$INWW%PkfoYSsIZ96MqY_p*K!emt?6g$Pq& z32WQpOfYJbjRXegAny<%cH#BPP86Xn*b>*+VoT5E!eE_;qPSh#$C?~-x}|6!@OIvK zBW6tMREOE2@UGvkh+#H1reM9N4=I@#2BoqUnfW?7=j5=4;|RENqs~k*X1%gro}-j^ zr&wPFJFKiKMf`U*UPdJL_hH2gTWS?vxrTQbyQ+TWI3Dz;3q#*L!jj1GmaA z&JEr`xj=10DM8stVtmgGxxA`Fc0hh;#cd9?Me1c0B26pI0zx_9Q|E=Nac#Y)wwDY` zNC6tS$YM5TO{ykVbV{Y&0yo4DtXI}QfauALryl^h!fPa2o9BvtkO6tb(ujtPBrwuf z7{35=BDC?x3Q{$*Ok~ixL2oo}*>%|2N+(Pr@fuz<4$pLpdS*m^^|w8)Ac0=I@b%ZC z=>>BEK*%{v+@0!rG~|lIAfND!-kLg@XmIBL3PAk)I`!}$4VX3Tx~5u7Lk?sFnbaVu zuht)d$M>|a6VC)`#g;Wpl}6A4OcM)B`xJ9@Z`#Do6O~~orcI<^pfYr)T18kKzDlin z+T?f|=p;}TV*;@QS>E}os6P&Wm}7FZLTa5#BRz|>*)+vDRtk-YlsAl;MgWajQ~jy> z;-E@Ti)GxQ_Y?}_X3 zAcyYRkPsE9mJ<_%IDTtKqB}q)pJ@_RZtXHBDcFcj9hkMRaHlA-oKezgX_p(onxyJwYibPVfK)M*UO4 zg0tgVvJ5lIYj#%KNMlFhcRG&Nv+=wuy>3X)R22C`9G^*Q~! zeZiOqyfjyqJj)8%p*}DCW3p9tiXkS@i+Bd9ITTw$K=_g(BSy&I%0L~HqLV$h-qQ#u z?Kaks?Hk7_aocGcKP^C}9z zH{dBnMlp{0Xda?+f$9W^!Kck_!#G@rNNwx);z_n3Nh9F|bnDGHggiA6D?wGYHmo5& z9)2-!9mQfA6+27rP>~1W%Rnr&0kEv8>#v0-b?BMW0KriEse`OJs=O1+F4nsN;@JJ^ zIW>dpHbVQ;a*?%k3;99F6}p=#34sAUV>D^ju1%F@rsQiBf|eZ$GgZ$+9)pD&raWZc z98s{kM^p-#c*;?#+(m=%8v#;&yYX98xAi%xWhT|);sG1QCmz)32Xq}x4}#*Ga;^0{ zeNVN6!co;L2;oZ%D~&?)55-}$55U||nj!Wn6Rm{~bI7l!hl389p@^MdlxZ$#llf-F z0$|3NdBbGMMqGPtm@48B&#Y!Sn{P7p)=JqTtQtzm(J?P(KiHj^3nZ@U92QpzXm=al z5O+8Ky~tzrq`aP4K69ll>-84=q2D(1bQ%Jku80k!b4OY zs>sMtNugIeSXWXjd1q-b*x`cbl|Uo8aK zq9Mk2B)6QKdD5f_|DLnOOt_JXWMc%ik?S0a(+L>RMGmY6q%;oS`pr>_v6ir*%`ye+ z!Q^uH-+1||I#L~`1Smm?DX^&d)`C^Uo!qfz>vIa`op1n$I4sH&%ZOGGCZgN1uUT05 zo{7n~WI*}OSJk1dWyZG`hNxeVO4Im=kwECw5uyXlJH>_ie!3gY`*VhcFwil68V*(4 z$^*6j`fIV-C@)6(I_1&$*-nrM!navVCVY;^w~&d2In)b^8*Wrs8CE<+mv8`BATq&Yikq1WHkmdp zxs<4?#DkCqoB)z)=GCg2io;|g<3o9@3O(pC+6Ai*fvmq)>Z5g21uLcM)(8E`@oXr> z3RzI#wgjj1Keg{uE4FOv;B5x2hJtY{Xk+zN(J@knZ?xW1OPCaPnzi3BP2zz7Hedh=#+fO*@R zjSO^&2Qv?2iY7h+sUazovL>Y@OJgHRGq`7-u)4y1?IEw|6QOY;gWG;j)J~tH`WOBOekk zL?Gc>+m8})KyN-5`;1{`Boc;30lHZwP#i9!`mr(kc)j6DLwc<|e>n=OA}I@_4%?$& zmBQqo;R~mFMGq6Jx|yo6Jeq&A3wN*=QeC)Z#>eoWVuzJr>;f2F=Q*bdy~$U%&i@^~ z2jtXV-oZ-4N@!{U3y%(DZDcL~=8OQ=oSq#Y(u5Rs)8uv{Sz@i!s@!=QO*M}T(LRI( zVLjN>h8>s@w5~qRNJSe~*?*gqXy%pN&8Ha_XCOkWA;~6ZgJ31d_eJ>;4AiTcPLG&^ z4j)?2thseOzXPUL!{HO94&hw4g%Kkb4Y5K6QtLxUcVMKZb*s!I!x@8v9><>oCR(oR z!$reO$`XFI^U=NLpGuI}CE!aN03``osjC=isGQ(7B_)xV*Ef`NBG(~q2$|`A0S8nB zpz582MQlR)HHN)%46p*H>UtN*=xYsZRu~n3nS!Jg4Ewapv|-jyi$!RvrveN&;~7!x z>;lps$*`#$(;A{%qx!i)>q4ki6zBq~;4%_Xhrr+rnC{o-%&FbbdSy`~4G~``+e9o3 z7R$O_U^IYWxL#?~qLd|UArk7V6UmPTOD*U>p4F^1pznYaBrX;=>#w##@|6#(AXlU{ zfyn;WM{G^~2K1(J2qVmrB{Rt&NZI@`jiIdP-f;>+H<)VpwfI9UpEV{k({p`2ZAb?2 zF&@=XC6^tuj)yB@NePqEpizQFh8@OVff6C|PAP}o%$=C3NEL|!REVt|ksd=c#SQYF zv#&Kl2~os5{~mI710q71na$J)YV*<=Oh2*|@M3JbX$X_PkEksrf`f=Gps7^i*xc>y@xiYemHeVybJ>VeBqT zf^D)=kOQ1tH$+Vx-wyWZ+!h^MjZT$l5m+(X+DMVu3U`{v@N1hbgOkDz)7u1X@EdMZ zkm=C`8x`-0LXNNX*Z%9N7x@fN0nE{Z++zj=)I$sk`5g#v!F;_^7~nxgZ}7Ky&+1e} z5=F8ua^?>lIb5Xsd$!_*DNc05jlSBbCdmG)BEA(fqP&E+~~ zpbX*zK;jVuC_Ok+7blLydbRn5IrJj>orN0LnQ5{iIhb!Lf13MYfP{@CaIj(EXh;IO zlGu8rR3fiRptVF8U4N}?qS}B$EL6o6hmG|Lj5}$P5mD0)bF`g1e9w*<^B@ja^)ofX zyE$2g>@8b!4+Io+5uB4GzPpngEP82YRnfs^D8%{1$;m8tcuAr+Jj z3Rrv7sSet0@yPbNh-l2HY&GPvj*|0ios2+4#{n=gqKCX?xI`4?aJH<**r%sLV%3u5 znev-KonmejJnL=4K=5Z|^7Yp;d<*}cL{FG*`3A`9S&`U0v3pC*=ruz1dS&k7!w4#d zFkRA6ZMn|16IrNU{O3L_ANhKv3JjW+f_OL%s;)v57NOBakHds4RubrXrRIxXj4}tZ zKyB+QOMY#77FkKtowuXqiMg5rV#oOHoDF!W|1&lAI`h&D4^Zig_i5ODRfCn*h?S0aKakOI~> zfGZJ6@u@2+QZx>l9n-`2GCZezt1hvX)Hfe>q_Od0vvCT1h`bIaoK>$4SK{BB^Wk40 z#K>QoiM+2v?`s-XDN%RkG_AL@Zc*~yPJulYz`$kJJ?jdUp=r{jq=xUWzg95uF4(Y; znW{%FfvglPY%(vP0dqitR@8cBbN$L^F$kDS=#4u*blJu7(+&6 za6TKQ1UyA5sb-P#+y>ZRyzk@{z|AnJ)NLiTtG8=?#Q;P+H*&bPHK?otPI0Ga492J&^w*1D}h@_z2jyFYV93ABy4Gr=mee@lLb?SeuHpAiDP!?lzbB5Zu@-eJ zG>*atp~n-iRO{Hu&VIuZjJ@x29{emBWrBrIqCdE#=tn|(3P3#xQp|eKpb!zxnkCkC zj!t@$o!1muz=FcWU@=Z|lyWR_=J$ z>TxBxNm8Pyq>4GDcd+G53b9onc-h`|wZT74NlcRl4#-5ZK0P6K>kx;~KTW|LSO$4SoKrAh|3(KVw>D&DQc3iP0xpNK7;i$L zXSgGq5d8cOktQdF|Hlx)#PegmQ3F!F85O;3XqVPBsKA!m=o#Z=F=hbHKvkns2x3P} zHSCw+lk2;=)woRz+I{eT*daQrFgDD6-V_f#DqS19aS^6dF#l0bB*9^S>JWuLun6>E zN1ky?GEzHJQ|PV-MF{6XL%6OhJ|T#9R5?Skk4i_j=tj0em?OajRh#pGrrLo;fWa;1 zA9tntl^29U#RO>*{nF4J)xf~oaX|<(79E*Yt%>JD6R{^-Su8IdyjolRRH5S`l?zB_ z+eyhvV$eh9lQby_8dF)0Wl>wcgBphCWRW#%p+qUa=d6Q!nT^vjAupfU38#Fgmo4_{YIMouqC%3%Pz4 z|E~P55d+Ok%K|nI=aE_j&vc%i(;{tNF*T1PN)KGKRm>IuSnLHc$Uo;EAHFArO>7nR z#61Ee+ZcdNDaFAnJVB1yTva3M_w0lqO){JTl9<}q>eG(E=4^Z_dPyn3w=6lXS0Vy3 zwWF;X`-a$p8IjvMtnqlfw9r{om51yAOZ#+Q0)81o&iBI`W^3E7MzIuJgn7=n^_~s> zvl&5xByRB5eJ`FDfq+yV*0e$`Mkafbk&SrM6v22H z%mmg)#>=Iu(wJ(iSQoV(nr2Md#Gy@nR|t~yl#owDBPDm3LWSb{1FFEk98S#~-cSRq z8)wHQZZ9(^sIPeB8gT8^669r<&K6#u6SD{=)JFnz9@V;^j>SMz!ZU(C3x|9*tRag9 zSJvE+XmLHfYEABR=!C_UvnW-He`MGz>T}sBq4qfJ0EyR75+fSb+qyFyiD=RZNVoo4 zawi6>VMhgbh=JLJfPq)g^bRu~Gu?3D>y>ab{AM8Z*3)@tTSa4V^Hc3`w3AoleGe;v zfKq2YRIL85^juzXt%JaT}688`g(&`w9s_$E<@+Yn74NueF_1y1nibq)qdCfsMP0_1qzMZnvz zKO1(GJ>Ke*;4>yPLBYC7jKa1{ays9XVP%1<;BZ#3;vXEZMOY2uL zCn-R9iHfCMfQ`;CQNjs5irzAWbqKGoSMs$3lMuXMtHj4W*d6Lh98;ru!^S!Fhc%=> zm3NST6v=BDuoBvh4H!h8*d$Nv8YkYwjmuR!t4V;44&@Bc3tZY}c7TYSYAwdwXz)NeHTROg`3HMHxqYVcenD3K9Ls+}$% zWAC$fRp!dIR%U7Y=H)d8bN`*VM>MvI8BwQ3R?~RT7MVl ziLMm~bwmCEZbsui>NG;-jNl z?(DY|2;qUp+ACK^P?2ck!_GD%y5>^-k47Kh=7HIURHAT~4WyjmX`f9i9@M7Qqcn*~ zIhN#Fh!~SXi}q_d%q;9l)A5~UKG8safF9An9-l{Ad#(bVZh+>lt#1FGxKBonMWgvy zwMzJSYUajj$Y(;K*llXyeq|HBQQ9>oDnbDUz{*GsD3x)YjZ7MDWW!L=C0Iyf%(mD_ zElfDK8t*jf%i~(S`3qxyhwtg(G??kR0<3E_sLjx*BZ8N3YS+cK+jBz}tcl6oJax6z zsccOg;u5An;1yKq9Y_H03~z|Op?H)P#2v0#?Z(Y|GaLggqJ^$vi%2q^HE)cQD2KRZ zECu0`jIy$s!3^!O0~GaDK10;>OPc9wW9ouz?rFuR?;*HrnP@P9U5Ad_zY6^sYT-fU zEHoBK>@XujLrBwjY%YV(Uh!L`#n{P=6j&@ z&@>EvC`r-MbVSBA<8vP2#dPS6Ga#*KB@{7PrKAtajfnYf+f)cH!QyPlLMC4)hVa(al@y4V&U{nPG?}5a+51T|_r=&GbihtS^ zk-nox#RY~vAE$}N$k0_6$`H-;7}hPOOkpjN!A)4uxMRlZidSJPipp$tkYU@>x+d9c*|0*IS%#D(7q_(zkb^&pKLr0Zm*hxrAMw+^E;TIWD2@>Y5*g-htdxX%Q%1FMZnE0YovILlzWBKzRYo z&n-U3q1XDV7Y_^w@lhyoMEgDSm5UaRakBjxK_n&!0TavG>`OW68LuY%?N^$pnu!Iw z)Xg~?65|;gOvnf9QL@r8rF_6c$j?U1N!>UXX+rW8nK1~gU;-KYl|}2n+waMPVT%c0 zaCLKnc~q4H3|6A12kEQ_hNf|P2N$TSUm32j$&6)s zSBu5>=sv2m)oXdNevNF^esLVGLq<+O~lR9hj&)3zzQ$CMK3g={of$&9x z0&jBW=y^gXz|`PZws2O;2@h#ZttB5sVMoyT$Kd{v0WHMk28ep;NOLP{c(?hV<-T6M z9h0g;Q{qNaA^WA!HgpRu50ScgSF&wpqfWRHmeo9Vn2&nY3NCnqR&??Gdul!rg1maZ zDr6(lN5zo!3B1zI%YW4oZj*N9cLiT~HVHT?Ynuvik{HAl`P8D2(G*SlJr#@o8@(9p zxk48Cj6IYzQ(dY6Hy*4W)Tyrn)N3!YrvNAQE2A@wWhB#D91Rb;_7M)DEOP!#0GWAhBFen)L}g`bCu{^!qE>X{TIfeW+$& z7@JDZyEW6yHVw=j{ew+mPSB4!b-t)(xNp52*$?xX=RzI8cFWr!24a@{x9YY14UuM* z)NaM_;R%fw!HU7>kMPufy{E3DpLtp-uP;mLspm zUJ{%0GgJ}Hg@sZYlH$sDk9u)BUA+DMuX=gBd3}7(52~nWw&Vo};uPFKKRO2QMu`zH z*#9U-Mos+km!EI$-}7c1bCHXkyVl3lHppY8s|T8;sn8&pMH-9v?3cgjcz$*>|4m$9 zJjKoNuweP-BECg?nGIFdz%D#3s&mNRR9XoPY|6YS3@AN?6vxJclz=ijTb706fEc`a zeW0Qa=1%ZUIPbh%{by#i)VoWVKyeKBBy^~Y)qfB#LL!cnyvT{iVrq-pJA@{=>x1*% z-Oc^s^yc<_{pxtQzO|xmFOTyp;1Q&vmg&~SGCBp^X6Y!aZ6ybKHEYRk-ZvD~Ou&*w z6kAR%%DRoJm7#g35j_UuV0gw9(koYG(ohvtgda1AS#KmCx)i<=wd z)8F5-ESk0JMP}fs@|531E&0uA`+P~9zzQIG3? zJ`HxLC)pHCqKLaw<=Qbut_pq4(CG}paAo}^Q|CRV*C1T*fR`V~=(kHtru3`R^dL}k zp|cj-{u&@S-TcZ_P&|j8_AdpLWy$*_YzoE#7qq`$2~wbCAR5PSn#Q4XWp%X+*{i<8 zs7hUS)_x`X8UDeX9dH$*h0cK!oe4sNW=))7XKwO8>{qfQqoiCTeX*k^uXP+1mCr;} zzk*)mPfULI&UIqO$2wOI=p(K_te#;14~wjxZWhv{{WqT>gJmP~=`mibD9&D=q#(QC zf@?0GstC>$Od6m7g)PS$#Gx?~(dwV9LyNGc@Yeo2A#jIU@@pUiXqdvJ13p9Ld`O_t zIwt@PHDF{8lLkRDF=3XFFcdq0Q46f|JsF^C<)WHT)2ysazDKn+JZ2eyR6LE!K}C~y zPQ{lzke>tA;Lfafg;m)!D}RXFRR0$j9`;aqOFZ*)(3r#TM5Y;JVzLGI2lxbxWqGdK zMrzWrMn6N~4fi~dJz&kk0JIKmY0}}Ye9e3Cb$1iQh06wY?#nQdo|&X)nb`Q z=ur+kYGfx~Y`@a7=3<5Slpa2Sm@hIA4{-ImVDM>SpYaXZ#iEFuYuS3M-VNMGm5@{P zK^Pao0+AlO-xG*WcdsN;6zZnau~lmj#2`fT==&xet+rpOZGeQWrd%gYWx=j4vwbmCt)?=|pECvyrhc^Tm6V~X0Y{xvG_|*pGGq|F9DxazI4I&zNXBb04$F2g0IlLGH8_g(s zkuqy2#&j)dX@6SYOUF(sjGw3&C`TQRicjtM?*>2-Ys5Gu$$n*Ae5V!D04!Q77inb8 z@CoXhAZcWjh75<8VD*qlg)UX2j%U%`vzuflKcH+-KByNih~alCj7hY-b5=i?Pr|BIPmyX167!a@B~@g)-yHNNthmvq0Uy$@060wcD9dZ=4F z)mq{pP{XG6@d8Z!f3^y{l=501JNQE7ZrR`nY7f9{v7FU~F{~kfT~em82(X5EUzmv2 zISZSSBOVsrN=%rT+#2UY_>5?VY$9%jG&F`u5vmk~Ds95vpL$4z8DyO~<#OY{ua`$k` z8pHge0~&RLkD;|;SXtUG2fimys#Y@0iDoO4&@euoaxIZ}w2Gl3mJt)mQ1D@a472Ox zEN&d4t*6sxNu7j<$wCkgS%adtKP_^_!-LMyree5U{ljG@-0b&6qiGYR^x}0qV&ZPYtuXqy)*^qefn9RH5^l590U=RR z%R(;()Uex-YD^_r%R;5iKR}lk*56i;c2B~7C))3v!YG$ z4r;>nsvPeY5$;o2X48ZL-=8a19p0g#+zljkEDb~_8?kUCkt=y8mV6oHb!Q;$5bXXe zZru(*WUDCo4wA&1zOug|W=7tyx`QfeEIu+CVzlruqz7=xPL3(UWz%I5ObthOJ)+Xy z@~HeV0Ebg84BVTXVayoJ!iG%iMX!H}fKJ5K%%s|p=`~0t$4^s%_<0C8%)gz3R<@^r z31YRAFrJosp>9VW4evHTqGc560UWT>B9a;)-Y7l1fCk1@Bkosr>>Up_XEs>`YUgK# z$z#y~5)n~-$LTuhnbgkCXTpS2^t>Fd9V^&2a_Wa^7|{@ipa2n?9aSG?joGwj zDOHc0zsOw;k>^YIQ2Wzz(27)~C@a8b>e-YNZI+IHso&q58h!m>L5DbYN(ACz+1y2U zZbjUt(AF70D5A-EBEdaUCR*>*BbBaENcuyR3*x*&J3&%c^jM8o$qo{;YY6ks3AvMX;E zuvJYV9eQM}%DJ*%AbniY)eu`7vX?5+}1-PXzj_1rW~S^Q}T9-|drxU=w7 z1S!p|J&<*yKk2KS68rDuSSLX?W)3sM7Yov$q9F8!%TWC@T5xO)m|8^Dx+L`?yQFwN z!46yMICg5c@KUc5gfk#UJ<_~=R*=C}an^zYq0s}Yxv+RV+EM+}xiPi!;!8UFNx8dP zUPKUZ4eiPRSCcpA107=1b{Yx6zoDv9T_{7fE;d3CuO@-YQ^-)0J*J$ki_Wo}cw++^ zwedArA9JE_T3;sLirKIF&2%X3_teOa2cj^T@U{*QF9=2MIEI@T(U zOyCQ}N~t#-gyDr}4}{0WHko($ogoiYfZ8MxpC-@GgZCj+%Y+b8@QN@s#M_RPgFujy zosce)2w9yQ-LlOm#NEo_J)M1vzU=kU`%&Jh(i)j%S{yTOGxy#ntg`aq{)QAPvWMm# zACcu$G>FG-{+IkHAfTPrf7q`ykwl%djrm5`ov5kJ z)f5{O?)nZ{bBVn`-||R83;R6-(i-$xEqQ$*nEHu2e3T-ik~3&c3$sFL_?=#@->I40)_s*-J(T}+L*-xICF4OwTJZL0OtIuLgCD*CoLkRV3ml%`pv`b#-8 z)qqf!h3XR-pBekyDdT$Z8r?1j3^4(JB>$~ptEw=?u148T73I#zGOue%M7HGjrzH|J zA%99D zdf547wC75^5SP%&s={fe%hz6@0xN_DMKM`7E|ds>!eo*|pegMAC*RQ$p!_t!X84|3 zaBp!urAJTN_TbEpgU6uC&6E@9!4m z=k`gOg@%>_$NN_Yn6m;TMS}xyj8OJ|Ws+jeHC2M-9Bdy)v~n;3o&Q}aVSLW`Zh0v2 z+pc1%7iZhg1PozQE*3V`Kf2dosr{ZLd!&+NW$DoFB{OTzeAx_JI7;A`6oeMuujIVo z`DmyTLxaT2+R+#xy9aN_AK`s*4^JK>rH!Z4p(~K_`vGhE93XzY5-g|AK~nJD3`h#_ z)k&ojBNCx35{D`_!HYgLRhgK|Gcm*je*(qbR5~^}yBi8ivA{QRx@MT@1mH1e!Pu6wq<_PjHSRsTr0Inkvbgw-{E(5OrDX-WM6r(&5bUBg5BW{Aj=TJSaH(p!8e>m)&b6Wl`JCI9_oZ(6VChv1NYWo zl+sCEWgY5;h=&UBnaUo-gu>ec$c_8c;#=%PZH3y?P!3i3M#7*Us9;D(4Ra8dceG!r zNrJr6oOSTK0Ss(n`d0Zw37srW0on9`cz~-Bj zHiZFh(wHKwRY_Z~k(CVFBdRc){P~{{3@46}(UO)dZ5x3ALN#~@;@4QDONtPi(KCjiEa#}bWA~hZwHDi^@40up+Grt$a=G*#x{Qer1f#dym zB48;@@jwil%etMvUwmogRM;Wr3I5x!N zEilY+vxY=-!|}MI2vpvp(3(J>R*R&a=4xA}@^s8^{as3oPWn?L6J*l;X#U>&cp5*5R%JU=XwS!mqeER-3lY}s@A{^t|ofuwD7moSX(E%lQruw!He!! zQkPUun$lrAC4g#-`&8siiAPOZgO%@77UbTLx1?n(FJlS#luj)x3BrVqCN%mklT#kC zlf{bPL!qsORBhs&$el$rsig*nJW2c0QVToVPkW($X=H+K8VFMohpIr6Xeo*1`4s!= zwb1GiN$AfbthE=_VXKn#*phAouP6Ioeex&-`f;N#K4wTnSrf z=x3VLtW#x=L_&QT%E#EF1dtk({P^$vX^~@?SL+-noh6J>7a2}DXt=E7yZNSZ64MzG z)OF>PCLd9c9*+3ZV$xBSzM?&dg$*VX`h~(u#pJ{k zI_H7+LLzL4tXxJkfoSZV0Ir0?J+F3|G}l;oEq*FMP)~!e(R>lc{E)_B5sahW8V9^T ztstDuM-o+HlQzHxP==1}Z;^1aH?kv6Q%6*}h&Po6t^`*bd)F~UJ}3Hw4x|#rm`E7}%s;&7NW}tZ0esphoe_F&lP{`S!q^cL!J8A9`yJ}$sn z))yo>0W&^}5}Q{^(=on8jxmBuUZCR2i^IBQwe)8gS8;I3_g-W3OPa!~81Y#N#G>GU zYPi?1a>xi}^1}T5gVY#?OB|y95Q-sV;B-Q!HEMG;lR`+)>c!zCkI*IIJ(h4`rP;Al zMaO4Wv1bc|;{ZYpYKFzCu$oxNCGAvDRL}6VepEdOjvMiiO6J%-oUfc>>O_P1F&j}! z`&U6h`dogIB0}_l7*rWVgQ!;vNH{v~M%`^_}i^u@-r6gfN4EHo<$38QA11hAZ(9tmiaqMwLpCi3V z7;*0V)9QFnSVLS@#R-0Jj1K`aEILiGoi}D;Kl~1BMTn2~6g}AWJcbRXkCY?PPZkxp z(Dr+pOMv}qHV(^=!dG2IPnH?<;S(o~M?fE=q4z6&M}UxlM@I(}Di%|Jf-tGI6MYta zqF5$5?pK=AgiFw`NAS1k8m&RK%2I?Dt!}4l-0()=#odIOeqozTN%kkc%v6IWAUo>f$6S!hI!B)(ScyRV3M#EkgAk)r}I}uMB76mUyYv>Ea!8o^oAfMn}pF zAe$pXCLYWHG_Qq<9$SNbVS@Dy8Zlg&={#e>h>v8yCtWlTDBTK8Xo>>}g<#ezq!5I6 zsnc>HqH@2oW1q;pY*nf{Q;^|#dV)=D_X!l3EtQ$bxnHTRQJGvf4#}N60BUcpJK)Ho z!tlpkUxphZnB}HqU8fyzj1e|0@eT?REy*N=2mEneqWe85rGnc6X&n|p@*uhz8=!!| zis*R--vot`=3W8MO4nWt{gvN@Rm_Uz&<1ASbly)_p-4}~xu_0Cb8lecu!x_jR zpgqHXG;trt&)vG;Q_$(KNK~pnue$*=Zp+sH9uu)@4$aMDyiI6x*aN3<9z6@udm zwwrs*EXdT0VGY4*b?8H4ap}#wcaDHd$xyn5ba#uI%wj{fSBwL<73W^=GZKB4ZY=?I zL<;>*D)Y8+%KIA<`rsH7YZb}(kp?fd(F0fHfl?rFLfP7{3`dJU4;fp1mivV8#zAKn ziAVATVqo&Z#uIZ)%D5CEe4ScB*CrYd%U^dIF8HHn zOyM*>A7VTwP7M}{du61Q>Bu*^$o&m0@4WA(Xj+=Xm7+;;4k93`S+)uk-v;@Q8;Cn< z6^E7fl@P-!%^6R@sYeHJy(rR9gRBS5jJ1!rwf8IQqLX!SW`J`?){A7!Xm~$pK1wbo zR`%GhWGB!jh(3$B?HbUMH&I%XuSV7?C6FQLoFV7gR{0^->xA zJb6EQ?HbAm(>$@FoZB*y!pCB)pmUHY&di~VxJVzKqV#R zG%u3{zE(YsM2v|I2jk$V^+`7%Sjz<(MAO2Ad!8{!Tl=SOjUM zqi~1Vr@b#mJud>06hD9r^4scZBaUdy!^EO;hAS~{SV-JCSr8ckTgXXR0DcqfI!aUF zC9n=`7XKJG0H)OpW$QuR!RyhXoQgY0K?YV2`nvn?gj`73Yk)TXl&SG=lsJmeK6oI+b*ttk_H6xR)_q-|@l(N=}z zff)#P`&Y>;o8t(bAW#$KY8#MG*haW=aA`c5%{1Dt^y-?~W`Uc89iA38*D!7jHL!z$ zR?4_^zY=64lBoLV0M3u`dGuD3Q&o1Ni(P|_W0M$GU(v)SqIF@p8ypjbhQYwjBfjfl zLaC1on$#zk@aRD$cmrG7ZOJ)`S3DlZ*}t-G4(rzF9&@MULL!!&$qJ?~$URie4PK=} zNU2Es;dkALEudzvKi-)ZfLa}oOq&G^8KCyp9INkl#7CL0F#v%*l>d4^hUI! ze>3DVHHHYp(2vx{RuHXf8YM-kjPP%~3HAUh_e-L8hKoM zqz;e$Y2g^+PmSj$Scw3^FVnCg&RX0&YxBd@7yFf}xCR*m5>2}@SHkG7`VN^ks1JfB z)>Hj8tau^DYZu2Yu_hNPWZAXET#(|h zs%QG1x|B48a~Gi4IB<}k>?WcXVUS+!+UR6Xy8UF%b)gMf@SF-1&)w;Xi6Ui?th_c`}#m(fU+OAYej@q=8*i)%V zygB=oDkn5Rj`l{FK%Oy74R*qIqPKkJfXc{8c{e;+LY+cfsBVHBgA5nBvKM=ca)EoN ziY~pgc?96B%^4_PB#XIh2w+GVMy5GWGjvI$oi0d^6%sI#9SE^xZTmKh0Wy^$I(Dnd zR1M-`Z8B%mC&UAwwxAVl2lj!G-_XrrmpR4^vt!8-S%ohxe04esu*uChDz|M74{=DU z%E-qpW|<0SynM}u@K@=Bp?+GB8V;vuQY%KoKbvCFOdL)Sf3(&o0wlbOT}#3rDmoO0 z9#u91BtF?c{he^;?JzXzY>`5BGVmbmE1?4cVLUZJLtX8;ax_f^R)K9A4J8xenD#3> zoXCgNGUK2P`%0Zc0hRT+O&K^4A3_QOa=)^VX34Z@0V4ZKv|n~N{F#}dIw)Adb@A+1 z*5d4#K_ZfPqz4jApkdM94HamBhqFv$Vu$@H;$emf(X~kl1Aqx(N!?89hXLc#Iw5Gd zC$W*$`1Wr{#*N+Myj_9+->|u^B(g`)0qY& z#f9gaD2n4hSUo{qa~kX(l^QKo*{>~xOJ{#WM&wAdnGAeFtfqEg4~s1Za^X-Lk6dj$ z-+rZSZ(Ykh*b>EmbD|sb+d){qq;lWuhJA-@4;)xCjcd|FF7Gu$Rn8~7Sq&?tU>f}$ z`#lMd&;?>i%!S9C^Je#8Gqv{kst$hOeo`t53Orc61cJA}O1mXU>#Q0tVvt zpAS5kk>m(I`bwvgP(l&LojY;p=ZkTA!HJTm2hTg2WXc;e(b=Lyo3w77qpqZnMkH?%=D5y7Wze8 z`gFt7G8y}&stszdwSXdVzKGrlE0CC!Kuz$w8giN0eJIUk(o@8eGu3lk$?PhWc$%3? zu*SAw-6DW!fSDgUlm@F*r_ z?NIxbf*T5g@GKqRdr-irg&0by$!^esLAoFFrv+!<5-`DXLoLV?id-hGdX^ogVBg@! z1i1a43PIIwpUrBootI|=-iwuWFd1wCMK~>Ez|jV;-&BOqq*@ko9IqcTLRiR%Z(WJsp z28J8GEqxj0s&j^Q(nj{il+B{NNTFy@^vEqkyyYKDywT8YHE7R4`cx!g?F4v|vp39@ z`fPYZhLK@E8%B$`SR-itT_Sv#Iv)vU$s3!pJ=&HZqF!19SdKK$=21acEGA72Xni&2 zY51Ou!9u*|pPI7-l9hXz8aybOMaoEvH&J!}p4N+)2(t?&CayK?)MAJEoK}<7o$ykb zHGCBwoQ|7{vJosv-^eRWIb{Gx*iaZJ3}ab`E4AXp3Og)KiEU?iFD6!rVp;#av)NET1P706}$H2~F{m;SDMWX%RNDeJUNGsP>|Mi+78d z8t!SFB+Aqn6D|xRtb}~p6+>aemTJVW??GnSugq})PlE{LHGaM$jTwpRO+~Qx*1ZS` zYPd4tT6<3C{K3Mk@B~yQMg#>B_BVYvd)vX zU+EtU0n(SIU&O6GZ$uv>4vQGP;*J_))CWUGl9nYtRGn&DWlytbvgGPODEJ%rYx$(9 z`olfz9MFu`jPq!6uTkn{0<7n0&u7QquaW%~hv;Q|CWokN6CYhk)t8h=7up zuwN-cCR@dnsjRVOS`n}&aAxPNxs)#s{2XGu)>$S-{*UEg0niOL7{}bumLU2W_}LevvU_|Y9u3Ec4{#$slIA^Ps+wP8!N-F zGei^h9JU4lf<96n<)&&_#08?g=BFlzcjUvc%OL0~1vpeC@TvNhrMhlG&N<7L5Nbtx z+~J-|1GE6f0&ya}6VE$Vl@T(pl)C2+wp>E*{#DorNEYIagRfX3u!2=P#)UP{!!q#J z8rwE}6$&q#qMDxaU}|G!oV2fIw(KEEKY?e4UuC~1Wz{jhXfh--O~j%joQYn*MzeIe z0cu-x9@%e`Rxcam`ucSD{QBm2I+)}-&o;Hk6}6c-eOu08`-%J1dh`JyOF+O^L`Ck; z#8yjhtN7w~W!n-76X#WzLKX^Bdn~vPi~iFyy|^*a_k29vy`G;)74?}DLJC*JHR01@ zq{y3}1g5i6i1z&bQy;NJZL#$E8J}QW3$ZUtI<9vnx2*r6jPAdM)CCj@Kb>BrpG7{U zS0Q%2Ty|Jyr$&@cb8tB1?e}Ez?F=3Z++s)7K(11m zHJ^9NmjpsoC&-JX~fZo76$pF_;kr!%DN`&%gc>}ZJ4H-gtuJM`2Sr+3MX0(%L z+V21)YKX0-Ru5gz|Fkxb|F^~I1*oHOn{}LHWIM}GOr;4@d0!S+!O9ZL|;{bhszs5FL`} z$D&j-KfEsnV|fto&5eR(EPw$rsn|&q+CL;YT?pK1KtTF&lg@yx7z}ZFSk@+m@n~UY zP!&3mYF`siZC$dw52>cn;b=hj{yVix)LjXedBf(sES)H7W6c#1Dxr9s*6@aCC{3c_ z&1^EMz9s$qaY)F=Nm`)M7G9Sc0!+*o?JMyZvCe4*Zt~Yk(4>apD>5 zlJ%Txm7z)i)SCnI$iFNq4C7bB(@In3(5zZY`Au47i_`$;gLuI{DCR}cFww0wQ|KaX z;Xy}K9$VP#3}u4KpxTp@QMLK$KQHT_u3lff`PWfb)`AhpYT4ZU9SR_rtZjlA?Tlr6 z)*2dKp+d@%*0zqYLHhd1R(f91b;J`Y+4v*raoDAzS53dvFNK`&iJKxUvRIcEQJ!`h zI&wM>nFT^kh`Uvb`SS`Dhj@5kKLSjHZPY;C@<%4<-`yYXei`1Yq= zVIOH724y~B5NYfyZIo(3q~{g2YexTI^r*e9R?-~mWi|0rWHL?@qGox-^~QP)0VPcw ze=Lz=gOwJDEYS#a^54h0fs&umoXXs?L5T z1R^dr@rfLx9M|~Nx$701&LZ@N@n003VI`nhr4R!y7~=i?#$0$sm_m=BbX87Ma9liK zSsa5a-Bvw8kE+{}|I|xviU!?FN;Cg@nnQs^CQ9i}qMvb?HEs=MiKFqtm7ZoJV#Lhd z*ng*OEh*L6B-AHGgIVTsDLfqggr-Hibk^K}L6!kr*$C8O_I&y59uzBls=~MV6!|)z z48a;njvdjzWB4jEk_C*L#IKZLq!qSVb9RvzLv-sX1ksv136&>@;sH#sGxA%2G!DWN zftp>v|4s=M#i4L_=y0YenTBG{=_HCeK@oNkn3cTyl{(2(v6i@+*c0kV;1Z#);XF}2 zc3%&z6K=oKe+hxGx0!p;@yHDhGgz>niE05AG-5Cb4sVFKZ2?NTzKV`-H%E+6L}W5S z$p|xWLuoOr_(HsrNq4yyIcWb)80BhC1| z6iJLeRAfU8F~N)~bU$H~b=5>MzGLgqpcm-A=E6)?SeuEf zVuNOVOjs5M#peD!!CS~!EI{QLf+BSyp}+!PsgXYLAD6nB2K$ww6T&<%W;`jIKS^F) z3DRlVGnov5&xSGSaX3#17aqqRE+`IC+a?%hDxw){)JjGdz1ZQ6f4}(t;`YVy{>zKY zm+v{IMOo9ZM}-j&k(``~i@iYF$mbCCW?@S}`)^=h%x$4s#;VJVBxs5Y{EV(d{it5i z3L0DwyPv9NUC1peTA!$LB>pZGFhMa*wEUE{ehZQ$UM%? zX9phWgM~-k&}RGyCCfO2{u+J*9@tv!AY0*(I3*bPOGrk>OEo?F60$(->{n7^{aBa; z(8Adhq|6P))f#hPNKHfJtRENeS2DE8dEU3gXlFTIz~CvrSn8~oh<{??*5RHhu__zd zy-Q7%dBhOubLB%~4vzw`x09v3C*P z%*Xwha3`hLmqXb0T+giAMC?tN{os=DV7tNG3O`rQFrm#6dn`OWj^A6|ZNbvzwkT;HRY4(C^g z%bUB~++Q6?V@z%vBIAQ^WTG|i6hj<-&$A88SISWo&lw0p7CiF#vO(h_%X8I!+F^PO=0b_&b_O0EP{V z*fA5_qu!*YC(TMnYI^k!?Gl8um>Oa+T1%SK)Ukrt9KrxPX&KL0lf_#MEVQ89#?BAF z(^eEi`LDA2P+>3uzNWvAyOc)J&hdMPV9taBlqeOI%!&;X5BC(9YQrMRs4PTik#YzS z+Il7Qb(DDrYipIqcd&`$^{9z3iR~}G4R1*A*21M&Q?;sy@3cf_DD|r!4#T@CpUG&t zmLz$>xx+$-;35X4EbTFBY*Z$q4E+E74KW&Mh%3~Yv;onqVP|WU3ap~45STl>ec-c@ zhy+R45WCIb? zJw+4#2E{a06p4V9L>y@)laIkDK%pkh;O>WQh55j;@dbc7XF*E8Zpw>R9SQXaU=QTgb27!Z0GeiwM;|C za3x1<6rmCTZr4)5D62O z^^-`-1!8!o?lp0tso=mXSBR#D+-58-eg(_NWL|C39zkv>y_%InN{l(`8iF1u#k#xZb&R!y1D04d!LFL7Jg4>K1TeV>Bfs z^Fr8rJIH5|`+Fblqk|1Ud)4D&c-{c?;xPZi)`#wK8XSbGQioo1^JcaaSm25&KU0fp5{SlkrQGOD?%o&MJIU2 zA;rDgDT+jb@?_;pPr+V`2MBU}ote-WP{@c!#b62%+Ktg% z?n3GG7_9J|V<=k;wZ0^;nXX%F0Odzqv|#j8s=oJoqUiV!^Hht``8Sri9s8aSU+PgL zV`-)u+u3RYrNfHYQa}x?9dM$~gl=pd-1^df{GgWXghFv~aGT1`Hbc85Nw%GgV8MNFu)ut|mB-rwelWYCL9?1#O`dN7rk@ZR(p_)yh>8 zDJt&wG&x&OycrW6{~(hRU=%D^NKqLM!I61xCt>YZvSYQ_iN|ti@p_#h1=WMl>*R3@ ztdkD+D_MrXTy_QtxWS4RoJfRR?N~uv031z~n1Bv|g8YaJ@w8+)XoDWt@Hh?`2M}56hjf{4^xbE!R2GVf0-A;~Z<)KX zryjz-QjjA{dcsRIqE1SpL>b{hjB4yLM$?+xyEKhcd9o$=)+KWxX^0)kpA{7HQpg^KjSSm(y$q7bU3^hi3xOR zqMgQNNM`t*mMVDUYbyni)ewVJC6a3;&?t>~YbYKHa=#~4w;ApTcA%3!BhX>m*U&f- zLDQ?eQ(WAy^n$pckTJfFk|5E+Tk)*mgjmQi=)X0)ZNHKL91_Y)#I5a!8YxX*k47B{ zj-)J1q)`n3KuDk>D`UkEp9GL=7Pdfdpr0&(X0rw@sQsSk<-BK)bisM6#zJGii3=UG z3IgjEV*ViJ4e-+yFu1k_tJh2*0s>pS*Gs~3t`_M|SB(8M>=m}6+EAFF9S(#@v39(V z+=7kB)-fZ&@COX{1P{0@Q=f`r1eAKsyrs|jfe{oo5VtbgKWm`bzlwB{6R&CCmYi7+5)G2xlnI3sDC_+&O-y}ElxX(!nkj8>+mTKK z-XRABQLta9MU5)&i`bKr5wt36YoYS6myvko_95`Xl{TV}f?KfkS4m1_2b8esVqAw;>3kf5J%$49qpT35 zEewSgfWRWC-3?pSBq3q}HDO=C85(d^Oi99zhz5rFjEs8?2mqB)!SrHikmmupiGpRjI0=92;Q%3Y;!~M zokpP+)}NvNw!O3E@{5v_$fC;H;hvgObvmymZx$l_r$(LP126^DiD|M1t!oe{E@VkP ze1;xL`TEU>%@sZNua3H~F7uX!Jyl*H6xFyE1k{4w15AY}3JPN;Pa{>Ct1>1I-?OS7 zNXd(#0|gtCi<+&6-A6v{Trk>7p0B-nxBu$8Ql;}-G!iuahiO=0%L*agsc6PQO=?** z3heDfH!}kf*-dPd+Wd{e6sxvc*9gn~o-!GQ7)60(AUU!B8N8FkmR2tPKeFc=*W-hK{nxRlIW2np)+kGz>hBPE<6Z+faL?{l~-8 zHeLpQ=4UB7eN6pOz$SFlqyW>gOeHe|WUAgX&RX+U3ys)30E!yyfex%ATz2h*=>~P~ zZ;0)n&Xs%_{8LgU49W4}Qiw=iG+YmioDRcQPGW{29IQOfL3ad8hs+nI?TpF+T(MDIXcgQ?JPo`xwIXr82kx;yi{Z16zz^7fR|_v5aT+ z84b{Jh4_GF&YF6CjMeu;k>iO^y!L{RVo4ie1ry6xWX#+^ zS_f!ToSGlb6)6gVQzkpr_6(WZZbA*q#(q!qGvmFYriov6DrUnH#&AF%4kqKOW^P2* z?N`=gjHs#ot%+t{V1ZbwK5g^~p0_bO zPln%VZ?LX#tYg?Zn3^uY?;#*E(V~1U;JQ2~M$eDrO!J4VGQm&hiIt$iM48ENh*?$< z*X_Hn1naJIAp9>n5EmsAsp^fTm%i;lgb@XPY}3{{k4r_%h|tijsDihb<~x*w_98_> zOk)v&vE(upJq+9cNF=I0P%;s^J#Vv|`5 z!23Nr0m3KXONmF&*a&M5gl$3tgu8fH44xeQw@IT~q89NJ_iim4`#6==bleHebKFy*yvv-R?g^=Z5HG zPI7ci(}SH5(=^uljiEd3|9WXz(f2EHL$bFgwr+E?Vd;>IDiUA7U()zicBl!mC}H#z z*stVEp&MyVN)bPyZoJ77QS+=%8v*Ibz$kX9x5Qmxf_ex7B9D}^^rdE7Ptub`Pn7CZ z71XLGjtXfp2_@ICTq2gNi-j1{4ZDqqZOR5L>N9&hC+0M^L5h@As<#4_cPK7a8_olsnDd3VI{;c z<+0_oqp2=$skBC0vw<1{TAL4kVt~DN+UI;B`q_+kgw82(SS<7)8=m$tso9nKwD+eq zenGXJ4^t#-Z2OwTgm>`9lCrDc)R~?#5IvLdkYbs zzqFnhWG?TaIRiOY(N%@A{Yr(RBB+B`Vm2t+e9P!TEtEbp7-U+Yas!K62zYpoAMe&v z9A2NV?)Se?F~fiyv$gPhE*y=azCQ{`T>=cq$Uwk;B|cFy=txBxGG_qws^+(L5-&!x zSMdXI@_wcLi@KMM%u*K$xmWZuGaxwMjypi|aVoe685SzWf>^ig;2-H*<1)*4pu&Vw z8ewO{S`O22Gr6Y;{qRi)l1G519Eemupv@6+ot3C0-=CK6s}f9n&C{M?SH@T92sWzN z=BPuF`U>|exiC8jQ=+v?DCM@UttF1AxGg1fpe#KBX}?m#D1%m7Ay{Psrg>uoeP|LZ zr{ly+Hc$pFvR`R-gW5rP;ZT&$_90y-h08%vtQDK-Mm%K~Q8R;>liY+!rsfk}fHOsFZY4-rxFMmSC*AokzsKBO}`ukzVk58AI)1uVCn zs5h3Sz#(HyW z=(s7wqKx)?axUvL@+DbstT@s$;;d0iDhjVnR|B7?AG2Qx!>~@|P9&9}t5IPR5||_V zV#=f9faIyyGw9|ka_M8A5hxf6OjKJvdvkbDizG#Nzh_5O38c;93r(Z7{TuzU294r1 zMV4%Qs?_~Tygxs2Wxf($sgvTJTwPD z6(UJA180I1wuY}#4rjj%QFs1d7H4}7GRU$om3}(B+mx~rlXf&|WZ88xu89<4tb>^aofEWoFip`h>fSJEG`A+^F?g<=}o6YDU!6A+i zFBBTO(VC72C1^(TjfW(G5QF%sIbxU)ui(nTlK0DlY7=#aJb`P{?v$|1@EoYJN(X=n zwJL(9qfuLqop=&oqTj)9xLvLPc38~az01X0|+sF6a* zKT%!d1iQ6@q$4%_KU{-qYrhhT^w;Oej|%@fsjx8mB!wR15A=i z*^WUH`iQ8+CBM=E8^%@G^Kis|C40DmJYEykmd@i5>jG|n1^RjQ&|_lTK>9TCqd;%f zAk!ovT3_Y?fuhL@Y<+4PD#3nFl_4*Vyje-_mkEX#19oQ4CSpD-LZf!4IX`A{&`*Wy z$Xji5)$B64M2?qZW7U=oW=ytrBWOr<&A3MOkZVnIklR?gxb+m{wFD_SFNScm?1C6y z57?0p&=pRLi2;;G0n|TbmsuYB@3bo|5+rc0K2|Z1MPVpgfpxYnf`e^C=-sdMPP`aj z&Hl7YgisU^?%X!WxS*qqsR7TjU#Xe_Z6SBbNG}(M258pYP=`~HXsl(j3G>B%rD90U z028pPX=iO(qUqjB6pIz0a}G@@ahm6$M8Qqcp6Wgd7YM!LS8jEVGsXWSmMYc2a8H|9 zA~i-NnPBJ(K-qzXK9*2oa*9srR+fy`h^i>I{JTjB9{ndhueLra?OMn0vzDGBHpq3RGBwJi#fgld!_dq*c@b;?TL zdDtst3yTxLJhFysKtw$I^At0*C{B(&n4&P6d?^Sj8feN2*P&mxf`_%+tq51+9*l~i zukBAuPa?I`cN`q5fkTHq^k)~?po%iuvqhVxykF_h^Vo*N>orly$+hqSa4hVJW%Z+w zRE8@BM)zoRF8;p`WtucUsR)D$BHlz1BmCm~3HYI!C+X$s7O1wTh*q za18NQ9&iAgvR~Tg93k1tW-=IbAbYcZV-bLpfwmUEy+$5?jhl*4BV#)MxAQ*HXGKEg zE81;9HGN2wBX-zk6EhtF; zC&TZgrBDL7ew7S$aW7*7q0bPx=3Wcp9v-gQ*AN0o^da8*`Z5HYtnlHJE<+SdWrm3} ziXIO;TNj5((Ol_%r`j*CH9Z$w#|WZuFC!`UCn`gICDCU;OV*}+@kX+$qJ>r48d>yE zq2V44>sG~x_n||<#So6+6&5~liuabcmBlJT71WS{sBCf`e|92!21 z-R|d1Cji#?r5(dsR}h&enjdGG9!QeP2I@dFEvJ?N{VxPL#yO6}6(5CH19M=96k}>P zt2Jygd{1vcCnTP^ktvMBl%(9IiKNUo5tHdv)08rVBl)yRNV**x%!t$i<`HN@is&!N zNNtn*UH2hEfY(`jmzE+E&bS3_WoLje*V!-)-~(jWz?EFVjI7EHBN9z#no; z!i>!pnixp8sGh+=1M4Vz0Kw2z*%$9b^u_O++cBQi%8Vw9AwD`35`|Cu?c5uUU=(^K z8nBTqX?R+6mcp9xyYZk}yo@_wVgs#AtH$1A8dq<}R3oA1Z3g|5tpoQoNm`a+(=s7*=tkXcU#WY}6}?b)1aRbfPQ(Yi#j_iSh&U?aMC>6y|)%T0Tz2^(r8?oa};v6%dQA z#LG$SR+Ly?H@|wgXA&l}yekX^;273%3Upy9;Z>rCz@%iFni8E8)7TS?Lv5S71>%M3 zXCieenG^`}HcYwS)AnpytmUA#aViCSU?7=Q0gz%KAq%mJPdOX+3QQTiNwozp2+}ws zoeT;ODJ8wEj@hYl6`MgJBGkD&^&}`xy&vv8^EoV23(jsO zNhXYNma$mGNKbV(*Cy|z5(<_@@bDR0<2uTCN9k3%6DXVPU&FfX00Y%6k3QW%FO0h@ za)_#oegrxd1dT(a+21XE!R3Hrhh(G@@!q#bj#|IS5UieR7^OO_KDw#4L{>Il3Mh!t zX^mz^mRLGXkTFS-8DdyNP!mYlqP5sLoSUBRQ^-Y)P{DzBKoMeKe_D*MX-Iw&xn4-; zdd53<;(*oDd51`lxR@cYSS8uN%z1}PJSt?uM1rOcEc;J55W#dho!H9ONFv|o zfw5Pw@V^_5%Srn-f%s_J-B6Q@~)#dAQ(6hJ~d+&`pq=~sE>2pVJzxu?_F6bq=qCX&|R?H{Yc zrf{M3F^J7G%K8`;yxjaZc-P~6cqLBVHB#bP;r zVShv5n^h_#taB_-YfW`RSW(o}vXTe;0)N)+C~fWZuU5YXhE+D*JO-oE-8iFw}L z=R-Nnq3t7z)!{!fj9Lg;Y-#>=-5(lHy_#4yN7&E%i(NAD5CroRtKE z)7yV1u+98cjo-+5luqO$BD*FH868HIw{)$<`_cZN8I3bQ47(TOZ) zlDU)~Cxfbxo06}Fmy8$5Q71dg?XaLO5LQX_fq0@05RA|+G^hRDis=|ZwI#ny_$Q|} zG)S`|3%7UGfd0s^^tJt4o`#><$V6;*Y?KQ6yh-AE&fL1ecT;bgN?$(?sBXJDD?yu@ z5i#C1We!0}iWhD=5@mndMt#7$LK)6Ug^H+fz$J$hbwWU`+eHwbyeMoB^+KvEjV&QM z;dQug)#VMx$X|v-!0`ryJ;mO@Q66tkFkdPTXtyO0y%H>5g6^K*kx>+#hkYU#W!CSI3CK#}DDy zGb%flNbs-YlT`#YuuYOSDo6VDA+6#%I+d(E+~j6qg6ePkH)&xS0R@|>awKKY13gF@ zX+VewtfYkG{gp^ST+{xva$z`ynhQ>1TIE8Wp=MaoF!D|Dbs|p2?n8_ufZDJEU%=V` z`!h1h#O!rOVyGL?u|t$-Af891ET};nM}ik5t4kV~2!`j**vp2pKdo4#Zd1FW62OpV zT?mKSb2}K`PZZP|pS54fIOy{;sVR8Ldftub3rbRs_|FU)ApU}(!}sJdf}Pd1A_4}I zY-Gd%4x(C4rZj0@9`u&>dn#G!oh)@WSBLsA7r-hFX8=ohU7GpLiZ`C$|BFC8t zN>!>UloE1QV0Tm(EG`;c4nRPEjrh^I5_YFpn!k#{o|LaWScs}8)k`0KXP)a&%PI%S z!akn%QrJ~;<#lV$rY^EcdFR0rm1J@$%?j63;5qS}w703QNo4%RiDzj3L zYq1nOu_dHlx(Dlkd0SAyP}kE$(qK^df(hds4^vHq?BF7>20PO{?TB&ET5dD%(p73+ zG7}>io|>YBeDm;5_&{_|%%mS-E*G}g3$~Y)@pMFiMLBBmbHGWcSi<3Z!cfYQ;Fw_9 z;ax_v`KCfW4MFGj6G&EVHb8tP=FjQLIxg4{T%tP?4bb7=&iQ1c)f$UmzZ~)f9+CUn z8}{-Wlu38sm;#xaAf6xF=fUg_d&SA!po3727uG&t7#X6&zt?7oDIxp%nAx`X@2Tof zqvEA$R(#VcI=Q6~M7z+RMhNwnjk>b3o(Z{Q*FY+0Ki>pwsqv5a&2fS)B?=BJ0ed41 zRVK-QvDxH+%p5YE)^82~V=~oa!~P_~_`N2vZNKn)Eu{7$it zYVW1s!z+WW3u(`xlODD?6*lS`l(oMhX9K7NPTA9gY)PgB8JzUGpIJ-a0h8xjwR?Ao0y~ z+#oJcNeF=RohQ3&w| zByT;sRkt1Pi!)R?HP{o??HqvN%8qhS)&f0^i)1wMc~us2REE{;HVi0Y_P!DGEm{H4GA8>>}ix!4U5}~i6z8)KU3yKkx2~V z!8%o{GXqwKc5OV_c#Lvbs`~J>fMwsJG^=(B|6A^839ranXcCEDcv{W=w8~IA4h=ZV z(qkl7+6D&Cx@ZoyvQ!mltL|57H52%d8sumn$TIi37~crmR;&MjEbyKNY~p8ic#L>% z$zfNdcT5>CZni`jG0LU(zTuvhSS^E+3RgR~3XJ!-_97`fw{!ItFVaxUx(%^Wvnq@! z-b*oR6_CnT%Ju0(TNOmD{hsmn38c)ZY9ZMj@WZ|9)IkV#aGOv>z8Y`>48==qX&ZG) zfC2e)-XV)16{(5>ASRC7gpNC{sb~Se+#)1K@ydD!6G{aK8^0t8gcYG^ zGCIQsRs;msD#^Ugayoq##Z9s(1=6t#2APvsJ|WhzST*jiE)5Z1HL<@TyiIfP33Pf~ zSqjw6Y7nU#2&4RaY^0SqvtKDF!uo8{UOvMyJ0bqqCZ%EOOF$Y~Qhx7HT?roygo;$Q zPUIAm8mnmQm}Y`Bs)Lk+csh}x)-+#1znS1*y)+P{)(_pf`gUUxS?KUL`_uYl-W`{_ zfWVHUoT`+i8)yry*+R=0o%|02HW5r12+ZTrr__O0Tqd2TN9?0n=zM~1L9@vLB-QG` z%;<}HL{q99Ku^R-r(&@RS{v&x+MiZezqluwxB4(A^~!S7=ws@PcD@AlyLx+wn(80a zHPT(0_mcTE6#INBtUd5z*ofeVYu)dOh*ltR@PMbQZ_P?*w`LiKG&5oPE2cLD7KdvZ za-O^vB(u56;a?HKnm#L!j38DC0E7}3Z# zsJFL+VX1tiT9YSWCQ}hU^6m; zlSUON;wD^jgE3Wk;pjNt8ARKDrO(9|qW0oPLHZ$pOS%+sHqp?cna4Whr$IZN!X>k# z9dre)QVP=ZE3tm!QL&G3sw~~_$+%|G3+l#`!RZNtH2=!MsU(zK}BeD<$m-6gnWB&%UG zpvvSRF@oVjuBmFceX7lVrA9fFDA%jElQ*BolxYtUA^Iu-n1$I?<^26h2~UzUGUiH3 z(6{HqWFhlvWx3dQ#S*n@ctf>bnNv)M1rMY=3DME3G_B5%RN*f|$` zpG=)YCR*M!tinCNA&b^DAPVJ4e7`2DMR_d}Gi>8KHJ% z##B>exM+Nk^h!jZaz<4s(M87w#k|G@3s@0q%W)K;`%`e@6!&{RVjF>41yURbRfY2(XMil@k5vo0Q9_u_4X2PDPyWT z3UG{32}e1ur_O*(rF{|_Se+%&Kkm>`|_&7pvVUM zN&NRWpl(^O|M1TB@^81loM!U%FTR)kclha9d<|}pZAm|DotkW4 zex(Ri!%F>pQVB0kvoXn$&^rDWc#G$Iv8dc?d?l07 z#{RL0o>hk-seJ)jmo9CK&e+e4AW}V->#+Y&(wJVQ6FME9wtOR`!Dw%skI7ZqlFWfoJg6Vg_e;0 zcM1~(QL&GgsZsEz`v6<0-r$fQ{G`r8w8(y?kOZ!ayP4WRyi_WckUE_hrKVe=FALOu zW&K(D5EN93T$s>n|kZA8!q2Wn-Y!W=G7SUuy za<+q*hcIQU@EPHB90_BSz>W9E9;z*c=iv<@C&WY3rc~{+Xapq=gDDLiCDDRif{!9; z|DD`=)_P|fTSY!Oe8C(nAD}1|q5!^5;rSNZdz_J_H+evqE#SJOp`*Ul|Zd#?djmc4$(pZ)PhMuVnS8nFyJTvgw$b| z=``@6>vfV@Pza-3qYsO0+@w`G&|lDbHHK=!K0NhtIFqxu z&bqWsal?0$+B3*Rtyo0ZB$}im7LebcR!L5HRE$U^HA7qBGA4{E9Kat4xTuMWx(_B>o8S5Qy{ zY|=o4(C{;qp$)pRgw(v~7Z(Z6wv^R@^sxl^Iw!JH^C@EDQ`L%YKJ}~snQO&wP%<;Q z!8eRMmqSYCC-ZK#y7)?5eHhhv9<~*fjrl-m;ME{EED;Q-&jaOguBh?Vm0}%qDn+Rb z?RF+qLyw05g(wCVfCw91E1r8$B5-9iR9lKl@AtF93_;NkLv!jP_ELhsL<@AERBKtw z14uwc6)yXImgD`M)3!qYmbY6s+o~ock8O^HF*!|y7fx~i`<2{s7!_5ap(pyI@^aDS z>@n-6$pJ^s3N(O!lf=j{rj7)?GAY=QlWL<9FVTDvsDUnc-bwvPNKDp6U z8d{l4d<#{xfvuz1sSO29jx4W<%ON2OUC`LG8(N@*5)W;a$pDcP(Hmx_#fuP(%;i@g z2rHai*d@fgYbC1v4W%jwQBr^c(co^cr3rp&A?{Jj5!Kfqz9ChUYjmcn0=0EXR&-W) zz(SQD(9_1cQrhX+!`iYAwHc-RV!C+M)|pq&#IMKf44`h?+4V!P6rzfAP+|p7!U|s< zKfIDaQIEc7Mf7b3g4njy*MM~wXK0q$s_PsPaMDJYS}beQ?2y7_yyQxidoD`>xq(`u zrV`kS>KJg4Zk*uA&ngT9)SeG|5?7E(I?Z5?q= zElM9|ok*vO+8$zsM3aDvD-lfzmNaKeAwJNnYk;>@kG39uXTCsdVGZ_BC1C4`&m0g< z;HFO@-tom~pZ#ew{|PE&8+e!@l?j0(j;seMXyJ$r(h4^<0V$|t$~J|OdmNpzAkX&` z#gR_~$mzyMr)uDMn1uJYyVqY{+}wP5cl-SM#hcT`JPl8d5+9L%+E`j=vS~t+tw^57 ztIEe#;Ki_Yr6~F=!)P<;tYQ>|%8j+xLo$}qv7Ew;#MocKIsww|RU1l)WH8^p6XlHK z<99_0K!SqJu#HH3s3G@~<275;%phRy&RT&D)694vSB&VBuFH?3Td)IxVY<3VJ0FmH z)W&2Sw|Pxa-=9`5nJt*$iT|lJGn0UQ=pTZPq79HQ;0(dt(iM17zDy?YeXX_T#n8xA z<_#3$B5DrAu)O#wD&^gd)WSITnJH(YsENE@(o%~#I!xu*pSF4I1W@%DVO!@Zf)IxE zKeggz2NpOoQSDbs8_G%CKbl>w+-L|rZ5wK^v{9peqT{U2{b?zVXv*ThG4NO`uz~`{ zbpqiV_MI)cUnDM#o%lZVoO%Wy6&I!@34I+Ti+ zNu!bTk)w3HT=Yh>?oZ2*g<7|gvKo+I8G{vTK$qf8mZbX7@DW)1mDaP`2%u=-rn=H+ z4}~HD7_(5oz9$`ZI_^w4hr6gn;Gq}Ndsfa^bBGNVLvI!%24C&>G_=QvRAusKR}C~U zq0qSR_^ox^Sa^zC2&_{Fz} zzkdDo4^MwQ{P@KmzkNC!M5`i!2taQ&ftFkFo+YN?vx;h=$MD5JsI{h%T%8D4LxPRd z`Isnp%i8Hg9B#${P{uf)k#NJVMbd?!6xMpxWCzqeLN#K**R_qBcUwT%f4x7Ie;>SM z0%`VHQ^v!c+Cf2w1V@$D6xTRZeQ327^1%{`Du$$DW^`4NuEZPF##E0tNDxJ+(ARgU zA5MJm^N4s3-eAoI?Gsw@NNX~pd~i1)zf~C{caQ=YGKC4!&64IL^`TKEiL)kBJpNs| zvHyA>);AZ8sffal<)U3493m?=ZWQdcP_-!RS90;GB)R^KXp#K|^#io#mLq0HvrMjY0~$P29`)GVY5 z=;IIT1D3^A+x+^DWnSHKO7(hb#6XVS4qi~OUkp)Qv8X-H=V-8EE&LexFr?u;Iz!^l zAy=lJ{ddBpcs9lbA}1#rRE+gzE0#hL`3RW?sG-*OE9?GK@{mbEQ%pdEf$?AdG69QO z6dkWI@$(@HGy6U!N|rvP zW?fwkY6Ss?2urDg`YCsUS6$2SSG=98;_~#J;`F4M;SI5-VEJ`HKwwaW3KyHf1Hy5} zILfkaACm|NZnG&CXgY5b!S8yZ3=oqDDz)o{#QzywGQ1%zps+CX4)IFX3JI&KjsT_# z%h-f}?L10_{oN9yk(rEi`W$2cS=lOv9Mv7ZzoCWA{<3%XD|1>C)99QMtFm01fzBN@ zHJcyNF0~KKI(2k#`uOL1bu4@O86R>Md8LE3%&W?Lpy*M8?f0}7{GE1%MXwCUQAzF| z0Gpqzw+?W^iwp%*^rgiqzX=5RuNo}!F*nT~*l+G%{y!jWK;5iD%NN;A#lX}q;aMuw*(|!lhV+H$TccYgidp#3&dgEV_zwOcs0KkN$K#KRuo9 zPCuMa*S9bB*Mb6Fs(WVt&Q(WmL(904n#d)~`7zM7SocO#a=~(6*qhal@}y4k z<}C@;Rre*Q2XXfMBDmxsq6KKbwu>*4-%x_JHa zi>oWMg+1SQcdU8O&&QjaU;p6a4~L+H4q#pte0=`SmtcfcX<0{-yDx`%vsmHW4_=>N zo`k!@<=ySo;r{x??Zt0@^OFyU?P2E_M=BO}X1v7!HX!1CYEjH|bpPD>8)I`L2AZ|Y z5uTz9%r5L0Pf~Xb>c@H)m}*6sN()LjWW)8uAzO=rh7Nvo+Y3dK~4Qvx9@JGMH9ADg1?)NWjkN{K*RDU9;8%zLL zYo&NZMWvqbY>1>a0Dk&zmEE6DcW-|@{(OFOI{x+9|2kftKREo)?|wKxe)8&gxZ(r%@@~a6}re@>ZFoRgmWBmL6=KrI^|_g6mpZ2e0oVTEa*K7I7)@R!4j*EsRT-gz5CnvS2PpIcN(N~@Gc~KeD${zH`V#_q#g@bDi>=0K~F8Fash;G-^+<#P0gx{OSG6H_xBn z9KZSQ^TXlA?VH2p&p$u<^l-SnJH5KNIb7Rq7w5avH-EeS;rz)@_N0G*{lmpK*H8V= z_y50a&Zj^9c=+Lq!(V^==&+W{-%fYWuWybr=iTe|5572^F5cQS(!|~A?f1w3{pR{~ ze097%->?6AeZ1?-dr9u@&FS*kpS*be`gry9#m(2Ji&q0`lfA> zef#kCEV8RNm&cQMCp(=V)=3Zh@LyX)UtYW}nSFEn{BGZ-+H@JR>9NWU2#k~8-_$&2Pjm+PpY=&?tvpY{-eet2`jUi^|)x6}W4 zuJ!y8(diP&m_jnkuE?2F+B95B7;mC+K<~b(Sp4JN4{u*RySsT$?#JC$cN>rZw@5m) zg3M$*@cILrQ=ws4q5S}Ke|=%=#lL4IVri9w7PSV}zu&)p9D{SoaP*3s@^Xilb@rU<9e9_~RPZYG{YvnT)P)~M z-Z6s13lw9qM~xWGL7CJokBj&<>4aVPoHND{e2>ORjHZ5C(kNM3(g5wzKupK1>IpCu zoc*bAn5sA(83y5`k?WkVr;XOjt!B1SlYu(pL^L@bfaQpgncX|I05olZITBBEss7V^}_DU1BR}u}WoBNg@ z$*c_@$F?-kwiy|8}Pa`QzJv2Sq!*=(mmV_^Xv%-W_YQzZoSs12+i_ zlvZ(K>p664E2%k5f1@FoNuy>KG&S9$?haAjr`o zK_Bpy{`!G_E5?5NM88y03j!UyP#ElY<=nu{lYwNh>IIWtv0~zrCK`rA1gf(=v*6Ua zJ(ZR!72UvcO3qRnR;NA&(*QA*JCTKr42Pst?1?)g`ClaxPK6|CqM=HN4IeM}F{Pfd z!pp1Jt>u_8=i%oc&;L-t`~oQc{rdQyUmfp-_JgJ1D0*)E4k(?=>D5-17F)<>xAewOfjXsrN{`jkZeJT&Gkl4-J zukQxUhbMw0OfAY^)Uk=^i}KLBQH-%c0IjlHGnth zU?5DhVcM;!b!r8thLA;R(%d&v7K3fTi;?Wn!;6X*c>444a*q{zP)PpgtZSM~rssNc zJN^z!iDg0~BC%CC4~2-2Seg0@7J0yv>y{6R_RE(S3e}tStsmsxhwALVgD%IL{bR9S zUK!WK*5_^tKsHKrAk3A9s*rCI3glsm5hnl1kYS(OI^xkgt$NM(a*M3zE=9uOaE=#VYo=vK1r~H#nX{B zz7PSq!zhmfP18hKRC}X`v3BYthB@?CLwxvk^RQcBolxJ8cz`GW_F5J_zJqjM9bX@B zua38u*T?(!m$)pBdLT^JN1E3pl`?R*Z`jmNfD?)PjYlI?m%+#lFZ&Wy7!D3yKYIaR8;n@)DX=6%fhfRkciw8WZv!7=&pdDgOcmr9@B262B^ z%wpAk|10}cajQ_@H1FsS>3#C%7$ua9Cwh@0h1MmZT$p8MjSY|Ae zpu*p0jX%N`clHBYANJV#CleB!9Zw+G`cHYG?iysV`7+$02dK8>2A!&0or^+YM$amYf| zF}&cANU10hYC;Vb?KERlb;pac%emHzoT125HVPngwM-Lzb~;w}ohK5g znz`9!)_}MlyQz)(c?br33%ZV*gT0lEX1PXnx~rO2UgiQig2CxAT2~P@gbgK690?{oIZjs@dZ z5TJ$Y($hA=FMJTtD03RrEUwoiNEbR*Q3pl0f+^O?RwxE}b2r&MJ++ z1;IQ~E(Bmfl(6uN8$=EyTe6N(RF`bzn8RO6%26(U+#-)J-}Dv@Dvh2Cywv?ips>^R zHhG?FLWAYe##I%8%i9l_i5*3NrjL&Gfy^5k0=sN4us4c#3F1d5Dv4HL0D6>okf;V} zkQ3GrALGk~c1enb#ao|Ez3G8^>-m-s^>jpCKw_&m8UnsvOf7;fWb(*X6E^0Uk91he+`lrG*Q zp+n=2?y6kCZMXHSF$xLY}cQ6msH(<(!Pgk#vyqc3!#UkHjVufa<&e=D{VgkD1gmAc9k`beJy)eLWO+G@q)%YDR5>E+}*o4 zxVT)MEtgjtpCOB3csS3_gUpq}TvwpdsBm*a#s5Om$J_?D+e5(~ zwg;13NNS>>qA5g==tMdzmc#^EHxW^zjUy5x0$3x6ME4C^pB`T?(y1@BieWbB$vA_y zIxQj78SqjlO31=ET4H{CwQ@n`#`@n9VI3+Z_W|p?h-LI8VhW(Lb+T4~u7-_Tk8Hx3 zBMkoh?BJr4ib#pceef(8$fqVvJw*oq97r%1UII9wezeyoHahKe!rc#Sf7dhUTXI#9c=HeUkmHf>v3vdB+yr1S~aH{O?Wj+a|f zaqY#kA1+om$EO#IH>;k50%9Qr14PLw16)!m61@a|an?Ge01}P~pmqDK!(qm|<0+R! zf}dTo*a#GYKB@qaE49FTT*VOiYh>cNTJg%rP)$7*or)6d)jApq zI;LR}A$V;TSOzx?fXj}ikXDG?QLo$xx!4i|O;8h1^!dW_GRSBWjBuoxk~S1zGN)xy zyY)Hx!=s}&R|gkI@4h(r=98lvkpHJy%d6+h>o4A%-JGVeuw1P!uV=rdp8>L$a+cF( zAUJ{%(VEnhcto}@EF)A%`Wux|`9;%7<-X^F+B=3~pBYFRyPBfbF*qrPWFDx+LPUi* z2@C2?XM@E+GI=q<>$q+irGznn3?_NBw>7RbMzf^rmKzI(SsZOnOywjv&OvF$j*JJ9 z2O8jabIGU3albhr5c6*}^oFOG4(N_2n0aUlhZ9c^!NTuns;wCjn;Ly6LwPmWpnIL1 z0~ysDt5{@@k^Pu`1`?8uqF+(upq@p6+>;`zRV4r9gHk+T5H1p4hfzP$9Umk<_;_d9 z59RLEY)YS8Jn^JvM|sxNRF}ASr5ilfCCv@AGqoHd8O30ao0GPRw^JSfsbt=60g%<$ zp6m1D(_64HsX`3iC7k42I5M#jwfATotQKT31Vm@oa=?C(88-5!&zEm|P_&K-g&yx| z28I+sGz}bwU^#wUjHI-dMFB*#x@PJzz1@-jR^WjCg9aAwSF%1HRoWA(b6sXft~Qc9 zGNS>dn)Qu72l;&O^SW8uEu!_1Pp!s63UTjTXBlV0eO9VuZZk#)?m86}Opp~^?-+*?>XNvm_?aYwi2Q`k+sUVU755SO z9Zylcfo~2LC&ts9vAdb#WU4eN?Ah{S<6F&Ql5OT}hiPT)2WSKx;B|{j#$`B0?Msid z(>4&37+m1sp%3v8izPdVk{J$u7xNf>*YG8rnCG&~^S1V?+u`rLSzf zmI60H6rEW@cLH&CikV0}B+?jx2Zg8EUO$5gf@Zag;A?Iy+)Bd~f1B$If`ILcpRN1f zA@<^Ga=90Y%+oxi%Yw1M+2z(kqydZwccd#Bu3HX`pm}q*qY{GKQ&?wVz1hZ27WilA z+~ieZ{MjJejG^)ivqhg>tZoi2Zceo>QVP~r)@6Tk^!ohr7BVP}3b~9Z!x=$G%uS;f z3Uw034~hUOYgZYZT`m)1^V3gmK9|)M+H(2caD5ZaX#IHtuhpIk?$Fuk#kv`sO^^>z z_q@+r(8!#D6yt$1>3}ts;HRSASd2uxF07JVAVH|!H z`#dyPEv!81da78+>qp$&WfI(d-Jg_^a(m~m|26HTh#cs9qY%QHHQ*_~&}!MNjkn@< zSttYWwy{#CoiqGn(-zyn?A~*^ncofX1qetkg747y#cv!Ro4g5$PNo`Xjm{&||5oY> z;%0+8fkKLiZ{2%ytg9^*}*O)Y&K)EV?L0x=jr0}^d**Qk?&2Y2lqVPmHc*WsZ960$@Bl#c3UAgRUR>`rA3a9&eDntlnKMb*KeH0iNP2 zI-fUlZ*|w?S|J{JPi7N*1P(gn8?|d0M}jnmuo#LIi+hH0SYi~P6clmph5d#Cb@cTu zr@8!1WEAwxRi(BRTSLiD5#bcHjQ8skDh9*Q* z4=+|09jPX{Wk%O4*>TsjU1((pSDaDwo;D_|3&fx$+TMT+ut3v`Y*EfnC27^hX9Q;^ zw?+o0YpsdUzS27ZspG(+_frlygcgyIU78ZomQ+EKqzt{%ZRmE57L3qyVfB_%Voco1 z?Gt!bJ)u-29FhUCTVbX=6>{VE86AFfaPV<=&b5?Z@;>I{z7e%AQl>g*}A zvVZV`3QWVA6`}|9JapK@ynBZBOs2p54aA&-$-ctd=5idX=25~7UbUrdEG$o09 z`~FjjCf;wsxCtVxYbt+dnG&(QV+!yb(P(gUB%v4_M$Z= zpn6j6E5U(rt>QjVycnG1F`)#+u{WgpG@4FYsi08x9j`7IQc2Q~_SYy3N%t~pNO8uY zOC!zI2<9wDGcpt7jwrL&UX9QkW6&eORmk{&sHfw7L0d^Sugn%Z@EF?n43uu)Fbblr z*NE}%5M*5eEfDlFUM7&3uAdWJCJc3zRy41|E-OZnga9?>1V}4rn&5*6d*^R1G;QAh z)H1)%!m~XjhQcDaOE6FcLLZ=Cveej%4?_2vEUvM^_EYKW#K#A$!diq$M%r~!shD*{ z>S`+jcg5BAl?3j35$0@1km+ID4&We;DsCkQfY`t%B6r|T0z6X=JTsrb!bPFSK??(b zZH;o{{ET1=nL^2&O2qF`^I8GNW;C2o_ixoUtzDWUDn@O{zc>ulS%) zBOFG&D*uKg)xIYb5{X}rg4+;*=RfuI1J&=!n4 zVM|ojHj&@jQ#x$DdI!QnHqHl4o0LwI3NRfSkBrqlWw(99KA=~%K<6J4gHkK#=XnT_ zP9Hs(IoJ&0jIt|E)s=KMfEe?HuDRthK~@E^hBKT1mjdG&LleVGFHnG^aboU5dDMP< zWB`S6ynmeF4~07JtLj7vG!)b*H1p1Y#l192W^5gzNf|NViUl7lQ%3}~k2-)c9yS8& z{!Rjxw#hw>Eg(Aqy1j$X0W_7E9C}XS9#eY|O|@5x_k$pkCL`62lpoHi>W1NF-8hzH z4al@THxcVNeGA4MM^Gj9QgIJ4H^!}}M%8tsg~)Gc-&0;>`KpLhMC;jVH3(Q@28tMI zo9=-S#hJ}zaS!I)K{7icr zvHl{lKm}!ffl5ntOCS{s%UlWN0TL>Qky;Txetmhlg3`tLz5P{Q;|B5*!UfV|k1GJ; zKty8_Wt!uZ!nnbmY*I?XR@SlxKp>(zmJB15lF>(Ms7u2D1zHa?Bz6awE#exuVAKJ$ z3Vm983yv=sGfT=gSGkL-=;?cJSF}fQDA;(q?FpgJljFf?Z^RfyyTvQdM438~>%=@- zeW3R~b;@Tg^;_k_!2CjY$1V?B2BM%Om4cFlW?rIA8L5T5Whng$I3{8pSDj-mTAzNS zHGc7GS+~%zdA^9JLi=It5V{0q7%Mp(R#acu8{f3JvcXew#*l^j{;iht;=!Q>U7X~eg8+kQ^E1j)Z@1|TJk5hEC%7AGdDHfLKUr&}&IMWf5n@BK@F zR|pxp5Uks28Ax(zlThuHr1-n&IdsI{ZFCBJMkMa`zv&eV+(%+6qb*|YCA&-%Eg7^A zmpg;9hrA^T#C({NI=g>&KGa)u$5rbxeWadD-EL+HD%!=K*lv4d*pfg6ht&m(kuyi%=kEx=wC8os9r|B;Z-419I~ku>6wSYz*4DlsZ!*@#FUyS zdCbl5fl9-Fy8bQ&GSeKK*79|3k^FCXK&Vv3BSlwu=)o^_#45SyM^B!A@)bm+d>xLi z+~1l2rbCldp%M;_4yk5MhN_j|tf;&g9*(+_65QY|VgOZBr#8tpKK^ z@Gakwh$$5vl@Iog&)%-yoll?Dvs$G`a_2K_NcHl2K2h7@NcEN~1h z*o(!>TpkV-iFE-EAT}0Vd$q6%#@zxtB73x(&@P%Gq9>hJS)zC2Jw1*qpU4PE2!$m5 zV8aqL*P7*KtlH14L*$*~iWSK!5su6X$z0dNX#ojHUx5o% z=d`wMkuzn}5JVQ6nJi34ufZVA%m5-KB4~#lTQ+T3Up233uOX8z5D1(p++T2^8T=|^ zL~QNWO>@!X@%vq}`Dc(KK8UxgO`ReqjkMxf6*yCmP!F(I%QtPdPp0E2& zE0z$qg`2n@a%X{_umVCG2AQ(u!*b3zLRbwwyByr%k@xs&HPTdHxCX7me6ymNB+kX* zC*OH?b@W5pw{r7-y8>DH_MBGs^qa@!#ia!2s$p4VQgIDz^{odza1r~b$F=I#t zj;c8Us%P0g@`Tu#CM6*vPXV67@%NTxgh_EaUUA87-cLr|$2!+Ag|aZpM_tZrW`m5F zV8up*L`4k11L!P%YGQE*x+>du#DM%#(<5N;^$vO1mOy<*y=gX_yH9pz*O17m>a0hp zAND-C_7Ut^J}HrU=XmM;zdDcMu0wAnX3>YHN}CB zVc2lx?$pfALYfn^-tO;!EnT{k3`wf018+uK>x}gWMjmq3e`-}sMM!SzCH3y=k z+1)`9cuD{@$fCWM@K-qT>$iN4)Bd00gGVOQYtKt|+ggB-Oel zpC>IvVf4STh3-^o)-ixyG=4z#`M{JRj0+_bhFuOf)p`5}jf!YLr@p(XVd`)6T*iHU9Vl?UM&pzFJ^d9Pm3-HzF~z9PE?X^yftD(q-S{;O1?Gd2w;4-j ztHoQF;@IS^M_K8Vg-%tsbJ-MO49?>U6~+#=D3&+v8PWoL$Fa8J#eClv^g{vvje?fy`E8 z_F)Ku{#k>!(<(EXn`a0*UKD_VU2S=lJJcT+Q9&+6wPu)!h>~$+XzaCB>eQf|cJ_Gs<-zzh;)lXGdr7r1yr(jPPUH{IR4k zBglvb6aX^+40lt6##h9<_GSmgu{;JM!HPlX=v=Y$(~D!%TZs#6p8>tspDJKdzs^E>yQw~oJ$IiE@>fSzN#=| zc4g;lt95p_oJSEE4@{Fi;`xi86q`THeu~W4$f$xz;LAl#QQ@=Gi{ob(kIyb?$L7(e zK9FqI^+Rb_8-LY|Ym|x7C~Hnjlrl^&6SiVoCA~mzkEKC=bxALuo*i7Rmd7tKG}>Rs zvzWjhqgq!tXQ!RxsRAG9g6tkcUI>(&i|s4Zhf4`#wOexH#}Ss1c6Ii?ZaKki98y@2 ztQYT?zLxO2;oH{iU^%JjQ&BbP-H9|A@j)Exh{t(`@xkI$R`)8uc1E%3i9!%g!MX9g zg%p7s6`4LTPzU;{B>=0ol!>#}PeZotv>VaePT0mpgMV85q@CP@HHnFdQ1o0M4iND# zKs`f2f>$5i)~1B*>O_ejEEcrJ71S9k;+RKOOCOnMkS9JI1NBJSRd3z(NLa|@|7w)N zkhGZ&wKc?htRJIYV-Z4dJGE2ZZ+xf%7ulKpUC znB#Bk@_E{kB-&$vJcJA-iTv205@0*8TP=DzM-66{d*}o0;>!}S{(_KG7|LhOZFAs3 z$V~(6x1+Xq#=u|RR)CuERxibK=sFm8Q_3(+h{7ilf;3z5^pc#Q8Dt!z` z5cLQnJ7<<&m%>MM%p^GlqZT7R2V4)HEfoYVfbCJ6wyOdr4cEsTr9W2ZkUP@vF_(>xf`I@T^N0^0|D{fdfEo~H=k8@zp4prCu|xRz!oAENBKe23crFtF z0^fVz;sD3sW(7mR^I^9GrsGqVfmm1xj$g~g?(U6uPPp{5vZ^q5;v}rPl^A*I3}UTk znrJM>8PL6h`FHP0`z%%aegi%fXPn5>xRiJx9xUQ(_(+i7NclP|4`W)@L#zMjZqwevk_x(#<0U;w2O#B2<6)U1C}7AgYn4K!ELgk%qD^++K?_5=5B__!wkN)p3{n<6|}IWhm`tdxhCPWTS`{&L3g67^NcyL{ zp^dslSVqZN)60M8F<@)s zW|v%K3i&CZxO}oW^4_1}Ms?Lp7)TtBGHRt*Euo zd{4?!RVTp4C2*nyWm@KiD$|j>+E=n2iz?=xa0M^Zeq!hecGVqLETr}pf6)RuR}1^o zZ}57+5=a|cR=xxxgW*X}o5z>3qNV9Af*yZ|nWNA2#8bnV9HwrkRW(B*Ug4MQ8 z&CmxJcgHO^hCso^cv~x4pH*6cM+5$1B51%5;VOUxU@T`!Bw~er6YBJ|9E~???r3V+ zjCl-}CctT~0PivxD2`feOGxdp_j^rZdKRc79Zn`Fha1R01)I*{m=gaxN45~bMe#Zy5rI8u+A8WDRPiVUmTVz!ZGde)j`lyl6!t14fw-xf)DH>fVOW~T zDOhvwAZndMkQ70}h7AOA*0WLGBQ}6*^)U(8g%Yj|Ztf;kBL&q6c7PNsY5hxT!Hv_& zqfLy+5ASU}kQ|-aa;1FR-T3vJcM{>OE#SDmPFf$vyPGk>Cj(*4=oP61>{k=1x0NuF zG9=xAR>m%(jN6{+F^a6TaX6O1+=8d>t!}QN_0uBi9{28(R1QEBsYVRk4jAbZJ~*Bn zcI4G0MHGl<}6-J8Ym%VD(T;_!G0d#x=s8|CVR(*W7)h0$o zj`U!92EFUT*+Q7**`Z7*GjSrHBmJ-l_?HMQDRjF`|IBp3Xv?rmzLD0sWZ5B}Wu>bf z3r2+$Af-G4Yk5PG(BAS${PjN5@z3}M2!~S6Vx(m;X9LqE4OJ;(`%3wOv)GADJ%ez_ zWYmQ-2(Sr(q=F4g17Kh0bcZg;=Hoc+DL4dCX<*DEQ%XImEImRNp5`fLw}rA%S5kWk z_d?$lxTM}137Y?zq|1v-T8r^#F=vb!yU+Qy9eB87`T^N2=}7y_m6TB3jLV~w&44k? zVVw-vyy>}wV_Mo0f}Y$=2VYl8hMhzhZ0FWy&6pv;gHMJO+h_jbb(ef=uY^tGp`ohW zDgP1KW#RzUOd`YOh+cstDy}@4C>e2vr~I&Uw31U8vz5XI=Q^Xo8P&$H+Zl~CsWS~` z7D#8pp)E=5+Uz~cj}Lt%3_TmdA7WuJ-u2r>kQi^ zR*HIm7;(4*hFzjzYMekJ0a;ob4>~bT+95f^Y>{!(Asf}_{rOd!PU!8k!!Q9eDkm$@ zr%;RCpEcaIY=L&GrGJ@qY^U??`TghX&zs*+F!dc~`{Ou|lTEa>dvLR2aByV0mf`DivbqzX$=ofJz;5Gb7~UP*k!JeUY-4d+&n{oUiU=Woxy`}ik6 z`Q+1Qi+g4+4gIl#QkSMi`|FufKsWJHAt4F|xkD;yZ67TvsH~jM;3sd@zA|bD`@;b* zJ;bx)m5`Ye#11k5yPuNcQTAH7=k-&&Rpky^+3O|TeBun(CZI5L4jfK@1y<5(Q}K$; zq5BHj)GyG$=9Th!g%iUiA?qV9Oi~tiPO`^33nt-|q&#Kk*}hU@E+bG&=qhB|m(qfq z22U5l%9{gGPB%}cP(Dl&xW1tbN*uHCI01=o7-Gsac`sB(=fTk^^zcm!OTf-J01O{7=YR?m)*Q0}32UN3I0=^s|lj-DFfa`g1+!_}KZKlAi_V}IT0c`fs# zh28+_6ec>S#PT2=s0p^GnqF$f=`cd6_Eta~k%Tl$6`!c-?EVp~$i4UtLW~U#fC>aM zXRUWj8D z0x1>>eUx^FjeHoiDrwZocvMt+fdDCrsTW9B?Q?OH97 zDZ9BwvO+4~QEEqnY1V?95w){lg~O!$=UPOYl{G+#iUTpVJL?FY)Pjq}Nk5R(sPFv{ zx|`hq3v>I)3h_p@jv_?S);6-*c`WIqQK3cxr;X995U4ikYz~+QB+JKzuJ2rVbGX=T zskZi3O9*pmNvnoAI+w+&Bv#`?F49~rL|wU$vTt$~$nZ#|obETM5aA*EI?Yq7^L>P- z&f;=#xCw%a2Z%Y8!OjwJJ`$iV`B$KLH{!5!l(QB?&%zswvod3S`nHhVjiCS+`6fie z751~@ML5a7U#CT383Mh27FtEMy(Jk6HPE?=8vkCwGHV76<6;{!uQeHT za5-Fk?I_5F^g-Y7ZYMdX&6P35G)wo=kLZ|C_9Zk5&u%4O44qJ(8`%q+E-y7~)PJb7 zO5d5K==CIdwyFuSNM6sAlNF<#sa_v(o-b-v7NX{kV@Hd^X-NM4@xxT}I<#Cfbb&Z( zJE5&95GImE2mS}+a<5ZM5mM-S#HvEio?PFafoFx}msIUz=aV!SI%rhq;^g3TEpyH6 zz1)DYlm69(aS?j^Wvo`|W3>-EMrKxZCdDEnq5O-%BAyYdW+14XG9VcTY_cFNG?#hx z*4aPO%9v=97r+Ijy;1_%nN^R6sT~_9_9Vm|4mWEpfHcgRja%6G`mxMkQQy&4ECK8? z5?F>M^$;x&~`|tf@?b;sPWS#71P1*7NM>HY6Et)fa#vBZf0!8@mZIo z*C%~(dAW<9m*HSV5&}+w!^IyS?iqt(G|4=3`FQw$?QJKfp0O&C0toXW#ck2=RA5?HNKGVgdR`RdDRJ5#KwqQN)1aY!eYI1OPmid;thx}7A=v?cpES(?++=OMA$!f5;wGw|1H>r)#421lXQ+*;lbty^ z>JhPTRBw$(T`IdD9dx*)0kav~Wt^SFAOaE1W+Y3d4LO{t&>7)C-`Y=aEQ-ulECio& z7>w*it^xVA+w8umMes;YI;%s3*CB&*(p4ZRfdG(5y|=;~G_KaAN+B8S6l2N35zOJ+ z_!#JHh}RssZ1RW-kT?MdOg9WvY!U?`Ih+v482v=7HhJ>Frd074*}j1JiCENuYJ}=0qwxx;O1~w9-FmDx&cg|8)6I z4RB_T^z?@M1^J~DAhVuJTrXh`>1|y@fwEtev6}(D+~EptpTI+=-`_3BWSdZUjUC`3 zN5?~?8_W&ofrAI_!d~Eu3NLBzYaB-5@G&EZbFf*t4nrL|;E)!86|G~18s6D-fiJie zF!y%89_q)$5=vK8eDNfr6jWL8yKLXnIdh*}La#!62cbxp5N4%NQ3GRhk(g=#a0Shc z9LlAf!_^xj-z@iq7(27a)~B*(xR%yb#&i4TNDYu>`LPgUYxA!P=fpZ!O}QEe1u3tz zuze*q0-=S9LP-#k4)jXzT-r`NmjoUNiwz5g1r^O>q6<bYCMA&{07 z!HPIu7&@6ueC&$!Q#Aba$fA>P&U27cT1^_1I)DL^8Ag%s#`?uE^rAKh=qi3(5=!p}i>ex?~id1c#NMD=K90 zc0E+XbHeJCBgfUZeWgS}!4t*50jZ2CE31Y_hx!lRetC2n0@V9Z9*1V6h$T$82LZX$>;suIBF6FI zTrS^R*2*{e<$APu`-nl{)+*phwu^1Aqad?D`lTS(H7Db6=pjY*P;~Xa)YKx3HzpJe zgGyg4Q)an&z(0|zqopdJupVpcldQ59oBfCxEXCG6pz=`XDsrKG7);8)7}crn)3nCe z%{lSH04v#?+cpa7n%~E6&S~QT*x@0u2QG$3@z8Ot%z?CEoSwaco&eEY5$Up2A!8Lk z4$3bVuvOHHb^!hbibvrA3p5ttk#W)K;YETK4mvQ?M+|e=r&ybYgFuVH&g@h`Afn_+?jS{~^R0t?Y7uk$ z4>ioF6j~a40>hO806Wjn1yz8+>Id4DgR+D{BUhk2P-sM4&%{7(%xRdhdQKL;TZ3m| zeg31Xj7)E^7D+zCbAUbR>)LcJ1@Fbl&DYbxy?O1dRDSf~?We$80?aX_(Ue5Am92p#q|?XLZG18`c(t;+Q$l^$6G1lvE2ihg zwF?kod>DcpT}IlGK!%=e2-bnSmf=8Df=&W`OL-WvkkA091y1lB@KM^U6_qlrM_7rG zXU0i-Z*5dDC*&g8rX`Yl-rOOxUS-A76|FJzo1ALSGBH5S#WezzGj_2!lvASc)6=sx zKsTiEQv}?hnA6I~m)Cnk9;djCfv$!vU6UXSqDN;42K}(p2F&0@a)qx4!t0ew<Ky_5AO})9L>h1BTaF(L3qm+|Z9XUzkvg?!Qe!0g$oAl19|4Ob&q41s7ea4>ba-bL?ahLTEoM02 z#iCz~m$7GZ1|pEG4z(oK;<|42D1I-IqW#@4pxD{)z;dQKCT%lGrM3l14xk^kp4*o( ziL=mge;h(RJ0|k^>%r0+hDXCfjN!8y!4$2CZYn5(lZ)wSxPFos|3uQ*ULI>a5Wnr{ zATf0r7e~v9Tm;z(mZXtNv7Y`)`^vbU@XhdIyk6ClZlJIl?iK7sbrl>iUP20#%v#=9 zkIfTcVvxBA7{5I|y)=fDxtD|y972pKWm0TI7(P{YDp}9oafS(cV7#4y5`Tr}65d6d< z9-a6B<(U?X9ILkO)%HFjKuIJrp8++HT^&vyadG+#93!2Vf+>#g!%ifOZW{3tri7`F zXqmY$WXjTeb_ZHXz*jZAvBS;nJ{G#X3im>7>GDNE3SPQssi7<=I&O)Ov}!D+3g&dM zn_<+v14%p10mNF$nF+rBv-IJc8STfr0)(Ti>3u3T5M1C zKtUkOooW4slP$+W`%%HE4Dp;TPH2R~z!Ro36_tUpj&P+o+{ywmaF6jn-@iFuoe6cG9eu3u%N;T7))h`&~gt{&aFvqF=p zXJetU$TkxUNWw;PpX!m^EDy+PO?^s%=dkGPPpKnfGM^0Sw`Mj;U^p?#=*i1Wr9jyPBPg*6 z+I&KDiJXS*)e2S`hD_g_TtwJzDC|IXVDDp=&={bA8tqrhn}SxtZ)zAQs~r!)yydhS zuW#DlEx9{mrN$7b-G9M-NfTpNMtnIKg`3)&6oC+%H_LUklv@%4bN=Yep5iz4}%k%L; z!nl^Rk$HEHV?aC-nb@Tj6_tgm1UCskNdKHOOX_BQ4Xn@wG5Oxf%{7}9@~Zc5b;7*N ztr1n3;ka>JIfySpqp{{gpo43NiQaw?XjzPJ6cwyL9MEtfz4-)ZNbDm>pmj)9(%GN* zhj4dxe00Rgt@SoQEDCuWD76NBNv_yC<-j)~6B2*fk{LW-ylpKb$vzzwL2a0Ky)F=y z3l1kL6Q&pfjxZ1+uJcXXh_r+6uBNGh7VYPx*hftXGC`M&$ES_N+$Pw+<&2gU4K=t| zFZ_>1$@}n{mC^B2?w>6wj|Q~kZBtWrJ7k<{)n2nO8Tm!Ld9x`bmCY_P!-KiU162WjgzT{Bt(bvF;`tTEzZ1PP19K?s#-$hkO;L8F8n$SDHBuRIFJv)2+Jj8MxZ*XhAdw4 z@TlJG8ec{hck|%1n0PE}s)7hfA(`GMZ$ZY5cd0e4vC7KmUgw;?C#VqrQLcoy1Q-`p zKn{8;4^fLT9;p<;`kjMOHR0$5cMHZ2d7!tTmU9wqHULz-L>xjjPEJhmaT4Lo{4ZtH z^mspgx7&zC>=!gar>@aCDA&`1S0_o)l~d#u?xyK>^&KZsM=^7J%>DHARar@;)l%X9 zwG5=WqbUK63CX;k1pgQr>UgIc&0Z@!1-9W}yiWBd7HNJ+-^5k;4-=cBJ}) zinC)Fw7zaY4Al9~Ix$U=Y*2%iLmNpLu_^YMToXg&(9vF}Ug)*vKGskDluFqN&%k*a z(>q+cTOq9b|qAn%`$^tr}uJo z+X%4C1b{f%ZRmZr2cm<;6{BrBP`6mzg-e>1+^mgE^3-(G>v0z9%4JRq22j}C9=Kk$aW8To6Q>q8y?7&(Kv{<(l#9}NiYdB*bt~h8f_xj=Jjp17<03= z?GJ8QdFj++Iy;vg;_Lw66)DY>$@}0`*=<^6LNIe00GGpEo8u*>63abg?8?F$* z%hXGC88%4<)u!wdl0he7(PtaI*1x&X2%Vl$?qw3a+Xr1z<;mIvM&f8bA_U2qg6k;J zt1{|;Cl!qcpr#7LJ8KN zLL%Ws2cNU14v{3Ue44s<#y&;)Ryt@CR5g-d7K_8xYN#>CeN|fPg_Iv$x zP*xHRZ6(`@h(0_xrDc+EIVW-^03o8>as?&Rt5=q#=wfz>vh{{(e-zC$Xg;epsR#w0 z2zZNoCouW}Z2oBnSz)WIzie&ed?LIuk9gPcSAsD*~S*)E1S`^I1Cn6$zBuniy`+$W=xyV{lc?!>t*C)!9 zKzU9{JEuEbR>kcLqV#MtLwsTdpQcQNsP7dKpb%+=1`Qtmy zZp)m|HE1;JO=^wxl1V)Cl;fuzdO5?y~;kfemK z+t1t#gbG6BVAsI~fM)u(y@E&>ON6L^5z>04G{bVk67ap{?i7+4ca}$oHi@JW;WY+_ z4r6;a;%XY52*iQZLkW*QrP(1p^b4VHq7)~JjbyRf#nzTt^IUX58GX1RB>OxJLoWtT zhciLXXj_1LHT)md{I48M19#_SdD)uYjAxgl`Rz zCwda>a%u`?1M2CuH-zmh^akNZ6oVK!SIgW#wn82Yp{9nvvJq<~;cG5ge|{;vn1+1z z7-`b*@?xja+#fN66M7^M43JU#+<)OZZhQy@==7-Nc5ScLQ?5vD17s=bp#s`Uc%}FV zewCAE31w3+00eaE{;d zi-&@EgP^v4M|bt<@vG%31$q0?1${hSV5zphrZdfBW~NBglxaL+(r`Djpo4hp3Prbo z)2Qu7#~x2LL!j(H)GGzBI@yT&9?A}NgTuQ;ssz$V8%pC`+fHxJo9XXMx5>Ub;3?w- zXSsKft-9mTEJwH&19}RVTa1d}uIl#ob21Zx%_=0(n{=@R&%_iNzGMh~iGYF(C$HZ- z5kJ>~GwH{xi#Kt*pC#O3iVKGa}spsB& zbg1}tP=~5QZiM%$cG47TKUjuKQjo;XQ9yTQ_@tR$FH#^!*?+MaiimPrfrDMzuzkgf zovBA=)Y8xDRWtXm*>`seWIFGulYm5!1|;_w>2Eq+9}^oo{F4x8im~?YK->?f$U6M; z&Ea^uIsmIqyA;rS=U3OF!qGaN@75S{TKflb!V1C@=Eo#zbU z0AXSUP#EENaxsY8fR5#(JS|8EKwYKTIi#3+2xufwh@G%LtTTaGHv}jMInun)=`jNuNGz6OrgEn^Wm_XrL_ za$vUWcmoH>a!`>&N=fo$>~IlJc`IEq{<(>!90t=Jkx6@35eMiLOFGR1&kmYJH>lYf zvSa*NZp}UQ?7f&ZrO|g9nof3SFSOKCQS|b0#@XQ-Siredsh23qYv`xDtmWa*G&O`{ z&f|7__)S3HO;il$)|z$aDJ%BQm*?k~Z#O}T=JR@cQAdZx0L=q=@P|IHiJh7eo?d2k znXqKP^zsfFA!eMkLEFcUK$wF)`LLjjG(aCxmT^xy1Q47rIu&?_se=KnjKy8RIHJLo zg*lB`$MHufQxPDZI@>25ey1Eu`6F1MouiZ>P^8Zt9}o;9jV!r=&Oa81kaRoACy?cl zqzYMwr3CLv#lKZ9$r4wboJt$NlMN1Wf1M*2`Roi_s0Uff+fVXt?J^U(LNvhjz#ViJ zIb$GsWyFgTh@b)MAm>&4N;NuN2O#w@6<4arz?-Hgw#rh7{G*C=0KSx3-)ixOJ_l0Qw_f(SBmikfF+|ov7l5% z4pl)(BAb*uYALCbZe@FoQbwH)`$?XZMG3VXb>p~_ zYUw#>{BATYW_U(@W1Ym@%0>}S0fOyS3D^=DQ)jdFz#Tk=P1QnGQtw$v@q4kFd12-3 ztC-RKkviA@HuNlqloUP#H`JJ+3ZgiA5`b$YI5xJp68Af(gLGZ*L-AuoyMr6cM>-x_!U8x6ta z9(@8$VPWpEOfuCf_^3KQ0m4K!q8%$)jNV@65ei8^|y)aKsU^}4^P zWkpqm1xrSN6kzfXPS0R{S5k1jf~V(KH$}cx*231{tNP>-0T$a-jpkOttATlzqPm39 zJ)St$HtBr?dVvD5H?@jYE5?VNtxC!1r`A-x&Vk0+AV;nKbVhLcfAZsWMe#Laktk6B zYjh7Cz#2*iq66{_j7$knY?{L#FHvU|!J9*&``bRZjLY&mk_I`6HiV}Z^F4u5e~*+W zHrdHR+gD<$5wmg6Ibk`H%o@KW<{9h;9hjOz2vka=&gWd}fg2kEY_<_}IuIwE<3IyP zl59mrq|N3KY2TAz6Pked!}yLCzlC4M>I=mlAL57=B1NdOf>T$u2 zLUGH4EHr&ph^kuirG3xfRE)+jJk;?%s#;lk5l)_rGRAUnL+)7jOKw9dwXQ^ZMXpc= z;Q|L`jv#?t^aW@sF`c*UakHRkiuBr7m}6g`9NnD0T@JukCqcGF!u-Y4B8DYT@I)b4 z5v!(Ij60W%UW(p+K+Gwu_E=L9Jws>hbbCBgKBTCkzYiC}cjs}?g!0Wm(7?`-oMkR9 zh~JDY@E|J(8_*%gO16DZ)`Fx*FeyZ{G$trw$XY^J^b+}nUb?$*(s>;E#`0X%h+Xb9 z7U}N_{Mf)wP_unGoT}r%%Vm3)O<#lTM)i$|GljjJ35{Li+GVS~_N;fi-T#xagsP7W zS*CaE0?5Oh0+Q%>Q#EG>*Ar^MkspgDB>EU`!#05s%o_VCM3po|6Mtbzmt- zpJPW<4ruk>915eg|6$Bx2mv!KsjQibg3Mff+Dm+tsqxmmaF-g$K#P6j8=$B3c9O?T zZxd(d(9pnbS(9DLTh)cT&R({Z6=iYPX^*oPHj6IC?siOew=5Q2M92!sleY_rgu~Bq zh(O$l=>mh~&ICK&}y^fc7hM5nE zPL$eH=`ZsVP22a(L<@BT4n@RJfCSSYG=9y1ag2%co}zWy)l!RkCD+A?ha}(>W+n$L zPMZpG0PKUstcSloZ90e1)XZKydr5D*9D!&4E*aMJvY0G2H;M`k77;ZdY{?^1TZq;g z)`FOZF57p#CXi=;xyR@`ySicCD7R|1+AQCyrWMU=&T*S8_ z@c>y6*)hsia=O2TsW;mw73fK-KRQ{o7sNHUC}A8KC>G!m`Clj(b|h%VxSwb>wPyAf zUtN5SUb|4Hyb0st@#Dq*olXq~L8x}>E-q5dH59M1wXyKS|=4<97z5gy|IQ5;Zuy;f_h_3 z$N`91^qVjP1gp;BPXQrY%@L(ZjugnSvma&dSpU9rmTBJ$G`M5T zx3HYBp5m9pR8|5Cq9_wu;cm4At2S=WPswH1dw#o*@}tw^<>k=cYd>QM=veVUgG|%Y z2m#(Yl?>*C0IPVBmF2$o6c&FRP5&d3{-e^1dHSNIs3&690H=@~jGWWMUA*0gmNf|C zJcqJm3%->+tNl<4bOG8uTe9OQQ#Ktj!Iq_nPL=FBJc=G+Unj%DjGuv1Ic6D@3L>kr z!w$DjgtE+l=`7F~SjlQ(_Tnw28=Ds;Sq2|E7addxO;UviGx2hIX>Bezvme~mThr%} z34@Uxp*9`54N_NvK=P>wZ8J?5K3dj9@Q2$xW?iz=D(IV7mITM1fq~+bGSbx|!ayg4 zF(0JaA{03>IHQ#I?^-zQhtw!c?l>-z2~MBMv1foV_QadA zcX{SiPF3$=ZHh- z`d;3DlAN9cHykO8QM$+P*SIdAf`G4j=@UpxQL@FoJ4O z3e6X91-4~uTFXPNc?CT|l8>nE2WP7GdYCE5_xVxKQ{k%7{iMUjXP!3@G>RtK)`$L0 z=Y9^%jl#OURG-LWCI>>hAq8;=!y{y-xv{9+8rPAH(d9$kj&DhGtRn&&$1A60OV&LA z6guNFP71nxlGH83Qf6zpS2N9k?%<_e)9=QlwYgiFSE|z$rm$&q3L#I7fS5~#`O*#* z3OpV&nlHIq6=!^W30Ay52#`}Pg}xxvIUUG-(@ouQ8=88e?VV+sQN}{ja^n=~eacwj z#2IFkiBbxKV7Evx&83IdoPm;LT+SS*5K>n-i2|1934;SAJXeQKOVlEuY-S>l@&Juw ztc|VeL$cn{@zAgnc4F9_r@3IQaC$Log>|;NFhI4C(}*A^g_E(h&MK$j$Ly{26jX4T zNqg|R=c7nB(M5T#D1i=q~q*IYTASGnSpzExz za%Y^|dhb{S5c^ETk+t&We9+n7h$xmiz#jO`&K&%mu{DuP+D1o@iYg-Gx$1H)y+~m! zo*C^U6LG96AdOxZ;f>26ebl{1{fjbC#w`cdKyF`Ywo>?J`v*>66c5iHy@nAB*Mof) zK!6FIdtJTul`(saI}cHpqeb>9e;DcH z8I&U+L6<@FgZZm5d473OdD@Ijo0ZDMM}1+}hdvqYziKWtO$$%9&N5JLo@Lj*lH7zL zf&UL}1u0RCXkeIvC~?7W2&J4(RNh};+i%knG~0)G066BzmYQhb#9)%31VhOfURsFc zn><~!ktHQ+H>04ZT|G-++Kc@do1~~R>4C+~%s^G(&>djI!O?g{k&8uR(%hi)g)5!7d5gXs;Hcv`&8d&=D9 zDzSdW#5KDnLOAs?lqeG_J?M-J0~@!mwEqO;m`^G1ggP)-W+-WB67HDIkrB=m44ncZ zf+3FU{J`QY5r++Kr*U7jXVU-!3WZP9`JB>aa5g?^=E~`4uq@DG3FY32lX(dIM?&A- zEAY#=17E^vke)*>v&a-|SZ7)__+v063NVxf3;*F@8;DE@8JP13OH|rBSsfi*Y%+42 zdyV75k1U2lcnFwCCus)Sx4}omycj9SYCftQdaG_U8(5o9?g%|Q&PnE^rjQ4(bfghE zp!R?P1XVtc${Dm3UoFeBu-~s3ElyDtg%xINR9o+d(g+?)EB{{pUjDhZG0WcvH}x_9 zEL8nwulD2{a;QiP02JxXpu_kyj$A?(z??{}RUNm0-a^X}O@yxuekiF&^+~+kw6#cJv!F~`Qz)4)mZfKKjyAp8JNY_8g*FhXX1&Em(C&mYEJX$w zyDo>l$+HgIo0boEDZ+`CL_5j|3*4Vy@5&i878v0N0EPciJACGT`uI@xIw*NPA&8{*SIWUsYgm zD+ir&mS>&z7J{4RncjmQKav5MRS|;0=kB3+xql8{Abw}zsss2($OL3Kai4VRDQWm4 z;eJQc5Nks~ZHEO~43wQGII~b;I!9Vk{agxZSeuCrl11wMqt4l?PGdQuS0~&ceIS5^ zE~oH`dq(QELnlVg^C=AKwrxM~@^5C#9jvOYX!{&dZI~C~5(xW%;0y(g!FrhL+7mjT z$U+gnB%N5^a5z34CL%5F-|6C|a`(HkXI;8r{Z0xM2wFUbwc3Zo!wDyXnzuMS%$%xq z0?Mc_Yc>wk4lI6XHAaj{L)bpXW#T@EvlvTK)VZwNdzH zLHiNy1wZZUqNZN{Z1=FL!x!KG!A=X(my4Ho7ccKEo^sCk^22IqKLoQnbE7oDjKG4_ zzGw7|jVi%p2|_xVNi%%g7)WaQOTP8irBu?l9x!8hqnh}r!Ykm-_#@uvh|@9?l_oGM zy>#Dg?+^DWtzIM^1S_4c*wx^k5Z%kULQ;~WXh7kJ?%grD^M*I%ofSuh^7Zxjr_&4S zk*mEs7nsa<2o&z%G%FNu-p#&s_~!KN_&cY^!?(&`YGm&}A%py!Bgi zL2eFDy>9t>adJ)fx_Eu;_l{Pn*#yng)pn_EBsr?&q7 zZ0q&^dU*Z#^@FXS-+uj%{rms?#V;<$>;J>y_2bvy8eacrhOgV#f8hJS;{V3i?~QLT ze0}|w>kIQ4bMMC2|62X_-l?y7%klNE|7!h*@#`P`x#0(gFWdM3XTJZ7+4X<+H|h_L zU;p0lg7Nyt_Zh$bjvxO&v)BLr->k16zkYXkeXc(rX}tdWQ+s>=aQOcC`~KSp^`tkGs%9FcmMqOllANHIQPb{|J=9dumAbKs6RJ;9j|x% zE#u$EuYa)h`ac+6KYslO|2B7i{onY$<9GgzKg{3%!Abqiwo(n)z^<-Up^Rr zvVPsZ{y*A!{m=h>ef{|L<6q6)S^u~F{{PiK1|5yGSUpIXHVEFd#w+=Y?1NxAB?XX zzHYtUw139e|241AXBuDs-Qji9*R31y!FVCV*WdKw?7i{zzx%gy8t(0lUq2Xb?6``@ z_Z_e6U;5ek`~Up6>g&g^-~8$F>!$x1Uq62R&erws-L0=5zy4%;W&OhkTYul*di_s^ z*N_{V={YmC=Fey;46@!IFFzxutuQ2zR_{`=-{AK!QU*}t;m S^}qf*_27Q7^@6Rx?)_gsO#@B< diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/gpu_cache_bench.cu b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/gpu_cache_bench.cu deleted file mode 100644 index 45015f77d..000000000 --- a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/gpu_cache_bench.cu +++ /dev/null @@ -1,124 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -// Simple error macro -#define CHECK(call) \ - do { \ - cudaError_t e = (call); \ - if (e != cudaSuccess) { \ - fprintf(stderr, "CUDA error: %s (%d)\n", \ - cudaGetErrorString(e), (int)e); \ - exit(1); \ - } \ - } while (0) - -// Kernel: pointer chasing with an accumulator "sink" to prevent optimization -__global__ void pointer_chase(const int* next, - int start, - int iters, - unsigned long long* cycles_out, - int* sink_out) { - int cur = start; - int acc = 0; - - // Optional warmup - int warmup_iters = min(iters, 1024); - for (int i = 0; i < warmup_iters; ++i) { - cur = next[cur]; - acc += cur; - } - - unsigned long long t0 = clock64(); - for (int i = 0; i < iters; ++i) { - cur = next[cur]; - acc += cur; - } - unsigned long long t1 = clock64(); - - if (threadIdx.x == 0 && blockIdx.x == 0) { - cycles_out[0] = t1 - t0; - sink_out[0] = acc; // observable side effect - } -} - -int main(int argc, char** argv) { - if (argc < 4) { - fprintf(stderr, - "Usage: %s \n", - argv[0]); - return 1; - } - - size_t ws_bytes = std::strtoull(argv[1], nullptr, 10); - std::string pattern = argv[2]; // "sequential", "stride_4", "random" - int iters = std::atoi(argv[3]); - - size_t n = ws_bytes / sizeof(int); - if (n == 0) n = 1; - - // Build index array on host - std::vector h_next(n); - - if (pattern == "sequential") { - for (size_t i = 0; i < n; ++i) - h_next[i] = (int)((i + 1) % n); - } else if (pattern.rfind("stride_", 0) == 0) { - int stride = std::stoi(pattern.substr(std::string("stride_").size())); - for (size_t i = 0; i < n; ++i) - h_next[i] = (int)((i + stride) % n); - } else if (pattern == "random") { - std::vector perm(n); - for (size_t i = 0; i < n; ++i) perm[i] = (int)i; - std::mt19937 rng(42); - std::shuffle(perm.begin(), perm.end(), rng); - for (size_t i = 0; i < n; ++i) - h_next[perm[i]] = perm[(i + 1) % n]; - } else { - fprintf(stderr, "Unknown pattern '%s'\n", pattern.c_str()); - return 1; - } - - int* d_next = nullptr; - unsigned long long* d_cycles = nullptr; - int* d_sink = nullptr; - - CHECK(cudaMalloc(&d_next, n * sizeof(int))); - CHECK(cudaMalloc(&d_cycles, sizeof(unsigned long long))); - CHECK(cudaMalloc(&d_sink, sizeof(int))); - - CHECK(cudaMemcpy(d_next, h_next.data(), n * sizeof(int), - cudaMemcpyHostToDevice)); - - dim3 grid(1), block(1); - pointer_chase<<>>(d_next, 0, iters, d_cycles, d_sink); - CHECK(cudaDeviceSynchronize()); - - unsigned long long cycles = 0; - int sink_val = 0; - - CHECK(cudaMemcpy(&cycles, d_cycles, sizeof(unsigned long long), - cudaMemcpyDeviceToHost)); - CHECK(cudaMemcpy(&sink_val, d_sink, sizeof(int), - cudaMemcpyDeviceToHost)); - - cudaFree(d_next); - cudaFree(d_cycles); - cudaFree(d_sink); - cudaDeviceReset(); - - double avg_cycles = (iters > 0) ? (double)cycles / (double)iters : 0.0; - - // Print JSON - printf("{\"working_set_bytes\": %zu, \"pattern\": \"%s\", " - "\"iterations\": %d, \"total_cycles\": %llu, " - "\"avg_cycles\": %.3f, \"sink\": %d}\n", - ws_bytes, pattern.c_str(), iters, - (unsigned long long)cycles, avg_cycles, sink_val); - - return 0; -} diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/handler.py b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/handler.py deleted file mode 100644 index 94c9400d7..000000000 --- a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/handler.py +++ /dev/null @@ -1,31 +0,0 @@ -# benchmarks/gpu_cache_latency/handler.py - -import json -import subprocess - -def handler(event, context=None): - working_set_kb = int(event["working_set_kb"]) - pattern = event["pattern"] - iterations = int(event["iterations"]) - - ws_bytes = working_set_kb * 1024 - - result = subprocess.check_output( - [ - "./gpu_cache_bench", - str(ws_bytes), - pattern, - str(iterations), - ], - text=True, - ) - - metrics = json.loads(result) - metrics.update( - { - "working_set_kb": working_set_kb, - "pattern": pattern, - "iterations": iterations, - } - ) - return metrics diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/input.py b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/input.py new file mode 100644 index 000000000..dcbe70729 --- /dev/null +++ b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/input.py @@ -0,0 +1,30 @@ +# benchmarks/000.microbenchmarks/050.gpu-cache-latency/input.py + +# You can tune these as you like later +size_generators = { + "test": {"working_set_bytes": 1 << 16, "iterations": 10_000}, + "small": {"working_set_bytes": 1 << 20, "iterations": 100_000}, + "large": {"working_set_bytes": 1 << 24, "iterations": 1_000_000}, +} + +def generate_input( + data_dir, # path to benchmark data dir (unused here) + size, # "test" | "small" | "large" + benchmarks_bucket, # storage bucket (unused locally) + input_paths, # list of input paths (unused here) + output_paths, # list of output paths (unused here) + upload_func, # function to upload data (unused here) + nosql_func # function to access NoSQL (unused here) +): + """ + SeBS calls this to get the JSON-like dict that becomes event['input'] + for the function. + """ + cfg = size_generators[size] + + return { + "working_set_bytes": cfg["working_set_bytes"], + "pattern": "random", # or "sequential", "stride_4", etc. + "iterations": cfg["iterations"], + "seed": 42 + } diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/function.py b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/function.py new file mode 100644 index 000000000..369644a99 --- /dev/null +++ b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/function.py @@ -0,0 +1,115 @@ +# benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/function.py + +import time +import math +import torch + + +def build_next_indices(n: int, pattern: str, device: torch.device, seed: int = 42): + """ + Build the 'next' array with the given pattern, similar to your C++ version. + """ + if n <= 0: + n = 1 + + idx = torch.empty(n, dtype=torch.long) + + if pattern == "sequential": + idx = (torch.arange(n, dtype=torch.long) + 1) % n + elif pattern.startswith("stride_"): + stride = int(pattern.split("_", 1)[1]) + idx = (torch.arange(n, dtype=torch.long) + stride) % n + elif pattern == "random": + # deterministic permutation + g = torch.Generator() + g.manual_seed(seed) + perm = torch.randperm(n, generator=g) + idx[perm] = perm.roll(-1) + else: + raise ValueError(f"Unknown pattern '{pattern}'") + + return idx.to(device) + + +def pointer_chase(working_set_bytes: int, pattern: str, iterations: int, seed: int = 42): + """ + Pointer-chase microbenchmark, implemented in PyTorch. + Uses GPU if available; otherwise falls back to CPU. + """ + + # Number of ints in the working set + n = max(1, working_set_bytes // 4) + + device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + + next_idx = build_next_indices(n, pattern, device, seed=seed) + + cur = torch.tensor(0, dtype=torch.long, device=device) + acc = torch.tensor(0, dtype=torch.long, device=device) + + # Warmup (like your C++ version) + warmup_iters = min(iterations, 1024) + for _ in range(warmup_iters): + cur = next_idx[cur] + acc = acc + cur + + # Measure time + if device.type == "cuda": + torch.cuda.synchronize() + start_event = torch.cuda.Event(enable_timing=True) + end_event = torch.cuda.Event(enable_timing=True) + + start_event.record() + for _ in range(iterations): + cur = next_idx[cur] + acc = acc + cur + end_event.record() + torch.cuda.synchronize() + + elapsed_ms = start_event.elapsed_time(end_event) # ms + total_seconds = elapsed_ms / 1000.0 + else: + start_time = time.perf_counter() + for _ in range(iterations): + cur = next_idx[cur] + acc = acc + cur + total_seconds = time.perf_counter() - start_time + + avg_ns = (total_seconds * 1e9 / iterations) if iterations > 0 else 0.0 + + return { + "working_set_bytes": int(working_set_bytes), + "pattern": pattern, + "iterations": int(iterations), + "device": str(device), + "total_seconds": total_seconds, + "avg_ns_per_step": avg_ns, + "sink": int(acc.item()), + } + + +def handler(event, context=None): + """ + Entry point for SeBS. + + For Python benchmarks, SeBS passes: + event = { + "input": { ...whatever generate_input returned... }, + ... + } + We must return: { "result": } + """ + + params = event.get("input", {}) + + working_set_bytes = int(params.get("working_set_bytes", 1 << 20)) + pattern = params.get("pattern", "random") + iterations = int(params.get("iterations", 100_000)) + seed = int(params.get("seed", 42)) + + result = pointer_chase(working_set_bytes, pattern, iterations, seed=seed) + + # SeBS expects this shape + return { + "result": result + } diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/requirements.txt b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/requirements.txt new file mode 100644 index 000000000..f9b2aa91e --- /dev/null +++ b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/requirements.txt @@ -0,0 +1,2 @@ +torch +numpy \ No newline at end of file diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/read.me b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/read.me deleted file mode 100644 index af17c1c31..000000000 --- a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/read.me +++ /dev/null @@ -1,118 +0,0 @@ -# 📘 Benchmark: GPU Cache Latency (050.gpu-cache-latency) - -This benchmark measures **GPU memory access latency** as a function of: - -- **Working-set size** (bytes) -- **Access pattern** (`sequential`, `stride_k`, `random`) -- **Iteration count** - -It uses a CUDA kernel (`gpu_cache_bench`) to perform pointer-chasing and -reports: - total cycles - average cycles per access - sink value -(anti-optimization) - all returned as JSON - -The benchmark is integrated with **SeBS** and can be run as a **local -serverless workload** inside a GPU-enabled Docker container. - - -To run this benchmark WITH GPU support, you need a local Linux machine -with: - -### System - -- **NVIDIA GPU** -- **CUDA drivers installed** -- **Docker installed** -- **NVIDIA Container Toolkit installed** - -Check GPU + Docker availability: - -``` bash -nvidia-smi -docker run --gpus all nvidia/cuda:12.3.0-base nvidia-smi -``` - - -# Step 1 --- Build the CUDA binary (optional) - -``` bash -cd benchmarks/000.microbenchmarks/050.gpu-cache-latency - -nvcc gpu_cache_bench.cu -O3 -std=c++14 -gencode arch=compute_61,code=sm_61 -gencode arch=compute_61,code=compute_61 -o gpu_cache_bench -``` - - -# Step 2 --- Build the Docker image - -``` bash -cd - -docker build -t gpu-cache-latency benchmarks/000.microbenchmarks/050.gpu-cache-latency -``` - -Test: - -``` bash -docker run --gpus all gpu-cache-latency ./gpu_cache_bench 65536 sequential 1000000 -``` - - -# Step 3 --- Install SeBS - -``` bash -./install.py --local -source python-venv/bin/activate -``` - - -# Step 4 --- Deploy via SeBS - -``` bash -python3 sebs.py benchmark deploy 050.gpu-cache-latency local -``` - - -# ▶ Step 5 --- Run via SeBS - -``` bash -python3 sebs.py benchmark invoke 050.gpu-cache-latency local --dataset tiny -``` - -Example output: - -``` json -{ - "working_set_bytes": 65536, - "pattern": "sequential", - "iterations": 1000000, - "total_cycles": 46387045, - "avg_cycles": 46.387, - "sink": -401872096 -} -``` - - - -# Step 6 --- Run standalone sweep - -``` bash -cd benchmarks/000.microbenchmarks/050.gpu-cache-latency -python3 run_sweep.py -``` - -Outputs `cache_latency_results.csv`. - - -# Workflow Summary - -``` bash -./install.py --local -source python-venv/bin/activate -python3 sebs.py benchmark deploy 050.gpu-cache-latency local -python3 sebs.py benchmark invoke 050.gpu-cache-latency local --dataset tiny -``` - -Or run directly: - -``` bash -./gpu_cache_bench 65536 sequential 1000000 -``` diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/run_sweep.py b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/run_sweep.py deleted file mode 100644 index 48d42bff3..000000000 --- a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/run_sweep.py +++ /dev/null @@ -1,40 +0,0 @@ -import json -import subprocess -import csv - -BINARY = "./gpu_cache_bench" - -working_sets = [ - 8 * 1024, - 32 * 1024, - 64 * 1024, - 256 * 1024, - 1 * 1024 * 1024, - 4 * 1024 * 1024, - 16 * 1024 * 1024, -] -patterns = ["sequential", "stride_4", "random"] -iters = 1_000_000 - -with open("cache_latency_results.csv", "w", newline="") as f: - writer = csv.writer(f) - writer.writerow(["working_set_bytes", "pattern", "iterations", - "total_cycles", "avg_cycles", "sink"]) - for ws in working_sets: - for pattern in patterns: - print(f"WS={ws} bytes, pattern={pattern} ...", flush=True) - out = subprocess.check_output( - [BINARY, str(ws), pattern, str(iters)], - text=True, - ) - data = json.loads(out) - writer.writerow( - [ - data["working_set_bytes"], - data["pattern"], - data["iterations"], - data["total_cycles"], - data["avg_cycles"], - data["sink"], - ] - ) From a1caa5a0c49f63c8329ee812fde60deead80b85e Mon Sep 17 00:00:00 2001 From: JessieeeLoki Date: Sat, 22 Nov 2025 16:46:38 +0100 Subject: [PATCH 55/58] removed unnecesary commits --- benchmarks/read.me | 118 ----------------------------------------- requirements.local.txt | 2 - 2 files changed, 120 deletions(-) delete mode 100644 benchmarks/read.me delete mode 100644 requirements.local.txt diff --git a/benchmarks/read.me b/benchmarks/read.me deleted file mode 100644 index af17c1c31..000000000 --- a/benchmarks/read.me +++ /dev/null @@ -1,118 +0,0 @@ -# 📘 Benchmark: GPU Cache Latency (050.gpu-cache-latency) - -This benchmark measures **GPU memory access latency** as a function of: - -- **Working-set size** (bytes) -- **Access pattern** (`sequential`, `stride_k`, `random`) -- **Iteration count** - -It uses a CUDA kernel (`gpu_cache_bench`) to perform pointer-chasing and -reports: - total cycles - average cycles per access - sink value -(anti-optimization) - all returned as JSON - -The benchmark is integrated with **SeBS** and can be run as a **local -serverless workload** inside a GPU-enabled Docker container. - - -To run this benchmark WITH GPU support, you need a local Linux machine -with: - -### System - -- **NVIDIA GPU** -- **CUDA drivers installed** -- **Docker installed** -- **NVIDIA Container Toolkit installed** - -Check GPU + Docker availability: - -``` bash -nvidia-smi -docker run --gpus all nvidia/cuda:12.3.0-base nvidia-smi -``` - - -# Step 1 --- Build the CUDA binary (optional) - -``` bash -cd benchmarks/000.microbenchmarks/050.gpu-cache-latency - -nvcc gpu_cache_bench.cu -O3 -std=c++14 -gencode arch=compute_61,code=sm_61 -gencode arch=compute_61,code=compute_61 -o gpu_cache_bench -``` - - -# Step 2 --- Build the Docker image - -``` bash -cd - -docker build -t gpu-cache-latency benchmarks/000.microbenchmarks/050.gpu-cache-latency -``` - -Test: - -``` bash -docker run --gpus all gpu-cache-latency ./gpu_cache_bench 65536 sequential 1000000 -``` - - -# Step 3 --- Install SeBS - -``` bash -./install.py --local -source python-venv/bin/activate -``` - - -# Step 4 --- Deploy via SeBS - -``` bash -python3 sebs.py benchmark deploy 050.gpu-cache-latency local -``` - - -# ▶ Step 5 --- Run via SeBS - -``` bash -python3 sebs.py benchmark invoke 050.gpu-cache-latency local --dataset tiny -``` - -Example output: - -``` json -{ - "working_set_bytes": 65536, - "pattern": "sequential", - "iterations": 1000000, - "total_cycles": 46387045, - "avg_cycles": 46.387, - "sink": -401872096 -} -``` - - - -# Step 6 --- Run standalone sweep - -``` bash -cd benchmarks/000.microbenchmarks/050.gpu-cache-latency -python3 run_sweep.py -``` - -Outputs `cache_latency_results.csv`. - - -# Workflow Summary - -``` bash -./install.py --local -source python-venv/bin/activate -python3 sebs.py benchmark deploy 050.gpu-cache-latency local -python3 sebs.py benchmark invoke 050.gpu-cache-latency local --dataset tiny -``` - -Or run directly: - -``` bash -./gpu_cache_bench 65536 sequential 1000000 -``` diff --git a/requirements.local.txt b/requirements.local.txt deleted file mode 100644 index bb007e6d3..000000000 --- a/requirements.local.txt +++ /dev/null @@ -1,2 +0,0 @@ -minio==5.0.10 -black>=24.4.0 From 38e00229ce835ebc0fe19a0d0db73697520c8ac6 Mon Sep 17 00:00:00 2001 From: JessieeeLoki Date: Tue, 25 Nov 2025 21:19:50 +0100 Subject: [PATCH 56/58] added wrap divergence --- .../060.wrap-divergence/config.json | 6 + .../060.wrap-divergence/input.py | 56 +++++++++ .../060.wrap-divergence/python/function.py | 113 ++++++++++++++++++ .../python/requirements.txt | 1 + 4 files changed, 176 insertions(+) create mode 100644 benchmarks/000.microbenchmarks/060.wrap-divergence/config.json create mode 100644 benchmarks/000.microbenchmarks/060.wrap-divergence/input.py create mode 100644 benchmarks/000.microbenchmarks/060.wrap-divergence/python/function.py create mode 100644 benchmarks/000.microbenchmarks/060.wrap-divergence/python/requirements.txt diff --git a/benchmarks/000.microbenchmarks/060.wrap-divergence/config.json b/benchmarks/000.microbenchmarks/060.wrap-divergence/config.json new file mode 100644 index 000000000..93ce2f561 --- /dev/null +++ b/benchmarks/000.microbenchmarks/060.wrap-divergence/config.json @@ -0,0 +1,6 @@ +{ + "timeout": 120, + "memory": 128, + "languages": ["python", "nodejs"], + "modules": [] +} diff --git a/benchmarks/000.microbenchmarks/060.wrap-divergence/input.py b/benchmarks/000.microbenchmarks/060.wrap-divergence/input.py new file mode 100644 index 000000000..2e90b8c5e --- /dev/null +++ b/benchmarks/000.microbenchmarks/060.wrap-divergence/input.py @@ -0,0 +1,56 @@ +import os +import json +from typing import Tuple + + +def buckets_count() -> Tuple[int, int]: + """ + One input bucket, one output bucket. + """ + return (1, 1) + + +def generate_input( + data_dir, + size, + benchmarks_bucket, + input_paths, + output_paths, + upload_func, + nosql_func, +): + """ + Generate a JSON config for the warp-divergence microbenchmark + and upload it to the input bucket. + + The JSON is what will be passed as `event` to function.handler(). + """ + if size == "test": + num_warps = 512 + iters = 500 + elif size == "small": + num_warps = 2048 + iters = 1000 + else: # "large" + num_warps = 8192 + iters = 2000 + + active_lanes = [0, 4, 8, 16, 24, 32] + + config = { + "num_warps": num_warps, + "iters": iters, + "active_lanes": active_lanes, + } + + os.makedirs(data_dir, exist_ok=True) + local_path = os.path.join(data_dir, f"warp_div_config_{size}.json") + with open(local_path, "w") as f: + json.dump(config, f) + + key = f"{input_paths[0].rstrip('/')}/warp_div_config_{size}.json" + upload_func(0, key, local_path) + + # Return the config directly so runtimes that already have the payload + # don't need to fetch it back from storage. + return {"config": config} diff --git a/benchmarks/000.microbenchmarks/060.wrap-divergence/python/function.py b/benchmarks/000.microbenchmarks/060.wrap-divergence/python/function.py new file mode 100644 index 000000000..68b3e623b --- /dev/null +++ b/benchmarks/000.microbenchmarks/060.wrap-divergence/python/function.py @@ -0,0 +1,113 @@ +import json +import time +from typing import List, Dict, Any + +import torch + + +def heavy_work(x: torch.Tensor, iters: int) -> torch.Tensor: + """ + Simple compute-heavy loop: about 2 FLOPs per element per iteration. + """ + for _ in range(iters): + x = x * 1.000001 + 1.0 + return x + + +def run_one_case( + num_warps: int, + iters: int, + active_lanes: int, + device: torch.device, +) -> float: + """ + Run one configuration with a given number of active lanes per 'warp'. + Returns elapsed time in milliseconds. + """ + warp_size = 32 + n = num_warps * warp_size + + # lane_id: 0..31 repeated for each warp + lane_ids = torch.arange(warp_size, device=device).repeat(num_warps) + + # Boolean mask for "active" lanes + mask = lane_ids < active_lanes + + # Data tensor + x = torch.ones(n, device=device) + + if device.type == "cuda": + torch.cuda.synchronize() + t0 = time.perf_counter() + + # Only active lanes do heavy work; inactive lanes do almost nothing + x_active = x[mask] + if active_lanes > 0: + x_active = heavy_work(x_active, iters) + x[mask] = x_active + + if device.type == "cuda": + torch.cuda.synchronize() + t1 = time.perf_counter() + + # Prevent optimization away + _ = x.sum().item() + + return (t1 - t0) * 1e3 # ms + + +def run_benchmark(config: Dict[str, Any]) -> Dict[str, Any]: + """ + Core benchmark logic used by handler(). + """ + num_warps = int(config["num_warps"]) + iters = int(config["iters"]) + active_lanes_list: List[int] = [int(x) for x in config["active_lanes"]] + + device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + + results = [] + for active_lanes in active_lanes_list: + time_ms = run_one_case(num_warps, iters, active_lanes, device) + + # Useful FLOPs: only active lanes count + active_threads = num_warps * active_lanes + flops = 2.0 * iters * active_threads # 2 FLOPs per iter + gflops = flops / (time_ms * 1e6) if time_ms > 0 else 0.0 + + results.append( + { + "active_lanes": active_lanes, + "time_ms": time_ms, + "gflops_effective": gflops, + } + ) + + return { + "num_warps": num_warps, + "iters": iters, + "device": str(device), + "results": results, + } + + +def handler(event, context=None): + """ + Entry point used by SeBS local backend for Python. + + The event is the JSON config uploaded by input.py: + { + "num_warps": ..., + "iters": ..., + "active_lanes": [...] + } + """ + if isinstance(event, str): + event = json.loads(event) + + if isinstance(event, dict) and "config" in event and isinstance(event["config"], dict): + config = event["config"] + else: + config = event + + return run_benchmark(config) diff --git a/benchmarks/000.microbenchmarks/060.wrap-divergence/python/requirements.txt b/benchmarks/000.microbenchmarks/060.wrap-divergence/python/requirements.txt new file mode 100644 index 000000000..320f98057 --- /dev/null +++ b/benchmarks/000.microbenchmarks/060.wrap-divergence/python/requirements.txt @@ -0,0 +1 @@ +torch>=2.0 From 947eddd8928046ad05dc7379d5dadaeabfd0ef9e Mon Sep 17 00:00:00 2001 From: JessieeeLoki Date: Mon, 15 Dec 2025 15:40:16 +0100 Subject: [PATCH 57/58] update black --- .pre-commit-config.yaml | 2 +- .../050.gpu-cache-latency/config.json | 10 +- .../050.gpu-cache-latency/input.py | 54 +-- .../050.gpu-cache-latency/python/function.py | 338 ++++++++++++++---- .../python/requirements.txt | 2 +- .../060.wrap-divergence/config.json | 6 - .../060.wrap-divergence/input.py | 56 --- .../060.wrap-divergence/python/function.py | 113 ------ .../python/requirements.txt | 1 - requirements.txt | 2 +- 10 files changed, 308 insertions(+), 276 deletions(-) delete mode 100644 benchmarks/000.microbenchmarks/060.wrap-divergence/config.json delete mode 100644 benchmarks/000.microbenchmarks/060.wrap-divergence/input.py delete mode 100644 benchmarks/000.microbenchmarks/060.wrap-divergence/python/function.py delete mode 100644 benchmarks/000.microbenchmarks/060.wrap-divergence/python/requirements.txt diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 58f8adb8d..bb0519cd2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: - id: black-check-local name: black --check (project env) language: python - additional_dependencies: ["black==22.8.0"] + additional_dependencies: ["black==24.4.2"] entry: black args: ["--config=.black.toml", "--check", "--diff"] types: [python] diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/config.json b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/config.json index 0ec4c3353..4fafbe712 100644 --- a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/config.json +++ b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/config.json @@ -1,12 +1,6 @@ { - "timeout": 300, + "timeout": 60, "memory": 1024, "languages": ["python"], - "modules": [], - "name": "050.gpu-cache-latency", - "runtime": "python3", - "handler": "python/function.handler", - "dockerfile": "Dockerfile", - "data_dir": "../../benchmarks-data/050.gpu-cache-latency", - "datasets": ["tiny", "small", "large"] + "modules": [] } diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/input.py b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/input.py index dcbe70729..87a251370 100644 --- a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/input.py +++ b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/input.py @@ -1,30 +1,44 @@ # benchmarks/000.microbenchmarks/050.gpu-cache-latency/input.py -# You can tune these as you like later + +# No object storage needed for this benchmark. +def buckets_count(): + return (0, 0) + + +# Presets used by `--size` and by SeBS generate_input(size=...) size_generators = { - "test": {"working_set_bytes": 1 << 16, "iterations": 10_000}, - "small": {"working_set_bytes": 1 << 20, "iterations": 100_000}, - "large": {"working_set_bytes": 1 << 24, "iterations": 1_000_000}, + "l1_4kb": {"working_set_bytes": 1 << 12, "iterations": 50_000}, + "l1_16kb": {"working_set_bytes": 1 << 14, "iterations": 50_000}, + "l2_256kb": {"working_set_bytes": 1 << 18, "iterations": 100_000}, + "l2_1mb": {"working_set_bytes": 1 << 20, "iterations": 150_000}, + "l2_2mb": {"working_set_bytes": 2 << 20, "iterations": 200_000}, + "dram_4mb": {"working_set_bytes": 4 << 20, "iterations": 200_000}, + "dram_16mb": {"working_set_bytes": 16 << 20, "iterations": 400_000}, + "dram_32mb": {"working_set_bytes": 32 << 20, "iterations": 500_000}, + "dram_64mb": {"working_set_bytes": 64 << 20, "iterations": 800_000}, + "dram_128mb": {"working_set_bytes": 128 << 20, "iterations": 1_000_000}, + "dram_256mb": {"working_set_bytes": 256 << 20, "iterations": 1_500_000}, + "dram_512mb": {"working_set_bytes": 512 << 20, "iterations": 2_000_000}, + "test": {"working_set_bytes": 1 << 16, "iterations": 10_000}, + "small": {"working_set_bytes": 1 << 20, "iterations": 100_000}, + "large": {"working_set_bytes": 1 << 24, "iterations": 1_000_000}, } + def generate_input( - data_dir, # path to benchmark data dir (unused here) - size, # "test" | "small" | "large" - benchmarks_bucket, # storage bucket (unused locally) - input_paths, # list of input paths (unused here) - output_paths, # list of output paths (unused here) - upload_func, # function to upload data (unused here) - nosql_func # function to access NoSQL (unused here) + data_dir, + size, + benchmarks_bucket, + input_paths, + output_paths, + upload_func, + nosql_func, ): - """ - SeBS calls this to get the JSON-like dict that becomes event['input'] - for the function. - """ cfg = size_generators[size] - return { - "working_set_bytes": cfg["working_set_bytes"], - "pattern": "random", # or "sequential", "stride_4", etc. - "iterations": cfg["iterations"], - "seed": 42 + "working_set_bytes": int(cfg["working_set_bytes"]), + "pattern": "random", + "iterations": int(cfg["iterations"]), + "seed": 42, } diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/function.py b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/function.py index 369644a99..0abcc3b79 100644 --- a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/function.py +++ b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/function.py @@ -1,115 +1,315 @@ # benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/function.py +import argparse +import csv +import json import time -import math +from datetime import datetime +from pathlib import Path +from typing import Any, Dict, List, Optional + import torch -def build_next_indices(n: int, pattern: str, device: torch.device, seed: int = 42): +def _load_input_module(): + """Import the benchmark's input.py from the benchmark package.""" + try: + import importlib + + return importlib.import_module("input") + except ModuleNotFoundError as exc: + raise RuntimeError("input.py is required to use --size but could not be imported.") from exc + + +def build_next_indices(n: int, pattern: str, device: torch.device, seed: int = 42) -> torch.Tensor: """ - Build the 'next' array with the given pattern, similar to your C++ version. + Build the 'next' array (int64 indices) implementing a pointer-chase permutation. """ - if n <= 0: - n = 1 - - idx = torch.empty(n, dtype=torch.long) + n = max(1, int(n)) if pattern == "sequential": - idx = (torch.arange(n, dtype=torch.long) + 1) % n - elif pattern.startswith("stride_"): - stride = int(pattern.split("_", 1)[1]) - idx = (torch.arange(n, dtype=torch.long) + stride) % n - elif pattern == "random": - # deterministic permutation - g = torch.Generator() - g.manual_seed(seed) - perm = torch.randperm(n, generator=g) - idx[perm] = perm.roll(-1) - else: - raise ValueError(f"Unknown pattern '{pattern}'") - - return idx.to(device) + idx = (torch.arange(n, dtype=torch.long, device=device) + 1) % n + return idx.contiguous() + if pattern.startswith("stride_"): + stride = int(pattern.split("_", 1)[1]) + idx = (torch.arange(n, dtype=torch.long, device=device) + stride) % n + return idx.contiguous() -def pointer_chase(working_set_bytes: int, pattern: str, iterations: int, seed: int = 42): - """ - Pointer-chase microbenchmark, implemented in PyTorch. - Uses GPU if available; otherwise falls back to CPU. - """ + if pattern == "random": + # Build deterministically on CPU, then move to target device. + g = torch.Generator(device="cpu") + g.manual_seed(int(seed)) + perm = torch.randperm(n, generator=g, device="cpu") + idx_cpu = torch.empty(n, dtype=torch.long, device="cpu") + idx_cpu[perm] = perm.roll(-1) + return idx_cpu.to(device).contiguous() - # Number of ints in the working set - n = max(1, working_set_bytes // 4) + raise ValueError(f"Unknown pattern '{pattern}'") - device = torch.device("cuda" if torch.cuda.is_available() else "cpu") - next_idx = build_next_indices(n, pattern, device, seed=seed) +def _pointer_chase_torch(next_idx: torch.Tensor, iterations: int) -> torch.Tensor: + """ + Pointer chase implemented using torch tensor indexing. + Returns a small tensor [cur, acc] so results depend on the loop + (prevents dead-code elimination style effects). + """ + device = next_idx.device cur = torch.tensor(0, dtype=torch.long, device=device) acc = torch.tensor(0, dtype=torch.long, device=device) - # Warmup (like your C++ version) - warmup_iters = min(iterations, 1024) - for _ in range(warmup_iters): + for _ in range(int(iterations)): cur = next_idx[cur] acc = acc + cur - # Measure time + return torch.stack([cur, acc], dim=0) + + +def pointer_chase( + working_set_bytes: int, + pattern: str, + iterations: int, + seed: int = 42, +) -> Dict[str, Any]: + """ + Pointer-chase microbenchmark (JIT-free). + + - Uses CUDA if available; otherwise CPU. + - Timing uses CUDA events on GPU and perf_counter on CPU. + - Pure torch indexing loop (no custom extensions / nvcc). + """ + working_set_bytes = int(working_set_bytes) + iterations = int(iterations) + n = max(1, working_set_bytes // 8) # int64 indices + + device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + next_idx = build_next_indices(n, pattern, device=device, seed=seed) + + # Warmup: reduce first-use overhead / cache cold-start effects. + warmup_iters = min(iterations, 1024) + _ = _pointer_chase_torch(next_idx, warmup_iters) if device.type == "cuda": torch.cuda.synchronize() - start_event = torch.cuda.Event(enable_timing=True) - end_event = torch.cuda.Event(enable_timing=True) - - start_event.record() - for _ in range(iterations): - cur = next_idx[cur] - acc = acc + cur - end_event.record() - torch.cuda.synchronize() - elapsed_ms = start_event.elapsed_time(end_event) # ms - total_seconds = elapsed_ms / 1000.0 + if device.type == "cuda": + start = torch.cuda.Event(enable_timing=True) + end = torch.cuda.Event(enable_timing=True) + + start.record() + sink = _pointer_chase_torch(next_idx, iterations) + end.record() + + torch.cuda.synchronize() + total_seconds = float(start.elapsed_time(end)) / 1000.0 else: - start_time = time.perf_counter() - for _ in range(iterations): - cur = next_idx[cur] - acc = acc + cur - total_seconds = time.perf_counter() - start_time + t0 = time.perf_counter() + sink = _pointer_chase_torch(next_idx, iterations) + total_seconds = time.perf_counter() - t0 + cur_value, acc_value = [int(x) for x in sink.tolist()] avg_ns = (total_seconds * 1e9 / iterations) if iterations > 0 else 0.0 return { - "working_set_bytes": int(working_set_bytes), - "pattern": pattern, - "iterations": int(iterations), + "working_set_bytes": working_set_bytes, + "pattern": str(pattern), + "iterations": iterations, + "seed": int(seed), "device": str(device), - "total_seconds": total_seconds, - "avg_ns_per_step": avg_ns, - "sink": int(acc.item()), + "total_seconds": float(total_seconds), + "avg_ns_per_step": float(avg_ns), + "sink": int(acc_value), + "cur": int(cur_value), } -def handler(event, context=None): +def _unwrap_event_input(event: Any) -> Dict[str, Any]: """ - Entry point for SeBS. - - For Python benchmarks, SeBS passes: - event = { - "input": { ...whatever generate_input returned... }, - ... - } - We must return: { "result": } + Make handler compatible with both styles: + - event is already the input dict + - event = {"input": {...}, ...} """ + if isinstance(event, dict) and isinstance(event.get("input"), dict): + return event["input"] + if isinstance(event, dict): + return event + return {} - params = event.get("input", {}) + +def handler(event, context=None): + """ + SeBS entry point. + Returns JSON-serializable payload with both result + basic measurement fields. + """ + params = _unwrap_event_input(event) working_set_bytes = int(params.get("working_set_bytes", 1 << 20)) - pattern = params.get("pattern", "random") + pattern = str(params.get("pattern", "random")) iterations = int(params.get("iterations", 100_000)) seed = int(params.get("seed", 42)) result = pointer_chase(working_set_bytes, pattern, iterations, seed=seed) - # SeBS expects this shape return { - "result": result + "result": result, + "measurement": { + "total_seconds": result["total_seconds"], + "avg_ns_per_step": result["avg_ns_per_step"], + }, } + + +# --------------------------- +# Optional local CLI harness +# --------------------------- + + +def _parse_args(): + parser = argparse.ArgumentParser( + description="Run the pointer-chase microbenchmark without SeBS." + ) + parser.add_argument("--working-set-bytes", type=int, default=1 << 20, dest="working_set_bytes") + parser.add_argument( + "--pattern", + action="append", + dest="patterns", + default=None, + help="Access pattern(s): random, sequential, stride_X. Repeat to sweep multiple.", + ) + parser.add_argument("--iterations", type=int, default=100_000) + parser.add_argument("--seed", type=int, default=42) + + size_choices = _size_choices() + size_kwargs: Dict[str, Any] = {"dest": "size", "help": "Use preset from input.py (e.g. test)."} + if size_choices: + size_kwargs["choices"] = size_choices + size_kwargs["help"] += f" Choices: {', '.join(size_choices)}." + parser.add_argument("--size", **size_kwargs) + + parser.add_argument("--batch", action="store_true", help="Run all selected presets.") + parser.add_argument( + "--sizes", type=str, help="Comma-separated preset names (e.g. test,small,large)." + ) + parser.add_argument("--csv", type=str, help="Optional path to write results as CSV.") + return parser.parse_args() + + +def _size_choices() -> List[str]: + try: + module = _load_input_module() + except RuntimeError: + return [] + return sorted(module.size_generators.keys()) + + +def _comma_separated_list(raw: Optional[str]) -> List[str]: + if not raw: + return [] + return [entry.strip() for entry in raw.split(",") if entry.strip()] + + +def _pattern_list(patterns_arg: Optional[List[str]]) -> List[str]: + patterns = patterns_arg or ["random"] + out: List[str] = [] + for pat in patterns: + out.extend([p.strip() for p in pat.split(",") if p.strip()]) + return out or ["random"] + + +def _config_from_size(size: str) -> Dict[str, Any]: + module = _load_input_module() + cfg = module.generate_input(None, size, None, None, None, None, None) + return dict(cfg) + + +def _augment_result(result: Dict[str, Any], size_label: str) -> Dict[str, Any]: + total_seconds = float(result["total_seconds"]) + iterations = int(result["iterations"]) + steps_per_second = iterations / total_seconds if total_seconds > 0 else 0.0 + approx_gb_per_s = (iterations * 8) / total_seconds / (1024**3) if total_seconds > 0 else 0.0 + + out = dict(result) + out.update( + { + "timestamp": datetime.utcnow().isoformat(), + "size_label": size_label, + "steps_per_second": float(steps_per_second), + "approx_gb_per_s": float(approx_gb_per_s), + } + ) + return out + + +def _write_csv(records: List[Dict[str, Any]], csv_path: str): + if not records: + return + path = Path(csv_path) + path.parent.mkdir(parents=True, exist_ok=True) + fieldnames = [ + "timestamp", + "size_label", + "pattern", + "working_set_bytes", + "iterations", + "seed", + "device", + "total_seconds", + "avg_ns_per_step", + "steps_per_second", + "approx_gb_per_s", + "sink", + "cur", + ] + with path.open("w", newline="") as handle: + writer = csv.DictWriter(handle, fieldnames=fieldnames) + writer.writeheader() + for row in records: + writer.writerow({key: row.get(key, "") for key in fieldnames}) + + +if __name__ == "__main__": + args = _parse_args() + patterns = _pattern_list(args.patterns) + + def run_config(config: Dict[str, Any], size_label: str) -> List[Dict[str, Any]]: + records: List[Dict[str, Any]] = [] + for pat in patterns: + cfg = dict(config) + cfg["pattern"] = pat + out = pointer_chase( + working_set_bytes=cfg["working_set_bytes"], + pattern=cfg["pattern"], + iterations=cfg["iterations"], + seed=cfg.get("seed", args.seed), + ) + rec = _augment_result(out, size_label=size_label) + records.append(rec) + print(json.dumps(rec, indent=2)) + return records + + all_records: List[Dict[str, Any]] = [] + + if args.batch: + available = _size_choices() + selected = _comma_separated_list(args.sizes) if args.sizes else available + for preset in selected: + if preset not in available: + raise ValueError(f"Unknown preset '{preset}'. Available: {', '.join(available)}") + cfg = _config_from_size(preset) + all_records.extend(run_config(cfg, size_label=preset)) + else: + if args.size: + cfg = _config_from_size(args.size) + size_label = args.size + else: + size_label = "manual" + cfg = { + "working_set_bytes": args.working_set_bytes, + "pattern": patterns[0], + "iterations": args.iterations, + "seed": args.seed, + } + all_records.extend(run_config(cfg, size_label=size_label)) + + if args.csv: + _write_csv(all_records, args.csv) diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/requirements.txt b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/requirements.txt index f9b2aa91e..919000d36 100644 --- a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/requirements.txt +++ b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/requirements.txt @@ -1,2 +1,2 @@ torch -numpy \ No newline at end of file +ninja diff --git a/benchmarks/000.microbenchmarks/060.wrap-divergence/config.json b/benchmarks/000.microbenchmarks/060.wrap-divergence/config.json deleted file mode 100644 index 93ce2f561..000000000 --- a/benchmarks/000.microbenchmarks/060.wrap-divergence/config.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "timeout": 120, - "memory": 128, - "languages": ["python", "nodejs"], - "modules": [] -} diff --git a/benchmarks/000.microbenchmarks/060.wrap-divergence/input.py b/benchmarks/000.microbenchmarks/060.wrap-divergence/input.py deleted file mode 100644 index 2e90b8c5e..000000000 --- a/benchmarks/000.microbenchmarks/060.wrap-divergence/input.py +++ /dev/null @@ -1,56 +0,0 @@ -import os -import json -from typing import Tuple - - -def buckets_count() -> Tuple[int, int]: - """ - One input bucket, one output bucket. - """ - return (1, 1) - - -def generate_input( - data_dir, - size, - benchmarks_bucket, - input_paths, - output_paths, - upload_func, - nosql_func, -): - """ - Generate a JSON config for the warp-divergence microbenchmark - and upload it to the input bucket. - - The JSON is what will be passed as `event` to function.handler(). - """ - if size == "test": - num_warps = 512 - iters = 500 - elif size == "small": - num_warps = 2048 - iters = 1000 - else: # "large" - num_warps = 8192 - iters = 2000 - - active_lanes = [0, 4, 8, 16, 24, 32] - - config = { - "num_warps": num_warps, - "iters": iters, - "active_lanes": active_lanes, - } - - os.makedirs(data_dir, exist_ok=True) - local_path = os.path.join(data_dir, f"warp_div_config_{size}.json") - with open(local_path, "w") as f: - json.dump(config, f) - - key = f"{input_paths[0].rstrip('/')}/warp_div_config_{size}.json" - upload_func(0, key, local_path) - - # Return the config directly so runtimes that already have the payload - # don't need to fetch it back from storage. - return {"config": config} diff --git a/benchmarks/000.microbenchmarks/060.wrap-divergence/python/function.py b/benchmarks/000.microbenchmarks/060.wrap-divergence/python/function.py deleted file mode 100644 index 68b3e623b..000000000 --- a/benchmarks/000.microbenchmarks/060.wrap-divergence/python/function.py +++ /dev/null @@ -1,113 +0,0 @@ -import json -import time -from typing import List, Dict, Any - -import torch - - -def heavy_work(x: torch.Tensor, iters: int) -> torch.Tensor: - """ - Simple compute-heavy loop: about 2 FLOPs per element per iteration. - """ - for _ in range(iters): - x = x * 1.000001 + 1.0 - return x - - -def run_one_case( - num_warps: int, - iters: int, - active_lanes: int, - device: torch.device, -) -> float: - """ - Run one configuration with a given number of active lanes per 'warp'. - Returns elapsed time in milliseconds. - """ - warp_size = 32 - n = num_warps * warp_size - - # lane_id: 0..31 repeated for each warp - lane_ids = torch.arange(warp_size, device=device).repeat(num_warps) - - # Boolean mask for "active" lanes - mask = lane_ids < active_lanes - - # Data tensor - x = torch.ones(n, device=device) - - if device.type == "cuda": - torch.cuda.synchronize() - t0 = time.perf_counter() - - # Only active lanes do heavy work; inactive lanes do almost nothing - x_active = x[mask] - if active_lanes > 0: - x_active = heavy_work(x_active, iters) - x[mask] = x_active - - if device.type == "cuda": - torch.cuda.synchronize() - t1 = time.perf_counter() - - # Prevent optimization away - _ = x.sum().item() - - return (t1 - t0) * 1e3 # ms - - -def run_benchmark(config: Dict[str, Any]) -> Dict[str, Any]: - """ - Core benchmark logic used by handler(). - """ - num_warps = int(config["num_warps"]) - iters = int(config["iters"]) - active_lanes_list: List[int] = [int(x) for x in config["active_lanes"]] - - device = torch.device("cuda" if torch.cuda.is_available() else "cpu") - - results = [] - for active_lanes in active_lanes_list: - time_ms = run_one_case(num_warps, iters, active_lanes, device) - - # Useful FLOPs: only active lanes count - active_threads = num_warps * active_lanes - flops = 2.0 * iters * active_threads # 2 FLOPs per iter - gflops = flops / (time_ms * 1e6) if time_ms > 0 else 0.0 - - results.append( - { - "active_lanes": active_lanes, - "time_ms": time_ms, - "gflops_effective": gflops, - } - ) - - return { - "num_warps": num_warps, - "iters": iters, - "device": str(device), - "results": results, - } - - -def handler(event, context=None): - """ - Entry point used by SeBS local backend for Python. - - The event is the JSON config uploaded by input.py: - { - "num_warps": ..., - "iters": ..., - "active_lanes": [...] - } - """ - if isinstance(event, str): - event = json.loads(event) - - if isinstance(event, dict) and "config" in event and isinstance(event["config"], dict): - config = event["config"] - else: - config = event - - return run_benchmark(config) diff --git a/benchmarks/000.microbenchmarks/060.wrap-divergence/python/requirements.txt b/benchmarks/000.microbenchmarks/060.wrap-divergence/python/requirements.txt deleted file mode 100644 index 320f98057..000000000 --- a/benchmarks/000.microbenchmarks/060.wrap-divergence/python/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -torch>=2.0 diff --git a/requirements.txt b/requirements.txt index b8c1517f0..bee695ee6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ tzlocal>=2.1 requests #linting flake8 -black==22.8.0 +black==24.4.2 mypy types-pycurl types-requests From 59e8efd80effed785c51562c795d739928b07204 Mon Sep 17 00:00:00 2001 From: JessieeeLoki Date: Mon, 15 Dec 2025 16:27:55 +0100 Subject: [PATCH 58/58] fixed formatting --- .../050.gpu-cache-latency/input.py | 44 --- .../050.gpu-cache-latency/python/function.py | 315 ------------------ .../320.monte-carlo-pi}/config.json | 0 .../300.utilities/320.monte-carlo-pi/input.py | 32 ++ .../320.monte-carlo-pi/python/function.py | 113 +++++++ .../python/requirements.txt | 1 - 6 files changed, 145 insertions(+), 360 deletions(-) delete mode 100644 benchmarks/000.microbenchmarks/050.gpu-cache-latency/input.py delete mode 100644 benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/function.py rename benchmarks/{000.microbenchmarks/050.gpu-cache-latency => 300.utilities/320.monte-carlo-pi}/config.json (100%) create mode 100644 benchmarks/300.utilities/320.monte-carlo-pi/input.py create mode 100644 benchmarks/300.utilities/320.monte-carlo-pi/python/function.py rename benchmarks/{000.microbenchmarks/050.gpu-cache-latency => 300.utilities/320.monte-carlo-pi}/python/requirements.txt (50%) diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/input.py b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/input.py deleted file mode 100644 index 87a251370..000000000 --- a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/input.py +++ /dev/null @@ -1,44 +0,0 @@ -# benchmarks/000.microbenchmarks/050.gpu-cache-latency/input.py - - -# No object storage needed for this benchmark. -def buckets_count(): - return (0, 0) - - -# Presets used by `--size` and by SeBS generate_input(size=...) -size_generators = { - "l1_4kb": {"working_set_bytes": 1 << 12, "iterations": 50_000}, - "l1_16kb": {"working_set_bytes": 1 << 14, "iterations": 50_000}, - "l2_256kb": {"working_set_bytes": 1 << 18, "iterations": 100_000}, - "l2_1mb": {"working_set_bytes": 1 << 20, "iterations": 150_000}, - "l2_2mb": {"working_set_bytes": 2 << 20, "iterations": 200_000}, - "dram_4mb": {"working_set_bytes": 4 << 20, "iterations": 200_000}, - "dram_16mb": {"working_set_bytes": 16 << 20, "iterations": 400_000}, - "dram_32mb": {"working_set_bytes": 32 << 20, "iterations": 500_000}, - "dram_64mb": {"working_set_bytes": 64 << 20, "iterations": 800_000}, - "dram_128mb": {"working_set_bytes": 128 << 20, "iterations": 1_000_000}, - "dram_256mb": {"working_set_bytes": 256 << 20, "iterations": 1_500_000}, - "dram_512mb": {"working_set_bytes": 512 << 20, "iterations": 2_000_000}, - "test": {"working_set_bytes": 1 << 16, "iterations": 10_000}, - "small": {"working_set_bytes": 1 << 20, "iterations": 100_000}, - "large": {"working_set_bytes": 1 << 24, "iterations": 1_000_000}, -} - - -def generate_input( - data_dir, - size, - benchmarks_bucket, - input_paths, - output_paths, - upload_func, - nosql_func, -): - cfg = size_generators[size] - return { - "working_set_bytes": int(cfg["working_set_bytes"]), - "pattern": "random", - "iterations": int(cfg["iterations"]), - "seed": 42, - } diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/function.py b/benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/function.py deleted file mode 100644 index 0abcc3b79..000000000 --- a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/function.py +++ /dev/null @@ -1,315 +0,0 @@ -# benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/function.py - -import argparse -import csv -import json -import time -from datetime import datetime -from pathlib import Path -from typing import Any, Dict, List, Optional - -import torch - - -def _load_input_module(): - """Import the benchmark's input.py from the benchmark package.""" - try: - import importlib - - return importlib.import_module("input") - except ModuleNotFoundError as exc: - raise RuntimeError("input.py is required to use --size but could not be imported.") from exc - - -def build_next_indices(n: int, pattern: str, device: torch.device, seed: int = 42) -> torch.Tensor: - """ - Build the 'next' array (int64 indices) implementing a pointer-chase permutation. - """ - n = max(1, int(n)) - - if pattern == "sequential": - idx = (torch.arange(n, dtype=torch.long, device=device) + 1) % n - return idx.contiguous() - - if pattern.startswith("stride_"): - stride = int(pattern.split("_", 1)[1]) - idx = (torch.arange(n, dtype=torch.long, device=device) + stride) % n - return idx.contiguous() - - if pattern == "random": - # Build deterministically on CPU, then move to target device. - g = torch.Generator(device="cpu") - g.manual_seed(int(seed)) - perm = torch.randperm(n, generator=g, device="cpu") - idx_cpu = torch.empty(n, dtype=torch.long, device="cpu") - idx_cpu[perm] = perm.roll(-1) - return idx_cpu.to(device).contiguous() - - raise ValueError(f"Unknown pattern '{pattern}'") - - -def _pointer_chase_torch(next_idx: torch.Tensor, iterations: int) -> torch.Tensor: - """ - Pointer chase implemented using torch tensor indexing. - - Returns a small tensor [cur, acc] so results depend on the loop - (prevents dead-code elimination style effects). - """ - device = next_idx.device - cur = torch.tensor(0, dtype=torch.long, device=device) - acc = torch.tensor(0, dtype=torch.long, device=device) - - for _ in range(int(iterations)): - cur = next_idx[cur] - acc = acc + cur - - return torch.stack([cur, acc], dim=0) - - -def pointer_chase( - working_set_bytes: int, - pattern: str, - iterations: int, - seed: int = 42, -) -> Dict[str, Any]: - """ - Pointer-chase microbenchmark (JIT-free). - - - Uses CUDA if available; otherwise CPU. - - Timing uses CUDA events on GPU and perf_counter on CPU. - - Pure torch indexing loop (no custom extensions / nvcc). - """ - working_set_bytes = int(working_set_bytes) - iterations = int(iterations) - n = max(1, working_set_bytes // 8) # int64 indices - - device = torch.device("cuda" if torch.cuda.is_available() else "cpu") - next_idx = build_next_indices(n, pattern, device=device, seed=seed) - - # Warmup: reduce first-use overhead / cache cold-start effects. - warmup_iters = min(iterations, 1024) - _ = _pointer_chase_torch(next_idx, warmup_iters) - if device.type == "cuda": - torch.cuda.synchronize() - - if device.type == "cuda": - start = torch.cuda.Event(enable_timing=True) - end = torch.cuda.Event(enable_timing=True) - - start.record() - sink = _pointer_chase_torch(next_idx, iterations) - end.record() - - torch.cuda.synchronize() - total_seconds = float(start.elapsed_time(end)) / 1000.0 - else: - t0 = time.perf_counter() - sink = _pointer_chase_torch(next_idx, iterations) - total_seconds = time.perf_counter() - t0 - - cur_value, acc_value = [int(x) for x in sink.tolist()] - avg_ns = (total_seconds * 1e9 / iterations) if iterations > 0 else 0.0 - - return { - "working_set_bytes": working_set_bytes, - "pattern": str(pattern), - "iterations": iterations, - "seed": int(seed), - "device": str(device), - "total_seconds": float(total_seconds), - "avg_ns_per_step": float(avg_ns), - "sink": int(acc_value), - "cur": int(cur_value), - } - - -def _unwrap_event_input(event: Any) -> Dict[str, Any]: - """ - Make handler compatible with both styles: - - event is already the input dict - - event = {"input": {...}, ...} - """ - if isinstance(event, dict) and isinstance(event.get("input"), dict): - return event["input"] - if isinstance(event, dict): - return event - return {} - - -def handler(event, context=None): - """ - SeBS entry point. - Returns JSON-serializable payload with both result + basic measurement fields. - """ - params = _unwrap_event_input(event) - - working_set_bytes = int(params.get("working_set_bytes", 1 << 20)) - pattern = str(params.get("pattern", "random")) - iterations = int(params.get("iterations", 100_000)) - seed = int(params.get("seed", 42)) - - result = pointer_chase(working_set_bytes, pattern, iterations, seed=seed) - - return { - "result": result, - "measurement": { - "total_seconds": result["total_seconds"], - "avg_ns_per_step": result["avg_ns_per_step"], - }, - } - - -# --------------------------- -# Optional local CLI harness -# --------------------------- - - -def _parse_args(): - parser = argparse.ArgumentParser( - description="Run the pointer-chase microbenchmark without SeBS." - ) - parser.add_argument("--working-set-bytes", type=int, default=1 << 20, dest="working_set_bytes") - parser.add_argument( - "--pattern", - action="append", - dest="patterns", - default=None, - help="Access pattern(s): random, sequential, stride_X. Repeat to sweep multiple.", - ) - parser.add_argument("--iterations", type=int, default=100_000) - parser.add_argument("--seed", type=int, default=42) - - size_choices = _size_choices() - size_kwargs: Dict[str, Any] = {"dest": "size", "help": "Use preset from input.py (e.g. test)."} - if size_choices: - size_kwargs["choices"] = size_choices - size_kwargs["help"] += f" Choices: {', '.join(size_choices)}." - parser.add_argument("--size", **size_kwargs) - - parser.add_argument("--batch", action="store_true", help="Run all selected presets.") - parser.add_argument( - "--sizes", type=str, help="Comma-separated preset names (e.g. test,small,large)." - ) - parser.add_argument("--csv", type=str, help="Optional path to write results as CSV.") - return parser.parse_args() - - -def _size_choices() -> List[str]: - try: - module = _load_input_module() - except RuntimeError: - return [] - return sorted(module.size_generators.keys()) - - -def _comma_separated_list(raw: Optional[str]) -> List[str]: - if not raw: - return [] - return [entry.strip() for entry in raw.split(",") if entry.strip()] - - -def _pattern_list(patterns_arg: Optional[List[str]]) -> List[str]: - patterns = patterns_arg or ["random"] - out: List[str] = [] - for pat in patterns: - out.extend([p.strip() for p in pat.split(",") if p.strip()]) - return out or ["random"] - - -def _config_from_size(size: str) -> Dict[str, Any]: - module = _load_input_module() - cfg = module.generate_input(None, size, None, None, None, None, None) - return dict(cfg) - - -def _augment_result(result: Dict[str, Any], size_label: str) -> Dict[str, Any]: - total_seconds = float(result["total_seconds"]) - iterations = int(result["iterations"]) - steps_per_second = iterations / total_seconds if total_seconds > 0 else 0.0 - approx_gb_per_s = (iterations * 8) / total_seconds / (1024**3) if total_seconds > 0 else 0.0 - - out = dict(result) - out.update( - { - "timestamp": datetime.utcnow().isoformat(), - "size_label": size_label, - "steps_per_second": float(steps_per_second), - "approx_gb_per_s": float(approx_gb_per_s), - } - ) - return out - - -def _write_csv(records: List[Dict[str, Any]], csv_path: str): - if not records: - return - path = Path(csv_path) - path.parent.mkdir(parents=True, exist_ok=True) - fieldnames = [ - "timestamp", - "size_label", - "pattern", - "working_set_bytes", - "iterations", - "seed", - "device", - "total_seconds", - "avg_ns_per_step", - "steps_per_second", - "approx_gb_per_s", - "sink", - "cur", - ] - with path.open("w", newline="") as handle: - writer = csv.DictWriter(handle, fieldnames=fieldnames) - writer.writeheader() - for row in records: - writer.writerow({key: row.get(key, "") for key in fieldnames}) - - -if __name__ == "__main__": - args = _parse_args() - patterns = _pattern_list(args.patterns) - - def run_config(config: Dict[str, Any], size_label: str) -> List[Dict[str, Any]]: - records: List[Dict[str, Any]] = [] - for pat in patterns: - cfg = dict(config) - cfg["pattern"] = pat - out = pointer_chase( - working_set_bytes=cfg["working_set_bytes"], - pattern=cfg["pattern"], - iterations=cfg["iterations"], - seed=cfg.get("seed", args.seed), - ) - rec = _augment_result(out, size_label=size_label) - records.append(rec) - print(json.dumps(rec, indent=2)) - return records - - all_records: List[Dict[str, Any]] = [] - - if args.batch: - available = _size_choices() - selected = _comma_separated_list(args.sizes) if args.sizes else available - for preset in selected: - if preset not in available: - raise ValueError(f"Unknown preset '{preset}'. Available: {', '.join(available)}") - cfg = _config_from_size(preset) - all_records.extend(run_config(cfg, size_label=preset)) - else: - if args.size: - cfg = _config_from_size(args.size) - size_label = args.size - else: - size_label = "manual" - cfg = { - "working_set_bytes": args.working_set_bytes, - "pattern": patterns[0], - "iterations": args.iterations, - "seed": args.seed, - } - all_records.extend(run_config(cfg, size_label=size_label)) - - if args.csv: - _write_csv(all_records, args.csv) diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/config.json b/benchmarks/300.utilities/320.monte-carlo-pi/config.json similarity index 100% rename from benchmarks/000.microbenchmarks/050.gpu-cache-latency/config.json rename to benchmarks/300.utilities/320.monte-carlo-pi/config.json diff --git a/benchmarks/300.utilities/320.monte-carlo-pi/input.py b/benchmarks/300.utilities/320.monte-carlo-pi/input.py new file mode 100644 index 000000000..8332fafe8 --- /dev/null +++ b/benchmarks/300.utilities/320.monte-carlo-pi/input.py @@ -0,0 +1,32 @@ +# benchmarks/000.microbenchmarks/060.monte-carlo-pi/input.py + + +def buckets_count(): + # No object storage needed for this benchmark. + return (0, 0) + + +size_generators = { + "test": {"total_samples": 1_000_000, "batch_size": 250_000}, + "small": {"total_samples": 10_000_000, "batch_size": 1_000_000}, + "medium": {"total_samples": 50_000_000, "batch_size": 2_000_000}, + "large": {"total_samples": 200_000_000, "batch_size": 5_000_000}, +} + + +def generate_input( + data_dir, + size, + benchmarks_bucket, + input_paths, + output_paths, + upload_func, + nosql_func, +): + cfg = size_generators[size] + return { + "total_samples": int(cfg["total_samples"]), + "batch_size": int(cfg["batch_size"]), + "seed": 42, + "prefer_gpu": True, + } diff --git a/benchmarks/300.utilities/320.monte-carlo-pi/python/function.py b/benchmarks/300.utilities/320.monte-carlo-pi/python/function.py new file mode 100644 index 000000000..329149799 --- /dev/null +++ b/benchmarks/300.utilities/320.monte-carlo-pi/python/function.py @@ -0,0 +1,113 @@ +# benchmarks/000.microbenchmarks/060.monte-carlo-pi/python/function.py + +import time +from typing import Any, Dict, Tuple + +import torch + + +def _unwrap_event_input(event: Any) -> Dict[str, Any]: + # Compatible with both styles: + # - event is already the input dict + # - event = {"input": {...}, ...} + if isinstance(event, dict) and isinstance(event.get("input"), dict): + return event["input"] + if isinstance(event, dict): + return event + return {} + + +def _resolve_device(prefer_gpu: bool) -> torch.device: + if prefer_gpu and torch.cuda.is_available(): + return torch.device("cuda") + return torch.device("cpu") + + +def _time_call(device: torch.device, fn) -> Tuple[float, Any]: + # Returns (seconds, fn_result) + if device.type == "cuda": + torch.cuda.synchronize() + start = torch.cuda.Event(enable_timing=True) + end = torch.cuda.Event(enable_timing=True) + start.record() + out = fn() + end.record() + torch.cuda.synchronize() + seconds = float(start.elapsed_time(end)) / 1000.0 + return seconds, out + + t0 = time.perf_counter() + out = fn() + seconds = time.perf_counter() - t0 + return seconds, out + + +def estimate_pi_torch( + total_samples: int, + batch_size: int, + seed: int, + prefer_gpu: bool, +) -> Dict[str, Any]: + total_samples = int(total_samples) + batch_size = int(batch_size) + seed = int(seed) + + if total_samples <= 0: + raise ValueError("total_samples must be > 0") + if batch_size <= 0: + raise ValueError("batch_size must be > 0") + + device = _resolve_device(prefer_gpu) + + # Seed deterministically (good for reproducibility / debugging) + torch.manual_seed(seed) + if device.type == "cuda": + torch.cuda.manual_seed_all(seed) + + def run(): + hits = torch.zeros((), dtype=torch.int64, device=device) + remaining = total_samples + + while remaining > 0: + cur = min(batch_size, remaining) + + # Uniform samples in [0, 1) + xy = torch.rand((cur, 2), device=device) + r2 = xy[:, 0] * xy[:, 0] + xy[:, 1] * xy[:, 1] + hits = hits + (r2 <= 1.0).sum(dtype=torch.int64) + + remaining -= cur + + return int(hits.item()) + + compute_seconds, hits = _time_call(device, run) + pi_est = 4.0 * float(hits) / float(total_samples) + samples_per_s = float(total_samples) / compute_seconds if compute_seconds > 0 else 0.0 + + return { + "pi_estimate": pi_est, + "hits": int(hits), + "samples": int(total_samples), + "batch_size": int(batch_size), + "device": str(device), + "compute_seconds": float(compute_seconds), + "samples_per_second": float(samples_per_s), + } + + +def handler(event, context=None): + params = _unwrap_event_input(event) + + total_samples = int(params.get("total_samples", 10_000_000)) + batch_size = int(params.get("batch_size", 1_000_000)) + seed = int(params.get("seed", 42)) + prefer_gpu = bool(params.get("prefer_gpu", True)) + + result = estimate_pi_torch(total_samples, batch_size, seed, prefer_gpu) + + return { + "result": result, + "measurement": { + "compute_time": result["compute_seconds"] * 1e6, # microseconds + }, + } diff --git a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/requirements.txt b/benchmarks/300.utilities/320.monte-carlo-pi/python/requirements.txt similarity index 50% rename from benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/requirements.txt rename to benchmarks/300.utilities/320.monte-carlo-pi/python/requirements.txt index 919000d36..12c6d5d5e 100644 --- a/benchmarks/000.microbenchmarks/050.gpu-cache-latency/python/requirements.txt +++ b/benchmarks/300.utilities/320.monte-carlo-pi/python/requirements.txt @@ -1,2 +1 @@ torch -ninja