mirror of
https://github.com/lubosz/overte.git
synced 2025-04-07 04:42:49 +02:00
V8 memory usage statistics
This commit is contained in:
parent
2faacfaec6
commit
56c3bad002
6 changed files with 124 additions and 27 deletions
|
@ -46,6 +46,14 @@ inline ScriptValue scriptValueFromValue(ScriptEngine* engine, const T& t);
|
|||
template <typename T>
|
||||
inline T scriptvalue_cast(const ScriptValue& value);
|
||||
|
||||
class ScriptEngineMemoryStatistics {
|
||||
public:
|
||||
size_t totalHeapSize;
|
||||
size_t usedHeapSize;
|
||||
size_t totalAvailableSize;
|
||||
size_t totalGlobalHandlesSize;
|
||||
size_t usedGlobalHandlesSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Provides an engine-independent interface for a scripting engine
|
||||
|
@ -374,6 +382,16 @@ public:
|
|||
* @param title Informative title for the backtrace
|
||||
*/
|
||||
virtual void logBacktrace(const QString &title) = 0;
|
||||
|
||||
/**
|
||||
* @brief Return memory usage statistics data.
|
||||
*
|
||||
* Returns memory usage statistics data for debugging.
|
||||
*
|
||||
* @return ScriptEngineMemoryStatistics Object containing memory usage statistics data.
|
||||
*/
|
||||
virtual ScriptEngineMemoryStatistics getMemoryUsageStatistics() = 0;
|
||||
|
||||
public:
|
||||
// helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways
|
||||
bool IS_THREADSAFE_INVOCATION(const QString& method);
|
||||
|
|
|
@ -12,42 +12,54 @@
|
|||
|
||||
#include "ScriptManager.h"
|
||||
#include "ScriptManagerScriptingInterface.h"
|
||||
#include "ScriptEngine.h"
|
||||
#include <QMetaType>
|
||||
|
||||
|
||||
|
||||
ScriptManagerScriptingInterface::ScriptManagerScriptingInterface(ScriptManager *parent): QObject(parent), _manager(parent) {
|
||||
|
||||
qRegisterMetaType<ScriptException>();
|
||||
qRegisterMetaType<ScriptEngineException>();
|
||||
qRegisterMetaType<ScriptRuntimeException>();
|
||||
qRegisterMetaType<ScriptException>();
|
||||
qRegisterMetaType<ScriptEngineException>();
|
||||
qRegisterMetaType<ScriptRuntimeException>();
|
||||
|
||||
qRegisterMetaType<std::shared_ptr<ScriptException>>();
|
||||
qRegisterMetaType<std::shared_ptr<ScriptEngineException>>();
|
||||
qRegisterMetaType<std::shared_ptr<ScriptRuntimeException>>();
|
||||
qRegisterMetaType<std::shared_ptr<ScriptException>>();
|
||||
qRegisterMetaType<std::shared_ptr<ScriptEngineException>>();
|
||||
qRegisterMetaType<std::shared_ptr<ScriptRuntimeException>>();
|
||||
|
||||
|
||||
connect(_manager, &ScriptManager::scriptLoaded, this, &ScriptManagerScriptingInterface::scriptLoaded);
|
||||
connect(_manager, &ScriptManager::errorLoadingScript, this, &ScriptManagerScriptingInterface::errorLoadingScript);
|
||||
connect(_manager, &ScriptManager::update, this, &ScriptManagerScriptingInterface::update);
|
||||
connect(_manager, &ScriptManager::scriptEnding, this, &ScriptManagerScriptingInterface::scriptEnding);
|
||||
connect(_manager, &ScriptManager::finished, this, &ScriptManagerScriptingInterface::finished);
|
||||
connect(_manager, &ScriptManager::printedMessage, this, &ScriptManagerScriptingInterface::printedMessage);
|
||||
connect(_manager, &ScriptManager::errorMessage, this, &ScriptManagerScriptingInterface::errorMessage);
|
||||
connect(_manager, &ScriptManager::warningMessage, this, &ScriptManagerScriptingInterface::warningMessage);
|
||||
connect(_manager, &ScriptManager::infoMessage, this, &ScriptManagerScriptingInterface::infoMessage);
|
||||
connect(_manager, &ScriptManager::runningStateChanged, this, &ScriptManagerScriptingInterface::runningStateChanged);
|
||||
connect(_manager, &ScriptManager::clearDebugWindow, this, &ScriptManagerScriptingInterface::clearDebugWindow);
|
||||
connect(_manager, &ScriptManager::loadScript, this, &ScriptManagerScriptingInterface::loadScript);
|
||||
connect(_manager, &ScriptManager::doneRunning, this, &ScriptManagerScriptingInterface::doneRunning);
|
||||
connect(_manager, &ScriptManager::entityScriptDetailsUpdated, this, &ScriptManagerScriptingInterface::entityScriptDetailsUpdated);
|
||||
connect(_manager, &ScriptManager::entityScriptPreloadFinished, this, &ScriptManagerScriptingInterface::entityScriptPreloadFinished);
|
||||
connect(_manager, &ScriptManager::unhandledException, this, &ScriptManagerScriptingInterface::scriptManagerException);
|
||||
}
|
||||
connect(_manager, &ScriptManager::scriptLoaded, this, &ScriptManagerScriptingInterface::scriptLoaded);
|
||||
connect(_manager, &ScriptManager::errorLoadingScript, this, &ScriptManagerScriptingInterface::errorLoadingScript);
|
||||
connect(_manager, &ScriptManager::update, this, &ScriptManagerScriptingInterface::update);
|
||||
connect(_manager, &ScriptManager::scriptEnding, this, &ScriptManagerScriptingInterface::scriptEnding);
|
||||
connect(_manager, &ScriptManager::finished, this, &ScriptManagerScriptingInterface::finished);
|
||||
connect(_manager, &ScriptManager::printedMessage, this, &ScriptManagerScriptingInterface::printedMessage);
|
||||
connect(_manager, &ScriptManager::errorMessage, this, &ScriptManagerScriptingInterface::errorMessage);
|
||||
connect(_manager, &ScriptManager::warningMessage, this, &ScriptManagerScriptingInterface::warningMessage);
|
||||
connect(_manager, &ScriptManager::infoMessage, this, &ScriptManagerScriptingInterface::infoMessage);
|
||||
connect(_manager, &ScriptManager::runningStateChanged, this, &ScriptManagerScriptingInterface::runningStateChanged);
|
||||
connect(_manager, &ScriptManager::clearDebugWindow, this, &ScriptManagerScriptingInterface::clearDebugWindow);
|
||||
connect(_manager, &ScriptManager::loadScript, this, &ScriptManagerScriptingInterface::loadScript);
|
||||
connect(_manager, &ScriptManager::doneRunning, this, &ScriptManagerScriptingInterface::doneRunning);
|
||||
connect(_manager, &ScriptManager::entityScriptDetailsUpdated, this, &ScriptManagerScriptingInterface::entityScriptDetailsUpdated);
|
||||
connect(_manager, &ScriptManager::entityScriptPreloadFinished, this, &ScriptManagerScriptingInterface::entityScriptPreloadFinished);
|
||||
connect(_manager, &ScriptManager::unhandledException, this, &ScriptManagerScriptingInterface::scriptManagerException);
|
||||
}
|
||||
|
||||
void ScriptManagerScriptingInterface::scriptManagerException(std::shared_ptr<ScriptException> exception) {
|
||||
// V8TODO: What should we actually handle here?
|
||||
void ScriptManagerScriptingInterface::scriptManagerException(std::shared_ptr<ScriptException> exception) {
|
||||
// V8TODO: What should we actually handle here?
|
||||
|
||||
|
||||
// emit unhandledException(exception.thrownValue);
|
||||
}
|
||||
// emit unhandledException(exception.thrownValue);
|
||||
}
|
||||
|
||||
QVariantMap ScriptManagerScriptingInterface::getMemoryUsageStatistics() {
|
||||
auto statistics = _manager->engine()->getMemoryUsageStatistics();
|
||||
QVariantMap map;
|
||||
map.insert("totalHeapSize", QVariant((qulonglong)(statistics.totalHeapSize)));
|
||||
map.insert("usedHeapSize", QVariant((qulonglong)(statistics.usedHeapSize)));
|
||||
map.insert("totalAvailableSize", QVariant((qulonglong)(statistics.totalAvailableSize)));
|
||||
map.insert("totalGlobalHandlesSize", QVariant((qulonglong)(statistics.totalGlobalHandlesSize)));
|
||||
map.insert("usedGlobalHandlesSize", QVariant((qulonglong)(statistics.usedGlobalHandlesSize)));
|
||||
return map;
|
||||
}
|
||||
|
|
|
@ -479,6 +479,30 @@ public:
|
|||
*/
|
||||
Q_INVOKABLE QString getExternalPath(ExternalResource::Bucket bucket, const QString& path) { return _manager->getExternalPath(bucket, path); }
|
||||
|
||||
/**jsdoc
|
||||
* <p>Object containing memory usage statistics data.</p>
|
||||
* <table>
|
||||
* <thead>
|
||||
* <tr><th>Name</th><th>Type</th><th>Description</th></tr>
|
||||
* </thead>
|
||||
* <tbody>
|
||||
* <tr><td><code>totalHeapSize</code></td><td>{number}</td><td>Total heap size allocated by scripting engine.</td></tr>
|
||||
* <tr><td><code>usedHeapSize</code></td><td>{number}</td><td></td>Amount of heap memory that is currently in use.</tr>
|
||||
* <tr><td><code>totalAvailableSize</code></td><td>{number}</td><td>Amount of remaining available heap memory</td></tr>
|
||||
* <tr><td><code>totalGlobalHandlesSize</code></td><td>{number}</td><td>V8-specific property</td></tr>
|
||||
* <tr><td><code>usedGlobalHandlesSize</code></td><td>{number}</td><td>V8-specific property</td></tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
* @typedef {object} Script.MemoryUsageData
|
||||
*/
|
||||
|
||||
/**jsdoc
|
||||
* Returns memory usage statistics data.
|
||||
* @function Script.getMemoryUsageStatistics
|
||||
* @Returns {Script.MemoryUsageData} Object containing statistics about memory usage.
|
||||
*/
|
||||
Q_INVOKABLE QVariantMap getMemoryUsageStatistics();
|
||||
|
||||
signals:
|
||||
|
||||
/**jsdoc
|
||||
|
|
|
@ -1708,3 +1708,18 @@ QStringList ScriptEngineV8::getCurrentScriptURLs() const {
|
|||
}
|
||||
return scriptURLs;
|
||||
}
|
||||
|
||||
ScriptEngineMemoryStatistics ScriptEngineV8::getMemoryUsageStatistics() {
|
||||
v8::Locker locker(_v8Isolate);
|
||||
v8::Isolate::Scope isolateScope(_v8Isolate);
|
||||
ScriptEngineMemoryStatistics statistics;
|
||||
v8::HeapStatistics heapStatistics;
|
||||
_v8Isolate->GetHeapStatistics(&heapStatistics);
|
||||
statistics.totalHeapSize = heapStatistics.total_available_size();
|
||||
statistics.usedHeapSize = heapStatistics.used_heap_size();
|
||||
statistics.totalAvailableSize = heapStatistics.total_available_size();
|
||||
statistics.totalGlobalHandlesSize = heapStatistics.total_global_handles_size();
|
||||
statistics.usedGlobalHandlesSize = heapStatistics.used_global_handles_size();
|
||||
|
||||
return statistics;
|
||||
}
|
|
@ -135,6 +135,7 @@ public: // ScriptEngine implementation
|
|||
virtual QString scriptValueDebugListMembers(const ScriptValue &value) override;
|
||||
QString scriptValueDebugListMembersV8(const V8ScriptValue &v8Value);
|
||||
virtual void logBacktrace(const QString &title = QString("")) override;
|
||||
virtual ScriptEngineMemoryStatistics getMemoryUsageStatistics() override;
|
||||
|
||||
// helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways
|
||||
inline bool IS_THREADSAFE_INVOCATION(const QString& method) { return ScriptEngine::IS_THREADSAFE_INVOCATION(method); }
|
||||
|
|
27
scripts/developer/debugging/scriptMemoryReport.js
Normal file
27
scripts/developer/debugging/scriptMemoryReport.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// scriptMemoryReport.js
|
||||
// scripts/developer/debugging
|
||||
//
|
||||
// Created by dr Karol Suprynowicz on 2023/04/23
|
||||
// Copyright 2023 Overte e.V.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
// A simple script that prints memory usage statistics for a given script engine every 5 seconds
|
||||
// It can be included for example as a part of default scripts or controller scripts
|
||||
|
||||
var memoryStatisticsIntervalHandle = Script.setInterval(function () {
|
||||
statistics = Script.getMemoryUsageStatistics();
|
||||
print("Script memory usage: Total heap size: " + statistics.totalHeapSize
|
||||
+ " usedHeapSize: " + statistics.usedHeapSize
|
||||
+ " totalAvailableSize: " + statistics.totalAvailableSize
|
||||
+ " totalGlobalHandlesSize: " + statistics.totalGlobalHandlesSize
|
||||
+ " usedGlobalHandlesSize: " + statistics.usedGlobalHandlesSize);
|
||||
}, 5000);
|
||||
|
||||
Script.scriptEnding.connect(function () {
|
||||
Script.clearInterval(memoryStatisticsIntervalHandle);
|
||||
});
|
Loading…
Reference in a new issue