#include "perfjson.h" #include #include #include #include #include #include #include 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; }