xref: /aosp_15_r20/external/pigweed/pw_perf_test/docs.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker.. _module-pw_perf_test:
2*61c4878aSAndroid Build Coastguard Worker
3*61c4878aSAndroid Build Coastguard Worker============
4*61c4878aSAndroid Build Coastguard Workerpw_perf_test
5*61c4878aSAndroid Build Coastguard Worker============
6*61c4878aSAndroid Build Coastguard Worker
7*61c4878aSAndroid Build Coastguard Worker.. pigweed-module::
8*61c4878aSAndroid Build Coastguard Worker   :name: pw_perf_test
9*61c4878aSAndroid Build Coastguard Worker
10*61c4878aSAndroid Build Coastguard Worker   - **Simple**: Automatically manages boilerplate like iterations and durations.
11*61c4878aSAndroid Build Coastguard Worker   - **Easy**: Uses an intuitive API that resembles GoogleTest.
12*61c4878aSAndroid Build Coastguard Worker   - **Reusable**: Integrates with modules like ``pw_log`` that you already use.
13*61c4878aSAndroid Build Coastguard Worker
14*61c4878aSAndroid Build Coastguard WorkerPigweed's perf test module provides an easy way to measure performance on
15*61c4878aSAndroid Build Coastguard Workerany test setup!
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Worker---------------
18*61c4878aSAndroid Build Coastguard WorkerGetting started
19*61c4878aSAndroid Build Coastguard Worker---------------
20*61c4878aSAndroid Build Coastguard WorkerYou can add a simple performance test using the follow steps:
21*61c4878aSAndroid Build Coastguard Worker
22*61c4878aSAndroid Build Coastguard WorkerConfigure your toolchain
23*61c4878aSAndroid Build Coastguard Worker========================
24*61c4878aSAndroid Build Coastguard WorkerIf necessary, configure your toolchain for performance testing:
25*61c4878aSAndroid Build Coastguard Worker
26*61c4878aSAndroid Build Coastguard Worker.. note:: Currently, ``pw_perf_test`` provides build integration with Bazel and
27*61c4878aSAndroid Build Coastguard Worker   GN. Performance tests can be built in CMake, but must be built as regular
28*61c4878aSAndroid Build Coastguard Worker   executables.
29*61c4878aSAndroid Build Coastguard Worker
30*61c4878aSAndroid Build Coastguard Worker.. tab-set::
31*61c4878aSAndroid Build Coastguard Worker
32*61c4878aSAndroid Build Coastguard Worker   .. tab-item:: Bazel
33*61c4878aSAndroid Build Coastguard Worker      :sync: bazel
34*61c4878aSAndroid Build Coastguard Worker
35*61c4878aSAndroid Build Coastguard Worker       - ``pw_perf_test_timer_backend``: Sets the backend used to measure
36*61c4878aSAndroid Build Coastguard Worker         durations. Options include:
37*61c4878aSAndroid Build Coastguard Worker
38*61c4878aSAndroid Build Coastguard Worker         - ``@pigweed//pw_perf_test:chrono_timer``: Uses
39*61c4878aSAndroid Build Coastguard Worker           ``pw_chrono::SystemClock`` to measure time.
40*61c4878aSAndroid Build Coastguard Worker         - ``@pigweed//pw_perf_test:arm_cortex_timer``: Uses cycle count
41*61c4878aSAndroid Build Coastguard Worker           registers available on ARM-Cortex to measure time.
42*61c4878aSAndroid Build Coastguard Worker
43*61c4878aSAndroid Build Coastguard Worker       - Currently, only the logging event handler is supported for Bazel.
44*61c4878aSAndroid Build Coastguard Worker
45*61c4878aSAndroid Build Coastguard Worker   .. tab-item:: GN
46*61c4878aSAndroid Build Coastguard Worker      :sync: gn
47*61c4878aSAndroid Build Coastguard Worker
48*61c4878aSAndroid Build Coastguard Worker       - ``pw_perf_test_TIMER_INTERFACE_BACKEND``: Sets the backend used to
49*61c4878aSAndroid Build Coastguard Worker         measure durations. Options include:
50*61c4878aSAndroid Build Coastguard Worker
51*61c4878aSAndroid Build Coastguard Worker         - ``"$dir_pw_perf_test:chrono_timer"``: Uses
52*61c4878aSAndroid Build Coastguard Worker           ``pw_chrono::SystemClock`` to measure time.
53*61c4878aSAndroid Build Coastguard Worker         - ``"$dir_pw_perf_test:arm_cortex_timer"``: Uses cycle count
54*61c4878aSAndroid Build Coastguard Worker           registers available on ARM-Cortex to measure time.
55*61c4878aSAndroid Build Coastguard Worker
56*61c4878aSAndroid Build Coastguard Worker       - ``pw_perf_test_MAIN_FUNCTION``: Indicates the GN target that provides
57*61c4878aSAndroid Build Coastguard Worker         a ``main`` function that sets the event handler and runs tests. The
58*61c4878aSAndroid Build Coastguard Worker         default is ``"$dir_pw_perf_test:logging_main"``.
59*61c4878aSAndroid Build Coastguard Worker
60*61c4878aSAndroid Build Coastguard WorkerWrite a test function
61*61c4878aSAndroid Build Coastguard Worker=====================
62*61c4878aSAndroid Build Coastguard WorkerWrite a test function that exercises the behavior you wish to benchmark. For
63*61c4878aSAndroid Build Coastguard Workerthis example, we will simulate doing work with:
64*61c4878aSAndroid Build Coastguard Worker
65*61c4878aSAndroid Build Coastguard Worker.. literalinclude:: examples/example_perf_test.cc
66*61c4878aSAndroid Build Coastguard Worker   :language: cpp
67*61c4878aSAndroid Build Coastguard Worker   :linenos:
68*61c4878aSAndroid Build Coastguard Worker   :start-after: [pw_perf_test_examples-simulate_work]
69*61c4878aSAndroid Build Coastguard Worker   :end-before: [pw_perf_test_examples-simulate_work]
70*61c4878aSAndroid Build Coastguard Worker
71*61c4878aSAndroid Build Coastguard WorkerCreating a performance test is as simple as using the ``PW_PERF_TEST_SIMPLE``
72*61c4878aSAndroid Build Coastguard Workermacro to name the function and optionally provide arguments to it:
73*61c4878aSAndroid Build Coastguard Worker
74*61c4878aSAndroid Build Coastguard Worker.. literalinclude:: examples/example_perf_test.cc
75*61c4878aSAndroid Build Coastguard Worker   :language: cpp
76*61c4878aSAndroid Build Coastguard Worker   :linenos:
77*61c4878aSAndroid Build Coastguard Worker   :start-after: [pw_perf_test_examples-simple_example]
78*61c4878aSAndroid Build Coastguard Worker   :end-before: [pw_perf_test_examples-simple_example]
79*61c4878aSAndroid Build Coastguard Worker
80*61c4878aSAndroid Build Coastguard WorkerIf you need to do additional setup as part of your test, you can use the
81*61c4878aSAndroid Build Coastguard Worker``PW_PERF_TEST`` macro, which provides an explicit ``pw::perf_test::State``
82*61c4878aSAndroid Build Coastguard Workerreference. the behavior to be benchmarked should be put in a loop that checks
83*61c4878aSAndroid Build Coastguard Worker``State::KeepRunning()``:
84*61c4878aSAndroid Build Coastguard Worker
85*61c4878aSAndroid Build Coastguard Worker.. literalinclude:: examples/example_perf_test.cc
86*61c4878aSAndroid Build Coastguard Worker   :language: cpp
87*61c4878aSAndroid Build Coastguard Worker   :linenos:
88*61c4878aSAndroid Build Coastguard Worker   :start-after: [pw_perf_test_examples-full_example]
89*61c4878aSAndroid Build Coastguard Worker   :end-before: [pw_perf_test_examples-full_example]
90*61c4878aSAndroid Build Coastguard Worker
91*61c4878aSAndroid Build Coastguard WorkerYou can even use lambdas in place of standalone functions:
92*61c4878aSAndroid Build Coastguard Worker
93*61c4878aSAndroid Build Coastguard Worker.. literalinclude:: examples/example_perf_test.cc
94*61c4878aSAndroid Build Coastguard Worker   :language: cpp
95*61c4878aSAndroid Build Coastguard Worker   :linenos:
96*61c4878aSAndroid Build Coastguard Worker   :start-after: [pw_perf_test_examples-lambda_example]
97*61c4878aSAndroid Build Coastguard Worker   :end-before: [pw_perf_test_examples-lambda_example]
98*61c4878aSAndroid Build Coastguard Worker
99*61c4878aSAndroid Build Coastguard Worker.. _module-pw_perf_test-pw_perf_test:
100*61c4878aSAndroid Build Coastguard Worker
101*61c4878aSAndroid Build Coastguard WorkerBuild Your Test
102*61c4878aSAndroid Build Coastguard Worker===============
103*61c4878aSAndroid Build Coastguard Worker.. tab-set::
104*61c4878aSAndroid Build Coastguard Worker
105*61c4878aSAndroid Build Coastguard Worker   .. tab-item:: Bazel
106*61c4878aSAndroid Build Coastguard Worker      :sync: bazel
107*61c4878aSAndroid Build Coastguard Worker
108*61c4878aSAndroid Build Coastguard Worker      Add your performance test to the build using the ``pw_cc_perf_test``
109*61c4878aSAndroid Build Coastguard Worker      rule from ``//pw_perf_test:pw_cc_perf_test.bzl``.
110*61c4878aSAndroid Build Coastguard Worker
111*61c4878aSAndroid Build Coastguard Worker      **Arguments**
112*61c4878aSAndroid Build Coastguard Worker
113*61c4878aSAndroid Build Coastguard Worker      * All ``native.cc_binary`` arguments are supported.
114*61c4878aSAndroid Build Coastguard Worker
115*61c4878aSAndroid Build Coastguard Worker      **Example**
116*61c4878aSAndroid Build Coastguard Worker
117*61c4878aSAndroid Build Coastguard Worker      .. code-block::
118*61c4878aSAndroid Build Coastguard Worker
119*61c4878aSAndroid Build Coastguard Worker         load("//pw_perf_test:pw_cc_perf_test.bzl", "pw_cc_perf_test")
120*61c4878aSAndroid Build Coastguard Worker
121*61c4878aSAndroid Build Coastguard Worker         pw_cc_perf_test(
122*61c4878aSAndroid Build Coastguard Worker             name = "my_perf_test",
123*61c4878aSAndroid Build Coastguard Worker             srcs = ["my_perf_test.cc"],
124*61c4878aSAndroid Build Coastguard Worker         )
125*61c4878aSAndroid Build Coastguard Worker
126*61c4878aSAndroid Build Coastguard Worker   .. tab-item:: GN
127*61c4878aSAndroid Build Coastguard Worker      :sync: gn
128*61c4878aSAndroid Build Coastguard Worker
129*61c4878aSAndroid Build Coastguard Worker      Add your performance test to the build using the ``pw_perf_test``
130*61c4878aSAndroid Build Coastguard Worker      template. This template creates two sub-targets.
131*61c4878aSAndroid Build Coastguard Worker
132*61c4878aSAndroid Build Coastguard Worker      * ``<target_name>.lib``: The test sources without a main function.
133*61c4878aSAndroid Build Coastguard Worker      * ``<target_name>``: The test suite binary, linked against
134*61c4878aSAndroid Build Coastguard Worker        ``pw_perf_test_MAIN_FUNCTION``.
135*61c4878aSAndroid Build Coastguard Worker
136*61c4878aSAndroid Build Coastguard Worker      **Arguments**
137*61c4878aSAndroid Build Coastguard Worker
138*61c4878aSAndroid Build Coastguard Worker      * All ``pw_executable`` arguments are supported.
139*61c4878aSAndroid Build Coastguard Worker      * ``enable_if``: Boolean indicating whether the test should be built. If
140*61c4878aSAndroid Build Coastguard Worker        false, replaces the test with an empty target. Defaults to true.
141*61c4878aSAndroid Build Coastguard Worker
142*61c4878aSAndroid Build Coastguard Worker      **Example**
143*61c4878aSAndroid Build Coastguard Worker
144*61c4878aSAndroid Build Coastguard Worker      .. code-block::
145*61c4878aSAndroid Build Coastguard Worker
146*61c4878aSAndroid Build Coastguard Worker         import("$dir_pw_perf_test/perf_test.gni")
147*61c4878aSAndroid Build Coastguard Worker
148*61c4878aSAndroid Build Coastguard Worker         pw_perf_test("my_perf_test") {
149*61c4878aSAndroid Build Coastguard Worker           sources = [ "my_perf_test.cc" ]
150*61c4878aSAndroid Build Coastguard Worker           enable_if = device_has_1m_flash
151*61c4878aSAndroid Build Coastguard Worker         }
152*61c4878aSAndroid Build Coastguard Worker
153*61c4878aSAndroid Build Coastguard WorkerRun your test
154*61c4878aSAndroid Build Coastguard Worker=============
155*61c4878aSAndroid Build Coastguard Worker.. tab-set::
156*61c4878aSAndroid Build Coastguard Worker
157*61c4878aSAndroid Build Coastguard Worker   .. tab-item:: GN
158*61c4878aSAndroid Build Coastguard Worker      :sync: gn
159*61c4878aSAndroid Build Coastguard Worker
160*61c4878aSAndroid Build Coastguard Worker      To run perf tests from GN, locate the associated binaries from the ``out``
161*61c4878aSAndroid Build Coastguard Worker      directory and run/flash them manually.
162*61c4878aSAndroid Build Coastguard Worker
163*61c4878aSAndroid Build Coastguard Worker   .. tab-item:: Bazel
164*61c4878aSAndroid Build Coastguard Worker      :sync: bazel
165*61c4878aSAndroid Build Coastguard Worker
166*61c4878aSAndroid Build Coastguard Worker      Use the default Bazel run command: ``bazel run //path/to:target``.
167*61c4878aSAndroid Build Coastguard Worker
168*61c4878aSAndroid Build Coastguard Worker-------------
169*61c4878aSAndroid Build Coastguard WorkerAPI reference
170*61c4878aSAndroid Build Coastguard Worker-------------
171*61c4878aSAndroid Build Coastguard Worker
172*61c4878aSAndroid Build Coastguard WorkerMacros
173*61c4878aSAndroid Build Coastguard Worker======
174*61c4878aSAndroid Build Coastguard Worker
175*61c4878aSAndroid Build Coastguard Worker.. doxygendefine:: PW_PERF_TEST
176*61c4878aSAndroid Build Coastguard Worker
177*61c4878aSAndroid Build Coastguard Worker.. doxygendefine:: PW_PERF_TEST_SIMPLE
178*61c4878aSAndroid Build Coastguard Worker
179*61c4878aSAndroid Build Coastguard WorkerEventHandler
180*61c4878aSAndroid Build Coastguard Worker============
181*61c4878aSAndroid Build Coastguard Worker
182*61c4878aSAndroid Build Coastguard Worker.. doxygenclass:: pw::perf_test::EventHandler
183*61c4878aSAndroid Build Coastguard Worker   :members:
184*61c4878aSAndroid Build Coastguard Worker
185*61c4878aSAndroid Build Coastguard Worker------
186*61c4878aSAndroid Build Coastguard WorkerDesign
187*61c4878aSAndroid Build Coastguard Worker------
188*61c4878aSAndroid Build Coastguard Worker
189*61c4878aSAndroid Build Coastguard Worker``pw_perf_test`` uses a ``Framework`` singleton similar to that of
190*61c4878aSAndroid Build Coastguard Worker``pw_unit_test``. This singleton is statically created, and tests declared using
191*61c4878aSAndroid Build Coastguard Workermacros such as ``PW_PERF_TEST`` will automatically register themselves with it.
192*61c4878aSAndroid Build Coastguard Worker
193*61c4878aSAndroid Build Coastguard WorkerA provided ``main`` function interacts with the ``Framework`` by calling
194*61c4878aSAndroid Build Coastguard Worker``pw::perf_test::RunAllTests`` and providing an ``EventHandler``. For each
195*61c4878aSAndroid Build Coastguard Workerregistered test, the ``Framework`` creates a ``State`` object and passes it to
196*61c4878aSAndroid Build Coastguard Workerthe test function.
197*61c4878aSAndroid Build Coastguard Worker
198*61c4878aSAndroid Build Coastguard WorkerThe State object tracks the number of iterations. It expects the test function
199*61c4878aSAndroid Build Coastguard Workerto include a loop with the condition of ``State::KeepRunning``. This loop
200*61c4878aSAndroid Build Coastguard Workershould include the behavior being banchmarked, e.g.
201*61c4878aSAndroid Build Coastguard Worker
202*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
203*61c4878aSAndroid Build Coastguard Worker
204*61c4878aSAndroid Build Coastguard Worker   while (state.KeepRunning()) {
205*61c4878aSAndroid Build Coastguard Worker     // Code to be benchmarked.
206*61c4878aSAndroid Build Coastguard Worker   }
207*61c4878aSAndroid Build Coastguard Worker
208*61c4878aSAndroid Build Coastguard WorkerIn particular, ``State::KeepRunning`` should be called exactly once before the
209*61c4878aSAndroid Build Coastguard Workerfirst iteration, as in a ``for`` or ``while`` loop. The ``State`` object will
210*61c4878aSAndroid Build Coastguard Workeruse the timer facade to measure the elapsed duration between successive calls to
211*61c4878aSAndroid Build Coastguard Worker``State::KeepRunning``.
212*61c4878aSAndroid Build Coastguard Worker
213*61c4878aSAndroid Build Coastguard WorkerAdditionally, the ``State`` object receives a reference to the ``EventHandler``
214*61c4878aSAndroid Build Coastguard Workerfrom the ``Framework``, and uses this to report both test progress and
215*61c4878aSAndroid Build Coastguard Workerperformance measurements.
216*61c4878aSAndroid Build Coastguard Worker
217*61c4878aSAndroid Build Coastguard WorkerTimers
218*61c4878aSAndroid Build Coastguard Worker======
219*61c4878aSAndroid Build Coastguard WorkerCurrently, Pigweed provides two implementations of the timer interface.
220*61c4878aSAndroid Build Coastguard WorkerConsumers may provide additional implementations and use them as a backend for
221*61c4878aSAndroid Build Coastguard Workerthe timer facade.
222*61c4878aSAndroid Build Coastguard Worker
223*61c4878aSAndroid Build Coastguard WorkerChrono Timer
224*61c4878aSAndroid Build Coastguard Worker------------
225*61c4878aSAndroid Build Coastguard WorkerThis timer depends :ref:`module-pw_chrono` and will only measure performance in
226*61c4878aSAndroid Build Coastguard Workerterms of nanoseconds. It is the default for performance tests on host.
227*61c4878aSAndroid Build Coastguard Worker
228*61c4878aSAndroid Build Coastguard WorkerCycle Count Timer
229*61c4878aSAndroid Build Coastguard Worker-----------------
230*61c4878aSAndroid Build Coastguard WorkerOn ARM Cortex devices, clock cycles may more accurately measure the actual
231*61c4878aSAndroid Build Coastguard Workerperformance of a benchmark.
232*61c4878aSAndroid Build Coastguard Worker
233*61c4878aSAndroid Build Coastguard WorkerThis implementation is OS-agnostic, as it directly accesses CPU registers.
234*61c4878aSAndroid Build Coastguard WorkerIt enables the `DWT register`_ through the `DEMCR register`_. While this
235*61c4878aSAndroid Build Coastguard Workerprovides cycle counts directly from the CPU, it notably overflows if the
236*61c4878aSAndroid Build Coastguard Workerduration of a test exceeding 2^32 clock cycles. At 100 MHz, this is
237*61c4878aSAndroid Build Coastguard Workerapproximately 43 seconds.
238*61c4878aSAndroid Build Coastguard Worker
239*61c4878aSAndroid Build Coastguard Worker.. warning::
240*61c4878aSAndroid Build Coastguard Worker  The interface only measures raw clock cycles and does not take into account
241*61c4878aSAndroid Build Coastguard Worker  other possible sources of pollution such as LSUs, Sleeps and other registers.
242*61c4878aSAndroid Build Coastguard Worker  `Read more on the DWT methods of counting instructions.`__
243*61c4878aSAndroid Build Coastguard Worker
244*61c4878aSAndroid Build Coastguard Worker.. __: `DWT methods`_
245*61c4878aSAndroid Build Coastguard Worker
246*61c4878aSAndroid Build Coastguard WorkerEventHandlers
247*61c4878aSAndroid Build Coastguard Worker=============
248*61c4878aSAndroid Build Coastguard WorkerCurrently, Pigweed provides one implementation of ``EventHandler``. Consumers
249*61c4878aSAndroid Build Coastguard Workermay provide additional implementations and use them by providing a dedicated
250*61c4878aSAndroid Build Coastguard Worker``main`` function that passes the handler to ``pw::perf_test::RunAllTests``.
251*61c4878aSAndroid Build Coastguard Worker
252*61c4878aSAndroid Build Coastguard WorkerLoggingEventHandler
253*61c4878aSAndroid Build Coastguard Worker-------------------
254*61c4878aSAndroid Build Coastguard WorkerThe default method of running performance tests uses a ``LoggingEventHandler``.
255*61c4878aSAndroid Build Coastguard WorkerThis event handler only logs the test results to the console and nothing more.
256*61c4878aSAndroid Build Coastguard WorkerIt was chosen as the default method due to its portability and to cut down on
257*61c4878aSAndroid Build Coastguard Workerthe time it would take to implement other printing log handlers. Make sure to
258*61c4878aSAndroid Build Coastguard Workerset a ``pw_log`` backend.
259*61c4878aSAndroid Build Coastguard Worker
260*61c4878aSAndroid Build Coastguard Worker-------
261*61c4878aSAndroid Build Coastguard WorkerRoadmap
262*61c4878aSAndroid Build Coastguard Worker-------
263*61c4878aSAndroid Build Coastguard Worker- `CMake support <https://g-issues.pigweed.dev/issues/309637691>`_
264*61c4878aSAndroid Build Coastguard Worker- `Unified framework <https://g-issues.pigweed.dev/issues/309639171>`_.
265*61c4878aSAndroid Build Coastguard Worker
266*61c4878aSAndroid Build Coastguard Worker.. _DWT register: https://developer.arm.com/documentation/ddi0337/e/System-Debug/DWT?lang=en
267*61c4878aSAndroid Build Coastguard Worker.. _DEMCR register: https://developer.arm.com/documentation/ddi0337/e/CEGHJDCF
268*61c4878aSAndroid Build Coastguard Worker.. _DWT methods: https://developer.arm.com/documentation/ka001499/1-0/
269