History

Add JS profiling API

Karol Suprynowicz committed 3 years ago

Commit a84c68f1 parent 47ec27f6 files · +144 −2Browse files

Showing the changes to libraries/script-engine/src/v8/ScriptEngineV8.cpp (1 of 6 files). Show all

Unified · Split

libraries/script-engine/src/v8/ScriptEngineV8.cpp+85−0
@@ -56,6 +56,7 @@ · 55 unmodified lines
5656 #include "ScriptValueV8Wrapper.h"
5757 #include "ScriptEngineLoggingV8.h"
5858 #include "ScriptValueIteratorV8Wrapper.h"
59+#include "shared/FileUtils.h"
5960
6061 static const int MAX_DEBUG_VALUE_LENGTH { 80 };
6162
@@ -1450,6 +1451,90 @@ void ScriptEngineV8::dumpHeapObjectStatistics() { · 1388 unmodified lines
14501451 }
14511452 }
14521453
1454+void ScriptEngineV8::startProfiling() {
1455+ if (_profiler) {
1456+ qWarning(scriptengine_v8) << "ScriptEngineV8::startProfiling: Profiler is already running";
1457+ return;
1458+ }
1459+ _profiler = v8::CpuProfiler::New(_v8Isolate);
1460+ v8::CpuProfilingResult result = _profiler->Start(v8::CpuProfilingOptions());
1461+ if (!result.id) {
1462+ qWarning(scriptengine_v8) << "ScriptEngineV8::startProfiling: Profiler failed to start";
1463+ _profiler->Dispose();
1464+ _profiler = nullptr;
1465+ return;
1466+ }
1467+ qDebug(scriptengine_v8) << "Script profiler started";
1468+ _profilerId = result.id;
1469+};
1470+
1471+// Helper function for ScriptEngineV8::stopProfilingAndSave
1472+
1473+int getTotalNodeHitCount(const v8::CpuProfileNode *node) {
1474+ int hitCount = node->GetHitCount();
1475+ for (int i = 0; i < node->GetChildrenCount(); i++) {
1476+ hitCount += getTotalNodeHitCount(node->GetChild(i));
1477+ }
1478+ return hitCount;
1479+}
1480+
1481+QString getLogFileName() {
1482+ static const QString FILENAME_FORMAT = "overte-profile_%1.txt";
1483+ static const QString DATETIME_FORMAT = "yyyy-MM-dd_hh.mm.ss";
1484+ static const QString LOGS_DIRECTORY = "Logs";
1485+
1486+ QString result = FileUtils::standardPath(LOGS_DIRECTORY);
1487+ QDateTime now = QDateTime::currentDateTime();
1488+
1489+ result.append(QString(FILENAME_FORMAT).arg(now.toString(DATETIME_FORMAT)));
1490+ return result;
1491+}
1492+
1493+void ScriptEngineV8::stopProfilingAndSave() {
1494+ // the following will produce 11/18 13:55:36
1495+ const QString DATE_STRING_FORMAT = "MM/dd hh:mm:ss";
1496+
1497+ if (!_profiler || !_profilerId) {
1498+ qWarning(scriptengine_v8) << "ScriptEngineV8::stopProfilingAndSave: Profiler is not running";
1499+ return;
1500+ }
1501+ v8::CpuProfile *profile = _profiler->Stop(_profilerId);
1502+ QString filename(getLogFileName());
1503+ QFile file(filename);
1504+ if (file.open(QIODevice::WriteOnly)) {
1505+ QStringList samples;
1506+ for (int i = 0; i < profile->GetSamplesCount(); i++) {
1507+ QString line;
1508+ QTextStream stream(&line);
1509+ const v8::CpuProfileNode *node = profile->GetSample(i);
1510+ stream << getTotalNodeHitCount(node) << ";"
1511+ << node->GetHitCount() << ";"
1512+ << node->GetFunctionNameStr() << ";"
1513+ << node->GetScriptResourceNameStr() << ";"
1514+ << node->GetLineNumber() << "\n";
1515+ samples.append(line);
1516+ }
1517+ samples.sort();
1518+ QStringList deduplicated;
1519+ deduplicated.append(samples[0]);
1520+ for (int i=1; i < samples.size(); i++) {
1521+ if (samples[i] != samples[i-1]) {
1522+ deduplicated.append(samples[i]);
1523+ }
1524+ }
1525+ QTextStream fileStream(&file);
1526+ for (QString line : deduplicated) {
1527+ fileStream << line;
1528+ }
1529+ } else {
1530+ qWarning(scriptengine_v8) << "ScriptEngineV8::stopProfilingAndSave: Cannot open output file";
1531+ }
1532+ profile->Delete();
1533+ _profiler->Dispose();
1534+ _profiler = nullptr;
1535+ qDebug(scriptengine_v8) << "Script profiler stopped, results written to: " << filename;
1536+};
1537+
14531538 ContextScopeV8::ContextScopeV8(ScriptEngineV8 *engine) :
14541539 _engine(engine) {
14551540 Q_ASSERT(engine);