You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
200 lines
5.3 KiB
C
200 lines
5.3 KiB
C
|
5 years ago
|
/*!
|
||
|
|
* \file PerfTimer.h
|
||
|
|
* \date 2018/01/16
|
||
|
|
*
|
||
|
|
* \author Lin, Chi
|
||
|
|
* Contact: lin.chi@hzleaper.com
|
||
|
|
*
|
||
|
|
* \note
|
||
|
|
*/
|
||
|
|
#ifndef __PerfTimer_h_
|
||
|
|
#define __PerfTimer_h_
|
||
|
|
|
||
|
|
#include "CVUtils.h"
|
||
|
|
#include "StdUtils.h"
|
||
|
|
#include <map>
|
||
|
|
|
||
|
|
class PerfTimerSimple
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
PerfTimerSimple() {
|
||
|
|
restart();
|
||
|
|
}
|
||
|
|
|
||
|
|
void restart() {
|
||
|
|
mTick = cv::getTickCount();
|
||
|
|
}
|
||
|
|
|
||
|
|
int64 elapsed() {
|
||
|
|
return cv::getTickCount() - mTick;
|
||
|
|
}
|
||
|
|
|
||
|
|
double elapsedMS() {
|
||
|
|
return tickToMS(elapsed());
|
||
|
|
}
|
||
|
|
|
||
|
|
static double tickToMS(int64 tick) {
|
||
|
|
static double freq = cv::getTickFrequency() / 1000.;
|
||
|
|
return (double)tick / freq;
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
int64 mTick;
|
||
|
|
};
|
||
|
|
|
||
|
|
class PerfTimer
|
||
|
|
{
|
||
|
|
struct PerfInfo
|
||
|
|
{
|
||
|
|
double totalTime;
|
||
|
|
double totalDivisor;
|
||
|
|
std::list<double> times;
|
||
|
|
std::list<double> divisors;
|
||
|
|
string divisorName;
|
||
|
|
|
||
|
|
PerfInfo(const char* dn = "pixel")
|
||
|
|
: divisorName(dn), totalTime(0.), totalDivisor(0.)
|
||
|
|
{}
|
||
|
|
|
||
|
|
void add(double t, double d) {
|
||
|
|
totalTime += t;
|
||
|
|
totalDivisor += d;
|
||
|
|
times.push_back(t);
|
||
|
|
divisors.push_back(d);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
typedef std::map<string, PerfInfo> StringPerfInfoMap;
|
||
|
|
typedef std::multimap<string, int64> StringInt64Map;
|
||
|
|
typedef std::multimap<string, int64>::iterator StringInt64MapIter;
|
||
|
|
|
||
|
|
public:
|
||
|
|
static PerfTimer* get() {
|
||
|
|
static PerfTimer perTimer;
|
||
|
|
return &perTimer;
|
||
|
|
}
|
||
|
|
|
||
|
|
static PerfTimer* getLogTimer() {
|
||
|
|
static PerfTimer perTimer;
|
||
|
|
return &perTimer;
|
||
|
|
}
|
||
|
|
|
||
|
|
PerfTimer() {
|
||
|
|
mTickFreq = cv::getTickFrequency();
|
||
|
|
}
|
||
|
|
|
||
|
|
~PerfTimer() {
|
||
|
|
if (!mPerfInfoMap.empty())
|
||
|
|
print_all("perf.csv");
|
||
|
|
}
|
||
|
|
|
||
|
|
inline void setScope(const std::string& name) { mCurScopeName = name; }
|
||
|
|
inline void clearScope() { mCurScopeName.clear(); }
|
||
|
|
|
||
|
|
inline string substitudeName(const std::string& name) {
|
||
|
|
if (!mCurScopeName.empty()) return string("[") + mCurScopeName + "]" + name;
|
||
|
|
else return string(name);
|
||
|
|
}
|
||
|
|
|
||
|
|
int64 start(const std::string& name) {
|
||
|
|
int64 tick = cv::getTickCount();
|
||
|
|
string fullname = substitudeName(name);
|
||
|
|
CyclopsLockGuard mLockGuard(&mLock);
|
||
|
|
mListenMap.insert(std::make_pair(fullname, tick));
|
||
|
|
return tick;
|
||
|
|
}
|
||
|
|
|
||
|
|
void end(const std::string& name, double divisor, const char* divisorName = "pixel", bool perfLog = false, int64 tick = 0) {
|
||
|
|
string fullname = substitudeName(name);
|
||
|
|
CyclopsLockGuard mLockGuard(&mLock);
|
||
|
|
StringInt64MapIter it = mListenMap.end();
|
||
|
|
auto rng = mListenMap.equal_range(fullname);
|
||
|
|
for (auto it0 = rng.first; it0 != rng.second; ++it0) {
|
||
|
|
if (tick == 0 || it0->second == tick) {
|
||
|
|
it = it0;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (it != mListenMap.end()) {
|
||
|
|
auto it2 = mPerfInfoMap.find(fullname);
|
||
|
|
double t = (getTickCount() - it->second) / mTickFreq;
|
||
|
|
if (it2 == mPerfInfoMap.end()) {
|
||
|
|
mPerfInfoMap[fullname] = PerfInfo(divisorName);
|
||
|
|
}
|
||
|
|
mPerfInfoMap[fullname].add(t, divisor);
|
||
|
|
mListenMap.erase(it);
|
||
|
|
|
||
|
|
if (perfLog) {
|
||
|
|
std::cout << "[PerfLog]" << fullname << ": " << t * 1000 << "ms" << std::endl;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void end(const std::string& name, bool perfLog = true, int64 tick = 0) {
|
||
|
|
end(name, 1, "execution", perfLog, tick);
|
||
|
|
}
|
||
|
|
|
||
|
|
void print_all(const std::string& filename) {
|
||
|
|
using namespace std;
|
||
|
|
CyclopsLockGuard mLockGuard(&mLock);
|
||
|
|
cout << "===============================================================================" << endl;
|
||
|
|
cout << "====PERFORMANCE ANALYSIS=======================================================" << endl;
|
||
|
|
cout << "====for detailed performance log, check the perf.csv under execution folder.===" << endl;
|
||
|
|
ofstream outFile;
|
||
|
|
outFile.open(filename, std::ofstream::out);
|
||
|
|
outFile << "name,div_name,time,div" << endl;
|
||
|
|
for (auto it = mPerfInfoMap.begin(); it != mPerfInfoMap.end(); it++)
|
||
|
|
{
|
||
|
|
double perT;
|
||
|
|
string div_name;
|
||
|
|
static const int cTrunk = 10000;
|
||
|
|
if (it->second.totalDivisor > cTrunk) {
|
||
|
|
perT = it->second.totalTime / (it->second.totalDivisor / cTrunk);
|
||
|
|
#if (defined(_MSC_VER) && _MSC_VER <= 1600)
|
||
|
|
div_name = std::to_string((_Longlong)cTrunk) + " " + it->second.divisorName;
|
||
|
|
#else
|
||
|
|
div_name = std::to_string(cTrunk) + " " + it->second.divisorName;
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
perT = it->second.totalTime / it->second.totalDivisor;
|
||
|
|
div_name = it->second.divisorName;
|
||
|
|
}
|
||
|
|
cout << it->first << ": " << perT * 1000 << "ms per " << div_name << endl;
|
||
|
|
for (auto it2 = it->second.times.begin(), it3 = it->second.divisors.begin();
|
||
|
|
it2 != it->second.times.end() && it3 != it->second.divisors.end(); ++it2, ++it3)
|
||
|
|
{
|
||
|
|
outFile << it->first << "," << it->second.divisorName << "," << *it2 << "," << *it3 << endl;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
outFile.close();
|
||
|
|
cout << "===============================================================================" << endl;
|
||
|
|
mPerfInfoMap.clear();
|
||
|
|
mListenMap.clear();
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
StringPerfInfoMap mPerfInfoMap;
|
||
|
|
StringInt64Map mListenMap;
|
||
|
|
double mTickFreq;
|
||
|
|
string mCurScopeName;
|
||
|
|
CyclopsLock mLock;
|
||
|
|
};
|
||
|
|
|
||
|
|
#ifdef _PERF_LOG
|
||
|
|
#define START_PERF_LOG(name) PerfTimer::getLogTimer()->start(name);
|
||
|
|
#define END_PERF_LOG(name) PerfTimer::getLogTimer()->end(name);
|
||
|
|
#define START_PERF_LOG_THREAD(name, tick) tick = PerfTimer::getLogTimer()->start(name);
|
||
|
|
#define END_PERF_LOG_THREAD(name, tick) PerfTimer::getLogTimer()->end(name, true, tick);
|
||
|
|
#define START_PERF_SCOPE(name) PerfTimer::getLogTimer()->setScope(name);
|
||
|
|
#define END_PERF_SCOPE() PerfTimer::getLogTimer()->clearScope();
|
||
|
|
#else
|
||
|
|
#define START_PERF_LOG(name)
|
||
|
|
#define END_PERF_LOG(name)
|
||
|
|
#define START_PERF_LOG_THREAD(name, tick)
|
||
|
|
#define END_PERF_LOG_THREAD(name, tick)
|
||
|
|
#define START_PERF_SCOPE(name)
|
||
|
|
#define END_PERF_SCOPE()
|
||
|
|
#endif // _DEBUG
|
||
|
|
|
||
|
|
#endif
|