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