| """Benchmarks for assigning large NumPy data to protobuf fields.""" | |
| from collections.abc import Callable | |
| import functools | |
| import sys | |
| import google_benchmark | |
| import numpy as np | |
| from google.protobuf import unittest_pb2 | |
| @functools.cache | |
| def make_array(num_bytes: int): | |
| return np.zeros(shape=(num_bytes,), dtype=np.uint8) | |
| def benchmark( | |
| func: Callable[[google_benchmark.State], None], | |
| ) -> Callable[[google_benchmark.State], None]: | |
| """Decorates a function for benchmarking.""" | |
| @google_benchmark.register | |
| @google_benchmark.option.unit(google_benchmark.kMillisecond) | |
| @google_benchmark.option.arg_names(['num_bytes']) | |
| @google_benchmark.option.arg(1024 * 1024 * 20) | |
| @google_benchmark.option.arg(1024 * 1024 * 100) | |
| @functools.wraps(func) | |
| def wrapper(state: google_benchmark.State) -> None: | |
| func(state) | |
| state.bytes_processed = state.iterations * state.range(0) | |
| return wrapper | |
| @benchmark | |
| def bench_build_message_via_slice(state: google_benchmark.State): | |
| arr = make_array(state.range(0)).view(dtype=np.int32) | |
| while state: | |
| msg = unittest_pb2.TestAllTypes() | |
| msg.repeated_int32[:] = arr | |
| @benchmark | |
| def bench_build_message(state: google_benchmark.State): | |
| arr = make_array(state.range(0)).view(dtype=np.int32) | |
| while state: | |
| _ = unittest_pb2.TestAllTypes(repeated_int32=arr) | |
| @benchmark | |
| def bench_build_message_nested_via_slice(state: google_benchmark.State): | |
| arr = make_array(state.range(0)).view(dtype=np.int32) | |
| while state: | |
| msg = unittest_pb2.NestedTestAllTypes() | |
| msg.payload.repeated_int32[:] = arr | |
| @benchmark | |
| def bench_build_nested_message_dict(state: google_benchmark.State): | |
| arr = make_array(state.range(0)).view(dtype=np.int32) | |
| while state: | |
| _ = unittest_pb2.NestedTestAllTypes(payload=dict(repeated_int32=arr)) | |
| @benchmark | |
| def bench_build_nested_message_int32(state: google_benchmark.State): | |
| arr = make_array(state.range(0)).view(dtype=np.int32) | |
| while state: | |
| _ = unittest_pb2.NestedTestAllTypes( | |
| payload=unittest_pb2.TestAllTypes(repeated_int32=arr) | |
| ) | |
| @benchmark | |
| def bench_build_nested_message_cord(state: google_benchmark.State): | |
| chunk_size = state.range(0) // 1000 | |
| strings = ['a' * chunk_size] * 1000 | |
| while state: | |
| _ = unittest_pb2.NestedTestAllTypes( | |
| payload=unittest_pb2.TestAllTypes(repeated_cord=strings) | |
| ) | |
| @benchmark | |
| def bench_build_nested_message_string_piece(state: google_benchmark.State): | |
| chunk_size = state.range(0) // 1000 | |
| strings = ['a' * chunk_size] * 1000 | |
| while state: | |
| _ = unittest_pb2.NestedTestAllTypes( | |
| payload=unittest_pb2.TestAllTypes(repeated_string_piece=strings) | |
| ) | |
| @benchmark | |
| def bench_build_nested_message_nested_message(state: google_benchmark.State): | |
| subs = [unittest_pb2.TestAllTypes.NestedMessage(bb=123)] * ( | |
| state.range(0) // 8 | |
| ) | |
| while state: | |
| _ = unittest_pb2.NestedTestAllTypes( | |
| payload=unittest_pb2.TestAllTypes(repeated_nested_message=subs) | |
| ) | |
| @benchmark | |
| def bench_assign_repeated_float(state: google_benchmark.State): | |
| arr = make_array(state.range(0)).view(dtype=np.float32) | |
| msg = unittest_pb2.TestAllTypes() | |
| msg_source = unittest_pb2.TestAllTypes() | |
| msg_source.repeated_float.extend(arr) | |
| while state: | |
| state.pause_timing() | |
| msg.Clear() | |
| state.resume_timing() | |
| msg.repeated_float[:] = msg_source.repeated_float | |
| @benchmark | |
| def bench_assign_repeated_int64_to_int32(state: google_benchmark.State): | |
| arr = make_array(state.range(0)).view(dtype=np.int64) | |
| msg = unittest_pb2.TestAllTypes() | |
| msg_source = unittest_pb2.TestAllTypes() | |
| msg_source.repeated_int64.extend(arr) | |
| while state: | |
| state.pause_timing() | |
| msg.Clear() | |
| state.resume_timing() | |
| msg.repeated_int32[:] = msg_source.repeated_int64 | |
| @benchmark | |
| def bench_assign_repeated_double_to_float(state: google_benchmark.State): | |
| arr = make_array(state.range(0)).view(dtype=np.float64) | |
| msg = unittest_pb2.TestAllTypes() | |
| msg_source = unittest_pb2.TestAllTypes() | |
| msg_source.repeated_double.extend(arr) | |
| while state: | |
| state.pause_timing() | |
| msg.Clear() | |
| state.resume_timing() | |
| msg.repeated_float[:] = msg_source.repeated_double | |
| @benchmark | |
| def bench_assign_numpy_int64_to_int32(state: google_benchmark.State): | |
| arr = make_array(state.range(0)).view(dtype=np.int64) | |
| msg = unittest_pb2.TestAllTypes() | |
| while state: | |
| state.pause_timing() | |
| msg.Clear() | |
| state.resume_timing() | |
| msg.repeated_int32[:] = arr | |
| @benchmark | |
| def bench_assign_numpy_double_to_float(state: google_benchmark.State): | |
| arr = make_array(state.range(0)).view(dtype=np.float64) | |
| msg = unittest_pb2.TestAllTypes() | |
| while state: | |
| state.pause_timing() | |
| msg.Clear() | |
| state.resume_timing() | |
| msg.repeated_float[:] = arr | |
| @benchmark | |
| def bench_extend_int32(state: google_benchmark.State): | |
| arr = make_array(state.range(0)).view(dtype=np.int32) | |
| msg = unittest_pb2.TestAllTypes() | |
| while state: | |
| state.pause_timing() | |
| msg.Clear() | |
| state.resume_timing() | |
| msg.repeated_int32.extend(arr) | |
| @benchmark | |
| def bench_decode_from_bytes(state: google_benchmark.State): | |
| arr = make_array(state.range(0)) | |
| msg = unittest_pb2.TestAllTypes() | |
| msg.optional_bytes = memoryview(arr) | |
| msg_bytes = msg.SerializeToString() | |
| while state: | |
| _ = unittest_pb2.TestAllTypes.FromString(msg_bytes) | |
| @benchmark | |
| def bench_decode_from_memoryview(state: google_benchmark.State): | |
| arr = make_array(state.range(0)) | |
| msg = unittest_pb2.TestAllTypes() | |
| msg.optional_bytes = memoryview(arr) | |
| msg_bytes = memoryview(msg.SerializeToString()) | |
| while state: | |
| _ = unittest_pb2.TestAllTypes.FromString(msg_bytes) | |
| @benchmark | |
| def bench_encode_into_bytes(state: google_benchmark.State): | |
| arr = make_array(state.range(0)) | |
| msg = unittest_pb2.TestAllTypes() | |
| msg.optional_bytes = memoryview(arr) | |
| while state: | |
| _ = msg.SerializeToString() | |
| @benchmark | |
| def bench_assign_int32(state: google_benchmark.State): | |
| arr = make_array(state.range(0)).view(dtype=np.int32) | |
| msg = unittest_pb2.TestAllTypes() | |
| while state: | |
| msg.repeated_int32[:] = arr | |
| state.pause_timing() | |
| msg.Clear() | |
| state.resume_timing() | |
| @benchmark | |
| def bench_assign_extend_int32(state: google_benchmark.State): | |
| arr = make_array(state.range(0)).view(dtype=np.int32) | |
| msg = unittest_pb2.TestAllTypes() | |
| msg.repeated_int32[:] = arr | |
| while state: | |
| msg.repeated_int32[len(arr) :] = arr | |
| state.pause_timing() | |
| msg.repeated_int32[:] = arr | |
| state.resume_timing() | |
| @benchmark | |
| def bench_assign_slice_int32(state: google_benchmark.State): | |
| arr = make_array(state.range(0)).view(dtype=np.int32) | |
| half_arr = arr[: len(arr) // 2] | |
| msg = unittest_pb2.TestAllTypes() | |
| msg.repeated_int32.extend(arr) | |
| while state: | |
| msg.repeated_int32[::2] = half_arr | |
| @benchmark | |
| def bench_extend_int64(state: google_benchmark.State): | |
| arr = make_array(state.range(0)).view(dtype=np.int64) | |
| msg = unittest_pb2.TestAllTypes() | |
| while state: | |
| state.pause_timing() | |
| msg.Clear() | |
| state.resume_timing() | |
| msg.repeated_int64.extend(arr) | |
| @benchmark | |
| def bench_extend_float(state: google_benchmark.State): | |
| arr = make_array(state.range(0)).view(dtype=np.float32) | |
| msg = unittest_pb2.TestAllTypes() | |
| while state: | |
| state.pause_timing() | |
| msg.Clear() | |
| state.resume_timing() | |
| msg.repeated_float.extend(arr) | |
| @benchmark | |
| def bench_extend_double(state: google_benchmark.State): | |
| arr = make_array(state.range(0)).view(dtype=np.float64) | |
| msg = unittest_pb2.TestAllTypes() | |
| while state: | |
| state.pause_timing() | |
| msg.Clear() | |
| state.resume_timing() | |
| msg.repeated_double.extend(arr) | |
| @benchmark | |
| def bench_assign_bytes(state: google_benchmark.State): | |
| arr = make_array(state.range(0)) | |
| msg = unittest_pb2.TestAllTypes() | |
| arr_bytes = arr.tobytes() | |
| while state: | |
| state.pause_timing() | |
| msg.Clear() | |
| state.resume_timing() | |
| msg.optional_bytes = arr_bytes | |
| @benchmark | |
| def bench_assign_bytes_with_conversion(state: google_benchmark.State): | |
| arr = make_array(state.range(0)) | |
| msg = unittest_pb2.TestAllTypes() | |
| while state: | |
| state.pause_timing() | |
| msg.Clear() | |
| state.resume_timing() | |
| msg.optional_bytes = memoryview(arr) | |
| if __name__ == '__main__': | |
| if any(arg.startswith('--benchmark_filter') for arg in sys.argv): | |
| google_benchmark.main() | |
| else: | |
| print('No benchmark filter specified. Skipping benchmarks.') |