From c9e7d227fe56b333b4008b51333e766fe6477bd4 Mon Sep 17 00:00:00 2001 From: "rmackay9@yahoo.com" Date: Wed, 3 Nov 2010 06:50:42 +0000 Subject: [PATCH] added APM_PerfMon library which can be used to track down performance bottlenecks git-svn-id: https://arducopter.googlecode.com/svn/trunk@765 f9c3cf11-9bcb-44bc-f272-b75c42450872 --- libraries/APM_PerfMon/APM_PerfMon.cpp | 165 ++++++++++++++++++ libraries/APM_PerfMon/APM_PerfMon.h | 49 ++++++ .../APM_PerfMon_test/APM_PerfMon_test.pde | 46 +++++ 3 files changed, 260 insertions(+) create mode 100644 libraries/APM_PerfMon/APM_PerfMon.cpp create mode 100644 libraries/APM_PerfMon/APM_PerfMon.h create mode 100644 libraries/APM_PerfMon/APM_PerfMon_test/APM_PerfMon_test.pde diff --git a/libraries/APM_PerfMon/APM_PerfMon.cpp b/libraries/APM_PerfMon/APM_PerfMon.cpp new file mode 100644 index 0000000000..4726755329 --- /dev/null +++ b/libraries/APM_PerfMon/APM_PerfMon.cpp @@ -0,0 +1,165 @@ + +extern "C" { + // AVR LibC Includes + #include "WConstants.h" +} + +#include "APM_PerfMon.h" + +// don't know why i need these +// see http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=410870 +int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);}; +void __cxa_guard_release (__guard *g) {*(char *)g = 1;}; +void __cxa_guard_abort (__guard *) {}; + +// static class variable definitions +int APM_PerfMon::nextFuncNum; +char APM_PerfMon::functionNames[PERFMON_MAX_FUNCTIONS][PERFMON_FUNCTION_NAME_LENGTH]; +unsigned long APM_PerfMon::time[PERFMON_MAX_FUNCTIONS]; +unsigned long APM_PerfMon::numCalls[PERFMON_MAX_FUNCTIONS]; +unsigned long APM_PerfMon::allStartTime; +unsigned long APM_PerfMon::allEndTime; +APM_PerfMon* APM_PerfMon::lastCreated = NULL; + +// constructor +APM_PerfMon::APM_PerfMon(int funcNum) +{ + // stop recording time from parent + if( lastCreated != NULL ) + lastCreated->stop(); + + // check global start time + if( allStartTime == 0 ) + allStartTime = micros(); + + _funcNum = funcNum; // record which function we should assign time to + _parent = lastCreated; // add pointer to parent + lastCreated = this; // record myself as the last created instance + + numCalls[_funcNum]++; // record that this function has been called + start(); // start recording time spent in this function +} + +// destructor +APM_PerfMon::~APM_PerfMon() +{ + stop(); // stop recording time spent in this function + lastCreated = _parent; // make my parent the last created instance + + // restart recording time for parent + if( lastCreated != NULL ) + lastCreated->start(); +} + +// stop recording time +void APM_PerfMon::stop() +{ + time[_funcNum] += (micros()-_startTime); +} + +// stop recording time +void APM_PerfMon::start() +{ + _startTime = micros(); // restart recording time spent in this function +} + +// record function name in static list +int APM_PerfMon::recordFunctionName(const char funcName[]) +{ + int nextNum = nextFuncNum++; + int i; + + // clear existing function name (if any) + functionNames[nextNum][0] = 0; + + // store function name + for( i=0; iprint("PerfMon start:"); + aSerial->print(allStartTime/1000); + aSerial->print(" (mils) end:"); + aSerial->print(allEndTime/1000); + aSerial->print(" (mils) elapsed:"); + aSerial->print(totalTime/1000); + aSerial->print(" (mils)"); + aSerial->println(); + aSerial->println("PerfMon: \tcpu%\tmils\t#called\tHz"); + for( i=0; iprint(functionNames[i]); + for(j=0;jprint(" "); + aSerial->print("\t"); + aSerial->print(pct); + aSerial->print("%\t"); + aSerial->print(time[i]/1000); + aSerial->print("\t"); + aSerial->print(numCalls[i]); + aSerial->print("\t"); + aSerial->print(hz,0); + aSerial->print("hz"); + aSerial->println(); + } + // display unexplained time + if( sumOfTime >= totalTime ) + unExplainedTime = 0; + else + unExplainedTime = totalTime - sumOfTime; + pct = ((float)unExplainedTime / (float)totalTime) * 100.0; + aSerial->print("unexplained \t"); + aSerial->print(pct); + aSerial->print("%\t"); + aSerial->print(unExplainedTime/1000); + aSerial->println(); + +} + +int APM_PerfMon::strLen(char* str) +{ + int i = 0; + while( str[i] != 0 ) + i++; + return i; +} \ No newline at end of file diff --git a/libraries/APM_PerfMon/APM_PerfMon.h b/libraries/APM_PerfMon/APM_PerfMon.h new file mode 100644 index 0000000000..8e4d557d5d --- /dev/null +++ b/libraries/APM_PerfMon/APM_PerfMon.h @@ -0,0 +1,49 @@ +#ifndef APM_PerfMon_h +#define APM_PerfMon_h + +// macros to make integrating into code easier +#define APM_PERFMON_REGISTER static int myFunc = APM_PerfMon::recordFunctionName(__func__); APM_PerfMon perfMon(myFunc); +#define APM_PERFMON_REGISTER_NAME(functionName) static int myFunc = APM_PerfMon::recordFunctionName(functionName); APM_PerfMon perfMon(myFunc); + +#define PERFMON_MAX_FUNCTIONS 50 +#define PERFMON_FUNCTION_NAME_LENGTH 20 + +__extension__ typedef int __guard __attribute__((mode (__DI__))); + +extern "C" int __cxa_guard_acquire(__guard *); +extern "C" void __cxa_guard_release (__guard *); +extern "C" void __cxa_guard_abort (__guard *); + +#include "HardwareSerial.h" + +class APM_PerfMon +{ + public: + // static variables + static int nextFuncNum; + static char functionNames[PERFMON_MAX_FUNCTIONS][PERFMON_FUNCTION_NAME_LENGTH]; + static unsigned long time[PERFMON_MAX_FUNCTIONS]; + static unsigned long numCalls[PERFMON_MAX_FUNCTIONS]; + static unsigned long allStartTime; + static unsigned long allEndTime; + static APM_PerfMon* lastCreated; + + // static methods + static int recordFunctionName(const char funcName[]); + static void DisplayResults(HardwareSerial* aSerial); + static void ClearAll(); + static int strLen(char* str); + + // normal variables + int _funcNum; + unsigned long _startTime; + APM_PerfMon* _parent; + + // normal methods + APM_PerfMon(int funcNum); // Constructor - records function start time + ~APM_PerfMon(); // Destructor - records function end time + void stop(); // stops recording time spent in this function - meant to be called by a child. + void start(); // restarts recording time spent in this function +}; + +#endif // APM_PerfMon_h \ No newline at end of file diff --git a/libraries/APM_PerfMon/APM_PerfMon_test/APM_PerfMon_test.pde b/libraries/APM_PerfMon/APM_PerfMon_test/APM_PerfMon_test.pde new file mode 100644 index 0000000000..f001c74c9b --- /dev/null +++ b/libraries/APM_PerfMon/APM_PerfMon_test/APM_PerfMon_test.pde @@ -0,0 +1,46 @@ +/* + APM_PerfMon + Code by Randy Mackay +*/ + +#include "APM_PerfMon.h" // PerfMonitor library + +void setup() +{ + APM_PERFMON_REGISTER_NAME("setupA") + Serial.begin(115200); + Serial.println("Performance Monitor test v1.0"); +} + +void loop() +{ + APM_PERFMON_REGISTER + + int i = 0; + + for( i=0; i<100; i++ ) + { + testFunction(); + } + + APM_PerfMon::DisplayResults(&Serial); + + APM_PerfMon::ClearAll(); + + delay(10000); + +} + +void testFunction() +{ + APM_PERFMON_REGISTER + delay(10); + testFunction2(); + delay(10); +} + +void testFunction2() +{ + APM_PERFMON_REGISTER + delay(10); +}