mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-10-19 06:23:33 +08:00
cmake remove circular linking and reorganize
- px4_add_module now requires MAIN - px4_add_library doesn't automatically link
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
############################################################################
|
||||
#
|
||||
# Copyright (c) 2017 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.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
add_library(perf perf_counter.c)
|
||||
add_dependencies(perf prebuild_targets)
|
||||
@@ -0,0 +1,634 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2012-2016 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 perf_counter.c
|
||||
*
|
||||
* @brief Performance measuring tools.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/queue.h>
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
#include <systemlib/err.h>
|
||||
|
||||
#include "perf_counter.h"
|
||||
|
||||
|
||||
#ifdef __PX4_QURT
|
||||
// There is presumably no dprintf on QURT. Therefore use the usual output to mini-dm.
|
||||
#define dprintf(_fd, _text, ...) ((_fd) == 1 ? PX4_INFO((_text), ##__VA_ARGS__) : (void)(_fd))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Header common to all counters.
|
||||
*/
|
||||
struct perf_ctr_header {
|
||||
sq_entry_t link; /**< list linkage */
|
||||
enum perf_counter_type type; /**< counter type */
|
||||
const char *name; /**< counter name */
|
||||
};
|
||||
|
||||
/**
|
||||
* PC_EVENT counter.
|
||||
*/
|
||||
struct perf_ctr_count {
|
||||
struct perf_ctr_header hdr;
|
||||
uint64_t event_count;
|
||||
};
|
||||
|
||||
/**
|
||||
* PC_ELAPSED counter.
|
||||
*/
|
||||
struct perf_ctr_elapsed {
|
||||
struct perf_ctr_header hdr;
|
||||
uint64_t event_count;
|
||||
uint64_t time_start;
|
||||
uint64_t time_total;
|
||||
uint32_t time_least;
|
||||
uint32_t time_most;
|
||||
float mean;
|
||||
float M2;
|
||||
};
|
||||
|
||||
/**
|
||||
* PC_INTERVAL counter.
|
||||
*/
|
||||
struct perf_ctr_interval {
|
||||
struct perf_ctr_header hdr;
|
||||
uint64_t event_count;
|
||||
uint64_t time_event;
|
||||
uint64_t time_first;
|
||||
uint64_t time_last;
|
||||
uint32_t time_least;
|
||||
uint32_t time_most;
|
||||
float mean;
|
||||
float M2;
|
||||
};
|
||||
|
||||
/**
|
||||
* List of all known counters.
|
||||
*/
|
||||
static sq_queue_t perf_counters = { NULL, NULL };
|
||||
|
||||
/**
|
||||
* mutex protecting access to the perf_counters linked list (which is read from & written to by different threads)
|
||||
*/
|
||||
pthread_mutex_t perf_counters_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
// FIXME: the mutex does **not** protect against access to/from the perf
|
||||
// counter's data. It can still happen that a counter is updated while it is
|
||||
// printed. This can lead to inconsistent output, or completely bogus values
|
||||
// (especially the 64bit values which are in general not atomically updated).
|
||||
// The same holds for shared perf counters (perf_alloc_once), that can be updated
|
||||
// concurrently (this affects the 'ctrl_latency' counter).
|
||||
|
||||
|
||||
perf_counter_t
|
||||
perf_alloc(enum perf_counter_type type, const char *name)
|
||||
{
|
||||
perf_counter_t ctr = NULL;
|
||||
|
||||
switch (type) {
|
||||
case PC_COUNT:
|
||||
ctr = (perf_counter_t)calloc(sizeof(struct perf_ctr_count), 1);
|
||||
break;
|
||||
|
||||
case PC_ELAPSED:
|
||||
ctr = (perf_counter_t)calloc(sizeof(struct perf_ctr_elapsed), 1);
|
||||
break;
|
||||
|
||||
case PC_INTERVAL:
|
||||
ctr = (perf_counter_t)calloc(sizeof(struct perf_ctr_interval), 1);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (ctr != NULL) {
|
||||
ctr->type = type;
|
||||
ctr->name = name;
|
||||
pthread_mutex_lock(&perf_counters_mutex);
|
||||
sq_addfirst(&ctr->link, &perf_counters);
|
||||
pthread_mutex_unlock(&perf_counters_mutex);
|
||||
}
|
||||
|
||||
return ctr;
|
||||
}
|
||||
|
||||
perf_counter_t
|
||||
perf_alloc_once(enum perf_counter_type type, const char *name)
|
||||
{
|
||||
pthread_mutex_lock(&perf_counters_mutex);
|
||||
perf_counter_t handle = (perf_counter_t)sq_peek(&perf_counters);
|
||||
|
||||
while (handle != NULL) {
|
||||
if (!strcmp(handle->name, name)) {
|
||||
if (type == handle->type) {
|
||||
/* they are the same counter */
|
||||
pthread_mutex_unlock(&perf_counters_mutex);
|
||||
return handle;
|
||||
|
||||
} else {
|
||||
/* same name but different type, assuming this is an error and not intended */
|
||||
pthread_mutex_unlock(&perf_counters_mutex);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
handle = (perf_counter_t)sq_next(&handle->link);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&perf_counters_mutex);
|
||||
|
||||
/* if the execution reaches here, no existing counter of that name was found */
|
||||
return perf_alloc(type, name);
|
||||
}
|
||||
|
||||
void
|
||||
perf_free(perf_counter_t handle)
|
||||
{
|
||||
if (handle == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&perf_counters_mutex);
|
||||
sq_rem(&handle->link, &perf_counters);
|
||||
pthread_mutex_unlock(&perf_counters_mutex);
|
||||
free(handle);
|
||||
}
|
||||
|
||||
void
|
||||
perf_count(perf_counter_t handle)
|
||||
{
|
||||
if (handle == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (handle->type) {
|
||||
case PC_COUNT:
|
||||
((struct perf_ctr_count *)handle)->event_count++;
|
||||
break;
|
||||
|
||||
case PC_INTERVAL: {
|
||||
struct perf_ctr_interval *pci = (struct perf_ctr_interval *)handle;
|
||||
hrt_abstime now = hrt_absolute_time();
|
||||
|
||||
switch (pci->event_count) {
|
||||
case 0:
|
||||
pci->time_first = now;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
pci->time_least = (uint32_t)(now - pci->time_last);
|
||||
pci->time_most = (uint32_t)(now - pci->time_last);
|
||||
pci->mean = pci->time_least / 1e6f;
|
||||
pci->M2 = 0;
|
||||
break;
|
||||
|
||||
default: {
|
||||
hrt_abstime interval = now - pci->time_last;
|
||||
|
||||
if ((uint32_t)interval < pci->time_least) {
|
||||
pci->time_least = (uint32_t)interval;
|
||||
}
|
||||
|
||||
if ((uint32_t)interval > pci->time_most) {
|
||||
pci->time_most = (uint32_t)interval;
|
||||
}
|
||||
|
||||
// maintain mean and variance of interval in seconds
|
||||
// Knuth/Welford recursive mean and variance of update intervals (via Wikipedia)
|
||||
float dt = interval / 1e6f;
|
||||
float delta_intvl = dt - pci->mean;
|
||||
pci->mean += delta_intvl / pci->event_count;
|
||||
pci->M2 += delta_intvl * (dt - pci->mean);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pci->time_last = now;
|
||||
pci->event_count++;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
perf_begin(perf_counter_t handle)
|
||||
{
|
||||
if (handle == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (handle->type) {
|
||||
case PC_ELAPSED:
|
||||
((struct perf_ctr_elapsed *)handle)->time_start = hrt_absolute_time();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
perf_end(perf_counter_t handle)
|
||||
{
|
||||
if (handle == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (handle->type) {
|
||||
case PC_ELAPSED: {
|
||||
struct perf_ctr_elapsed *pce = (struct perf_ctr_elapsed *)handle;
|
||||
|
||||
if (pce->time_start != 0) {
|
||||
int64_t elapsed = hrt_absolute_time() - pce->time_start;
|
||||
|
||||
if (elapsed >= 0) {
|
||||
|
||||
pce->event_count++;
|
||||
pce->time_total += elapsed;
|
||||
|
||||
if ((pce->time_least > (uint32_t)elapsed) || (pce->time_least == 0)) {
|
||||
pce->time_least = elapsed;
|
||||
}
|
||||
|
||||
if (pce->time_most < (uint32_t)elapsed) {
|
||||
pce->time_most = elapsed;
|
||||
}
|
||||
|
||||
// maintain mean and variance of the elapsed time in seconds
|
||||
// Knuth/Welford recursive mean and variance of update intervals (via Wikipedia)
|
||||
float dt = elapsed / 1e6f;
|
||||
float delta_intvl = dt - pce->mean;
|
||||
pce->mean += delta_intvl / pce->event_count;
|
||||
pce->M2 += delta_intvl * (dt - pce->mean);
|
||||
|
||||
pce->time_start = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
perf_set_elapsed(perf_counter_t handle, int64_t elapsed)
|
||||
{
|
||||
if (handle == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (handle->type) {
|
||||
case PC_ELAPSED: {
|
||||
struct perf_ctr_elapsed *pce = (struct perf_ctr_elapsed *)handle;
|
||||
|
||||
if (elapsed >= 0) {
|
||||
|
||||
pce->event_count++;
|
||||
pce->time_total += elapsed;
|
||||
|
||||
if ((pce->time_least > (uint32_t)elapsed) || (pce->time_least == 0)) {
|
||||
pce->time_least = elapsed;
|
||||
}
|
||||
|
||||
if (pce->time_most < (uint32_t)elapsed) {
|
||||
pce->time_most = elapsed;
|
||||
}
|
||||
|
||||
// maintain mean and variance of the elapsed time in seconds
|
||||
// Knuth/Welford recursive mean and variance of update intervals (via Wikipedia)
|
||||
float dt = elapsed / 1e6f;
|
||||
float delta_intvl = dt - pce->mean;
|
||||
pce->mean += delta_intvl / pce->event_count;
|
||||
pce->M2 += delta_intvl * (dt - pce->mean);
|
||||
|
||||
pce->time_start = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
perf_set_count(perf_counter_t handle, uint64_t count)
|
||||
{
|
||||
if (handle == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (handle->type) {
|
||||
case PC_COUNT: {
|
||||
((struct perf_ctr_count *)handle)->event_count = count;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
perf_cancel(perf_counter_t handle)
|
||||
{
|
||||
if (handle == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (handle->type) {
|
||||
case PC_ELAPSED: {
|
||||
struct perf_ctr_elapsed *pce = (struct perf_ctr_elapsed *)handle;
|
||||
|
||||
pce->time_start = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
perf_reset(perf_counter_t handle)
|
||||
{
|
||||
if (handle == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (handle->type) {
|
||||
case PC_COUNT:
|
||||
((struct perf_ctr_count *)handle)->event_count = 0;
|
||||
break;
|
||||
|
||||
case PC_ELAPSED: {
|
||||
struct perf_ctr_elapsed *pce = (struct perf_ctr_elapsed *)handle;
|
||||
pce->event_count = 0;
|
||||
pce->time_start = 0;
|
||||
pce->time_total = 0;
|
||||
pce->time_least = 0;
|
||||
pce->time_most = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case PC_INTERVAL: {
|
||||
struct perf_ctr_interval *pci = (struct perf_ctr_interval *)handle;
|
||||
pci->event_count = 0;
|
||||
pci->time_event = 0;
|
||||
pci->time_first = 0;
|
||||
pci->time_last = 0;
|
||||
pci->time_least = 0;
|
||||
pci->time_most = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
perf_print_counter(perf_counter_t handle)
|
||||
{
|
||||
if (handle == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
perf_print_counter_fd(1, handle);
|
||||
}
|
||||
|
||||
void
|
||||
perf_print_counter_fd(int fd, perf_counter_t handle)
|
||||
{
|
||||
if (handle == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (handle->type) {
|
||||
case PC_COUNT:
|
||||
dprintf(fd, "%s: %llu events\n",
|
||||
handle->name,
|
||||
(unsigned long long)((struct perf_ctr_count *)handle)->event_count);
|
||||
break;
|
||||
|
||||
case PC_ELAPSED: {
|
||||
struct perf_ctr_elapsed *pce = (struct perf_ctr_elapsed *)handle;
|
||||
float rms = sqrtf(pce->M2 / (pce->event_count - 1));
|
||||
dprintf(fd, "%s: %llu events, %lluus elapsed, %lluus avg, min %lluus max %lluus %5.3fus rms\n",
|
||||
handle->name,
|
||||
(unsigned long long)pce->event_count,
|
||||
(unsigned long long)pce->time_total,
|
||||
(pce->event_count == 0) ? 0 : (unsigned long long)pce->time_total / pce->event_count,
|
||||
(unsigned long long)pce->time_least,
|
||||
(unsigned long long)pce->time_most,
|
||||
(double)(1e6f * rms));
|
||||
break;
|
||||
}
|
||||
|
||||
case PC_INTERVAL: {
|
||||
struct perf_ctr_interval *pci = (struct perf_ctr_interval *)handle;
|
||||
float rms = sqrtf(pci->M2 / (pci->event_count - 1));
|
||||
|
||||
dprintf(fd, "%s: %llu events, %lluus avg, min %lluus max %lluus %5.3fus rms\n",
|
||||
handle->name,
|
||||
(unsigned long long)pci->event_count,
|
||||
(pci->event_count == 0) ? 0 : (unsigned long long)(pci->time_last - pci->time_first) / pci->event_count,
|
||||
(unsigned long long)pci->time_least,
|
||||
(unsigned long long)pci->time_most,
|
||||
(double)(1e6f * rms));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
perf_print_counter_buffer(char *buffer, int length, perf_counter_t handle)
|
||||
{
|
||||
int num_written = 0;
|
||||
|
||||
if (handle == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (handle->type) {
|
||||
case PC_COUNT:
|
||||
num_written = snprintf(buffer, length, "%s: %llu events",
|
||||
handle->name,
|
||||
(unsigned long long)((struct perf_ctr_count *)handle)->event_count);
|
||||
break;
|
||||
|
||||
case PC_ELAPSED: {
|
||||
struct perf_ctr_elapsed *pce = (struct perf_ctr_elapsed *)handle;
|
||||
float rms = sqrtf(pce->M2 / (pce->event_count - 1));
|
||||
num_written = snprintf(buffer, length, "%s: %llu events, %lluus elapsed, %lluus avg, min %lluus max %lluus %5.3fus rms",
|
||||
handle->name,
|
||||
(unsigned long long)pce->event_count,
|
||||
(unsigned long long)pce->time_total,
|
||||
(pce->event_count == 0) ? 0 : (unsigned long long)pce->time_total / pce->event_count,
|
||||
(unsigned long long)pce->time_least,
|
||||
(unsigned long long)pce->time_most,
|
||||
(double)(1e6f * rms));
|
||||
break;
|
||||
}
|
||||
|
||||
case PC_INTERVAL: {
|
||||
struct perf_ctr_interval *pci = (struct perf_ctr_interval *)handle;
|
||||
float rms = sqrtf(pci->M2 / (pci->event_count - 1));
|
||||
|
||||
num_written = snprintf(buffer, length, "%s: %llu events, %lluus avg, min %lluus max %lluus %5.3fus rms",
|
||||
handle->name,
|
||||
(unsigned long long)pci->event_count,
|
||||
(pci->event_count == 0) ? 0 : (unsigned long long)(pci->time_last - pci->time_first) / pci->event_count,
|
||||
(unsigned long long)pci->time_least,
|
||||
(unsigned long long)pci->time_most,
|
||||
(double)(1e6f * rms));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
buffer[length - 1] = 0; // ensure 0-termination
|
||||
return num_written;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
perf_event_count(perf_counter_t handle)
|
||||
{
|
||||
if (handle == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (handle->type) {
|
||||
case PC_COUNT:
|
||||
return ((struct perf_ctr_count *)handle)->event_count;
|
||||
|
||||
case PC_ELAPSED: {
|
||||
struct perf_ctr_elapsed *pce = (struct perf_ctr_elapsed *)handle;
|
||||
return pce->event_count;
|
||||
}
|
||||
|
||||
case PC_INTERVAL: {
|
||||
struct perf_ctr_interval *pci = (struct perf_ctr_interval *)handle;
|
||||
return pci->event_count;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
perf_iterate_all(perf_callback cb, void *user)
|
||||
{
|
||||
pthread_mutex_lock(&perf_counters_mutex);
|
||||
perf_counter_t handle = (perf_counter_t)sq_peek(&perf_counters);
|
||||
|
||||
while (handle != NULL) {
|
||||
cb(handle, user);
|
||||
handle = (perf_counter_t)sq_next(&handle->link);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&perf_counters_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
perf_print_all(int fd)
|
||||
{
|
||||
pthread_mutex_lock(&perf_counters_mutex);
|
||||
perf_counter_t handle = (perf_counter_t)sq_peek(&perf_counters);
|
||||
|
||||
while (handle != NULL) {
|
||||
perf_print_counter_fd(fd, handle);
|
||||
handle = (perf_counter_t)sq_next(&handle->link);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&perf_counters_mutex);
|
||||
}
|
||||
|
||||
// these are defined in drv_hrt.c
|
||||
extern const uint16_t latency_bucket_count;
|
||||
extern uint32_t latency_counters[];
|
||||
extern const uint16_t latency_buckets[];
|
||||
|
||||
void
|
||||
perf_print_latency(int fd)
|
||||
{
|
||||
dprintf(fd, "bucket [us] : events\n");
|
||||
|
||||
for (int i = 0; i < latency_bucket_count; i++) {
|
||||
printf(" %4i : %li\n", latency_buckets[i], (long int)latency_counters[i]);
|
||||
}
|
||||
|
||||
// print the overflow bucket value
|
||||
dprintf(fd, " >%4i : %i\n", latency_buckets[latency_bucket_count - 1], latency_counters[latency_bucket_count]);
|
||||
}
|
||||
|
||||
void
|
||||
perf_reset_all(void)
|
||||
{
|
||||
pthread_mutex_lock(&perf_counters_mutex);
|
||||
perf_counter_t handle = (perf_counter_t)sq_peek(&perf_counters);
|
||||
|
||||
while (handle != NULL) {
|
||||
perf_reset(handle);
|
||||
handle = (perf_counter_t)sq_next(&handle->link);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&perf_counters_mutex);
|
||||
|
||||
for (int i = 0; i <= latency_bucket_count; i++) {
|
||||
latency_counters[i] = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2012-2016 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 perf_counter.h
|
||||
* Performance measuring tools.
|
||||
*/
|
||||
|
||||
#ifndef _SYSTEMLIB_PERF_COUNTER_H
|
||||
#define _SYSTEMLIB_PERF_COUNTER_H value
|
||||
|
||||
#include <stdint.h>
|
||||
#include <px4_defines.h>
|
||||
|
||||
/**
|
||||
* Counter types.
|
||||
*/
|
||||
enum perf_counter_type {
|
||||
PC_COUNT, /**< count the number of times an event occurs */
|
||||
PC_ELAPSED, /**< measure the time elapsed performing an event */
|
||||
PC_INTERVAL /**< measure the interval between instances of an event */
|
||||
};
|
||||
|
||||
struct perf_ctr_header;
|
||||
typedef struct perf_ctr_header *perf_counter_t;
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* Create a new local counter.
|
||||
*
|
||||
* @param type The type of the new counter.
|
||||
* @param name The counter name.
|
||||
* @return Handle for the new counter, or NULL if a counter
|
||||
* could not be allocated.
|
||||
*/
|
||||
#ifndef perf_alloc // perf_alloc might be defined to be NULL in src/modules/px4iofirmware/px4io.h
|
||||
__EXPORT extern perf_counter_t perf_alloc(enum perf_counter_type type, const char *name);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get the reference to an existing counter or create a new one if it does not exist.
|
||||
*
|
||||
* @param type The type of the counter.
|
||||
* @param name The counter name.
|
||||
* @return Handle for the counter, or NULL if a counter
|
||||
* could not be allocated.
|
||||
*/
|
||||
__EXPORT extern perf_counter_t perf_alloc_once(enum perf_counter_type type, const char *name);
|
||||
|
||||
/**
|
||||
* Free a counter.
|
||||
*
|
||||
* @param handle The performance counter's handle.
|
||||
*/
|
||||
__EXPORT extern void perf_free(perf_counter_t handle);
|
||||
|
||||
/**
|
||||
* Count a performance event.
|
||||
*
|
||||
* This call only affects counters that take single events; PC_COUNT, PC_INTERVAL etc.
|
||||
*
|
||||
* @param handle The handle returned from perf_alloc.
|
||||
*/
|
||||
__EXPORT extern void perf_count(perf_counter_t handle);
|
||||
|
||||
/**
|
||||
* Begin a performance event.
|
||||
*
|
||||
* This call applies to counters that operate over ranges of time; PC_ELAPSED etc.
|
||||
*
|
||||
* @param handle The handle returned from perf_alloc.
|
||||
*/
|
||||
__EXPORT extern void perf_begin(perf_counter_t handle);
|
||||
|
||||
/**
|
||||
* End a performance event.
|
||||
*
|
||||
* This call applies to counters that operate over ranges of time; PC_ELAPSED etc.
|
||||
* If a call is made without a corresponding perf_begin call, or if perf_cancel
|
||||
* has been called subsequently, no change is made to the counter.
|
||||
*
|
||||
* @param handle The handle returned from perf_alloc.
|
||||
*/
|
||||
__EXPORT extern void perf_end(perf_counter_t handle);
|
||||
|
||||
/**
|
||||
* Register a measurement
|
||||
*
|
||||
* This call applies to counters that operate over ranges of time; PC_ELAPSED etc.
|
||||
* If a call is made without a corresponding perf_begin call. It sets the
|
||||
* value provided as argument as a new measurement.
|
||||
*
|
||||
* @param handle The handle returned from perf_alloc.
|
||||
* @param elapsed The time elapsed. Negative values lead to incrementing the overrun counter.
|
||||
*/
|
||||
__EXPORT extern void perf_set_elapsed(perf_counter_t handle, int64_t elapsed);
|
||||
|
||||
/**
|
||||
* Set a counter
|
||||
*
|
||||
* This call applies to counters of type PC_COUNT. It (re-)sets the count.
|
||||
*
|
||||
* @param handle The handle returned from perf_alloc.
|
||||
* @param count The counter value to be set.
|
||||
*/
|
||||
__EXPORT extern void perf_set_count(perf_counter_t handle, uint64_t count);
|
||||
|
||||
/**
|
||||
* Cancel a performance event.
|
||||
*
|
||||
* This call applies to counters that operate over ranges of time; PC_ELAPSED etc.
|
||||
* It reverts the effect of a previous perf_begin.
|
||||
*
|
||||
* @param handle The handle returned from perf_alloc.
|
||||
*/
|
||||
__EXPORT extern void perf_cancel(perf_counter_t handle);
|
||||
|
||||
/**
|
||||
* Reset a performance counter.
|
||||
*
|
||||
* This call resets performance counter to initial state
|
||||
*
|
||||
* @param handle The handle returned from perf_alloc.
|
||||
*/
|
||||
__EXPORT extern void perf_reset(perf_counter_t handle);
|
||||
|
||||
/**
|
||||
* Print one performance counter to stdout
|
||||
*
|
||||
* @param handle The counter to print.
|
||||
*/
|
||||
__EXPORT extern void perf_print_counter(perf_counter_t handle);
|
||||
|
||||
/**
|
||||
* Print one performance counter to a fd.
|
||||
*
|
||||
* @param fd File descriptor to print to - e.g. 0 for stdout
|
||||
* @param handle The counter to print.
|
||||
*/
|
||||
__EXPORT extern void perf_print_counter_fd(int fd, perf_counter_t handle);
|
||||
|
||||
/**
|
||||
* Print one performance counter to a buffer.
|
||||
*
|
||||
* @param buffer buffer to write to
|
||||
* @param length buffer length
|
||||
* @param handle The counter to print.
|
||||
* @param return number of bytes written
|
||||
*/
|
||||
__EXPORT extern int perf_print_counter_buffer(char *buffer, int length, perf_counter_t handle);
|
||||
|
||||
/**
|
||||
* Print all of the performance counters.
|
||||
*
|
||||
* @param fd File descriptor to print to - e.g. 0 for stdout
|
||||
*/
|
||||
__EXPORT extern void perf_print_all(int fd);
|
||||
|
||||
|
||||
typedef void (*perf_callback)(perf_counter_t handle, void *user);
|
||||
|
||||
/**
|
||||
* Iterate over all performance counters using a callback.
|
||||
*
|
||||
* Caution: This will aquire the mutex, so do not call any other perf_* method
|
||||
* that aquire the mutex as well from the callback (If this is needed, configure
|
||||
* the mutex to be reentrant).
|
||||
*
|
||||
* @param cb callback method
|
||||
* @param user custom argument for the callback
|
||||
*/
|
||||
__EXPORT extern void perf_iterate_all(perf_callback cb, void *user);
|
||||
|
||||
/**
|
||||
* Print hrt latency counters.
|
||||
*
|
||||
* @param fd File descriptor to print to - e.g. 0 for stdout
|
||||
*/
|
||||
__EXPORT extern void perf_print_latency(int fd);
|
||||
|
||||
/**
|
||||
* Reset all of the performance counters.
|
||||
*/
|
||||
__EXPORT extern void perf_reset_all(void);
|
||||
|
||||
/**
|
||||
* Return current event_count
|
||||
*
|
||||
* @param handle The counter returned from perf_alloc.
|
||||
* @return event_count
|
||||
*/
|
||||
__EXPORT extern uint64_t perf_event_count(perf_counter_t handle);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user