message_benchmark.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. """Benchmarks for assigning large NumPy data to protobuf fields."""
  2. from collections.abc import Callable
  3. import functools
  4. import sys
  5. import google_benchmark
  6. import numpy as np
  7. from google.protobuf import unittest_pb2
  8. @functools.cache
  9. def make_array(num_bytes: int):
  10. return np.zeros(shape=(num_bytes,), dtype=np.uint8)
  11. def benchmark(
  12. func: Callable[[google_benchmark.State], None],
  13. ) -> Callable[[google_benchmark.State], None]:
  14. """Decorates a function for benchmarking."""
  15. @google_benchmark.register
  16. @google_benchmark.option.unit(google_benchmark.kMillisecond)
  17. @google_benchmark.option.arg_names(['num_bytes'])
  18. @google_benchmark.option.arg(1024 * 1024 * 20)
  19. @google_benchmark.option.arg(1024 * 1024 * 100)
  20. @functools.wraps(func)
  21. def wrapper(state: google_benchmark.State) -> None:
  22. func(state)
  23. state.bytes_processed = state.iterations * state.range(0)
  24. return wrapper
  25. @benchmark
  26. def bench_build_message_via_slice(state: google_benchmark.State):
  27. arr = make_array(state.range(0)).view(dtype=np.int32)
  28. while state:
  29. msg = unittest_pb2.TestAllTypes()
  30. msg.repeated_int32[:] = arr
  31. @benchmark
  32. def bench_build_message(state: google_benchmark.State):
  33. arr = make_array(state.range(0)).view(dtype=np.int32)
  34. while state:
  35. _ = unittest_pb2.TestAllTypes(repeated_int32=arr)
  36. @benchmark
  37. def bench_build_message_nested_via_slice(state: google_benchmark.State):
  38. arr = make_array(state.range(0)).view(dtype=np.int32)
  39. while state:
  40. msg = unittest_pb2.NestedTestAllTypes()
  41. msg.payload.repeated_int32[:] = arr
  42. @benchmark
  43. def bench_build_nested_message_dict(state: google_benchmark.State):
  44. arr = make_array(state.range(0)).view(dtype=np.int32)
  45. while state:
  46. _ = unittest_pb2.NestedTestAllTypes(payload=dict(repeated_int32=arr))
  47. @benchmark
  48. def bench_build_nested_message_int32(state: google_benchmark.State):
  49. arr = make_array(state.range(0)).view(dtype=np.int32)
  50. while state:
  51. _ = unittest_pb2.NestedTestAllTypes(
  52. payload=unittest_pb2.TestAllTypes(repeated_int32=arr)
  53. )
  54. @benchmark
  55. def bench_build_nested_message_cord(state: google_benchmark.State):
  56. chunk_size = state.range(0) // 1000
  57. strings = ['a' * chunk_size] * 1000
  58. while state:
  59. _ = unittest_pb2.NestedTestAllTypes(
  60. payload=unittest_pb2.TestAllTypes(repeated_cord=strings)
  61. )
  62. @benchmark
  63. def bench_build_nested_message_string_piece(state: google_benchmark.State):
  64. chunk_size = state.range(0) // 1000
  65. strings = ['a' * chunk_size] * 1000
  66. while state:
  67. _ = unittest_pb2.NestedTestAllTypes(
  68. payload=unittest_pb2.TestAllTypes(repeated_string_piece=strings)
  69. )
  70. @benchmark
  71. def bench_build_nested_message_nested_message(state: google_benchmark.State):
  72. subs = [unittest_pb2.TestAllTypes.NestedMessage(bb=123)] * (
  73. state.range(0) // 8
  74. )
  75. while state:
  76. _ = unittest_pb2.NestedTestAllTypes(
  77. payload=unittest_pb2.TestAllTypes(repeated_nested_message=subs)
  78. )
  79. @benchmark
  80. def bench_assign_repeated_float(state: google_benchmark.State):
  81. arr = make_array(state.range(0)).view(dtype=np.float32)
  82. msg = unittest_pb2.TestAllTypes()
  83. msg_source = unittest_pb2.TestAllTypes()
  84. msg_source.repeated_float.extend(arr)
  85. while state:
  86. state.pause_timing()
  87. msg.Clear()
  88. state.resume_timing()
  89. msg.repeated_float[:] = msg_source.repeated_float
  90. @benchmark
  91. def bench_assign_repeated_int64_to_int32(state: google_benchmark.State):
  92. arr = make_array(state.range(0)).view(dtype=np.int64)
  93. msg = unittest_pb2.TestAllTypes()
  94. msg_source = unittest_pb2.TestAllTypes()
  95. msg_source.repeated_int64.extend(arr)
  96. while state:
  97. state.pause_timing()
  98. msg.Clear()
  99. state.resume_timing()
  100. msg.repeated_int32[:] = msg_source.repeated_int64
  101. @benchmark
  102. def bench_assign_repeated_double_to_float(state: google_benchmark.State):
  103. arr = make_array(state.range(0)).view(dtype=np.float64)
  104. msg = unittest_pb2.TestAllTypes()
  105. msg_source = unittest_pb2.TestAllTypes()
  106. msg_source.repeated_double.extend(arr)
  107. while state:
  108. state.pause_timing()
  109. msg.Clear()
  110. state.resume_timing()
  111. msg.repeated_float[:] = msg_source.repeated_double
  112. @benchmark
  113. def bench_assign_numpy_int64_to_int32(state: google_benchmark.State):
  114. arr = make_array(state.range(0)).view(dtype=np.int64)
  115. msg = unittest_pb2.TestAllTypes()
  116. while state:
  117. state.pause_timing()
  118. msg.Clear()
  119. state.resume_timing()
  120. msg.repeated_int32[:] = arr
  121. @benchmark
  122. def bench_assign_numpy_double_to_float(state: google_benchmark.State):
  123. arr = make_array(state.range(0)).view(dtype=np.float64)
  124. msg = unittest_pb2.TestAllTypes()
  125. while state:
  126. state.pause_timing()
  127. msg.Clear()
  128. state.resume_timing()
  129. msg.repeated_float[:] = arr
  130. @benchmark
  131. def bench_extend_int32(state: google_benchmark.State):
  132. arr = make_array(state.range(0)).view(dtype=np.int32)
  133. msg = unittest_pb2.TestAllTypes()
  134. while state:
  135. state.pause_timing()
  136. msg.Clear()
  137. state.resume_timing()
  138. msg.repeated_int32.extend(arr)
  139. @benchmark
  140. def bench_decode_from_bytes(state: google_benchmark.State):
  141. arr = make_array(state.range(0))
  142. msg = unittest_pb2.TestAllTypes()
  143. msg.optional_bytes = memoryview(arr)
  144. msg_bytes = msg.SerializeToString()
  145. while state:
  146. _ = unittest_pb2.TestAllTypes.FromString(msg_bytes)
  147. @benchmark
  148. def bench_decode_from_memoryview(state: google_benchmark.State):
  149. arr = make_array(state.range(0))
  150. msg = unittest_pb2.TestAllTypes()
  151. msg.optional_bytes = memoryview(arr)
  152. msg_bytes = memoryview(msg.SerializeToString())
  153. while state:
  154. _ = unittest_pb2.TestAllTypes.FromString(msg_bytes)
  155. @benchmark
  156. def bench_encode_into_bytes(state: google_benchmark.State):
  157. arr = make_array(state.range(0))
  158. msg = unittest_pb2.TestAllTypes()
  159. msg.optional_bytes = memoryview(arr)
  160. while state:
  161. _ = msg.SerializeToString()
  162. @benchmark
  163. def bench_assign_int32(state: google_benchmark.State):
  164. arr = make_array(state.range(0)).view(dtype=np.int32)
  165. msg = unittest_pb2.TestAllTypes()
  166. while state:
  167. msg.repeated_int32[:] = arr
  168. state.pause_timing()
  169. msg.Clear()
  170. state.resume_timing()
  171. @benchmark
  172. def bench_assign_extend_int32(state: google_benchmark.State):
  173. arr = make_array(state.range(0)).view(dtype=np.int32)
  174. msg = unittest_pb2.TestAllTypes()
  175. msg.repeated_int32[:] = arr
  176. while state:
  177. msg.repeated_int32[len(arr) :] = arr
  178. state.pause_timing()
  179. msg.repeated_int32[:] = arr
  180. state.resume_timing()
  181. @benchmark
  182. def bench_assign_slice_int32(state: google_benchmark.State):
  183. arr = make_array(state.range(0)).view(dtype=np.int32)
  184. half_arr = arr[: len(arr) // 2]
  185. msg = unittest_pb2.TestAllTypes()
  186. msg.repeated_int32.extend(arr)
  187. while state:
  188. msg.repeated_int32[::2] = half_arr
  189. @benchmark
  190. def bench_extend_int64(state: google_benchmark.State):
  191. arr = make_array(state.range(0)).view(dtype=np.int64)
  192. msg = unittest_pb2.TestAllTypes()
  193. while state:
  194. state.pause_timing()
  195. msg.Clear()
  196. state.resume_timing()
  197. msg.repeated_int64.extend(arr)
  198. @benchmark
  199. def bench_extend_float(state: google_benchmark.State):
  200. arr = make_array(state.range(0)).view(dtype=np.float32)
  201. msg = unittest_pb2.TestAllTypes()
  202. while state:
  203. state.pause_timing()
  204. msg.Clear()
  205. state.resume_timing()
  206. msg.repeated_float.extend(arr)
  207. @benchmark
  208. def bench_extend_double(state: google_benchmark.State):
  209. arr = make_array(state.range(0)).view(dtype=np.float64)
  210. msg = unittest_pb2.TestAllTypes()
  211. while state:
  212. state.pause_timing()
  213. msg.Clear()
  214. state.resume_timing()
  215. msg.repeated_double.extend(arr)
  216. @benchmark
  217. def bench_assign_bytes(state: google_benchmark.State):
  218. arr = make_array(state.range(0))
  219. msg = unittest_pb2.TestAllTypes()
  220. arr_bytes = arr.tobytes()
  221. while state:
  222. state.pause_timing()
  223. msg.Clear()
  224. state.resume_timing()
  225. msg.optional_bytes = arr_bytes
  226. @benchmark
  227. def bench_assign_bytes_with_conversion(state: google_benchmark.State):
  228. arr = make_array(state.range(0))
  229. msg = unittest_pb2.TestAllTypes()
  230. while state:
  231. state.pause_timing()
  232. msg.Clear()
  233. state.resume_timing()
  234. msg.optional_bytes = memoryview(arr)
  235. if __name__ == '__main__':
  236. if any(arg.startswith('--benchmark_filter') for arg in sys.argv):
  237. google_benchmark.main()
  238. else:
  239. print('No benchmark filter specified. Skipping benchmarks.')