1 # Copyright 2020 Google Inc. All rights reserved.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 """Python benchmarking utilities.
17 import google_benchmark as benchmark
20 def my_benchmark(state):
21 ... # Code executed outside `while` loop is not timed.
24 ... # Code executed within `while` loop is timed.
26 if __name__ == '__main__':
31 from google_benchmark
import _benchmark
32 from google_benchmark
._benchmark
import (
73 """A stateless class to collect benchmark options.
75 Collect all decorator calls like @option.range(start=0, limit=1<<5).
79 """Pure data class to store options calls, along with the benchmarked function."""
81 def __init__(self
, func
):
83 self
.builder_calls
= []
86 def make(cls
, func_or_options
):
87 """Make Options from Options or the benchmarked function."""
88 if isinstance(func_or_options
, cls
.Options
):
89 return func_or_options
90 return cls
.Options(func_or_options
)
92 def __getattr__(self
, builder_name
):
93 """Append option call in the Options."""
95 # The function that get returned on @option.range(start=0, limit=1<<5).
96 def __builder_method(*args
, **kwargs
):
98 # The decorator that get called, either with the benchmared function
99 # or the previous Options
100 def __decorator(func_or_options
):
101 options
= self
.make(func_or_options
)
102 options
.builder_calls
.append((builder_name
, args
, kwargs
))
103 # The decorator returns Options so it is not technically a decorator
104 # and needs a final call to @regiser
109 return __builder_method
112 # Alias for nicer API.
113 # We have to instantiate an object, even if stateless, to be able to use __getattr__
115 option
= __OptionMaker()
118 def register(undefined
=None, *, name
=None):
119 """Register function for benchmarking."""
120 if undefined
is None:
121 # Decorator is called without parenthesis so we return a decorator
122 return lambda f
: register(f
, name
=name
)
124 # We have either the function to benchmark (simple case) or an instance of Options
126 options
= __OptionMaker
.make(undefined
)
129 name
= options
.func
.__name
__
131 # We register the benchmark and reproduce all the @option._ calls onto the
132 # benchmark builder pattern
133 benchmark
= _benchmark
.RegisterBenchmark(name
, options
.func
)
134 for name
, args
, kwargs
in options
.builder_calls
[::-1]:
135 getattr(benchmark
, name
)(*args
, **kwargs
)
137 # return the benchmarked function because the decorator does not modify it
141 def _flags_parser(argv
):
142 argv
= _benchmark
.Initialize(argv
)
143 return app
.parse_flags_with_usage(argv
)
146 def _run_benchmarks(argv
):
148 raise app
.UsageError("Too many command-line arguments.")
149 return _benchmark
.RunSpecifiedBenchmarks()
153 return app
.run(_run_benchmarks
, argv
=argv
, flags_parser
=_flags_parser
)
156 # Methods for use with custom main function.
157 initialize
= _benchmark
.Initialize
158 run_benchmarks
= _benchmark
.RunSpecifiedBenchmarks