1*5dda2efdSMircea Trofin# Copyright 2020 Google Inc. All rights reserved. 2*5dda2efdSMircea Trofin# 3*5dda2efdSMircea Trofin# Licensed under the Apache License, Version 2.0 (the "License"); 4*5dda2efdSMircea Trofin# you may not use this file except in compliance with the License. 5*5dda2efdSMircea Trofin# You may obtain a copy of the License at 6*5dda2efdSMircea Trofin# 7*5dda2efdSMircea Trofin# http://www.apache.org/licenses/LICENSE-2.0 8*5dda2efdSMircea Trofin# 9*5dda2efdSMircea Trofin# Unless required by applicable law or agreed to in writing, software 10*5dda2efdSMircea Trofin# distributed under the License is distributed on an "AS IS" BASIS, 11*5dda2efdSMircea Trofin# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*5dda2efdSMircea Trofin# See the License for the specific language governing permissions and 13*5dda2efdSMircea Trofin# limitations under the License. 14*5dda2efdSMircea Trofin"""Python benchmarking utilities. 15*5dda2efdSMircea Trofin 16*5dda2efdSMircea TrofinExample usage: 17*5dda2efdSMircea Trofin import google_benchmark as benchmark 18*5dda2efdSMircea Trofin 19*5dda2efdSMircea Trofin @benchmark.register 20*5dda2efdSMircea Trofin def my_benchmark(state): 21*5dda2efdSMircea Trofin ... # Code executed outside `while` loop is not timed. 22*5dda2efdSMircea Trofin 23*5dda2efdSMircea Trofin while state: 24*5dda2efdSMircea Trofin ... # Code executed within `while` loop is timed. 25*5dda2efdSMircea Trofin 26*5dda2efdSMircea Trofin if __name__ == '__main__': 27*5dda2efdSMircea Trofin benchmark.main() 28*5dda2efdSMircea Trofin""" 29*5dda2efdSMircea Trofin 30*5dda2efdSMircea Trofinfrom absl import app 31*5dda2efdSMircea Trofinfrom google_benchmark import _benchmark 32*5dda2efdSMircea Trofinfrom google_benchmark._benchmark import ( 33*5dda2efdSMircea Trofin Counter, 34*5dda2efdSMircea Trofin kNanosecond, 35*5dda2efdSMircea Trofin kMicrosecond, 36*5dda2efdSMircea Trofin kMillisecond, 37*5dda2efdSMircea Trofin kSecond, 38*5dda2efdSMircea Trofin oNone, 39*5dda2efdSMircea Trofin o1, 40*5dda2efdSMircea Trofin oN, 41*5dda2efdSMircea Trofin oNSquared, 42*5dda2efdSMircea Trofin oNCubed, 43*5dda2efdSMircea Trofin oLogN, 44*5dda2efdSMircea Trofin oNLogN, 45*5dda2efdSMircea Trofin oAuto, 46*5dda2efdSMircea Trofin oLambda, 47*5dda2efdSMircea Trofin) 48*5dda2efdSMircea Trofin 49*5dda2efdSMircea Trofin 50*5dda2efdSMircea Trofin__all__ = [ 51*5dda2efdSMircea Trofin "register", 52*5dda2efdSMircea Trofin "main", 53*5dda2efdSMircea Trofin "Counter", 54*5dda2efdSMircea Trofin "kNanosecond", 55*5dda2efdSMircea Trofin "kMicrosecond", 56*5dda2efdSMircea Trofin "kMillisecond", 57*5dda2efdSMircea Trofin "kSecond", 58*5dda2efdSMircea Trofin "oNone", 59*5dda2efdSMircea Trofin "o1", 60*5dda2efdSMircea Trofin "oN", 61*5dda2efdSMircea Trofin "oNSquared", 62*5dda2efdSMircea Trofin "oNCubed", 63*5dda2efdSMircea Trofin "oLogN", 64*5dda2efdSMircea Trofin "oNLogN", 65*5dda2efdSMircea Trofin "oAuto", 66*5dda2efdSMircea Trofin "oLambda", 67*5dda2efdSMircea Trofin] 68*5dda2efdSMircea Trofin 69*5dda2efdSMircea Trofin__version__ = "0.2.0" 70*5dda2efdSMircea Trofin 71*5dda2efdSMircea Trofin 72*5dda2efdSMircea Trofinclass __OptionMaker: 73*5dda2efdSMircea Trofin """A stateless class to collect benchmark options. 74*5dda2efdSMircea Trofin 75*5dda2efdSMircea Trofin Collect all decorator calls like @option.range(start=0, limit=1<<5). 76*5dda2efdSMircea Trofin """ 77*5dda2efdSMircea Trofin 78*5dda2efdSMircea Trofin class Options: 79*5dda2efdSMircea Trofin """Pure data class to store options calls, along with the benchmarked function.""" 80*5dda2efdSMircea Trofin 81*5dda2efdSMircea Trofin def __init__(self, func): 82*5dda2efdSMircea Trofin self.func = func 83*5dda2efdSMircea Trofin self.builder_calls = [] 84*5dda2efdSMircea Trofin 85*5dda2efdSMircea Trofin @classmethod 86*5dda2efdSMircea Trofin def make(cls, func_or_options): 87*5dda2efdSMircea Trofin """Make Options from Options or the benchmarked function.""" 88*5dda2efdSMircea Trofin if isinstance(func_or_options, cls.Options): 89*5dda2efdSMircea Trofin return func_or_options 90*5dda2efdSMircea Trofin return cls.Options(func_or_options) 91*5dda2efdSMircea Trofin 92*5dda2efdSMircea Trofin def __getattr__(self, builder_name): 93*5dda2efdSMircea Trofin """Append option call in the Options.""" 94*5dda2efdSMircea Trofin 95*5dda2efdSMircea Trofin # The function that get returned on @option.range(start=0, limit=1<<5). 96*5dda2efdSMircea Trofin def __builder_method(*args, **kwargs): 97*5dda2efdSMircea Trofin 98*5dda2efdSMircea Trofin # The decorator that get called, either with the benchmared function 99*5dda2efdSMircea Trofin # or the previous Options 100*5dda2efdSMircea Trofin def __decorator(func_or_options): 101*5dda2efdSMircea Trofin options = self.make(func_or_options) 102*5dda2efdSMircea Trofin options.builder_calls.append((builder_name, args, kwargs)) 103*5dda2efdSMircea Trofin # The decorator returns Options so it is not technically a decorator 104*5dda2efdSMircea Trofin # and needs a final call to @regiser 105*5dda2efdSMircea Trofin return options 106*5dda2efdSMircea Trofin 107*5dda2efdSMircea Trofin return __decorator 108*5dda2efdSMircea Trofin 109*5dda2efdSMircea Trofin return __builder_method 110*5dda2efdSMircea Trofin 111*5dda2efdSMircea Trofin 112*5dda2efdSMircea Trofin# Alias for nicer API. 113*5dda2efdSMircea Trofin# We have to instantiate an object, even if stateless, to be able to use __getattr__ 114*5dda2efdSMircea Trofin# on option.range 115*5dda2efdSMircea Trofinoption = __OptionMaker() 116*5dda2efdSMircea Trofin 117*5dda2efdSMircea Trofin 118*5dda2efdSMircea Trofindef register(undefined=None, *, name=None): 119*5dda2efdSMircea Trofin """Register function for benchmarking.""" 120*5dda2efdSMircea Trofin if undefined is None: 121*5dda2efdSMircea Trofin # Decorator is called without parenthesis so we return a decorator 122*5dda2efdSMircea Trofin return lambda f: register(f, name=name) 123*5dda2efdSMircea Trofin 124*5dda2efdSMircea Trofin # We have either the function to benchmark (simple case) or an instance of Options 125*5dda2efdSMircea Trofin # (@option._ case). 126*5dda2efdSMircea Trofin options = __OptionMaker.make(undefined) 127*5dda2efdSMircea Trofin 128*5dda2efdSMircea Trofin if name is None: 129*5dda2efdSMircea Trofin name = options.func.__name__ 130*5dda2efdSMircea Trofin 131*5dda2efdSMircea Trofin # We register the benchmark and reproduce all the @option._ calls onto the 132*5dda2efdSMircea Trofin # benchmark builder pattern 133*5dda2efdSMircea Trofin benchmark = _benchmark.RegisterBenchmark(name, options.func) 134*5dda2efdSMircea Trofin for name, args, kwargs in options.builder_calls[::-1]: 135*5dda2efdSMircea Trofin getattr(benchmark, name)(*args, **kwargs) 136*5dda2efdSMircea Trofin 137*5dda2efdSMircea Trofin # return the benchmarked function because the decorator does not modify it 138*5dda2efdSMircea Trofin return options.func 139*5dda2efdSMircea Trofin 140*5dda2efdSMircea Trofin 141*5dda2efdSMircea Trofindef _flags_parser(argv): 142*5dda2efdSMircea Trofin argv = _benchmark.Initialize(argv) 143*5dda2efdSMircea Trofin return app.parse_flags_with_usage(argv) 144*5dda2efdSMircea Trofin 145*5dda2efdSMircea Trofin 146*5dda2efdSMircea Trofindef _run_benchmarks(argv): 147*5dda2efdSMircea Trofin if len(argv) > 1: 148*5dda2efdSMircea Trofin raise app.UsageError("Too many command-line arguments.") 149*5dda2efdSMircea Trofin return _benchmark.RunSpecifiedBenchmarks() 150*5dda2efdSMircea Trofin 151*5dda2efdSMircea Trofin 152*5dda2efdSMircea Trofindef main(argv=None): 153*5dda2efdSMircea Trofin return app.run(_run_benchmarks, argv=argv, flags_parser=_flags_parser) 154*5dda2efdSMircea Trofin 155*5dda2efdSMircea Trofin 156*5dda2efdSMircea Trofin# Methods for use with custom main function. 157*5dda2efdSMircea Trofininitialize = _benchmark.Initialize 158*5dda2efdSMircea Trofinrun_benchmarks = _benchmark.RunSpecifiedBenchmarks 159