Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion tests/perf/microbenchmarks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@ pytest --benchmark-json=output.json -vv -s tests/perf/microbenchmarks/reads/test

To run a single test, append `::` followed by the test name to the file path.

Example:
Examples:
```bash
pytest --benchmark-json=output.json -vv -s tests/perf/microbenchmarks/reads/test_reads.py::test_downloads_single_proc_single_coro
```
```bash
pytest --benchmark-json=output.json -vv -s tests/perf/microbenchmarks/writes/test_writes.py::test_uploads_single_proc_single_coro
```

## Configuration

Expand Down
19 changes: 13 additions & 6 deletions tests/perf/microbenchmarks/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
AsyncAppendableObjectWriter,
)
from google.cloud.storage._experimental.asyncio.async_grpc_client import AsyncGrpcClient
from tests.perf.microbenchmarks.writes.parameters import WriteParameters

_OBJECT_NAME_PREFIX = "micro-benchmark"

Expand Down Expand Up @@ -135,10 +136,16 @@ def _create_files(num_files, bucket_name, bucket_type, object_size, chunk_size=1
@pytest.fixture
def workload_params(request):
params = request.param
files_names = _create_files(
params.num_files,
params.bucket_name,
params.bucket_type,
params.file_size_bytes,
)
if isinstance(params, WriteParameters):
files_names = [
f"{_OBJECT_NAME_PREFIX}-{uuid.uuid4().hex[:5]}"
for _ in range(params.num_files)
]
else:
files_names = _create_files(
params.num_files,
params.bucket_name,
params.bucket_type,
params.file_size_bytes,
)
return params, files_names
Empty file.
100 changes: 100 additions & 0 deletions tests/perf/microbenchmarks/writes/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# 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.writes.parameters import WriteParameters
except ModuleNotFoundError:
from parameters import WriteParameters


def get_write_params() -> Dict[str, List[WriteParameters]]:
"""Generates benchmark parameters from a YAML configuration file.

This function reads the configuration from `config.yaml`, located in the
same directory, and generates all possible combinations of write parameters
based on the defined workloads. It uses `itertools.product` to create
a Cartesian product of parameters like bucket types, file sizes, etc.

Returns:
Dict[str, List[WriteParameters]]: A dictionary where keys are workload
names and values are lists of `WriteParameters` instances for that
workload.
"""
params: Dict[str, List[WriteParameters]] = {}
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"]

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] = []
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"{workload_name}_{bucket_type}_{num_processes}p_{num_coros}c"

params[workload_name].append(
WriteParameters(
name=name,
workload_name=workload_name,
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,
)
)
return params
34 changes: 34 additions & 0 deletions tests/perf/microbenchmarks/writes/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
common:
bucket_types:
- "regional"
- "zonal"
file_sizes_mib:
- 1024 # 1GiB
chunk_sizes_mib: [100]
rounds: 10

workload:

############# single proc single coroutines #########
- name: "write_seq"
pattern: "seq"
coros: [1]
processes: [1]

############# single proc multiple coroutines #########

- name: "write_seq_multi_coros"
pattern: "seq"
coros: [2, 4, 8, 16]
processes: [1]

############# multiple proc multiple coroutines #########
- name: "write_seq_multi_process"
pattern: "seq"
coros: [1, 2]
processes: [8, 16, 32, 64]


defaults:
DEFAULT_RAPID_ZONAL_BUCKET: "chandrasiri-benchmarks-zb"
DEFAULT_STANDARD_BUCKET: "chandrasiri-benchmarks-rb"
20 changes: 20 additions & 0 deletions tests/perf/microbenchmarks/writes/parameters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# 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 ..parameters import IOBenchmarkParameters


@dataclass
class WriteParameters(IOBenchmarkParameters):
pass
Loading