mirror of
https://github.com/overte-org/overte.git
synced 2025-07-23 09:43:51 +02:00
V8 heap object statistics
This commit is contained in:
parent
6466d39c05
commit
a57c7a5e5b
6 changed files with 74 additions and 14 deletions
|
@ -27,7 +27,8 @@
|
||||||
#include "ScriptException.h"
|
#include "ScriptException.h"
|
||||||
|
|
||||||
// These are used for debugging memory leaks caused by persistent handles
|
// These are used for debugging memory leaks caused by persistent handles
|
||||||
#define OVERTE_V8_HANDLE_COUNTERS
|
// V8TODO: Rename to something better, like for example OVERTE_V8_MEMORY_DEBUG
|
||||||
|
#define OVERTE_V8_MEMORY_DEBUG
|
||||||
|
|
||||||
class QByteArray;
|
class QByteArray;
|
||||||
class QLatin1String;
|
class QLatin1String;
|
||||||
|
@ -56,7 +57,7 @@ public:
|
||||||
size_t totalAvailableSize;
|
size_t totalAvailableSize;
|
||||||
size_t totalGlobalHandlesSize;
|
size_t totalGlobalHandlesSize;
|
||||||
size_t usedGlobalHandlesSize;
|
size_t usedGlobalHandlesSize;
|
||||||
#ifdef OVERTE_V8_HANDLE_COUNTERS
|
#ifdef OVERTE_V8_MEMORY_DEBUG
|
||||||
size_t scriptValueCount;
|
size_t scriptValueCount;
|
||||||
size_t scriptValueProxyCount;
|
size_t scriptValueProxyCount;
|
||||||
#endif
|
#endif
|
||||||
|
@ -399,6 +400,16 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual ScriptEngineMemoryStatistics getMemoryUsageStatistics() = 0;
|
virtual ScriptEngineMemoryStatistics getMemoryUsageStatistics() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Start collecting object statistics that can later be reported with dumpHeapObjectStatistics().
|
||||||
|
*/
|
||||||
|
virtual void startCollectingObjectStatistics() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prints heap statistics to a file. Collecting needs to first be started with dumpHeapObjectStatistics().
|
||||||
|
*/
|
||||||
|
virtual void dumpHeapObjectStatistics() = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways
|
// helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways
|
||||||
bool IS_THREADSAFE_INVOCATION(const QString& method);
|
bool IS_THREADSAFE_INVOCATION(const QString& method);
|
||||||
|
|
|
@ -61,13 +61,21 @@ QVariantMap ScriptManagerScriptingInterface::getMemoryUsageStatistics() {
|
||||||
map.insert("totalAvailableSize", QVariant((qulonglong)(statistics.totalAvailableSize)));
|
map.insert("totalAvailableSize", QVariant((qulonglong)(statistics.totalAvailableSize)));
|
||||||
map.insert("totalGlobalHandlesSize", QVariant((qulonglong)(statistics.totalGlobalHandlesSize)));
|
map.insert("totalGlobalHandlesSize", QVariant((qulonglong)(statistics.totalGlobalHandlesSize)));
|
||||||
map.insert("usedGlobalHandlesSize", QVariant((qulonglong)(statistics.usedGlobalHandlesSize)));
|
map.insert("usedGlobalHandlesSize", QVariant((qulonglong)(statistics.usedGlobalHandlesSize)));
|
||||||
#ifdef OVERTE_V8_HANDLE_COUNTERS
|
#ifdef OVERTE_V8_MEMORY_DEBUG
|
||||||
map.insert("scriptValueCount", QVariant((qulonglong)(statistics.scriptValueCount)));
|
map.insert("scriptValueCount", QVariant((qulonglong)(statistics.scriptValueCount)));
|
||||||
map.insert("scriptValueProxyCount", QVariant((qulonglong)(statistics.scriptValueProxyCount)));
|
map.insert("scriptValueProxyCount", QVariant((qulonglong)(statistics.scriptValueProxyCount)));
|
||||||
#endif
|
#endif
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScriptManagerScriptingInterface::startCollectingObjectStatistics() {
|
||||||
|
_manager->engine()->startCollectingObjectStatistics();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptManagerScriptingInterface::dumpHeapObjectStatistics() {
|
||||||
|
_manager->engine()->dumpHeapObjectStatistics();
|
||||||
|
}
|
||||||
|
|
||||||
ScriptValue ScriptManagerScriptingInterface::createGarbageCollectorDebuggingObject() {
|
ScriptValue ScriptManagerScriptingInterface::createGarbageCollectorDebuggingObject() {
|
||||||
//auto value = _manager->engine()->newQObject(new TestQObject, ScriptEngine::ScriptOwnership);
|
//auto value = _manager->engine()->newQObject(new TestQObject, ScriptEngine::ScriptOwnership);
|
||||||
return _manager->engine()->newQObject(new TestQObject, ScriptEngine::ScriptOwnership);
|
return _manager->engine()->newQObject(new TestQObject, ScriptEngine::ScriptOwnership);
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
class TestQObject : public QObject {
|
class TestQObject : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE virtual void testMethod() { qDebug() << "TestQObject::testMethod"; };
|
//Q_INVOKABLE virtual void testMethod() { qDebug() << "TestQObject::testMethod"; };
|
||||||
};
|
};
|
||||||
|
|
||||||
class ScriptManagerScriptingInterface : public QObject {
|
class ScriptManagerScriptingInterface : public QObject {
|
||||||
|
@ -510,6 +510,18 @@ public:
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE QVariantMap getMemoryUsageStatistics();
|
Q_INVOKABLE QVariantMap getMemoryUsageStatistics();
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Start collecting object statistics that can later be reported with Script.dumpHeapObjectStatistics().
|
||||||
|
* @function Script.dumpHeapObjectStatistics
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE void startCollectingObjectStatistics();
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Prints heap statistics to a file. Collecting needs to first be started with Script.dumpHeapObjectStatistics().
|
||||||
|
* @function Script.dumpHeapObjectStatistics
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE void dumpHeapObjectStatistics();
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Create test object for garbage collector debugging.
|
* Create test object for garbage collector debugging.
|
||||||
* @function Script.createGarbageCollectorDebuggingObject()
|
* @function Script.createGarbageCollectorDebuggingObject()
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
|
|
||||||
#include <Profile.h>
|
#include <Profile.h>
|
||||||
|
|
||||||
|
#include <v8-profiler.h>
|
||||||
|
|
||||||
#include "../ScriptEngineLogging.h"
|
#include "../ScriptEngineLogging.h"
|
||||||
#include "../ScriptProgram.h"
|
#include "../ScriptProgram.h"
|
||||||
#include "../ScriptValue.h"
|
#include "../ScriptValue.h"
|
||||||
|
@ -282,7 +284,11 @@ ScriptEngineV8::ScriptEngineV8(ScriptManager *manager) : ScriptEngine(manager),
|
||||||
// --assert-types
|
// --assert-types
|
||||||
|
|
||||||
v8::V8::InitializeICU();
|
v8::V8::InitializeICU();
|
||||||
v8::V8::SetFlagsFromString("--stack-size=256 --verify-heap --assert-types");
|
#ifdef OVERTE_V8_MEMORY_DEBUG
|
||||||
|
v8::V8::SetFlagsFromString("--stack-size=256 --track_gc_object_stats --assert-types");
|
||||||
|
#else
|
||||||
|
v8::V8::SetFlagsFromString("--stack-size=256");
|
||||||
|
#endif
|
||||||
//v8::V8::SetFlagsFromString("--stack-size=256 --single-threaded");
|
//v8::V8::SetFlagsFromString("--stack-size=256 --single-threaded");
|
||||||
v8::Platform* platform = getV8Platform();
|
v8::Platform* platform = getV8Platform();
|
||||||
v8::V8::InitializePlatform(platform);
|
v8::V8::InitializePlatform(platform);
|
||||||
|
@ -1720,10 +1726,31 @@ ScriptEngineMemoryStatistics ScriptEngineV8::getMemoryUsageStatistics() {
|
||||||
statistics.totalAvailableSize = heapStatistics.total_available_size();
|
statistics.totalAvailableSize = heapStatistics.total_available_size();
|
||||||
statistics.totalGlobalHandlesSize = heapStatistics.total_global_handles_size();
|
statistics.totalGlobalHandlesSize = heapStatistics.total_global_handles_size();
|
||||||
statistics.usedGlobalHandlesSize = heapStatistics.used_global_handles_size();
|
statistics.usedGlobalHandlesSize = heapStatistics.used_global_handles_size();
|
||||||
#ifdef OVERTE_V8_HANDLE_COUNTERS
|
#ifdef OVERTE_V8_MEMORY_DEBUG
|
||||||
statistics.scriptValueCount = scriptValueCount;
|
statistics.scriptValueCount = scriptValueCount;
|
||||||
statistics.scriptValueProxyCount = scriptValueProxyCount;
|
statistics.scriptValueProxyCount = scriptValueProxyCount;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return statistics;
|
return statistics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScriptEngineV8::startCollectingObjectStatistics() {
|
||||||
|
auto heapProfiler = _v8Isolate->GetHeapProfiler();
|
||||||
|
heapProfiler->StartTrackingHeapObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngineV8::dumpHeapObjectStatistics() {
|
||||||
|
// V8TODO: this is not very elegant, but very convenient
|
||||||
|
QFile dumpFile("/tmp/heap_objectStatistics_dump.csv");
|
||||||
|
if (!dumpFile.open(QFile::WriteOnly | QFile::Truncate)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QTextStream dump(&dumpFile);
|
||||||
|
size_t objectTypeCount = _v8Isolate->NumberOfTrackedHeapObjectTypes();
|
||||||
|
for (size_t i = 0; i < objectTypeCount; i++) {
|
||||||
|
v8::HeapObjectStatistics statistics;
|
||||||
|
if (_v8Isolate->GetHeapObjectStatisticsAtLastGC(&statistics, i)) {
|
||||||
|
dump << statistics.object_type() << " " << statistics.object_sub_type() << " " << statistics.object_count() << " "
|
||||||
|
<< statistics.object_size() << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -136,6 +136,8 @@ public: // ScriptEngine implementation
|
||||||
QString scriptValueDebugListMembersV8(const V8ScriptValue &v8Value);
|
QString scriptValueDebugListMembersV8(const V8ScriptValue &v8Value);
|
||||||
virtual void logBacktrace(const QString &title = QString("")) override;
|
virtual void logBacktrace(const QString &title = QString("")) override;
|
||||||
virtual ScriptEngineMemoryStatistics getMemoryUsageStatistics() override;
|
virtual ScriptEngineMemoryStatistics getMemoryUsageStatistics() override;
|
||||||
|
virtual void startCollectingObjectStatistics() override;
|
||||||
|
virtual void dumpHeapObjectStatistics() override;
|
||||||
|
|
||||||
// helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways
|
// 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); }
|
inline bool IS_THREADSAFE_INVOCATION(const QString& method) { return ScriptEngine::IS_THREADSAFE_INVOCATION(method); }
|
||||||
|
@ -205,7 +207,7 @@ public: // not for public use, but I don't like how Qt strings this along with p
|
||||||
void popContext();
|
void popContext();
|
||||||
// V8TODO: call this after initializing global object
|
// V8TODO: call this after initializing global object
|
||||||
void storeGlobalObjectContents();
|
void storeGlobalObjectContents();
|
||||||
#ifdef OVERTE_V8_HANDLE_COUNTERS
|
#ifdef OVERTE_V8_MEMORY_DEBUG
|
||||||
void incrementScriptValueCounter() { scriptValueCount++; };
|
void incrementScriptValueCounter() { scriptValueCount++; };
|
||||||
void decrementScriptValueCounter() { scriptValueCount--; };
|
void decrementScriptValueCounter() { scriptValueCount--; };
|
||||||
void incrementScriptValueProxyCounter() { scriptValueProxyCount++; };
|
void incrementScriptValueProxyCounter() { scriptValueProxyCount++; };
|
||||||
|
@ -264,7 +266,7 @@ protected:
|
||||||
//ArrayBufferClass* _arrayBufferClass;
|
//ArrayBufferClass* _arrayBufferClass;
|
||||||
// Counts how many nested evaluate calls are there at a given point
|
// Counts how many nested evaluate calls are there at a given point
|
||||||
int _evaluatingCounter;
|
int _evaluatingCounter;
|
||||||
#ifdef OVERTE_V8_HANDLE_COUNTERS
|
#ifdef OVERTE_V8_MEMORY_DEBUG
|
||||||
std::atomic<size_t> scriptValueCount{0};
|
std::atomic<size_t> scriptValueCount{0};
|
||||||
std::atomic<size_t> scriptValueProxyCount{0};
|
std::atomic<size_t> scriptValueProxyCount{0};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -47,7 +47,7 @@ public:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Q_ASSERT(false);*/
|
Q_ASSERT(false);*/
|
||||||
#ifdef OVERTE_V8_HANDLE_COUNTERS
|
#ifdef OVERTE_V8_MEMORY_DEBUG
|
||||||
_engine->incrementScriptValueCounter();
|
_engine->incrementScriptValueCounter();
|
||||||
#endif
|
#endif
|
||||||
_value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), value));
|
_value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), value));
|
||||||
|
@ -70,7 +70,7 @@ public:
|
||||||
v8::HandleScope handleScope(_engine->getIsolate());
|
v8::HandleScope handleScope(_engine->getIsolate());
|
||||||
v8::Context::Scope(_engine->getContext());
|
v8::Context::Scope(_engine->getContext());
|
||||||
//_value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), v8::Local<T>()));
|
//_value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), v8::Local<T>()));
|
||||||
#ifdef OVERTE_V8_HANDLE_COUNTERS
|
#ifdef OVERTE_V8_MEMORY_DEBUG
|
||||||
_engine->incrementScriptValueCounter();
|
_engine->incrementScriptValueCounter();
|
||||||
#endif
|
#endif
|
||||||
_value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), v8::Local<T>()));
|
_value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), v8::Local<T>()));
|
||||||
|
@ -82,7 +82,7 @@ public:
|
||||||
v8::HandleScope handleScope(_engine->getIsolate());
|
v8::HandleScope handleScope(_engine->getIsolate());
|
||||||
v8::Context::Scope(_engine->getContext());
|
v8::Context::Scope(_engine->getContext());
|
||||||
//_value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), copied.constGet()));
|
//_value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), copied.constGet()));
|
||||||
#ifdef OVERTE_V8_HANDLE_COUNTERS
|
#ifdef OVERTE_V8_MEMORY_DEBUG
|
||||||
_engine->incrementScriptValueCounter();
|
_engine->incrementScriptValueCounter();
|
||||||
#endif
|
#endif
|
||||||
_value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), copied.constGet()));
|
_value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), copied.constGet()));
|
||||||
|
@ -136,7 +136,7 @@ public:
|
||||||
v8::Isolate::Scope isolateScope(_engine->getIsolate());
|
v8::Isolate::Scope isolateScope(_engine->getIsolate());
|
||||||
v8::HandleScope handleScope(_engine->getIsolate());
|
v8::HandleScope handleScope(_engine->getIsolate());
|
||||||
//v8::Context::Scope(_engine->getContext());
|
//v8::Context::Scope(_engine->getContext());
|
||||||
#ifdef OVERTE_V8_HANDLE_COUNTERS
|
#ifdef OVERTE_V8_MEMORY_DEBUG
|
||||||
_engine->decrementScriptValueCounter();
|
_engine->decrementScriptValueCounter();
|
||||||
#endif
|
#endif
|
||||||
_value->Reset();
|
_value->Reset();
|
||||||
|
|
Loading…
Reference in a new issue