mirror of
https://github.com/PX4/PX4-Autopilot.git
synced 2026-07-24 15:27:41 +08:00
test(microbench): add perf_counter microbenchmark
Times perf_count and perf_begin/perf_end in tight loops with hrt, plus a plain non-atomic counter loop as reference, to quantify the overhead of the atomic perf_counter change. Run with: microbench microbench_perf
This commit is contained in:
@@ -49,6 +49,7 @@ px4_add_module(
|
||||
test_microbench_math.cpp
|
||||
test_microbench_matrix.cpp
|
||||
test_microbench_uorb.cpp
|
||||
test_microbench_perf.cpp
|
||||
|
||||
DEPENDS
|
||||
lat_lon_alt
|
||||
|
||||
@@ -47,6 +47,7 @@ extern int test_microbench_hrt(int argc, char *argv[]);
|
||||
extern int test_microbench_math(int argc, char *argv[]);
|
||||
extern int test_microbench_matrix(int argc, char *argv[]);
|
||||
extern int test_microbench_uorb(int argc, char *argv[]);
|
||||
extern int test_microbench_perf(int argc, char *argv[]);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
@@ -70,6 +71,7 @@ const struct {
|
||||
{"microbench_math", test_microbench_math, 0},
|
||||
{"microbench_matrix", test_microbench_matrix, 0},
|
||||
{"microbench_uorb", test_microbench_uorb, 0},
|
||||
{"microbench_perf", test_microbench_perf, 0},
|
||||
|
||||
{"null", nullptr, 0}
|
||||
};
|
||||
|
||||
140
src/systemcmds/microbench/test_microbench_perf.cpp
Normal file
140
src/systemcmds/microbench/test_microbench_perf.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2026 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name PX4 nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @file test_microbench_perf.cpp
|
||||
* Microbenchmark perf_counter hot-path operations (perf_count / perf_begin /
|
||||
* perf_end). Used to quantify the overhead of making the counters atomic.
|
||||
*
|
||||
* Each operation is run in a tight loop and timed once with hrt_absolute_time(),
|
||||
* then reported as ns per call. A plain (non-atomic) volatile counter loop is
|
||||
* included as a reference baseline so the atomic overhead is visible within a
|
||||
* single binary, without needing a separate non-atomic build.
|
||||
*/
|
||||
|
||||
#include <unit_test.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include <perf/perf_counter.h>
|
||||
#include <px4_platform_common/px4_config.h>
|
||||
#include <px4_platform_common/log.h>
|
||||
|
||||
namespace MicroBenchPerf
|
||||
{
|
||||
|
||||
// Number of iterations per measurement. Large enough that the loop runs for
|
||||
// several hundred microseconds even on fast hosts, so the hrt (1 us) timer
|
||||
// resolution does not dominate the per-op result.
|
||||
static constexpr unsigned ITERATIONS = 1000000;
|
||||
|
||||
// Report total elapsed and ns/op for a measured loop.
|
||||
#define REPORT(name, elapsed_us) \
|
||||
PX4_INFO("%-28s %6.1f ns/op (%llu us / %u iters)", name, \
|
||||
(double)(elapsed_us) * 1000.0 / (double)ITERATIONS, \
|
||||
(unsigned long long)(elapsed_us), ITERATIONS)
|
||||
|
||||
class MicroBenchPerf : public UnitTest
|
||||
{
|
||||
public:
|
||||
bool run_tests() override;
|
||||
|
||||
private:
|
||||
bool time_reference_nonatomic();
|
||||
bool time_perf_count();
|
||||
bool time_perf_begin_end();
|
||||
};
|
||||
|
||||
// Plain non-atomic increment of a volatile counter: the baseline the atomic
|
||||
// perf_count() is compared against. volatile prevents the loop being elided.
|
||||
bool MicroBenchPerf::time_reference_nonatomic()
|
||||
{
|
||||
static volatile uint64_t counter = 0;
|
||||
|
||||
const hrt_abstime t0 = hrt_absolute_time();
|
||||
|
||||
for (unsigned i = 0; i < ITERATIONS; i++) {
|
||||
counter = counter + 1;
|
||||
}
|
||||
|
||||
const hrt_abstime elapsed = hrt_absolute_time() - t0;
|
||||
REPORT("reference non-atomic ++", elapsed);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MicroBenchPerf::time_perf_count()
|
||||
{
|
||||
perf_counter_t c = perf_alloc(PC_COUNT, "microbench_perf_count");
|
||||
|
||||
const hrt_abstime t0 = hrt_absolute_time();
|
||||
|
||||
for (unsigned i = 0; i < ITERATIONS; i++) {
|
||||
perf_count(c);
|
||||
}
|
||||
|
||||
const hrt_abstime elapsed = hrt_absolute_time() - t0;
|
||||
REPORT("perf_count (PC_COUNT)", elapsed);
|
||||
perf_free(c);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MicroBenchPerf::time_perf_begin_end()
|
||||
{
|
||||
perf_counter_t c = perf_alloc(PC_ELAPSED, "microbench_perf_elapsed");
|
||||
|
||||
const hrt_abstime t0 = hrt_absolute_time();
|
||||
|
||||
for (unsigned i = 0; i < ITERATIONS; i++) {
|
||||
perf_begin(c);
|
||||
perf_end(c);
|
||||
}
|
||||
|
||||
const hrt_abstime elapsed = hrt_absolute_time() - t0;
|
||||
REPORT("perf_begin + perf_end", elapsed);
|
||||
perf_free(c);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MicroBenchPerf::run_tests()
|
||||
{
|
||||
ut_run_test(time_reference_nonatomic);
|
||||
ut_run_test(time_perf_count);
|
||||
ut_run_test(time_perf_begin_end);
|
||||
|
||||
return (_tests_failed == 0);
|
||||
}
|
||||
|
||||
ut_declare_test_c(test_microbench_perf, MicroBenchPerf)
|
||||
|
||||
} // namespace MicroBenchPerf
|
||||
Reference in New Issue
Block a user