Files

122 lines
3.4 KiB
C++

#include "perfjson.h"
#include <QHttpServer>
#include <QJsonObject>
#include <QDebug>
#include <QCoreApplication>
#include <unistd.h>
#include <sys/prctl.h>
#include <signal.h>
PerfJson::PerfJson(QHttpServer &server, QObject *parent) :
QObject{parent}
{
m_process.setProcessChannelMode(QProcess::MergedChannels);
m_process.setChildProcessModifier([] {
prctl(PR_SET_PDEATHSIG, SIGKILL);
});
connect(&m_process, &QProcess::started, this, &PerfJson::processStarted);
connect(&m_process, &QProcess::finished, this, &PerfJson::processFinished);
connect(&m_process, &QProcess::readyRead, this, &PerfJson::readyRead);
m_process.start("sudo", {"perf", "trace", "-e", "bcachefs:error_throw", "-e", "bcachefs:write_super"});
server.route("/perf_json", this, &PerfJson::getPerfJson);
}
void PerfJson::processStarted()
{
qDebug() << "started";
}
void PerfJson::processFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
qDebug() << "finished exitCode =" << exitCode << "exitStatus =" << exitStatus;
QCoreApplication::exit(exitCode);
}
void PerfJson::readyRead()
{
while (m_process.canReadLine())
{
auto lineStr = m_process.readLine();
QByteArrayView line = lineStr;
line = line.trimmed();
//qDebug() << "received" << line;
qsizetype tsEnd = line.indexOf(' ');
QByteArrayView timestamp = line.left(tsEnd);
qsizetype lparen = line.indexOf('(', tsEnd + 1);
qsizetype funcStart = line.lastIndexOf(' ', lparen);
QByteArrayView function = line.mid(funcStart + 1, lparen - funcStart - 1);
QByteArrayView thread = line.mid(tsEnd + 1, funcStart - tsEnd - 1);
qsizetype rparen = line.lastIndexOf(')');
QByteArrayView args = line.mid(lparen + 1, rparen - lparen - 1);
//qDebug() << "timestamp =" << timestamp;
//qDebug() << "thread =" << thread;
//qDebug() << "function =" << function;
//qDebug() << "args =" << args;
QByteArrayView fs, str;
while (!args.isEmpty())
{
qsizetype colon = args.indexOf(':');
qsizetype quote1 = args.indexOf('"', colon);
qsizetype quote2 = args.indexOf('"', quote1 + 1);
QByteArrayView key = args.left(colon).trimmed();
QByteArrayView value = args.mid(quote1 + 1, quote2 - quote1 - 1);
//qDebug() << "key =" << key << "value =" << value;
if (key == "fs")
fs = value;
else if (key == "str")
str = value;
qsizetype next = args.indexOf(',', quote2);
if (next == -1) break;
args = args.mid(next + 1).trimmed();
}
if (fs.isEmpty())
continue;
counters[fs][function][str]++;
}
}
QJsonObject PerfJson::getPerfJson() const
{
auto filesystems = QJsonObject{};
for (auto iter = std::cbegin(counters); iter != std::cend(counters); iter++)
{
auto functions = QJsonObject{};
for (auto iter2 = std::cbegin(iter.value()); iter2 != std::cend(iter.value()); iter2++)
{
auto strs = QJsonObject{};
for (auto iter3 = std::cbegin(iter2.value()); iter3 != std::cend(iter2.value()); iter3++)
strs[iter3.key()] = iter3.value();
functions[iter2.key()] = std::move(strs);
}
filesystems[iter.key()] = std::move(functions);
}
return filesystems;
}