forked from ArduPilot/ardupilot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
AP_PerfMon.cpp
216 lines (183 loc) · 5.8 KB
/
AP_PerfMon.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#include "AP_PerfMon.h"
extern const AP_HAL::HAL& hal;
// static class variable definitions
uint8_t AP_PerfMon::nextFuncNum;
char AP_PerfMon::functionNames[PERFMON_MAX_FUNCTIONS][PERFMON_FUNCTION_NAME_LENGTH];
uint32_t AP_PerfMon::time[PERFMON_MAX_FUNCTIONS];
uint32_t AP_PerfMon::maxTime[PERFMON_MAX_FUNCTIONS];
uint32_t AP_PerfMon::numCalls[PERFMON_MAX_FUNCTIONS];
uint32_t AP_PerfMon::allStartTime;
uint32_t AP_PerfMon::allEndTime;
AP_PerfMon* AP_PerfMon::lastCreated = NULL;
bool AP_PerfMon::_enabled = true;
// constructor
AP_PerfMon::AP_PerfMon(uint8_t funcNum) : _funcNum(funcNum), _time_this_iteration(0)
{
// exit immediately if we are disabled
if( !_enabled ) {
return;
}
// check global start time
if( allStartTime == 0 ) {
allStartTime = hal.scheduler->micros();
}
// stop recording time from parent
_parent = lastCreated; // add pointer to parent
if( _parent != NULL ) {
_parent->stop();
}
// record myself as the last created instance
lastCreated = this;
numCalls[_funcNum]++; // record that this function has been called
start(); // start recording time spent in this function
}
// destructor
AP_PerfMon::~AP_PerfMon()
{
// exit immediately if we are disabled
if( !_enabled ) {
return;
}
stop(); // stop recording time spent in this function
lastCreated = _parent; // make my parent the last created instance
// calculate max time spent in this function
if( _time_this_iteration > maxTime[_funcNum] ) {
maxTime[_funcNum] = _time_this_iteration;
}
// restart recording time for parent
if( _parent != NULL )
_parent->start();
}
// record function name in static list
uint8_t AP_PerfMon::recordFunctionName(const char funcName[])
{
uint8_t nextNum = nextFuncNum++;
uint8_t i;
// clear existing function name (if any)
functionNames[nextNum][0] = 0;
// store function name
for( i=0; i<PERFMON_FUNCTION_NAME_LENGTH-1 && funcName[i] != 0; i++ ) {
functionNames[nextNum][i] = funcName[i];
}
functionNames[nextNum][i] = 0;
return nextNum;
}
// stop recording time
void AP_PerfMon::start()
{
_startTime = hal.scheduler->micros(); // start recording time spent in this function
}
// stop recording time
void AP_PerfMon::stop()
{
uint32_t temp_time = hal.scheduler->micros()-_startTime;
_time_this_iteration += temp_time;
time[_funcNum] += temp_time;
}
// ClearAll - clears all data from static members
void AP_PerfMon::ClearAll()
{
uint8_t i;
AP_PerfMon *p = lastCreated;
for(i=0; i<PERFMON_MAX_FUNCTIONS; i++) {
time[i] = 0; // reset times
numCalls[i] = 0; // reset num times called
maxTime[i] = 0; // reset maximum time
}
// reset start time to now
allStartTime = hal.scheduler->micros();
allEndTime = 0;
// reset start times of any active counters
while( p != NULL ) {
p->_startTime = allStartTime;
p = p->_parent;
}
}
// DisplayResults - displays table of timing results
void AP_PerfMon::DisplayResults()
{
uint8_t i,j,changed;
float hz;
float pct;
uint32_t totalTime;
uint32_t avgTime;
uint32_t sumOfTime = 0;
uint32_t unExplainedTime;
uint8_t order[PERFMON_MAX_FUNCTIONS];
bool blocking_writes;
// record end time
if( allEndTime == 0 ) {
allEndTime = hal.scheduler->micros();
}
// turn off any time recording
if( lastCreated != NULL ) {
lastCreated->stop();
}
_enabled = false;
// reorder results
for(i=0; i<nextFuncNum; i++) {
order[i] = i;
}
changed=0;
do{
changed = 0;
for(i=0; i<nextFuncNum-1; i++)
if(time[order[i]]<time[order[i+1]]) {
j = order[i];
order[i] = order[i+1];
order[i+1] = j;
changed = 1;
}
}while(changed != 0);
// calculate time elapsed
totalTime = allEndTime - allStartTime;
// ensure serial is blocking
//blocking_writes = hal.console->get_blocking_writes();
hal.console->set_blocking_writes(true);
// print table of results
hal.console->printf_P(PSTR("\nPerfMon elapsed:%lu(ms)\n"),(unsigned long)totalTime/1000);
hal.console->printf_P(PSTR("Fn:\t\tcpu\ttot(ms)\tavg(ms)\tmax(ms)\t#calls\tHz\n"));
for( i=0; i<nextFuncNum; i++ ) {
j=order[i];
sumOfTime += time[j];
// calculate average execution time
if( numCalls[j] > 0 ) {
avgTime = time[j] / numCalls[j];
}else{
avgTime = 0;
}
hz = numCalls[j]/(totalTime/1000000);
pct = ((float)time[j] / (float)totalTime) * 100.0;
hal.console->printf_P(PSTR("%-10s\t%4.2f\t%lu\t%4.3f\t%4.3f\t%lu\t%4.1f\n"),
functionNames[j],
pct,
(unsigned long)time[j]/1000,
(float)avgTime/1000.0,
(float)maxTime[j]/1000.0,
numCalls[j],
hz);
}
// display unexplained time
if( sumOfTime >= totalTime ) {
unExplainedTime = 0;
} else {
unExplainedTime = totalTime - sumOfTime;
}
pct = ((float)unExplainedTime / (float)totalTime) * 100.0;
hal.console->printf_P(PSTR("unexpl:\t\t%4.2f\t%lu\n"),pct,(unsigned long)unExplainedTime/1000);
// restore to blocking writes if necessary
hal.console->set_blocking_writes(false);
// turn back on any time recording
if( lastCreated != NULL ) {
lastCreated->start();
}
_enabled = true;
}
// DisplayAndClear - will display results after this many milliseconds. should be called regularly
void AP_PerfMon::DisplayAndClear(uint32_t display_after_seconds)
{
if( (hal.scheduler->micros() - allStartTime) > (uint32_t)(display_after_seconds * 1000000) ) {
DisplayResults();
ClearAll();
}
}