2022-12-23 13:50:27 -05:00
|
|
|
/*
|
|
|
|
* Created by Brett on 23/12/22.
|
|
|
|
* Licensed under GNU General Public License V3.0
|
|
|
|
* See LICENSE file for license detail
|
|
|
|
*/
|
2022-12-26 00:31:00 -05:00
|
|
|
#include <blt/profiling/profiler.h>
|
2023-01-26 00:59:36 -05:00
|
|
|
#include <mutex>
|
|
|
|
#include <vector>
|
|
|
|
#include <blt/std/time.h>
|
|
|
|
#include <blt/std/logging.h>
|
|
|
|
#include <iostream>
|
2023-01-26 12:21:19 -05:00
|
|
|
#include <algorithm>
|
2023-01-27 00:49:44 -05:00
|
|
|
#include <blt/std/format.h>
|
2022-12-26 00:31:00 -05:00
|
|
|
|
2023-01-26 00:59:36 -05:00
|
|
|
namespace blt::profiling {
|
|
|
|
|
|
|
|
// TODO: a better way
|
|
|
|
std::mutex profileLock{};
|
2023-02-14 22:22:48 -05:00
|
|
|
std::unordered_map<std::string, profile> profiles;
|
2023-01-26 00:59:36 -05:00
|
|
|
|
|
|
|
void startInterval(const std::string& profileName, const std::string& intervalName) {
|
|
|
|
std::scoped_lock lock(profileLock);
|
2023-02-14 22:22:48 -05:00
|
|
|
capture_interval interval{};
|
2023-02-11 12:53:32 -05:00
|
|
|
interval.start = system::getCurrentTimeNanoseconds();
|
2023-01-26 00:59:36 -05:00
|
|
|
profiles[profileName].intervals[intervalName] = interval;
|
|
|
|
}
|
|
|
|
|
|
|
|
void endInterval(const std::string& profileName, const std::string& intervalName) {
|
|
|
|
std::scoped_lock lock(profileLock);
|
2023-02-11 12:53:32 -05:00
|
|
|
profiles[profileName].intervals[intervalName].end = system::getCurrentTimeNanoseconds();
|
2023-02-14 22:06:30 -05:00
|
|
|
profiles[profileName].historicalIntervals[intervalName].push_back(profiles[profileName].intervals[intervalName]);
|
2023-01-26 00:59:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void point(const std::string& profileName, const std::string& pointName) {
|
2023-01-27 10:45:18 -05:00
|
|
|
std::scoped_lock lock(profileLock);
|
2023-02-14 22:22:48 -05:00
|
|
|
capture_point point{};
|
2023-02-11 12:53:32 -05:00
|
|
|
point.point = system::getCurrentTimeNanoseconds();
|
2023-01-27 10:45:18 -05:00
|
|
|
point.name = pointName;
|
|
|
|
profiles[profileName].points.push(point);
|
2023-01-26 00:59:36 -05:00
|
|
|
}
|
|
|
|
|
2023-02-14 22:22:48 -05:00
|
|
|
capture_interval getInterval(const std::string& profileName, const std::string& intervalName) {
|
2023-01-26 00:59:36 -05:00
|
|
|
return profiles[profileName].intervals[intervalName];
|
|
|
|
}
|
|
|
|
|
2023-02-14 22:22:48 -05:00
|
|
|
profile getProfile(const std::string& profileName) {
|
2023-01-26 00:59:36 -05:00
|
|
|
return profiles[profileName];
|
|
|
|
}
|
|
|
|
|
2023-02-08 17:22:27 -05:00
|
|
|
inline void print(const std::vector<std::string>& lines, logging::LOG_LEVEL level) {
|
|
|
|
auto& logger = logging::getLoggerFromLevel(level);
|
|
|
|
for (const auto& line : lines)
|
|
|
|
logger << line;
|
2023-01-26 12:21:19 -05:00
|
|
|
}
|
|
|
|
|
2023-02-14 22:32:23 -05:00
|
|
|
void printProfile(const std::string& profileName, blt::logging::LOG_LEVEL loggingLevel, bool averageHistory, bool ignoreNegatives) {
|
2023-02-15 09:50:20 -05:00
|
|
|
string::TableFormatter formatter{profileName};
|
2023-01-27 00:49:44 -05:00
|
|
|
formatter.addColumn({"Interval"});
|
|
|
|
formatter.addColumn({"Time (ns)"});
|
|
|
|
formatter.addColumn({"Time (ms)"});
|
2023-02-15 09:50:20 -05:00
|
|
|
|
2023-02-14 22:28:58 -05:00
|
|
|
auto& profile = profiles[profileName];
|
2023-01-27 00:49:44 -05:00
|
|
|
const auto& intervals = profile.intervals;
|
|
|
|
const auto& points = profile.points;
|
|
|
|
|
|
|
|
for (const auto& interval : intervals) {
|
2023-02-14 22:28:58 -05:00
|
|
|
if (averageHistory) {
|
|
|
|
const auto& history = profile.historicalIntervals[interval.first];
|
|
|
|
long total_difference = 0;
|
|
|
|
for (const auto& h_interval : history) {
|
|
|
|
const auto difference = h_interval.end - h_interval.start;
|
2023-02-14 22:32:23 -05:00
|
|
|
if (ignoreNegatives && difference < 0)
|
|
|
|
continue;
|
2023-02-14 22:28:58 -05:00
|
|
|
total_difference += difference;
|
|
|
|
}
|
|
|
|
total_difference /= (long) history.size();
|
2023-02-15 09:50:20 -05:00
|
|
|
std::string name = "(";
|
|
|
|
name += std::to_string(history.size());
|
|
|
|
name += ") ";
|
|
|
|
name += interval.first;
|
|
|
|
formatter.addRow({name, std::to_string(total_difference), std::to_string((double) total_difference / 1000000.0)});
|
2023-02-14 22:28:58 -05:00
|
|
|
} else {
|
|
|
|
const auto difference = interval.second.end - interval.second.start;
|
2023-02-14 22:32:23 -05:00
|
|
|
if (ignoreNegatives && difference < 0)
|
|
|
|
continue;
|
2023-02-14 22:28:58 -05:00
|
|
|
formatter.addRow({interval.first, std::to_string(difference), std::to_string((double) difference / 1000000.0)});
|
|
|
|
}
|
2023-01-27 00:49:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string> updatedLines;
|
|
|
|
const auto& lines = formatter.createTable(true, true);
|
|
|
|
for (const auto& line : lines)
|
|
|
|
updatedLines.emplace_back(line + "\n");
|
|
|
|
|
|
|
|
print(updatedLines, loggingLevel);
|
|
|
|
}
|
|
|
|
|
2023-01-26 12:21:19 -05:00
|
|
|
struct timeOrderContainer {
|
|
|
|
long difference;
|
|
|
|
std::string name;
|
|
|
|
|
|
|
|
timeOrderContainer(long difference, std::string name): difference(difference), name(std::move(name)) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
inline bool timeCompare(const timeOrderContainer& container1, const timeOrderContainer& container2) {
|
|
|
|
return container1.difference < container2.difference;
|
|
|
|
}
|
|
|
|
|
2023-02-14 22:32:23 -05:00
|
|
|
void printOrderedProfile(const std::string& profileName, logging::LOG_LEVEL loggingLevel, bool averageHistory, bool ignoreNegatives) {
|
2023-02-14 22:28:58 -05:00
|
|
|
auto& profile = profiles[profileName];
|
2023-01-27 09:58:51 -05:00
|
|
|
const auto& intervals = profile.intervals;
|
|
|
|
const auto& points = profile.points;
|
2023-02-15 09:50:20 -05:00
|
|
|
|
2023-01-27 09:58:51 -05:00
|
|
|
std::vector<timeOrderContainer> unorderedIntervalVector;
|
2023-02-15 09:50:20 -05:00
|
|
|
|
2023-02-14 22:32:23 -05:00
|
|
|
// TODO: refactor to reduce nesting
|
|
|
|
|
2023-01-27 09:58:51 -05:00
|
|
|
for (const auto& interval : intervals) {
|
2023-02-14 22:28:58 -05:00
|
|
|
if (averageHistory) {
|
|
|
|
const auto& history = profile.historicalIntervals[interval.first];
|
|
|
|
long total_difference = 0;
|
|
|
|
for (const auto& h_interval : history) {
|
|
|
|
const auto difference = h_interval.end - h_interval.start;
|
2023-02-14 22:32:23 -05:00
|
|
|
if (ignoreNegatives && difference < 0)
|
|
|
|
continue;
|
2023-02-14 22:28:58 -05:00
|
|
|
total_difference += difference;
|
|
|
|
}
|
|
|
|
total_difference /= (long) history.size();
|
2023-02-15 09:50:20 -05:00
|
|
|
std::string name = "(";
|
|
|
|
name += std::to_string(history.size());
|
|
|
|
name += ") ";
|
|
|
|
name += interval.first;
|
|
|
|
unorderedIntervalVector.emplace_back(total_difference, name);
|
2023-02-14 22:28:58 -05:00
|
|
|
} else {
|
|
|
|
const auto difference = interval.second.end - interval.second.start;
|
2023-02-14 22:32:23 -05:00
|
|
|
if (ignoreNegatives && difference < 0)
|
|
|
|
continue;
|
2023-02-14 22:28:58 -05:00
|
|
|
unorderedIntervalVector.emplace_back(difference, interval.first);
|
|
|
|
}
|
2023-01-27 09:58:51 -05:00
|
|
|
}
|
2023-02-15 09:50:20 -05:00
|
|
|
|
2023-01-27 09:58:51 -05:00
|
|
|
std::sort(unorderedIntervalVector.begin(), unorderedIntervalVector.end(), timeCompare);
|
2023-02-15 09:50:20 -05:00
|
|
|
|
|
|
|
string::TableFormatter formatter{profileName};
|
2023-01-27 09:58:51 -05:00
|
|
|
formatter.addColumn({"Order"});
|
|
|
|
formatter.addColumn({"Interval"});
|
|
|
|
formatter.addColumn({"Time (ns)"});
|
|
|
|
formatter.addColumn({"Time (ms)"});
|
2023-02-15 09:50:20 -05:00
|
|
|
|
2023-01-27 09:58:51 -05:00
|
|
|
int index = 1;
|
|
|
|
for (const auto& interval : unorderedIntervalVector) {
|
2023-02-15 09:50:20 -05:00
|
|
|
formatter.addRow(
|
|
|
|
{std::to_string(index++), interval.name, std::to_string(interval.difference), std::to_string(interval.difference / 1000000.0)}
|
|
|
|
);
|
2023-01-27 09:58:51 -05:00
|
|
|
}
|
2023-02-15 09:50:20 -05:00
|
|
|
|
2023-01-27 09:58:51 -05:00
|
|
|
std::vector<std::string> updatedLines;
|
|
|
|
const auto& lines = formatter.createTable(true, true);
|
|
|
|
for (const auto& line : lines)
|
|
|
|
updatedLines.emplace_back(line + "\n");
|
2023-02-15 09:50:20 -05:00
|
|
|
|
2023-01-27 09:58:51 -05:00
|
|
|
print(updatedLines, loggingLevel);
|
|
|
|
}
|
|
|
|
|
2023-01-26 00:59:36 -05:00
|
|
|
void discardProfiles() {
|
|
|
|
profiles = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
void discardIntervals(const std::string& profileName) {
|
|
|
|
profiles[profileName].intervals = {};
|
2023-02-14 22:06:30 -05:00
|
|
|
profiles[profileName].historicalIntervals = {};
|
2023-01-26 00:59:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void discardPoints(const std::string& profileName) {
|
|
|
|
profiles[profileName].points = {};
|
|
|
|
}
|
2023-02-14 22:06:30 -05:00
|
|
|
|
2023-02-14 22:22:48 -05:00
|
|
|
std::vector<capture_interval> getAllIntervals(const std::string& profileName, const std::string& intervalName) {
|
2023-02-14 22:06:30 -05:00
|
|
|
return profiles[profileName].historicalIntervals[intervalName];
|
|
|
|
}
|
2022-12-26 00:31:00 -05:00
|
|
|
}
|