diff --git a/libraries/AP_HAL_Linux/AP_HAL_Linux_Namespace.h b/libraries/AP_HAL_Linux/AP_HAL_Linux_Namespace.h
index 5c51cb034d..8a6e1b144b 100644
--- a/libraries/AP_HAL_Linux/AP_HAL_Linux_Namespace.h
+++ b/libraries/AP_HAL_Linux/AP_HAL_Linux_Namespace.h
@@ -55,5 +55,4 @@ namespace Linux {
class VideoIn;
class OpticalFlow_Onboard;
class Flow_PX4;
- class Perf_Lttng;
}
diff --git a/libraries/AP_HAL_Linux/Perf.cpp b/libraries/AP_HAL_Linux/Perf.cpp
index 6a554751ba..4384db96bb 100644
--- a/libraries/AP_HAL_Linux/Perf.cpp
+++ b/libraries/AP_HAL_Linux/Perf.cpp
@@ -1,6 +1,6 @@
/// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
/*
- * Copyright (C) 2015 Intel Corporation. All rights reserved.
+ * Copyright (C) 2016 Intel Corporation. All rights reserved.
*
* This file is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -15,42 +15,22 @@
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
-#ifndef HAVE_LTTNG_UST
-
-#include
#include
+#include
#include
#include
#include "AP_HAL_Linux.h"
#include "Util.h"
+#include "Perf.h"
+#include "Perf_Lttng.h"
using namespace Linux;
-struct perf_counter_base_t {
- const char *name;
- enum Util::perf_counter_type type;
-};
+static const AP_HAL::HAL &hal = AP_HAL::get_HAL();
-struct perf_counter_count_t {
- struct perf_counter_base_t base;
- uint64_t count;
-};
-
-struct perf_counter_elapsed_t {
- struct perf_counter_base_t base;
- uint64_t count;
- /* Everything below is in nanoseconds */
- uint64_t start;
- uint64_t total;
- uint64_t least;
- uint64_t most;
- double mean;
- double m2;
-};
-
-static const AP_HAL::HAL& hal = AP_HAL::get_HAL();
+Perf *Perf::_instance;
static inline uint64_t now_nsec()
{
@@ -59,96 +39,92 @@ static inline uint64_t now_nsec()
return ts.tv_nsec + (ts.tv_sec * NSEC_PER_SEC);
}
-Util::perf_counter_t Util::perf_alloc(perf_counter_type type, const char *name)
+Perf *Perf::get_instance()
{
- struct perf_counter_base_t *base;
-
- switch(type) {
- case PC_COUNT: {
- struct perf_counter_count_t *count;
- count = (struct perf_counter_count_t *)calloc(1, sizeof(struct perf_counter_count_t));
- if (!count) {
- return nullptr;
- }
-
- base = &count->base;
- break;
- }
- case PC_ELAPSED: {
- struct perf_counter_elapsed_t *elapsed;
- elapsed = (struct perf_counter_elapsed_t *)calloc(1, sizeof(struct perf_counter_elapsed_t));
- if (!elapsed) {
- return nullptr;
- }
-
- elapsed->least = ULONG_MAX;
-
- base = &elapsed->base;
- break;
- }
- default:
- case PC_INTERVAL: {
- /*
- * Not implemented now because it is not used even on PX4 specific
- * code and by looking at PX4 implementation without perf_reset()
- * the average is broken.
- */
- return nullptr;
- }
+ if (!_instance) {
+ _instance = new Perf();
}
- base->name = name;
- base->type = type;
- return (perf_counter_t)base;
+ return _instance;
}
-void Util::perf_begin(perf_counter_t perf)
+Perf::Perf()
{
- struct perf_counter_elapsed_t *perf_elapsed = (struct perf_counter_elapsed_t *)perf;
-
- if (perf_elapsed == NULL) {
- return;
- }
- if (perf_elapsed->base.type != PC_ELAPSED) {
- hal.console->printf("perf_begin() called over a perf_counter_t(%s) that"
- " is not of the PC_ELAPSED type.\n",
- perf_elapsed->base.name);
- return;
+ if (pthread_rwlock_init(&_perf_counters_lock, nullptr) != 0) {
+ AP_HAL::panic("Perf: fail to initialize rw lock");
}
- perf_elapsed->start = now_nsec();
+ /* TODO: this number should come from vehicle code - just estimate the
+ * number of perf counters for now; if we grow more, it will just
+ * reallocate the memory pool */
+ _perf_counters.reserve(50);
}
-void Util::perf_end(perf_counter_t perf)
+void Perf::begin(Util::perf_counter_t pc)
{
- struct perf_counter_elapsed_t *perf_elapsed = (struct perf_counter_elapsed_t *)perf;
+ uintptr_t idx = (uintptr_t)pc;
- if (perf_elapsed == NULL) {
+ if (idx >= _perf_counters.size()) {
return;
}
- if (perf_elapsed->base.type != PC_ELAPSED) {
- hal.console->printf("perf_end() called over a perf_counter_t(%s) "
- "that is not of the PC_ELAPSED type.\n",
- perf_elapsed->base.name);
- return;
- }
- if (perf_elapsed->start == 0) {
- hal.console->printf("perf_end() called before an perf_begin() on %s.\n",
- perf_elapsed->base.name);
+ Perf_Counter &perf = _perf_counters[idx];
+ if (perf.type != Util::PC_ELAPSED) {
+ hal.console->printf("perf_begin() called on perf_counter_t(%s) that"
+ " is not of PC_ELAPSED type.\n",
+ perf.name);
return;
}
- const uint64_t elapsed = now_nsec() - perf_elapsed->start;
- perf_elapsed->count++;
- perf_elapsed->total += elapsed;
-
- if (perf_elapsed->least > elapsed) {
- perf_elapsed->least = elapsed;
+ if (perf.start != 0) {
+ hal.console->printf("perf_begin() called twice on perf_counter_t(%s)\n",
+ perf.name);
+ return;
}
- if (perf_elapsed->most < elapsed) {
- perf_elapsed->most = elapsed;
+ _update_count++;
+
+ perf.start = now_nsec();
+
+#ifdef HAVE_LTTNG_UST
+ perf.lttng.begin();
+#endif
+}
+
+void Perf::end(Util::perf_counter_t pc)
+{
+ uintptr_t idx = (uintptr_t)pc;
+
+ if (idx >= _perf_counters.size()) {
+ return;
+ }
+
+ Perf_Counter &perf = _perf_counters[idx];
+ if (perf.type != Util::PC_ELAPSED) {
+ hal.console->printf("perf_begin() called on perf_counter_t(%s) that"
+ " is not of PC_ELAPSED type.\n",
+ perf.name);
+ return;
+ }
+
+ if (perf.start == 0) {
+ hal.console->printf("perf_begin() called before begin() on perf_counter_t(%s)\n",
+ perf.name);
+ return;
+ }
+
+ _update_count++;
+
+ const uint64_t elapsed = now_nsec() - perf.start;
+ perf.count++;
+ perf.total += elapsed;
+
+ if (perf.least > elapsed) {
+ perf.least = elapsed;
+ }
+
+ if (perf.most < elapsed) {
+ perf.most = elapsed;
}
/*
@@ -156,29 +132,55 @@ void Util::perf_end(perf_counter_t perf)
* Knuth/Welford recursive mean and variance of update intervals (via Wikipedia)
* Same implementation of PX4.
*/
- const double delta_intvl = elapsed - perf_elapsed->mean;
- perf_elapsed->mean += (delta_intvl / perf_elapsed->count);
- perf_elapsed->m2 += (delta_intvl * (elapsed - perf_elapsed->mean));
-
- perf_elapsed->start = 0;
-}
-
-void Util::perf_count(perf_counter_t perf)
-{
- struct perf_counter_count_t *perf_counter = (struct perf_counter_count_t *)perf;
-
- if (perf_counter == NULL) {
- return;
- }
-
- if (perf_counter->base.type != PC_COUNT) {
- hal.console->printf("perf_count() called over a perf_counter_t(%s) "
- "that is not of the PC_COUNT type.\n",
- perf_counter->base.name);
- return;
- }
-
- perf_counter->count++;
-}
+ const double delta_intvl = elapsed - perf.mean;
+ perf.mean += (delta_intvl / perf.count);
+ perf.m2 += (delta_intvl * (elapsed - perf.mean));
+ perf.start = 0;
+#ifdef HAVE_LTTNG_UST
+ perf.lttng.end();
#endif
+}
+
+void Perf::count(Util::perf_counter_t pc)
+{
+ uintptr_t idx = (uintptr_t)pc;
+
+ if (idx >= _perf_counters.size()) {
+ return;
+ }
+
+ Perf_Counter &perf = _perf_counters[idx];
+ if (perf.type != Util::PC_COUNT) {
+ hal.console->printf("perf_begin() called on perf_counter_t(%s) that"
+ " is not of PC_COUNT type.\n",
+ perf.name);
+ return;
+ }
+
+ _update_count++;
+ perf.count++;
+
+#ifdef HAVE_LTTNG_UST
+ perf.lttng.count();
+#endif
+
+}
+
+Util::perf_counter_t Perf::add(Util::perf_counter_type type, const char *name)
+{
+ if (type != Util::PC_COUNT && type != Util::PC_ELAPSED) {
+ /*
+ * Other perf counters not implemented for now since they are not
+ * used anywhere.
+ */
+ return (Util::perf_counter_t)(uintptr_t) -1;
+ }
+
+ pthread_rwlock_wrlock(&_perf_counters_lock);
+ Util::perf_counter_t pc = (Util::perf_counter_t) _perf_counters.size();
+ _perf_counters.emplace_back(type, name);
+ pthread_rwlock_unlock(&_perf_counters_lock);
+
+ return pc;
+}
diff --git a/libraries/AP_HAL_Linux/Perf.h b/libraries/AP_HAL_Linux/Perf.h
new file mode 100644
index 0000000000..91ea1f552f
--- /dev/null
+++ b/libraries/AP_HAL_Linux/Perf.h
@@ -0,0 +1,97 @@
+/// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
+/*
+ * Copyright (C) 2016 Intel Corporation. All rights reserved.
+ *
+ * This file is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+#pragma once
+
+#include
+#include
+#include
+#include
+
+#include "AP_HAL_Linux.h"
+#include "Perf_Lttng.h"
+#include "Thread.h"
+#include "Util.h"
+
+namespace Linux {
+
+class Perf_Counter {
+ using perf_counter_type = AP_HAL::Util::perf_counter_type;
+ using perf_counter_t = AP_HAL::Util::perf_counter_t;
+
+public:
+ Perf_Counter(perf_counter_type type_, const char *name_)
+ : name{name_}
+ , type{type_}
+#ifdef HAVE_LTTNG_UST
+ , lttng{name_}
+#endif
+ , least{ULONG_MAX}
+ {
+ }
+
+ const char *name;
+#ifdef HAVE_LTTNG_UST
+ Perf_Lttng lttng;
+#endif
+
+ perf_counter_type type;
+
+ uint64_t count;
+
+ /* Everything below is in nanoseconds */
+ uint64_t start;
+ uint64_t total;
+ uint64_t least;
+ uint64_t most;
+
+ double mean;
+ double m2;
+};
+
+class Perf {
+ using perf_counter_type = AP_HAL::Util::perf_counter_type;
+ using perf_counter_t = AP_HAL::Util::perf_counter_t;
+
+public:
+ ~Perf();
+
+ static Perf *get_instance();
+
+ perf_counter_t add(perf_counter_type type, const char *name);
+
+ void begin(perf_counter_t pc);
+ void end(perf_counter_t pc);
+ void count(perf_counter_t pc);
+
+ unsigned int get_update_count() { return _update_count; }
+
+private:
+ static Perf *_instance;
+
+ Perf();
+
+ std::vector _perf_counters;
+
+ /* synchronize addition of new perf counters */
+ pthread_rwlock_t _perf_counters_lock;
+
+ /* allow to check if memory pool has changed */
+ std::atomic _update_count;
+};
+
+}
diff --git a/libraries/AP_HAL_Linux/Perf_Lttng.cpp b/libraries/AP_HAL_Linux/Perf_Lttng.cpp
index a61375b4e4..74b008a40d 100644
--- a/libraries/AP_HAL_Linux/Perf_Lttng.cpp
+++ b/libraries/AP_HAL_Linux/Perf_Lttng.cpp
@@ -24,66 +24,27 @@
#include "AP_HAL_Linux.h"
#include "Perf_Lttng_TracePoints.h"
#include "Perf_Lttng.h"
-#include "Util.h"
-
-#pragma GCC diagnostic ignored "-Wcast-align"
using namespace Linux;
-Perf_Lttng::Perf_Lttng(AP_HAL::Util::perf_counter_type type, const char *name)
- : _type(type)
+Perf_Lttng::Perf_Lttng(const char *name)
{
strncpy(_name, name, MAX_TRACEPOINT_NAME_LEN);
}
void Perf_Lttng::begin()
{
- if (_type != AP_HAL::Util::PC_ELAPSED) {
- return;
- }
tracepoint(ardupilot, begin, _name);
}
void Perf_Lttng::end()
{
- if (_type != AP_HAL::Util::PC_ELAPSED) {
- return;
- }
tracepoint(ardupilot, end, _name);
}
void Perf_Lttng::count()
{
- if (_type != AP_HAL::Util::PC_COUNT) {
- return;
- }
tracepoint(ardupilot, count, _name, ++_count);
}
-Util::perf_counter_t Util::perf_alloc(perf_counter_type type, const char *name)
-{
- return new Linux::Perf_Lttng(type, name);
-}
-
-void Util::perf_begin(perf_counter_t perf)
-{
- Linux::Perf_Lttng *perf_lttng = (Linux::Perf_Lttng *)perf;
-
- perf_lttng->begin();
-}
-
-void Util::perf_end(perf_counter_t perf)
-{
- Linux::Perf_Lttng *perf_lttng = (Linux::Perf_Lttng *)perf;
-
- perf_lttng->end();
-}
-
-void Util::perf_count(perf_counter_t perf)
-{
- Linux::Perf_Lttng *perf_lttng = (Linux::Perf_Lttng *)perf;
-
- perf_lttng->count();
-}
-
#endif
diff --git a/libraries/AP_HAL_Linux/Perf_Lttng.h b/libraries/AP_HAL_Linux/Perf_Lttng.h
index a043f1c8ca..6c160d2a68 100644
--- a/libraries/AP_HAL_Linux/Perf_Lttng.h
+++ b/libraries/AP_HAL_Linux/Perf_Lttng.h
@@ -12,21 +12,25 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-
#pragma once
-#include "AP_HAL_Linux.h"
+
#include
+#include "AP_HAL_Linux.h"
+
#define MAX_TRACEPOINT_NAME_LEN 128
-class Linux::Perf_Lttng {
+namespace Linux {
+
+class Perf_Lttng {
public:
- Perf_Lttng(enum AP_HAL::Util::perf_counter_type type, const char *name);
+ Perf_Lttng(const char *name);
void begin();
void end();
void count();
private:
char _name[MAX_TRACEPOINT_NAME_LEN];
uint64_t _count;
- enum AP_HAL::Util::perf_counter_type _type;
};
+
+}
diff --git a/libraries/AP_HAL_Linux/Perf_Lttng_TracePoints.h b/libraries/AP_HAL_Linux/Perf_Lttng_TracePoints.h
index 45b5804bc0..4faea63a02 100644
--- a/libraries/AP_HAL_Linux/Perf_Lttng_TracePoints.h
+++ b/libraries/AP_HAL_Linux/Perf_Lttng_TracePoints.h
@@ -62,4 +62,3 @@ TRACEPOINT_EVENT(
#endif
#include
-
diff --git a/libraries/AP_HAL_Linux/Util.h b/libraries/AP_HAL_Linux/Util.h
index bcbaf4bda4..cbf604a7cf 100644
--- a/libraries/AP_HAL_Linux/Util.h
+++ b/libraries/AP_HAL_Linux/Util.h
@@ -4,6 +4,7 @@
#include
#include "AP_HAL_Linux_Namespace.h"
+#include "Perf.h"
#include "ToneAlarm.h"
#include "Semaphores.h"
@@ -63,10 +64,25 @@ public:
*/
int read_file(const char *path, const char *fmt, ...) FMT_SCANF(3, 4);
- perf_counter_t perf_alloc(perf_counter_type t, const char *name) override;
- void perf_begin(perf_counter_t perf) override;
- void perf_end(perf_counter_t perf) override;
- void perf_count(perf_counter_t perf) override;
+ perf_counter_t perf_alloc(enum perf_counter_type t, const char *name) override
+ {
+ return Perf::get_instance()->add(t, name);
+ }
+
+ void perf_begin(perf_counter_t perf) override
+ {
+ return Perf::get_instance()->begin(perf);
+ }
+
+ void perf_end(perf_counter_t perf) override
+ {
+ return Perf::get_instance()->end(perf);
+ }
+
+ void perf_count(perf_counter_t perf) override
+ {
+ return Perf::get_instance()->count(perf);
+ }
// create a new semaphore
AP_HAL::Semaphore *new_semaphore(void) override { return new Linux::Semaphore; }