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