compute-runtime/shared/source/utilities/perf_profiler.cpp

179 lines
5.8 KiB
C++

/*
* Copyright (C) 2018-2025 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "shared/source/utilities/perf_profiler.h"
#include "shared/source/utilities/stackvec.h"
#include <atomic>
#include <cstring>
#include <fstream>
#include <sstream>
#include <thread>
namespace NEO {
std::atomic<int> PerfProfiler::counter(0);
thread_local PerfProfiler *gPerfProfiler = nullptr;
PerfProfiler *PerfProfiler::objects[PerfProfiler::objectsNumber] = {
nullptr,
};
PerfProfiler *PerfProfiler::create(bool dumpToFile) {
if (gPerfProfiler == nullptr) {
int old = counter.fetch_add(1);
if (!dumpToFile) {
std::unique_ptr<std::stringstream> logs = std::unique_ptr<std::stringstream>(new std::stringstream());
std::unique_ptr<std::stringstream> sysLogs = std::unique_ptr<std::stringstream>(new std::stringstream());
gPerfProfiler = new PerfProfiler(old, std::move(logs), std::move(sysLogs));
} else {
gPerfProfiler = new PerfProfiler(old);
}
objects[old] = gPerfProfiler;
}
return gPerfProfiler;
}
void PerfProfiler::destroyAll() {
int count = counter;
for (int i = 0; i < count; i++) {
if (objects[i] != nullptr) {
delete objects[i];
objects[i] = nullptr;
}
}
counter = 0;
gPerfProfiler = nullptr;
}
PerfProfiler::PerfProfiler(int id, std::unique_ptr<std::ostream> &&logOut, std::unique_ptr<std::ostream> &&sysLogOut) {
apiTimer.setFreq();
systemLogs.reserve(20);
if (logOut != nullptr) {
this->logFile = std::move(logOut);
} else {
std::stringstream filename;
filename << "PerfReport_Thread_" << id << ".xml";
std::unique_ptr<std::ofstream> logToFile = std::unique_ptr<std::ofstream>(new std::ofstream());
logToFile->exceptions(std::ios::failbit | std::ios::badbit);
logToFile->open(filename.str().c_str(), std::ios::trunc);
this->logFile = std::move(logToFile);
}
*logFile << "<report>" << std::endl;
if (sysLogOut != nullptr) {
this->sysLogFile = std::move(sysLogOut);
} else {
std::stringstream filename;
filename << "SysPerfReport_Thread_" << id << ".xml";
std::unique_ptr<std::ofstream> sysLogToFile = std::unique_ptr<std::ofstream>(new std::ofstream());
sysLogToFile->exceptions(std::ios::failbit | std::ios::badbit);
sysLogToFile->open(filename.str().c_str(), std::ios::trunc);
this->sysLogFile = std::move(sysLogToFile);
}
*sysLogFile << "<report>" << std::endl;
}
PerfProfiler::~PerfProfiler() {
*logFile << "</report>" << std::endl;
logFile->flush();
*sysLogFile << "</report>" << std::endl;
sysLogFile->flush();
gPerfProfiler = nullptr;
}
void PerfProfiler::readAndVerify(std::istream &stream, const std::string &token) {
StackVec<char, 4096> buff;
buff.resize(token.size());
size_t numRead = static_cast<size_t>(stream.readsome(&buff[0], token.size()));
if ((numRead != token.size()) || (0 != std::strncmp(&buff[0], token.c_str(), token.size()))) {
throw std::runtime_error("ReadAndVerify failed");
}
}
void PerfProfiler::LogBuilder::write(std::ostream &str, long long start, long long end, long long span, unsigned long long totalSystem, const char *function) {
str << "<api name=\"" << function << "\">\n";
str << "<data start=\"" << start << "\" end=\"" << end << "\" time=\""
<< span << "\" api=\"" << span - totalSystem << "\" system=\"" << totalSystem << "\" />\n";
str << "</api>\n";
}
void PerfProfiler::LogBuilder::read(std::istream &str, long long &start, long long &end, long long &span, unsigned long long &totalSystem, std::string &function) {
StackVec<char, 4096> funcNameBuff;
readAndVerify(str, "<api name=\"");
while ((str.eof() == false) && (str.peek() != '\"')) {
char c;
str.read(&c, 1);
funcNameBuff.push_back(c);
}
if (str.eof()) {
throw std::runtime_error("Could not read function name");
}
readAndVerify(str, "\">\n");
readAndVerify(str, "<data start=\"");
str >> start;
readAndVerify(str, "\" end=\"");
str >> end;
readAndVerify(str, "\" time=\"");
str >> span;
readAndVerify(str, "\" api=\"");
str >> totalSystem;
readAndVerify(str, "\" system=\"");
str >> totalSystem;
readAndVerify(str, "\" />\n");
readAndVerify(str, "</api>\n");
function.assign(funcNameBuff.begin(), funcNameBuff.end());
}
void PerfProfiler::SysLogBuilder::write(std::ostream &str, long long start, unsigned long long time, unsigned int id) {
str << "<sys id=\"" << id << "\">\n";
str << "<data start=\"" << start << "\" time=\"" << time << "\" />\n";
str << "</sys>\n";
}
void PerfProfiler::SysLogBuilder::read(std::istream &str, long long &start, unsigned long long &time, unsigned int &id) {
readAndVerify(str, "<sys id=\"");
str >> id;
readAndVerify(str, "\">\n");
readAndVerify(str, "<data start=\"");
str >> start;
readAndVerify(str, "\" time=\"");
str >> time;
readAndVerify(str, "\" />\n");
readAndVerify(str, "</sys>\n");
}
void PerfProfiler::logTimes(long long start, long long end, long long span, unsigned long long totalSystem, const char *function) {
std::stringstream str;
LogBuilder::write(str, start, end, span, totalSystem, function);
*logFile << str.str();
logFile->flush();
auto it = systemLogs.begin();
while (it != systemLogs.end()) {
str.str(std::string());
SysLogBuilder::write(str, it->start, it->time, it->id);
*sysLogFile << str.str();
it++;
}
sysLogFile->flush();
}
void PerfProfiler::logSysTimes(long long start, unsigned long long time, unsigned int id) {
systemLogs.emplace_back(SystemLog{id, start, time});
}
} // namespace NEO