This repository was archived by the owner on Mar 31, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 173
feat: add time based benchmarks #1749
Merged
Merged
Changes from 1 commit
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
e140109
feat: add time based benchmarks
chandra-siri ed67fcc
take sizes in kib
chandra-siri 0471f3b
add support for queue_depth (num_ranges)
chandra-siri eaefc31
fix throughput calculation logic
chandra-siri a1fa044
remove commented out code
chandra-siri cc6826c
support regional buckets for time based benchmarks
chandra-siri b358199
run both seq and random
chandra-siri 18393fd
Merge branch 'main' into time_based_benchmarks
chandra-siri b733577
fix lint issues
chandra-siri b625507
remove nonlocal reference
chandra-siri 9657d56
remove print statement
chandra-siri b320315
dynamically fetch cpu cores where hardIRQ is bound
chandra-siri a0a015d
use os.cpu_count()
chandra-siri 171e496
lint changes
chandra-siri c9e01cb
ahdere to linting standards
chandra-siri 7b7b199
Remove CORE_OFFSET variable from test_reads.py
chandra-siri File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| # Copyright 2026 Google LLC | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
| import pytest | ||
| import os | ||
| import multiprocessing | ||
| import logging | ||
| from google.cloud import storage | ||
|
|
||
| _OBJECT_NAME_PREFIX = "time_based_tests" | ||
|
|
||
|
|
||
| # def _upload_worker(args): | ||
| # bucket_name, object_name, object_size = args | ||
| # storage_client = storage.Client() | ||
| # bucket = storage_client.bucket(bucket_name) | ||
| # blob = bucket.blob(object_name) | ||
|
|
||
| # try: | ||
| # blob.reload() | ||
| # if blob.size >= object_size: | ||
| # logging.info(f"Object {object_name} already exists and has the required size.") | ||
| # return object_name, object_size | ||
| # except Exception: | ||
| # pass | ||
|
|
||
| # logging.info(f"Creating object {object_name} of size {object_size} bytes.") | ||
| # # For large objects, it's better to upload in chunks. | ||
| # # Using urandom is slow, so for large objects, we will write the same chunk over and over. | ||
| # chunk_size = 100 * 1024 * 1024 # 100 MiB | ||
| # data_chunk = os.urandom(chunk_size) | ||
| # num_chunks = object_size // chunk_size | ||
| # remaining_bytes = object_size % chunk_size | ||
|
|
||
| # from io import BytesIO | ||
| # with BytesIO() as f: | ||
| # for _ in range(num_chunks): | ||
| # f.write(data_chunk) | ||
| # if remaining_bytes > 0: | ||
| # f.write(data_chunk[:remaining_bytes]) | ||
|
|
||
| # f.seek(0) | ||
| # blob.upload_from_file(f, size=object_size) | ||
|
|
||
| # logging.info(f"Finished creating object {object_name}.") | ||
| # return object_name, object_size | ||
|
|
||
|
|
||
| # def _create_files(num_files, bucket_name, object_size): | ||
| # """ | ||
| # Create/Upload objects for benchmarking and return a list of their names. | ||
| # """ | ||
| # object_names = [f"{_OBJECT_NAME_PREFIX}_{i}" for i in range(num_files)] | ||
|
|
||
| # args_list = [ | ||
| # (bucket_name, object_names[i], object_size) for i in range(num_files) | ||
| # ] | ||
|
|
||
| # # Don't use a pool to avoid contention writing the same objects. | ||
| # # The check for existence should make this fast on subsequent runs. | ||
| # results = [_upload_worker(arg) for arg in args_list] | ||
|
|
||
| # return [r[0] for r in results] | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def workload_params(request): | ||
| params = request.param | ||
| files_names = [f'fio-go_storage_fio.0.{i}' for i in range(0, params.num_processes)] | ||
| # files_names = _create_files( | ||
| # params.num_processes, # One file per process | ||
| # params.bucket_name, | ||
| # params.file_size_bytes, | ||
| # ) | ||
| return params, files_names | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| # Copyright 2026 Google LLC | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
| import itertools | ||
| import os | ||
| from typing import Dict, List | ||
|
|
||
| import yaml | ||
|
|
||
| try: | ||
| from tests.perf.microbenchmarks.time_based.reads.parameters import ( | ||
| TimeBasedReadParameters, | ||
| ) | ||
| except ModuleNotFoundError: | ||
| from reads.parameters import TimeBasedReadParameters | ||
|
|
||
|
|
||
| def _get_params() -> Dict[str, List[TimeBasedReadParameters]]: | ||
| """Generates a dictionary of benchmark parameters for time based read operations.""" | ||
| params: Dict[str, List[TimeBasedReadParameters]] = {} | ||
| config_path = os.path.join(os.path.dirname(__file__), "config.yaml") | ||
| with open(config_path, "r") as f: | ||
| config = yaml.safe_load(f) | ||
|
|
||
| common_params = config["common"] | ||
| bucket_types = common_params["bucket_types"] | ||
| file_sizes_mib = common_params["file_sizes_mib"] | ||
| chunk_sizes_mib = common_params["chunk_sizes_mib"] | ||
| rounds = common_params["rounds"] | ||
| duration = common_params["duration"] | ||
| warmup_duration = common_params["warmup_duration"] | ||
|
|
||
| bucket_map = { | ||
| "zonal": os.environ.get( | ||
| "DEFAULT_RAPID_ZONAL_BUCKET", | ||
| config["defaults"]["DEFAULT_RAPID_ZONAL_BUCKET"], | ||
| ), | ||
| "regional": os.environ.get( | ||
| "DEFAULT_STANDARD_BUCKET", config["defaults"]["DEFAULT_STANDARD_BUCKET"] | ||
| ), | ||
| } | ||
|
|
||
| for workload in config["workload"]: | ||
| workload_name = workload["name"] | ||
| params[workload_name] = [] | ||
| pattern = workload["pattern"] | ||
| processes = workload["processes"] | ||
| coros = workload["coros"] | ||
|
|
||
| # Create a product of all parameter combinations | ||
| product = itertools.product( | ||
| bucket_types, | ||
| file_sizes_mib, | ||
| chunk_sizes_mib, | ||
| processes, | ||
| coros, | ||
| ) | ||
|
|
||
| for ( | ||
| bucket_type, | ||
| file_size_mib, | ||
| chunk_size_mib, | ||
| num_processes, | ||
| num_coros, | ||
| ) in product: | ||
| file_size_bytes = file_size_mib * 1024 * 1024 | ||
| chunk_size_bytes = chunk_size_mib * 1024 * 1024 | ||
| bucket_name = bucket_map[bucket_type] | ||
|
|
||
| num_files = num_processes * num_coros | ||
|
|
||
| # Create a descriptive name for the parameter set | ||
| name = f"{pattern}_{bucket_type}_{num_processes}p_{file_size_mib}MiB_{chunk_size_mib}MiB" | ||
|
chandra-siri marked this conversation as resolved.
Outdated
|
||
|
|
||
| params[workload_name].append( | ||
| TimeBasedReadParameters( | ||
| name=name, | ||
| workload_name=workload_name, | ||
| pattern=pattern, | ||
| bucket_name=bucket_name, | ||
| bucket_type=bucket_type, | ||
| num_coros=num_coros, | ||
| num_processes=num_processes, | ||
| num_files=num_files, | ||
| rounds=rounds, | ||
| chunk_size_bytes=chunk_size_bytes, | ||
| file_size_bytes=file_size_bytes, | ||
| duration=duration, | ||
| warmup_duration=warmup_duration, | ||
| ) | ||
| ) | ||
| return params | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| common: | ||
| bucket_types: | ||
| - "zonal" | ||
| file_sizes_mib: | ||
| - 10240 # 10GiB | ||
| chunk_sizes_mib: [1, 16, 100, 200] # 16MiB | ||
| rounds: 1 | ||
| duration: 60 # seconds | ||
| warmup_duration: 5 # seconds | ||
|
|
||
| workload: | ||
| ############# multi process multi coroutine ######### | ||
| - name: "read_seq_multi_process" | ||
| pattern: "seq" | ||
| coros: [1] | ||
| processes: [1, 48] | ||
|
|
||
|
|
||
| - name: "read_rand_multi_process" | ||
| pattern: "rand" | ||
| coros: [1] | ||
| processes: [1, 48] | ||
|
|
||
| defaults: | ||
| DEFAULT_RAPID_ZONAL_BUCKET: "chandrasiri-benchmarks-zb" | ||
| DEFAULT_STANDARD_BUCKET: "chandrasiri-benchmarks-rb" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| # Copyright 2026 Google LLC | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
| from dataclasses import dataclass | ||
| from tests.perf.microbenchmarks.parameters import IOBenchmarkParameters | ||
|
|
||
|
|
||
| @dataclass | ||
| class TimeBasedReadParameters(IOBenchmarkParameters): | ||
| pattern: str | ||
| duration: int | ||
| warmup_duration: int |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.