| 1 | // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. | 
|---|
| 2 | // | 
|---|
| 3 | // SPDX-License-Identifier: GPL-3.0-or-later | 
|---|
| 4 |  | 
|---|
| 5 | #include "tools.h" | 
|---|
| 6 |  | 
|---|
| 7 | #include <QDebug> | 
|---|
| 8 | #include <QDir> | 
|---|
| 9 | #include <QMetaEnum> | 
|---|
| 10 | #include <QRegularExpression> | 
|---|
| 11 | #include <QCoreApplication> | 
|---|
| 12 | #include <QStandardPaths> | 
|---|
| 13 | #include <QTextBrowser> | 
|---|
| 14 | #include <QApplication> | 
|---|
| 15 |  | 
|---|
| 16 | #include <iostream> | 
|---|
| 17 | #include <vector> | 
|---|
| 18 |  | 
|---|
| 19 | namespace { | 
|---|
| 20 | // perf top tool | 
|---|
| 21 | static std::string overhead{ "overhead"}; | 
|---|
| 22 | static std::string sample{ "sample"}; | 
|---|
| 23 | static std::string period{ "period"}; | 
|---|
| 24 | static std::string dso{ "dso"}; | 
|---|
| 25 | static std::string symbol{ "symbol"}; | 
|---|
| 26 | static std::string srcline{ "srcline"}; | 
|---|
| 27 |  | 
|---|
| 28 | /* top tool command out VIRT field : | 
|---|
| 29 | * VIRT stands for the virtual size of a process, | 
|---|
| 30 | * which is the sum of memory it is actually using, | 
|---|
| 31 | * memory it has mapped into itself (for instance the video card’s RAM for the X server), | 
|---|
| 32 | * files on disk that have been mapped into it (most notably shared libraries), | 
|---|
| 33 | * and memory shared with other processes. | 
|---|
| 34 | * VIRT represents how much memory the program is able to access at the present moment. | 
|---|
| 35 | */ | 
|---|
| 36 |  | 
|---|
| 37 | /* top tool command out RES field : | 
|---|
| 38 | * RES stands for the resident size, | 
|---|
| 39 | * which is an accurate representation of how much actual physical memory a process is consuming. | 
|---|
| 40 | * (This also corresponds directly to the %MEM column.) This will virtually always be less than the VIRT size, | 
|---|
| 41 | * since most programs depend on the C library. | 
|---|
| 42 | */ | 
|---|
| 43 |  | 
|---|
| 44 | /* top tool command out SHR field : | 
|---|
| 45 | * SHR indicates how much of the VIRT size is actually sharable (memory or libraries). | 
|---|
| 46 | * In the case of libraries, it does not necessarily mean that the entire library is resident. | 
|---|
| 47 | * For example, if a program only uses a few functions in a library, | 
|---|
| 48 | * the whole library is mapped and will be counted in VIRT and SHR, | 
|---|
| 49 | * but only the parts of the library file containing the functions being used will actually be loaded in and be counted under RES. | 
|---|
| 50 | */ | 
|---|
| 51 | static std::string processId{ "processId"}; | 
|---|
| 52 | static std::string user{ "user"}; | 
|---|
| 53 | static std::string priority{ "priority"}; | 
|---|
| 54 | static std::string nice{ "nice"}; | 
|---|
| 55 | static std::string virtualSize{ "virtualSize"}; | 
|---|
| 56 | static std::string residentSize{ "residentSize"}; | 
|---|
| 57 | static std::string sharable{ "sharable"}; | 
|---|
| 58 | static std::string status{ "status"}; | 
|---|
| 59 | static std::string cpuOverhead{ "cpuOverhead"}; | 
|---|
| 60 | static std::string memoryOverhead{ "memoryOverhead"}; | 
|---|
| 61 | static std::string timeCount{ "timeCount"}; | 
|---|
| 62 | static std::string command{ "command"}; | 
|---|
| 63 |  | 
|---|
| 64 | static std::string fd{ "fd"}; | 
|---|
| 65 | static std::string type{ "type"}; | 
|---|
| 66 | static std::string device{ "device"}; | 
|---|
| 67 | static std::string sizeOff{ "sizeOff"}; | 
|---|
| 68 | static std::string node{ "node"}; | 
|---|
| 69 | static std::string name{ "name"}; | 
|---|
| 70 |  | 
|---|
| 71 | static std::string netId{ "netId"}; | 
|---|
| 72 | static std::string state{ "state"}; | 
|---|
| 73 | static std::string recvQueue{ "recvQueue"}; | 
|---|
| 74 | static std::string sendQueue{ "sendQueue"}; | 
|---|
| 75 | static std::string localAddrPort{ "localAddrPort"}; | 
|---|
| 76 | static std::string peerAddrPort{ "peerAddressPort"}; | 
|---|
| 77 | static std::string usingProcesses{ "usingProcesses"}; | 
|---|
| 78 |  | 
|---|
| 79 | // device IO field | 
|---|
| 80 | static std::string userId{ "userId"}; | 
|---|
| 81 | //static std::string processId{"processId"}; | 
|---|
| 82 | static std::string kB_rd{ "kB_rd"}; | 
|---|
| 83 | static std::string kB_wd{ "kB_wd"}; | 
|---|
| 84 | static std::string kB_ccwr{ "kB_ccwr"}; | 
|---|
| 85 | static std::string iodelay{ "iodelay"}; | 
|---|
| 86 | //static std::string command{"command"}; | 
|---|
| 87 |  | 
|---|
| 88 |  | 
|---|
| 89 | static std::string feild{ "feild"}; | 
|---|
| 90 | static std::string key{ "key"}; | 
|---|
| 91 | static std::string lines{ "lines"}; | 
|---|
| 92 |  | 
|---|
| 93 | static std::string package_name{ "package_name"}; | 
|---|
| 94 | static std::string system_default{ "system default"}; | 
|---|
| 95 |  | 
|---|
| 96 | template<class E> | 
|---|
| 97 | const char * enumName() | 
|---|
| 98 | { | 
|---|
| 99 | return QMetaEnum::fromType<E>().name(); | 
|---|
| 100 | } | 
|---|
| 101 |  | 
|---|
| 102 | template<class Elem> | 
|---|
| 103 | const char * enumElemName(Elem type) | 
|---|
| 104 | { | 
|---|
| 105 | return QMetaEnum::fromType<Elem>().valueToKey(type); | 
|---|
| 106 | } | 
|---|
| 107 |  | 
|---|
| 108 | struct QStr : QString | 
|---|
| 109 | { | 
|---|
| 110 | QStr(const std::string &src) : QString(QString::fromStdString(src)){} | 
|---|
| 111 | }; | 
|---|
| 112 |  | 
|---|
| 113 | struct Add : QString, std::string | 
|---|
| 114 | { | 
|---|
| 115 | Add(const QString &x, const QString &y) | 
|---|
| 116 | : QString(QString::number(x.toULongLong() + y.toULongLong())) | 
|---|
| 117 | , std::string(QString::toStdString()) | 
|---|
| 118 | { | 
|---|
| 119 |  | 
|---|
| 120 | } | 
|---|
| 121 |  | 
|---|
| 122 | Add(const std::string &x, const std::string &y) | 
|---|
| 123 | : QString(QString::number(QStr(x).toLongLong() + QStr(y).toLongLong())) | 
|---|
| 124 | , std::string(QString::toStdString()) | 
|---|
| 125 | { | 
|---|
| 126 |  | 
|---|
| 127 | } | 
|---|
| 128 | }; | 
|---|
| 129 |  | 
|---|
| 130 | QString format(const QString &src) | 
|---|
| 131 | { | 
|---|
| 132 | QString temp = src; | 
|---|
| 133 | temp.replace(QRegExp( "[\\s]+"), " "); | 
|---|
| 134 | while (temp.startsWith( " ")) { | 
|---|
| 135 | temp.remove(0 , sizeof( " ")); | 
|---|
| 136 | } | 
|---|
| 137 | while (temp.endsWith( " ")) { | 
|---|
| 138 | temp.remove(temp.size() - 1, sizeof( " ")); | 
|---|
| 139 | } | 
|---|
| 140 | return temp; | 
|---|
| 141 | }; | 
|---|
| 142 |  | 
|---|
| 143 | struct Template | 
|---|
| 144 | { | 
|---|
| 145 | static QString scriptsPath() | 
|---|
| 146 | { | 
|---|
| 147 | QString cacheChildPath = QCoreApplication::applicationName(); | 
|---|
| 148 | QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation)); | 
|---|
| 149 | dir.cdUp(); | 
|---|
| 150 | if (!dir.cd(cacheChildPath)) { | 
|---|
| 151 | dir.mkdir(cacheChildPath); | 
|---|
| 152 | dir.cd(cacheChildPath); | 
|---|
| 153 | } | 
|---|
| 154 |  | 
|---|
| 155 | qInfo() << dir.path(); | 
|---|
| 156 | QString scriptChildPath = "scripts"; | 
|---|
| 157 | if (!dir.cd(scriptChildPath)) { | 
|---|
| 158 | dir.mkdir(scriptChildPath); | 
|---|
| 159 | dir.cd(scriptChildPath); | 
|---|
| 160 | } | 
|---|
| 161 | qInfo() << dir.path(); | 
|---|
| 162 | return dir.path(); | 
|---|
| 163 | } | 
|---|
| 164 |  | 
|---|
| 165 | static QString scriptsPathFrom(Tools::PerformanceType pt) | 
|---|
| 166 | { | 
|---|
| 167 | return scriptsPath() + QDir::separator() + enumElemName<Tools::PerformanceType>(pt) + "Lanuch.sh"; | 
|---|
| 168 | } | 
|---|
| 169 |  | 
|---|
| 170 | static void checkSocketScript() | 
|---|
| 171 | { | 
|---|
| 172 | QString filePath = scriptsPathFrom(Tools::PerformanceType::socket); | 
|---|
| 173 | QFile file(filePath); | 
|---|
| 174 | QByteArray readData; | 
|---|
| 175 | if (file.open(QFile::ReadOnly | QFile::Text)) { | 
|---|
| 176 | readData = file.readAll(); | 
|---|
| 177 | file.close(); | 
|---|
| 178 | } else { | 
|---|
| 179 | qCritical() << "can't open socket script"<< filePath; | 
|---|
| 180 | } | 
|---|
| 181 |  | 
|---|
| 182 | if (readData.isEmpty() || socketScriptCode() != readData) { | 
|---|
| 183 | QFile file(filePath); | 
|---|
| 184 | if (file.open(QFile::Truncate | QFile::WriteOnly | QFile::Text)) { | 
|---|
| 185 | file.write(socketScriptCode()); | 
|---|
| 186 | file.setPermissions(QFile::Permission::ExeUser | | 
|---|
| 187 | QFile::Permission::ReadUser| | 
|---|
| 188 | QFile::Permission::WriteUser); | 
|---|
| 189 | file.close(); | 
|---|
| 190 | } | 
|---|
| 191 | } | 
|---|
| 192 | } | 
|---|
| 193 |  | 
|---|
| 194 | static QByteArray socketScriptCode(){ | 
|---|
| 195 | #ifdef __linux__ | 
|---|
| 196 | return "#!/bin/bash\n" | 
|---|
| 197 | "if [ -z $1 ]; then\n" | 
|---|
| 198 | "    echo \"can't attach pid null\">&2\n" | 
|---|
| 199 | "    exit -1\n" | 
|---|
| 200 | "fi\n" | 
|---|
| 201 | "\n" | 
|---|
| 202 | "if [ -z $2 ]; then\n" | 
|---|
| 203 | "    echo \"can't parent pid null\">&2\n" | 
|---|
| 204 | "    exit -2\n" | 
|---|
| 205 | "fi\n" | 
|---|
| 206 | "\n" | 
|---|
| 207 | "while [ true ];\n" | 
|---|
| 208 | "do\n" | 
|---|
| 209 | "    if ps -p $1 >/dev/null; then\n" | 
|---|
| 210 | "        if ps -p $2 >/dev/null; then\n" | 
|---|
| 211 | "            ss -p|grep pid=$1;\n" | 
|---|
| 212 | "        else\n" | 
|---|
| 213 | "            echo \"can't found parent pid:'$2', add watch from parent\">&2\n" | 
|---|
| 214 | "        fi\n" | 
|---|
| 215 | "    else\n" | 
|---|
| 216 | "        echo \"can't found attach pid:'$1', process state no running\">&2\n" | 
|---|
| 217 | "        exit -1\n" | 
|---|
| 218 | "    fi\n" | 
|---|
| 219 | "    sleep 1;\n" | 
|---|
| 220 | "done\n"; | 
|---|
| 221 | #else | 
|---|
| 222 | #endif | 
|---|
| 223 | } | 
|---|
| 224 | }; | 
|---|
| 225 |  | 
|---|
| 226 | struct JsonOp | 
|---|
| 227 | { | 
|---|
| 228 |  | 
|---|
| 229 | static void setField(const std::vector<std::string> &feild, Json::Value &jsonObj) | 
|---|
| 230 | { | 
|---|
| 231 | Json::Value feildArray(Json::arrayValue); | 
|---|
| 232 | for (auto && val : feild) { | 
|---|
| 233 | feildArray.append(Json::Value(val)); | 
|---|
| 234 | } | 
|---|
| 235 | jsonObj[::feild] = feildArray; | 
|---|
| 236 | } | 
|---|
| 237 |  | 
|---|
| 238 |  | 
|---|
| 239 | static void setKey(const std::string &key, Json::Value &jsonObj) | 
|---|
| 240 | { | 
|---|
| 241 | jsonObj[::key] = key; | 
|---|
| 242 | } | 
|---|
| 243 | }; | 
|---|
| 244 |  | 
|---|
| 245 | } | 
|---|
| 246 |  | 
|---|
| 247 | class ToolsPrivate | 
|---|
| 248 | { | 
|---|
| 249 | friend class Tools; | 
|---|
| 250 | QHash<Tools::PerformanceType, QProcess*> toolsIns{}; | 
|---|
| 251 | QHash<Tools::PerformanceType, Json::Value> toolsCountCache{}; | 
|---|
| 252 | int attachPID{0}; | 
|---|
| 253 | QTextBrowser *textBrowser{nullptr}; | 
|---|
| 254 |  | 
|---|
| 255 | ~ToolsPrivate() | 
|---|
| 256 | { | 
|---|
| 257 | qDeleteAll(toolsIns); | 
|---|
| 258 | toolsCountCache.clear(); | 
|---|
| 259 | } | 
|---|
| 260 |  | 
|---|
| 261 | QTextBrowser *displayErrorWidget() | 
|---|
| 262 | { | 
|---|
| 263 | if (!textBrowser) { | 
|---|
| 264 | textBrowser = new QTextBrowser(); | 
|---|
| 265 | textBrowser->setWindowFlag(Qt::Dialog); | 
|---|
| 266 | textBrowser->setWindowTitle(QCoreApplication::applicationName() + " warning"); | 
|---|
| 267 | textBrowser->setMinimumSize(600,300); | 
|---|
| 268 | textBrowser->hide(); | 
|---|
| 269 | qApp->setQuitOnLastWindowClosed(false); | 
|---|
| 270 | } | 
|---|
| 271 | return textBrowser; | 
|---|
| 272 | } | 
|---|
| 273 |  | 
|---|
| 274 | void countFunction(const Json::Value &functionObj) | 
|---|
| 275 | { | 
|---|
| 276 | // no cache | 
|---|
| 277 | if (!toolsCountCache.contains(Tools::PerformanceType::function)) { | 
|---|
| 278 | toolsCountCache[Tools::PerformanceType::function] = functionObj; | 
|---|
| 279 | } else { // has cache | 
|---|
| 280 | // find array with cache | 
|---|
| 281 | Json::Value cache = toolsCountCache[Tools::PerformanceType::function]; | 
|---|
| 282 | Json::Value cacheFeild = cache[::feild]; | 
|---|
| 283 | Json::Value cacheLines = cache[::lines]; | 
|---|
| 284 | Json::Value paramFeild = functionObj[::feild]; | 
|---|
| 285 | Json::Value paramLines = functionObj[::lines]; | 
|---|
| 286 | if (paramFeild.size() != cacheFeild.size() | 
|---|
| 287 | && !cacheFeild.empty()) { | 
|---|
| 288 | qCritical() << __FUNCTION__ << "error feild not's same: " | 
|---|
| 289 | << "cache: "<< QString::fromStdString(cacheFeild.toStyledString()) | 
|---|
| 290 | << "current: "<< QString::fromStdString(paramFeild.toStyledString()); | 
|---|
| 291 |  | 
|---|
| 292 | return; | 
|---|
| 293 | } | 
|---|
| 294 |  | 
|---|
| 295 | int paramOverheadIdx = -1; | 
|---|
| 296 | int paramSampleIdx = -1; | 
|---|
| 297 | int paramPeriodIdx = -1; | 
|---|
| 298 | int paramDsoIdx = -1; | 
|---|
| 299 | int paramSymbolIdx = -1; | 
|---|
| 300 | int paramSrclineIdx = -1; | 
|---|
| 301 | int cacheOverheadIdx = -1; | 
|---|
| 302 | int cacheSampleIdx = -1; | 
|---|
| 303 | int cachePeriodIdx = -1; | 
|---|
| 304 | int cacheDsoIdx = -1; | 
|---|
| 305 | int cacheSymbolIdx = -1; | 
|---|
| 306 | int cacheSrclineIdx = -1; | 
|---|
| 307 |  | 
|---|
| 308 | for (unsigned int idx = 0; idx < qMin(cacheFeild.size(), paramFeild.size()); idx ++) { | 
|---|
| 309 | if (cacheFeild[idx] == ::overhead) { | 
|---|
| 310 | cacheOverheadIdx = static_cast<int>(idx); | 
|---|
| 311 | } | 
|---|
| 312 | if (cacheFeild[idx] == ::sample) { | 
|---|
| 313 | cacheSampleIdx = static_cast<int>(idx); | 
|---|
| 314 | } | 
|---|
| 315 | if (cacheFeild[idx] == ::period) { | 
|---|
| 316 | cachePeriodIdx = static_cast<int>(idx); | 
|---|
| 317 | } | 
|---|
| 318 | if (cacheFeild[idx] == ::dso) { | 
|---|
| 319 | cacheDsoIdx = static_cast<int>(idx); | 
|---|
| 320 | } | 
|---|
| 321 | if (cacheFeild[idx] == ::symbol) { | 
|---|
| 322 | cacheSymbolIdx = static_cast<int>(idx); | 
|---|
| 323 | } | 
|---|
| 324 | if (cacheFeild[idx] == ::srcline) { | 
|---|
| 325 | cacheSrclineIdx = static_cast<int>(idx); | 
|---|
| 326 | } | 
|---|
| 327 | if (paramFeild[idx] == ::overhead) { | 
|---|
| 328 | paramOverheadIdx = static_cast<int>(idx); | 
|---|
| 329 | } | 
|---|
| 330 | if (paramFeild[idx] == ::sample) { | 
|---|
| 331 | paramSampleIdx = static_cast<int>(idx); | 
|---|
| 332 | } | 
|---|
| 333 | if (paramFeild[idx] == ::period) { | 
|---|
| 334 | paramPeriodIdx = static_cast<int>(idx); | 
|---|
| 335 | } | 
|---|
| 336 | if (paramFeild[idx] == ::dso) { | 
|---|
| 337 | paramDsoIdx = static_cast<int>(idx); | 
|---|
| 338 | } | 
|---|
| 339 | if (paramFeild[idx] == ::symbol) { | 
|---|
| 340 | paramSymbolIdx = static_cast<int>(idx); | 
|---|
| 341 | } | 
|---|
| 342 | if (paramFeild[idx] == ::srcline) { | 
|---|
| 343 | paramSrclineIdx = static_cast<int>(idx); | 
|---|
| 344 | } | 
|---|
| 345 | } | 
|---|
| 346 |  | 
|---|
| 347 | for (unsigned int paramRow = 0; paramRow < paramLines.size(); paramRow ++) { | 
|---|
| 348 | auto paramLine = paramLines[paramRow]; | 
|---|
| 349 | bool hasSame = false; | 
|---|
| 350 | for (unsigned int cacheRow = 0; cacheRow < cacheLines.size();  cacheRow ++) { | 
|---|
| 351 | auto cacheLine = cacheLines[cacheRow]; | 
|---|
| 352 | if (paramSymbolIdx > 0 && cacheSymbolIdx > 0) { | 
|---|
| 353 | if (paramLine[paramSymbolIdx].asString() == cacheLine[cacheSymbolIdx].asString()) { | 
|---|
| 354 | if (cacheOverheadIdx > 0 && paramOverheadIdx > 0) | 
|---|
| 355 | cacheLine[cacheOverheadIdx] = paramLine[paramOverheadIdx].asString(); | 
|---|
| 356 | if (cacheSampleIdx > 0 && cacheSampleIdx > 0) | 
|---|
| 357 | cacheLine[cacheSampleIdx] = Add(cacheLine[cacheSampleIdx].asString(), paramLine[paramSampleIdx].asString()); | 
|---|
| 358 | if (cachePeriodIdx > 0 && paramPeriodIdx > 0) | 
|---|
| 359 | cacheLine[cachePeriodIdx] = Add(cacheLine[cachePeriodIdx].asString(), paramLine[paramPeriodIdx].asString()); | 
|---|
| 360 | if (cacheDsoIdx > 0 && paramDsoIdx > 0) | 
|---|
| 361 | cacheLine[cacheDsoIdx] = paramLine[paramDsoIdx].asString(); | 
|---|
| 362 | if (cacheSymbolIdx > 0 && paramSymbolIdx > 0) | 
|---|
| 363 | cacheLine[cacheSymbolIdx] = paramLine[paramSymbolIdx].asString(); | 
|---|
| 364 | if (cacheSrclineIdx > 0 && paramSrclineIdx > 0) | 
|---|
| 365 | cacheLine[cacheSrclineIdx] = paramLine[paramSrclineIdx].asString(); | 
|---|
| 366 | cacheLines[cacheRow] = cacheLine; | 
|---|
| 367 | hasSame = true; | 
|---|
| 368 | break; | 
|---|
| 369 | } | 
|---|
| 370 | } | 
|---|
| 371 | } | 
|---|
| 372 | if (!hasSame) { | 
|---|
| 373 | cacheLines.append(paramLine); | 
|---|
| 374 | } | 
|---|
| 375 | } | 
|---|
| 376 |  | 
|---|
| 377 | // rewrite overhead | 
|---|
| 378 | long long countPeriod = 0; | 
|---|
| 379 | for(unsigned int idx = 0; idx < cacheLines.size(); idx ++) { | 
|---|
| 380 | Json::Value cacheLine = cacheLines[idx]; | 
|---|
| 381 | if (!cacheLine.empty()) { | 
|---|
| 382 | countPeriod += QStr(cacheLine[cachePeriodIdx].asString()).toLongLong(); | 
|---|
| 383 | } | 
|---|
| 384 | } | 
|---|
| 385 | if (countPeriod > 0) { | 
|---|
| 386 | for (unsigned int i = 0; i < cacheLines.size(); i++) { | 
|---|
| 387 | Json::Value cacheLine =  cacheLines[i]; | 
|---|
| 388 | if (!cacheLine.empty()) { | 
|---|
| 389 | long long funcOnePeriod = QStr(cacheLine[cachePeriodIdx].asString()).toLongLong(); | 
|---|
| 390 | double onePeriod = double(funcOnePeriod)/ double(countPeriod); | 
|---|
| 391 | // qInfo() << "funcOnePeriod" << funcOnePeriod << "countPeriod" << countPeriod; | 
|---|
| 392 | cacheLine[cacheOverheadIdx] = QString(QString::number(onePeriod * 100, 10, 2)+ "%").toStdString(); | 
|---|
| 393 | // qInfo() << QStr(funcOne[::overhead].asString()); | 
|---|
| 394 | // qInfo() << "\n"; | 
|---|
| 395 | } | 
|---|
| 396 | cacheLines[i] = cacheLine; | 
|---|
| 397 | } | 
|---|
| 398 | } | 
|---|
| 399 | cache[::lines] = cacheLines; | 
|---|
| 400 | toolsCountCache[Tools::PerformanceType::function] = cache; | 
|---|
| 401 | } | 
|---|
| 402 | } | 
|---|
| 403 | }; | 
|---|
| 404 |  | 
|---|
| 405 | Tools::Tools() | 
|---|
| 406 | : d(new ToolsPrivate) | 
|---|
| 407 | { | 
|---|
| 408 |  | 
|---|
| 409 | } | 
|---|
| 410 |  | 
|---|
| 411 | Tools::~Tools() | 
|---|
| 412 | { | 
|---|
| 413 | stopAll(); | 
|---|
| 414 | if (d) { | 
|---|
| 415 | if (d->textBrowser) { | 
|---|
| 416 | delete d->textBrowser; | 
|---|
| 417 | } | 
|---|
| 418 | delete d; | 
|---|
| 419 | } | 
|---|
| 420 | } | 
|---|
| 421 |  | 
|---|
| 422 | void Tools::startAll() | 
|---|
| 423 | { | 
|---|
| 424 | for (auto ins : d->toolsIns) { | 
|---|
| 425 | ins->start(); | 
|---|
| 426 | qInfo() << "start"<< ins->program() << ins->arguments() | 
|---|
| 427 | << "pid :"<< ins->pid(); | 
|---|
| 428 | } | 
|---|
| 429 | } | 
|---|
| 430 |  | 
|---|
| 431 | void Tools::stopAll() | 
|---|
| 432 | { | 
|---|
| 433 | std::cout <<  __FUNCTION__ << std::endl; | 
|---|
| 434 | for (auto ins : d->toolsIns) { | 
|---|
| 435 | ins->kill(); | 
|---|
| 436 | ins->waitForFinished(); | 
|---|
| 437 | } | 
|---|
| 438 | d->toolsCountCache.clear(); | 
|---|
| 439 | } | 
|---|
| 440 |  | 
|---|
| 441 | void Tools::setAttachPID(int pid) | 
|---|
| 442 | { | 
|---|
| 443 | std::cout << __FUNCTION__ << ": "<<pid << std::endl; | 
|---|
| 444 | d->attachPID = pid; | 
|---|
| 445 |  | 
|---|
| 446 | if (d->displayErrorWidget()) { | 
|---|
| 447 | d->displayErrorWidget()->clear(); | 
|---|
| 448 | } | 
|---|
| 449 |  | 
|---|
| 450 | initTool(function); | 
|---|
| 451 | initTool(global); | 
|---|
| 452 | initTool(vfs); | 
|---|
| 453 | initTool(socket); | 
|---|
| 454 | initTool(deviceIO); | 
|---|
| 455 | } | 
|---|
| 456 |  | 
|---|
| 457 | int Tools::attachPID() const | 
|---|
| 458 | { | 
|---|
| 459 | return d->attachPID; | 
|---|
| 460 | } | 
|---|
| 461 |  | 
|---|
| 462 | Json::Value Tools::data() const | 
|---|
| 463 | { | 
|---|
| 464 | Json::Value result; | 
|---|
| 465 | for (auto key : d->toolsCountCache.keys()) { | 
|---|
| 466 | auto value = d->toolsCountCache.value(key); | 
|---|
| 467 | if (!value.empty()) { | 
|---|
| 468 | result[enumElemName(key)] = value; | 
|---|
| 469 | } | 
|---|
| 470 | } | 
|---|
| 471 | return result; | 
|---|
| 472 | } | 
|---|
| 473 |  | 
|---|
| 474 | bool Tools::initTool(Tools::PerformanceType pt) | 
|---|
| 475 | { | 
|---|
| 476 | std::cout << __FUNCTION__ << " : " | 
|---|
| 477 | << enumElemName<PerformanceType>(pt) | 
|---|
| 478 | << std::endl; | 
|---|
| 479 |  | 
|---|
| 480 | if (d->attachPID <= 0) { | 
|---|
| 481 | qCritical() << "unknown process from attach PID"<< d->attachPID; | 
|---|
| 482 | } | 
|---|
| 483 |  | 
|---|
| 484 | QProcess* process = new QProcess; | 
|---|
| 485 | process->setEnvironment({ "LINES=1000", "COLUMNS=1000"}); | 
|---|
| 486 | if (PerformanceType::function == pt) { | 
|---|
| 487 | process->setProperty(package_name.c_str(), "perf-tools-unstable"); | 
|---|
| 488 | process->setProperty(::enumName<PerformanceType>(), function); | 
|---|
| 489 | process->setProgram( "/usr/bin/perf"); | 
|---|
| 490 | process->setArguments({ "top", | 
|---|
| 491 | "--delay", "1", | 
|---|
| 492 | "--fields", "overhead,sample,period,dso,symbol,srcline", | 
|---|
| 493 | "--hide_kernel_symbols", | 
|---|
| 494 | "--verbose", | 
|---|
| 495 | "--stdio", | 
|---|
| 496 | "-p", QString::number(d->attachPID)}); | 
|---|
| 497 | QDir tempDir(QDir::tempPath()); | 
|---|
| 498 | if (!tempDir.exists( "perf_top_redirect_stdout")) { | 
|---|
| 499 | qInfo()  << "create redirect output from perf top"; | 
|---|
| 500 | QFile file(tempDir.filePath( "perf_top_redirect_stdout")); | 
|---|
| 501 | file.open(QFile::OpenModeFlag::NewOnly); | 
|---|
| 502 | file.close(); | 
|---|
| 503 | } | 
|---|
| 504 | process->setStandardInputFile(tempDir.filePath( "perf_top_redirect_stdout")); | 
|---|
| 505 | } | 
|---|
| 506 | if (PerformanceType::global == pt) { | 
|---|
| 507 | process->setProperty(package_name.c_str(), system_default.c_str()); | 
|---|
| 508 | process->setProperty(::enumName<PerformanceType>(), global); | 
|---|
| 509 | process->setProgram( "/usr/bin/top"); | 
|---|
| 510 | process->setArguments({ "-b", | 
|---|
| 511 | "-d", "1", | 
|---|
| 512 | "-p", QString::number(d->attachPID)}); | 
|---|
| 513 | } | 
|---|
| 514 |  | 
|---|
| 515 | if (PerformanceType::vfs == pt) { | 
|---|
| 516 | process->setProperty(package_name.c_str(), system_default.c_str()); | 
|---|
| 517 | process->setProperty(::enumName<PerformanceType>(), vfs); | 
|---|
| 518 | process->setProgram( "/usr/bin/lsof"); | 
|---|
| 519 | process->setArguments({ "-r", "1", | 
|---|
| 520 | "-p", QString::number(d->attachPID)}); | 
|---|
| 521 | } | 
|---|
| 522 |  | 
|---|
| 523 | if (PerformanceType::socket == pt) { | 
|---|
| 524 | Template::checkSocketScript(); | 
|---|
| 525 | process->setProperty(package_name.c_str(), system_default.c_str()); | 
|---|
| 526 | process->setProperty(::enumName<PerformanceType>(), socket); | 
|---|
| 527 | process->setProgram(Template::scriptsPathFrom(socket)); | 
|---|
| 528 | process->setArguments({QString::number(d->attachPID), QString::number(QCoreApplication::applicationPid())}); | 
|---|
| 529 | } | 
|---|
| 530 |  | 
|---|
| 531 | if (PerformanceType::deviceIO == pt) { | 
|---|
| 532 | process->setProperty(package_name.c_str(), "sysstat"); | 
|---|
| 533 | process->setProperty(::enumName<PerformanceType>(), deviceIO); | 
|---|
| 534 | process->setProgram( "/usr/bin/pidstat"); | 
|---|
| 535 | process->setArguments({ "-d", "1", | 
|---|
| 536 | "-p", QString::number(d->attachPID)}); | 
|---|
| 537 | } | 
|---|
| 538 |  | 
|---|
| 539 | QObject::connect(process, &QProcess::readyReadStandardOutput, | 
|---|
| 540 | this, &Tools::readAllStandardOutput, | 
|---|
| 541 | Qt::UniqueConnection); | 
|---|
| 542 |  | 
|---|
| 543 | QObject::connect(process, &QProcess::readyReadStandardError, | 
|---|
| 544 | this, &Tools::readAllStandardError, | 
|---|
| 545 | Qt::UniqueConnection); | 
|---|
| 546 |  | 
|---|
| 547 | QObject::connect(process, &QProcess::errorOccurred, | 
|---|
| 548 | this, &Tools::errorOccurred, | 
|---|
| 549 | Qt::UniqueConnection); | 
|---|
| 550 |  | 
|---|
| 551 | d->toolsIns.insert(pt, process); | 
|---|
| 552 |  | 
|---|
| 553 | if (!process->program().isEmpty()) { | 
|---|
| 554 | return true; | 
|---|
| 555 | } | 
|---|
| 556 |  | 
|---|
| 557 | return false; | 
|---|
| 558 | } | 
|---|
| 559 |  | 
|---|
| 560 | QRegularExpression Tools::lineRegExpRule(Tools::PerformanceType pt) | 
|---|
| 561 | { | 
|---|
| 562 | if (PerformanceType::global == pt) | 
|---|
| 563 | return QRegularExpression( | 
|---|
| 564 | QString( "\\s?") + | 
|---|
| 565 | "(?<"+ ::QStr(::processId) + ">[0-9]+)\\s+"+ | 
|---|
| 566 | "(?<"+ QStr(::user) + ">\\S+)\\s+"+ | 
|---|
| 567 | "(?<"+ QStr(::priority) + ">[0-9][0-9])\\s+"+ | 
|---|
| 568 | "(?<"+ QStr(::nice) + ">-?[0-9]+)\\s+"+ | 
|---|
| 569 | "(?<"+ QStr(::virtualSize) + ">[0-9]+\\.?[0-9]?+\\S?)\\s+"+ | 
|---|
| 570 | "(?<"+ QStr(::residentSize) + ">[0-9]+\\.?[0-9]?+\\S?)\\s+"+ | 
|---|
| 571 | "(?<"+ QStr(::sharable) + ">[0-9]+\\.?[0-9]?+\\S?)\\s+"+ | 
|---|
| 572 | "(?<"+ QStr(::status) + ">[A-Za-z])\\s+"+ | 
|---|
| 573 | "(?<"+ QStr(::cpuOverhead) + ">[0-9]{1,2}.[0-9]+)\\s+"+ | 
|---|
| 574 | "(?<"+ QStr(::memoryOverhead) + ">[0-9]{1,2}.[0-9]+)\\s+"+ | 
|---|
| 575 | "(?<"+ QStr(::timeCount) + ">[0-9]+:[0-9]+.[0-9]+)\\s+"+ | 
|---|
| 576 | "(?<"+ QStr(::command) + ">\\S+)"); | 
|---|
| 577 | if (PerformanceType::function == pt) | 
|---|
| 578 | return QRegularExpression( | 
|---|
| 579 | QString( "\\s+") + | 
|---|
| 580 | "(?<"+ QStr(::overhead) + ">[0-9]+.[0-9]+%)\\s+"+ | 
|---|
| 581 | "(?<"+ QStr(::sample) + ">[0-9]+)\\s+"+ | 
|---|
| 582 | "(?<"+ QStr(::period) + ">[0-9]+)\\s+"+ | 
|---|
| 583 | "(?<"+ QStr(::dso) + ">[\\S]+)\\s+"+ | 
|---|
| 584 | "(?<"+ QStr(::symbol) + ">\\S+\\s+\\w\\s+\\S+\\s[_:\\w<>(),&@*\\s]+)\\s+"+ | 
|---|
| 585 | "(?<"+ QStr(::srcline) + ">\\S+)" | 
|---|
| 586 | ); | 
|---|
| 587 | if (PerformanceType::vfs == pt) | 
|---|
| 588 | return QRegularExpression( | 
|---|
| 589 | QString( "\\s?") + | 
|---|
| 590 | "(?<"+ QStr(::command) + ">\\S+)\\s+"+ | 
|---|
| 591 | "(?<"+ QStr(::processId) + ">[0-9]+)\\s+"+ | 
|---|
| 592 | "(?<"+ QStr(::user) + ">\\S+)\\s+"+ | 
|---|
| 593 | "(?<"+ QStr(::fd) + ">[a-z0-9]+)\\s+"+ | 
|---|
| 594 | "(?<"+ QStr(::type) + ">[a-zA-z_]+)\\s+"+ | 
|---|
| 595 | "(?<"+ QStr(::device) + ">[0-9]+\\,[0-9]+)\\s+"+ | 
|---|
| 596 | "(?<"+ QStr(::sizeOff) + ">[0-9a-zA-Z]+)\\s+"+ | 
|---|
| 597 | "(?<"+ QStr(::node) + ">[0-9]+)\\s+"+ | 
|---|
| 598 | "(?<"+ QStr(::name) + ">\\S+)\\s?" | 
|---|
| 599 | ); | 
|---|
| 600 | if (PerformanceType::socket == pt) | 
|---|
| 601 | return QRegularExpression( | 
|---|
| 602 | QString( "\\s?") + | 
|---|
| 603 | "(?<"+ QStr(::netId) + ">\\S+)\\s+"+ | 
|---|
| 604 | "(?<"+ QStr(::state) + ">\\S+)\\s+"+ | 
|---|
| 605 | "(?<"+ QStr(::recvQueue) + ">[0-9]+)\\s+"+ | 
|---|
| 606 | "(?<"+ QStr(::sendQueue) + ">[0-9]+)\\s+"+ | 
|---|
| 607 | "(?<"+ QStr(::localAddrPort) + ">[\\S]+\\s?:?[\\S]+)\\s+"+ | 
|---|
| 608 | "(?<"+ QStr(::peerAddrPort) + ">[\\S]+\\s?:?[\\S]+)\\s+"+ | 
|---|
| 609 | "(?<"+ QStr(::usingProcesses) + ">users:\\(\\S+\\))?" | 
|---|
| 610 | ); | 
|---|
| 611 |  | 
|---|
| 612 | if (PerformanceType::deviceIO == pt) | 
|---|
| 613 | return QRegularExpression( | 
|---|
| 614 | QString( "\\s?") + | 
|---|
| 615 | "(?<"+ QStr(::userId) + ">[0-9]+)\\s+"+ | 
|---|
| 616 | "(?<"+ QStr(::processId) + ">[0-9]+)\\s+"+ | 
|---|
| 617 | "(?<"+ QStr(::kB_rd) + ">[0-9]+.[0-9]+)\\s+"+ | 
|---|
| 618 | "(?<"+ QStr(::kB_wd) + ">[0-9]+.[0-9]+)\\s+"+ | 
|---|
| 619 | "(?<"+ QStr(::kB_ccwr) + ">[0-9]+.[0-9]+)\\s+"+ | 
|---|
| 620 | "(?<"+ QStr(::iodelay) + ">[0-9]+)\\s+"+ | 
|---|
| 621 | "(?<"+ QStr(::command) + ">\\S+)\\s?" | 
|---|
| 622 | ); | 
|---|
| 623 |  | 
|---|
| 624 | return QRegularExpression(); | 
|---|
| 625 | } | 
|---|
| 626 |  | 
|---|
| 627 | void Tools::readAllStandardOutput() | 
|---|
| 628 | { | 
|---|
| 629 | QProcess *process = qobject_cast<QProcess*>(sender()); | 
|---|
| 630 | if (process) { | 
|---|
| 631 | QVariant variant = process->property(::enumName<PerformanceType>()); | 
|---|
| 632 | if (!variant.isValid()) { | 
|---|
| 633 | return; | 
|---|
| 634 | } | 
|---|
| 635 | if (variant.canConvert<PerformanceType>()) { | 
|---|
| 636 | PerformanceType type = qvariant_cast<PerformanceType>(variant); | 
|---|
| 637 | QString typeString = enumElemName<PerformanceType>(type); | 
|---|
| 638 | QRegularExpression regExp = lineRegExpRule(type); | 
|---|
| 639 |  | 
|---|
| 640 | Json::Value globalObj(Json::objectValue); | 
|---|
| 641 | JsonOp::setField({::processId, ::user, ::priority, ::nice, | 
|---|
| 642 | ::virtualSize, ::residentSize, ::sharable, status, | 
|---|
| 643 | ::cpuOverhead, ::memoryOverhead, ::timeCount, ::command} | 
|---|
| 644 | , globalObj); | 
|---|
| 645 |  | 
|---|
| 646 | Json::Value functionObj(Json::objectValue); | 
|---|
| 647 | JsonOp::setField({::overhead, ::sample, ::period, | 
|---|
| 648 | ::dso, ::symbol, srcline} | 
|---|
| 649 | , functionObj); | 
|---|
| 650 | Json::Value functionLines = functionObj[::lines]; | 
|---|
| 651 |  | 
|---|
| 652 | Json::Value vfsObj(Json::objectValue); | 
|---|
| 653 | JsonOp::setField({::command, ::processId, ::user, ::fd, | 
|---|
| 654 | ::type, ::device, ::sizeOff, ::node, ::name} | 
|---|
| 655 | , vfsObj); | 
|---|
| 656 |  | 
|---|
| 657 | Json::Value socketObj(Json::objectValue); | 
|---|
| 658 | JsonOp::setField({::netId, ::state, ::recvQueue, ::sendQueue, | 
|---|
| 659 | ::localAddrPort, ::peerAddrPort, usingProcesses} | 
|---|
| 660 | , socketObj); | 
|---|
| 661 |  | 
|---|
| 662 | Json::Value deviceIOObj(Json::objectValue); | 
|---|
| 663 | JsonOp::setField({::userId, ::processId, ::kB_rd+ "/s", ::kB_wd + "/s", | 
|---|
| 664 | ::kB_ccwr + "/s", ::iodelay, ::command} | 
|---|
| 665 | , deviceIOObj); | 
|---|
| 666 |  | 
|---|
| 667 | while (process->canReadLine()) { | 
|---|
| 668 | auto lineData = process->readLine(); | 
|---|
| 669 | if (!lineData.isEmpty()) { | 
|---|
| 670 | auto matchs = regExp.match(lineData); | 
|---|
| 671 | if (matchs.hasMatch()) { | 
|---|
| 672 |  | 
|---|
| 673 | if (function == type) { | 
|---|
| 674 |  | 
|---|
| 675 | Json::Value functionFeild = functionObj[::feild]; | 
|---|
| 676 | if (!functionFeild.empty() && functionFeild.isArray()) { | 
|---|
| 677 |  | 
|---|
| 678 | auto overheadData = ::format(matchs.captured(QStr(::overhead))); | 
|---|
| 679 | auto sampleData = ::format(matchs.captured(QStr(::sample))); | 
|---|
| 680 | auto periodData = ::format(matchs.captured(QStr(::period))); | 
|---|
| 681 | auto dsoData = ::format(matchs.captured(QStr(::dso))); | 
|---|
| 682 | auto symbolData = ::format(matchs.captured(QStr(::symbol))); | 
|---|
| 683 | auto srclineData = ::format(matchs.captured(QStr(::srcline))); | 
|---|
| 684 | if (!overheadData.isEmpty() && !sampleData.isEmpty() | 
|---|
| 685 | && !periodData.isEmpty() && !dsoData.isEmpty() | 
|---|
| 686 | && !symbolData.isEmpty() && !srclineData.isEmpty()) { | 
|---|
| 687 |  | 
|---|
| 688 | Json::Value functionLine(Json::arrayValue); | 
|---|
| 689 | functionLine.resize(functionFeild.size()); | 
|---|
| 690 | for (unsigned int feildIdx = 0; feildIdx < functionFeild.size(); feildIdx ++) { | 
|---|
| 691 | auto feild = functionFeild[feildIdx].asString(); | 
|---|
| 692 | if (feild == ::overhead) { | 
|---|
| 693 | functionLine[feildIdx] = overheadData.toStdString(); | 
|---|
| 694 | } else if (feild == ::sample) { | 
|---|
| 695 | functionLine[feildIdx] = sampleData.toStdString(); | 
|---|
| 696 | } else if (feild == ::period) { | 
|---|
| 697 | functionLine[feildIdx] = periodData.toStdString(); | 
|---|
| 698 | } else if (feild == ::dso) { | 
|---|
| 699 | functionLine[feildIdx] = dsoData.toStdString(); | 
|---|
| 700 | } else if (feild == ::symbol) { | 
|---|
| 701 | functionLine[feildIdx] = symbolData.toStdString(); | 
|---|
| 702 | } else if (feild == ::srcline) { | 
|---|
| 703 | functionLine[feildIdx] = srclineData.toStdString(); | 
|---|
| 704 | } else { | 
|---|
| 705 | qCritical() << "unknown feild from performance type : function"; | 
|---|
| 706 | } | 
|---|
| 707 | } | 
|---|
| 708 |  | 
|---|
| 709 | int symbolIdx = -1; | 
|---|
| 710 | int sampleIdx = -1; | 
|---|
| 711 | int periodIdx = -1; | 
|---|
| 712 | for (unsigned int idx = 0; idx < functionFeild.size(); idx++) { | 
|---|
| 713 | if (functionFeild[idx].asString() == ::symbol) { | 
|---|
| 714 | symbolIdx = static_cast<int>(idx); | 
|---|
| 715 | } else if (functionFeild[idx].asString() == ::sample) { | 
|---|
| 716 | sampleIdx = static_cast<int>(idx); | 
|---|
| 717 | } else if (functionFeild[idx].asString() == ::period) { | 
|---|
| 718 | periodIdx = static_cast<int>(idx); | 
|---|
| 719 | } else { | 
|---|
| 720 | // noting to do | 
|---|
| 721 | } | 
|---|
| 722 | } | 
|---|
| 723 |  | 
|---|
| 724 |  | 
|---|
| 725 | bool hasSame = false; | 
|---|
| 726 | if (symbolIdx >= 0) { | 
|---|
| 727 | for (unsigned int lineIdx = 0; lineIdx < functionLines.size(); lineIdx ++) { | 
|---|
| 728 | auto beforLine = functionLines[lineIdx]; | 
|---|
| 729 | if (!beforLine.empty() && beforLine[symbolIdx].asString() == symbolData.toStdString()) { | 
|---|
| 730 | functionLine[sampleIdx] = Add(functionLine[sampleIdx].asString(), beforLine[sampleIdx].asString()); | 
|---|
| 731 | functionLine[periodIdx] = Add(functionLine[periodIdx].asString(), beforLine[periodIdx].asString()); | 
|---|
| 732 | functionLines[lineIdx] = functionLine; | 
|---|
| 733 | hasSame = true; | 
|---|
| 734 | break; | 
|---|
| 735 | } | 
|---|
| 736 | } | 
|---|
| 737 | } | 
|---|
| 738 |  | 
|---|
| 739 | if (!hasSame || functionLines.empty()) { | 
|---|
| 740 | functionLines.append(functionLine); | 
|---|
| 741 | } | 
|---|
| 742 |  | 
|---|
| 743 | functionObj[::lines] = functionLines; | 
|---|
| 744 | } | 
|---|
| 745 | } | 
|---|
| 746 | } | 
|---|
| 747 |  | 
|---|
| 748 | if (global == type) { | 
|---|
| 749 | Json::Value feildArray = globalObj[::feild]; | 
|---|
| 750 | if (!feildArray.empty() && feildArray.isArray()) { | 
|---|
| 751 | auto processIdData = ::format(matchs.captured(QStr(::processId))); | 
|---|
| 752 | auto userData = ::format(matchs.captured(QStr(::user))); | 
|---|
| 753 | auto priorityData = ::format(matchs.captured(QStr(::priority))); | 
|---|
| 754 | auto niceData = ::format(matchs.captured(QStr(::nice))); | 
|---|
| 755 | auto virtualSizeData = ::format(matchs.captured(QStr(::virtualSize))); | 
|---|
| 756 | auto residentSizeData = ::format(matchs.captured(QStr(::residentSize))); | 
|---|
| 757 | auto sharableData = ::format(matchs.captured(QStr(::sharable))); | 
|---|
| 758 | auto statusData = ::format(matchs.captured(QStr(::status))); | 
|---|
| 759 | auto cpuOverheadData = ::format(matchs.captured(QStr(::cpuOverhead))); | 
|---|
| 760 | auto memoryOverheadData = ::format(matchs.captured(QStr(::memoryOverhead))); | 
|---|
| 761 | auto timeCountData = ::format(matchs.captured(QStr(::timeCount))); | 
|---|
| 762 | auto commandData = ::format(matchs.captured(QStr(::command))); | 
|---|
| 763 | if (!processIdData.isEmpty() && !userData.isEmpty() | 
|---|
| 764 | && !priorityData.isEmpty() && !niceData.isEmpty() | 
|---|
| 765 | && !virtualSizeData.isEmpty() && !residentSizeData.isEmpty() | 
|---|
| 766 | && !sharableData.isEmpty() && !statusData.isEmpty() | 
|---|
| 767 | && !cpuOverheadData.isEmpty() && !memoryOverheadData.isEmpty() | 
|---|
| 768 | && !timeCountData.isEmpty() && !commandData.isEmpty()) { | 
|---|
| 769 |  | 
|---|
| 770 | Json::Value globalLine(Json::arrayValue); | 
|---|
| 771 | globalLine.resize(feildArray.size()); | 
|---|
| 772 | for (unsigned int idx = 0; idx < feildArray.size(); idx ++) { | 
|---|
| 773 | auto feild = feildArray[idx]; | 
|---|
| 774 | if (feild == ::processId) { | 
|---|
| 775 | globalLine[idx] = processIdData.toStdString(); | 
|---|
| 776 | } else if (feild == ::user) { | 
|---|
| 777 | globalLine[idx] = userData.toStdString(); | 
|---|
| 778 | } else if (feild == ::priority) { | 
|---|
| 779 | globalLine[idx] = priorityData.toStdString(); | 
|---|
| 780 | } else if (feild == ::nice) { | 
|---|
| 781 | globalLine[idx] = niceData.toStdString(); | 
|---|
| 782 | } else if (feild == ::virtualSize) { | 
|---|
| 783 | globalLine[idx] = virtualSizeData.toStdString(); | 
|---|
| 784 | } else if (feild == ::residentSize) { | 
|---|
| 785 | globalLine[idx] = residentSizeData.toStdString(); | 
|---|
| 786 | } else if (feild == ::sharable) { | 
|---|
| 787 | globalLine[idx] = sharableData.toStdString(); | 
|---|
| 788 | } else if (feild == ::status) { | 
|---|
| 789 | globalLine[idx] = statusData.toStdString(); | 
|---|
| 790 | } else if (feild == ::cpuOverhead) { | 
|---|
| 791 | globalLine[idx] = cpuOverheadData.toStdString() + "%"; | 
|---|
| 792 | } else if (feild == ::memoryOverhead) { | 
|---|
| 793 | globalLine[idx] = memoryOverheadData.toStdString() + "%"; | 
|---|
| 794 | } else if (feild == ::timeCount) { | 
|---|
| 795 | globalLine[idx] = timeCountData.toStdString(); | 
|---|
| 796 | } else if (feild == ::command) { | 
|---|
| 797 | globalLine[idx] = commandData.toStdString(); | 
|---|
| 798 | } else { | 
|---|
| 799 | qCritical() << "unknown feild from performance type : global"; | 
|---|
| 800 | } | 
|---|
| 801 | } | 
|---|
| 802 |  | 
|---|
| 803 | Json::Value linesArray(Json::arrayValue); | 
|---|
| 804 | linesArray.append(globalLine); | 
|---|
| 805 | globalObj[::lines] = linesArray; | 
|---|
| 806 | } | 
|---|
| 807 | } | 
|---|
| 808 | } | 
|---|
| 809 |  | 
|---|
| 810 | if (vfs == type) { | 
|---|
| 811 | Json::Value feildArray = vfsObj[::feild]; | 
|---|
| 812 | if (!feildArray.empty() && feildArray.isArray()) { | 
|---|
| 813 | auto commandData = ::format(matchs.captured(QStr(::command))); | 
|---|
| 814 | auto processIdData = ::format(matchs.captured(QStr(::processId))); | 
|---|
| 815 | auto userData = ::format(matchs.captured(QStr(::user))); | 
|---|
| 816 | auto fdData = ::format(matchs.captured(QStr(::fd))); | 
|---|
| 817 | auto typeData = ::format(matchs.captured(QStr(::type))); | 
|---|
| 818 | auto deviceData = ::format(matchs.captured(QStr(::device))); | 
|---|
| 819 | auto sizeOffData = ::format(matchs.captured(QStr(::sizeOff))); | 
|---|
| 820 | auto nodeData = ::format(matchs.captured(QStr(::node))); | 
|---|
| 821 | auto nameData = ::format(matchs.captured(QStr(::name))); | 
|---|
| 822 | if (!commandData.isEmpty() && !processIdData.isEmpty() | 
|---|
| 823 | && !userData.isEmpty() && !fdData.isEmpty() | 
|---|
| 824 | && !typeData.isEmpty() && !deviceData.isEmpty() | 
|---|
| 825 | && !sizeOffData.isEmpty() && !nodeData.isEmpty() | 
|---|
| 826 | && !nameData.isEmpty()) { | 
|---|
| 827 |  | 
|---|
| 828 | Json::Value linesArray = vfsObj[::lines]; | 
|---|
| 829 | Json::Value vfsLine(Json::arrayValue); | 
|---|
| 830 | vfsLine.resize(feildArray.size()); | 
|---|
| 831 | for (unsigned int idx = 0; idx < feildArray.size(); idx ++) { | 
|---|
| 832 | auto feild = feildArray[idx]; | 
|---|
| 833 | if (feild == ::command) { | 
|---|
| 834 | vfsLine[idx] = commandData.toStdString(); | 
|---|
| 835 | } else if (feild == ::processId) { | 
|---|
| 836 | vfsLine[idx] = processIdData.toStdString(); | 
|---|
| 837 | } else if (feild == ::user) { | 
|---|
| 838 | vfsLine[idx] = userData.toStdString(); | 
|---|
| 839 | } else if (feild == ::fd) { | 
|---|
| 840 | vfsLine[idx] = fdData.toStdString(); | 
|---|
| 841 | } else if (feild == ::type) { | 
|---|
| 842 | vfsLine[idx] = typeData.toStdString(); | 
|---|
| 843 | } else if (feild == ::device) { | 
|---|
| 844 | vfsLine[idx] = deviceData.toStdString(); | 
|---|
| 845 | } else if (feild == ::sizeOff) { | 
|---|
| 846 | vfsLine[idx] = sizeOffData.toStdString(); | 
|---|
| 847 | } else if (feild == ::node) { | 
|---|
| 848 | vfsLine[idx] = nodeData.toStdString(); | 
|---|
| 849 | } else if (feild == ::name) { | 
|---|
| 850 | vfsLine[idx] = nameData.toStdString(); | 
|---|
| 851 | } else { | 
|---|
| 852 | qCritical() << "unknown feild from performance type : global"; | 
|---|
| 853 | } | 
|---|
| 854 | } | 
|---|
| 855 | linesArray.append(vfsLine); | 
|---|
| 856 | vfsObj[::lines] = linesArray; | 
|---|
| 857 | } | 
|---|
| 858 | } | 
|---|
| 859 | } | 
|---|
| 860 |  | 
|---|
| 861 | if (socket == type) { | 
|---|
| 862 | Json::Value feildArray = socketObj[::feild]; | 
|---|
| 863 | if (!feildArray.empty() && feildArray.isArray()) { | 
|---|
| 864 | auto netIdData = ::format(matchs.captured(QStr(::netId))); | 
|---|
| 865 | auto stateData = ::format(matchs.captured(QStr(::state))); | 
|---|
| 866 | auto recvQueueData = ::format(matchs.captured(QStr(::recvQueue))); | 
|---|
| 867 | auto sendQueueData = ::format(matchs.captured(QStr(::sendQueue))); | 
|---|
| 868 | auto localAddrPortData = ::format(matchs.captured(QStr(::localAddrPort))); | 
|---|
| 869 | auto peerAddrPortData = ::format(matchs.captured(QStr(::peerAddrPort))); | 
|---|
| 870 | auto usingProcessesData = ::format(matchs.captured(QStr(::usingProcesses))); | 
|---|
| 871 | // maybe usingProcesses is empty, also to do. | 
|---|
| 872 | if (!netIdData.isEmpty() && !stateData.isEmpty() | 
|---|
| 873 | && !recvQueueData.isEmpty() && !sendQueueData.isEmpty() | 
|---|
| 874 | && !localAddrPortData.isEmpty() && !peerAddrPortData.isEmpty()) | 
|---|
| 875 | { | 
|---|
| 876 | Json::Value socketOne; | 
|---|
| 877 | socketOne[::netId] = netIdData.toStdString(); | 
|---|
| 878 | socketOne[::state] = stateData.toStdString(); | 
|---|
| 879 | socketOne[::recvQueue] = recvQueueData.toStdString(); | 
|---|
| 880 | socketOne[::sendQueue] = sendQueueData.toStdString(); | 
|---|
| 881 | socketOne[::localAddrPort] = localAddrPortData.toStdString(); | 
|---|
| 882 | socketOne[::peerAddrPort] = peerAddrPortData.toStdString(); | 
|---|
| 883 | socketOne[::usingProcesses] = usingProcessesData.toStdString(); | 
|---|
| 884 |  | 
|---|
| 885 | Json::Value linesArray = socketObj[::lines]; | 
|---|
| 886 | Json::Value socketLine(Json::arrayValue); | 
|---|
| 887 | socketLine.resize(feildArray.size()); | 
|---|
| 888 | for (unsigned int idx = 0; idx < feildArray.size(); idx ++) { | 
|---|
| 889 | auto feild = feildArray[idx]; | 
|---|
| 890 | if (feild == ::netId) { | 
|---|
| 891 | socketLine[idx] = netIdData.toStdString(); | 
|---|
| 892 | } else if (feild == ::state) { | 
|---|
| 893 | socketLine[idx] = stateData.toStdString(); | 
|---|
| 894 | } else if (feild == ::recvQueue) { | 
|---|
| 895 | socketLine[idx] = recvQueueData.toStdString(); | 
|---|
| 896 | } else if (feild == ::sendQueue) { | 
|---|
| 897 | socketLine[idx] = sendQueueData.toStdString(); | 
|---|
| 898 | } else if (feild == ::localAddrPort) { | 
|---|
| 899 | socketLine[idx] = localAddrPortData.toStdString(); | 
|---|
| 900 | } else if (feild == ::peerAddrPort) { | 
|---|
| 901 | socketLine[idx] = peerAddrPortData.toStdString(); | 
|---|
| 902 | } else if (feild == ::usingProcesses) { | 
|---|
| 903 | socketLine[idx] = usingProcessesData.toStdString(); | 
|---|
| 904 | } else { | 
|---|
| 905 | qCritical() << "unknown feild from performance type : global"; | 
|---|
| 906 | } | 
|---|
| 907 | } | 
|---|
| 908 | linesArray.append(socketLine); | 
|---|
| 909 | socketObj[::lines] = linesArray; | 
|---|
| 910 | } | 
|---|
| 911 | } | 
|---|
| 912 | } | 
|---|
| 913 |  | 
|---|
| 914 | if (deviceIO == type) { | 
|---|
| 915 | Json::Value feildArray = deviceIOObj[::feild]; | 
|---|
| 916 | if (!feildArray.empty() && feildArray.isArray()) { | 
|---|
| 917 | auto userIdData = ::format(matchs.captured(QStr(::userId))); | 
|---|
| 918 | auto processIdData = ::format(matchs.captured(QStr(::processId))); | 
|---|
| 919 | auto kB_rdData = ::format(matchs.captured(QStr(::kB_rd))); | 
|---|
| 920 | auto kB_wdData = ::format(matchs.captured(QStr(::kB_wd))); | 
|---|
| 921 | auto kB_ccwrData = ::format(matchs.captured(QStr(::kB_ccwr))); | 
|---|
| 922 | auto iodelayData = ::format(matchs.captured(QStr(::iodelay))); | 
|---|
| 923 | auto commandData = ::format(matchs.captured(QStr(::command))); | 
|---|
| 924 | if (!userIdData.isEmpty() && !processIdData.isEmpty() | 
|---|
| 925 | && !kB_rdData.isEmpty() && !kB_wdData.isEmpty() | 
|---|
| 926 | && !kB_ccwrData.isEmpty() && !iodelayData.isEmpty() | 
|---|
| 927 | && !commandData.isEmpty()) | 
|---|
| 928 | { | 
|---|
| 929 | Json::Value linesArray; | 
|---|
| 930 | Json::Value deviceIOLine(Json::arrayValue); | 
|---|
| 931 | deviceIOLine.resize(feildArray.size()); | 
|---|
| 932 | for (unsigned int idx = 0; idx < feildArray.size(); idx ++) { | 
|---|
| 933 | auto feild = feildArray[idx]; | 
|---|
| 934 | if (feild == ::userId) { | 
|---|
| 935 | deviceIOLine[idx] = userIdData.toStdString(); | 
|---|
| 936 | } else if (feild == ::processId) { | 
|---|
| 937 | deviceIOLine[idx] = processIdData.toStdString(); | 
|---|
| 938 | } else if (feild == ::kB_rd + "/s") { | 
|---|
| 939 | deviceIOLine[idx] = kB_rdData.toStdString(); | 
|---|
| 940 | } else if (feild == ::kB_wd + "/s") { | 
|---|
| 941 | deviceIOLine[idx] = kB_wdData.toStdString(); | 
|---|
| 942 | } else if (feild == ::kB_ccwr + "/s") { | 
|---|
| 943 | deviceIOLine[idx] = kB_ccwrData.toStdString(); | 
|---|
| 944 | } else if (feild == ::iodelay) { | 
|---|
| 945 | deviceIOLine[idx] = iodelayData.toStdString(); | 
|---|
| 946 | } else if (feild == ::command) { | 
|---|
| 947 | deviceIOLine[idx] = commandData.toStdString(); | 
|---|
| 948 | } else { | 
|---|
| 949 | qCritical() << "unknown feild from performance type : global"; | 
|---|
| 950 | } | 
|---|
| 951 | } | 
|---|
| 952 | linesArray.append(deviceIOLine); | 
|---|
| 953 | deviceIOObj[::lines] = linesArray; | 
|---|
| 954 | } | 
|---|
| 955 | } | 
|---|
| 956 | } | 
|---|
| 957 | } | 
|---|
| 958 | } | 
|---|
| 959 | } | 
|---|
| 960 |  | 
|---|
| 961 | if (!functionObj[::lines].empty()) { | 
|---|
| 962 | d->countFunction(functionObj); // count function information | 
|---|
| 963 | } | 
|---|
| 964 |  | 
|---|
| 965 | if (!vfsObj[::lines].empty()) { | 
|---|
| 966 | d->toolsCountCache[PerformanceType::vfs] = vfsObj; | 
|---|
| 967 | } | 
|---|
| 968 |  | 
|---|
| 969 | if (!socketObj[::lines].empty()) { | 
|---|
| 970 | d->toolsCountCache[PerformanceType::socket] = socketObj; | 
|---|
| 971 | } | 
|---|
| 972 |  | 
|---|
| 973 | if (!deviceIOObj[::lines].empty()) { | 
|---|
| 974 | d->toolsCountCache[PerformanceType::deviceIO] = deviceIOObj; | 
|---|
| 975 | } | 
|---|
| 976 |  | 
|---|
| 977 | if (!globalObj[::lines].empty()) { // with global timer get count function information | 
|---|
| 978 | Json::Value result; | 
|---|
| 979 | d->toolsCountCache[PerformanceType::global] = globalObj; | 
|---|
| 980 | Json::Value countfunctionCache = d->toolsCountCache[PerformanceType::function]; | 
|---|
| 981 | if (!countfunctionCache[::lines].empty()) { | 
|---|
| 982 | d->toolsCountCache[PerformanceType::function] = countfunctionCache; | 
|---|
| 983 | result[::enumElemName(PerformanceType::function)] = countfunctionCache; | 
|---|
| 984 | } | 
|---|
| 985 | Json::Value vfsCache = d->toolsCountCache[PerformanceType::vfs]; | 
|---|
| 986 | if (!vfsCache[::lines].empty()) { | 
|---|
| 987 | result[::enumElemName(PerformanceType::vfs)] = vfsCache; | 
|---|
| 988 | } | 
|---|
| 989 | Json::Value socketCache = d->toolsCountCache[PerformanceType::socket]; | 
|---|
| 990 | if (!socketCache[::lines].empty()) { | 
|---|
| 991 | result[::enumElemName(PerformanceType::socket)] = socketCache; | 
|---|
| 992 | } | 
|---|
| 993 | Json::Value deviceIOCache = d->toolsCountCache[PerformanceType::deviceIO]; | 
|---|
| 994 | if (!deviceIOCache[::lines].empty()) { | 
|---|
| 995 | result[::enumElemName(PerformanceType::deviceIO)] = deviceIOCache; | 
|---|
| 996 | } | 
|---|
| 997 |  | 
|---|
| 998 | result[::enumElemName(PerformanceType::global)] = globalObj; | 
|---|
| 999 | qInfo() << qPrintable(QStr(result.toStyledString())); | 
|---|
| 1000 | emit attachData(result); | 
|---|
| 1001 | } | 
|---|
| 1002 | } | 
|---|
| 1003 | } | 
|---|
| 1004 | } | 
|---|
| 1005 |  | 
|---|
| 1006 | void Tools::readAllStandardError() | 
|---|
| 1007 | { | 
|---|
| 1008 | QProcess *process = qobject_cast<QProcess*>(sender()); | 
|---|
| 1009 | if (process) { | 
|---|
| 1010 | QString errorOut = process->readAllStandardError().replace( "\n", " "); | 
|---|
| 1011 | //        if (process->error() == QProcess::UnknownError) { | 
|---|
| 1012 | //            PerformanceType pt = qvariant_cast<PerformanceType>(process->property(::enumName<PerformanceType>())); | 
|---|
| 1013 | //            QString program = process->program(); | 
|---|
| 1014 | //            QString package_name = process->property(::package_name.c_str()).toString(); | 
|---|
| 1015 |  | 
|---|
| 1016 | //            d->displayErrorWidget()->append(QStr(::enumName<PerformanceType>()) + ": " + ::enumElemName<PerformanceType>(pt)); | 
|---|
| 1017 | //            d->displayErrorWidget()->append(QStr("program: ") + process->program() + process->arguments().join(" ")); | 
|---|
| 1018 | //            d->displayErrorWidget()->append(QStr("errorString: ") + errorOut); | 
|---|
| 1019 | //            if (package_name.toStdString() != ::system_default) { | 
|---|
| 1020 | //                d->displayErrorWidget()->append(Tools::tr("suggestion: " | 
|---|
| 1021 | //                                                          "please to install tool, the package-name \"%0\". " | 
|---|
| 1022 | //                                                          "If you confirm that the current tool exists and still cannot be used normally, " | 
|---|
| 1023 | //                                                          "the current operation does not support").arg(package_name)); | 
|---|
| 1024 | //            } else { | 
|---|
| 1025 | //                d->displayErrorWidget()->append(QStr("suggestion: ") | 
|---|
| 1026 | //                                                + "Because the current program is a system application, " | 
|---|
| 1027 | //                                                  "if it is not found, " | 
|---|
| 1028 | //                                                  "it means that the item is unavailable"); | 
|---|
| 1029 | //            } | 
|---|
| 1030 | //            d->displayErrorWidget()->append("\n"); | 
|---|
| 1031 | //            d->displayErrorWidget()->show(); | 
|---|
| 1032 | //        } | 
|---|
| 1033 | qCritical() << qvariant_cast<PerformanceType>(process->property(::enumName<PerformanceType>())) | 
|---|
| 1034 | << errorOut | 
|---|
| 1035 | << process->error() | 
|---|
| 1036 | << process->errorString(); | 
|---|
| 1037 | } | 
|---|
| 1038 | } | 
|---|
| 1039 |  | 
|---|
| 1040 | void Tools::errorOccurred(QProcess::ProcessError error) | 
|---|
| 1041 | { | 
|---|
| 1042 | QProcess *process = qobject_cast<QProcess*>(sender()); | 
|---|
| 1043 | if (process) { | 
|---|
| 1044 |  | 
|---|
| 1045 | PerformanceType pt = qvariant_cast<PerformanceType>(process->property(::enumName<PerformanceType>())); | 
|---|
| 1046 | QString program = process->program(); | 
|---|
| 1047 | QString package_name = process->property(::package_name.c_str()).toString(); | 
|---|
| 1048 |  | 
|---|
| 1049 | d->displayErrorWidget()->append(QStr(::enumName<PerformanceType>()) + ": "+ ::enumElemName<PerformanceType>(pt)); | 
|---|
| 1050 | d->displayErrorWidget()->append(QStr( "program: ") + process->program() + process->arguments().join( " ")); | 
|---|
| 1051 | d->displayErrorWidget()->append(QStr( "errorString: ") + process->errorString()); | 
|---|
| 1052 | if (package_name.toStdString() != ::system_default) { | 
|---|
| 1053 | d->displayErrorWidget()->append(Tools::tr( "suggestion: " | 
|---|
| 1054 | "please to install tool, the package-name \"%0\". " | 
|---|
| 1055 | "If you confirm that the current tool exists and still cannot be used normally, " | 
|---|
| 1056 | "the current operation does not support").arg(package_name)); | 
|---|
| 1057 | } else { | 
|---|
| 1058 | d->displayErrorWidget()->append(QStr( "suggestion: ") | 
|---|
| 1059 | + "Because the current program is a system application, " | 
|---|
| 1060 | "if it is not found, " | 
|---|
| 1061 | "it means that the item is unavailable"); | 
|---|
| 1062 | } | 
|---|
| 1063 | d->displayErrorWidget()->append( "\n"); | 
|---|
| 1064 | d->displayErrorWidget()->show(); | 
|---|
| 1065 |  | 
|---|
| 1066 | qCritical() << pt << error << process->errorString(); | 
|---|
| 1067 | } | 
|---|
| 1068 | } | 
|---|
| 1069 |  | 
|---|