Browse Source

Add method to dump nodes (by name and count) to metrics, use the actual node ptr and not the heap ptr for node backing store, expose GC to script

Josh Engebretson 10 years ago
parent
commit
cc8ec9cddd

+ 19 - 0
Data/AtomicPlayer/Resources/CoreData/AtomicModules/AtomicGame.js

@@ -98,6 +98,25 @@ Game.prototype.createScene2D = function() {
 
 
 }
 }
 
 
+Game.prototype.dumpMetrics = function() {
+
+	var metrics = Atomic.getVM().metrics;
+  metrics.capture();
+  print("--------------");
+  print("Object Instances:");
+  print("--------------");
+  metrics.dump();
+	print("--------------");
+  print("Nodes:");
+  print("--------------");
+  metrics.dumpNodes();
+  print("--------------");
+  print("JS Components:");
+  print("--------------");
+  metrics.dumpJSComponents();
+
+}
+
 Game.prototype.createScene3D = function(filename) {
 Game.prototype.createScene3D = function(filename) {
 
 
     var scene = new Atomic.Scene();
     var scene = new Atomic.Scene();

+ 12 - 13
Source/AtomicJS/Javascript/JSAtomic.cpp

@@ -158,17 +158,6 @@ static int js_atomic_destroy(duk_context* ctx)
 
 
         Node* node = (Node*) obj;
         Node* node = (Node*) obj;
 
 
-        if (node->JSGetHeapPtr())
-        {
-            int top = duk_get_top(ctx);
-            duk_push_global_stash(ctx);
-            duk_get_prop_index(ctx, -1, JS_GLOBALSTASH_INDEX_NODE_REGISTRY);
-            duk_push_pointer(ctx, node->JSGetHeapPtr());
-            duk_del_prop(ctx, -2);
-            duk_pop_2(ctx);
-            assert(top = duk_get_top(ctx));
-        }
-
         const Vector<SharedPtr<Component> >& components = node->GetComponents();
         const Vector<SharedPtr<Component> >& components = node->GetComponents();
 
 
         for (unsigned i = 0; i < components.Size(); i++)
         for (unsigned i = 0; i < components.Size(); i++)
@@ -187,9 +176,19 @@ static int js_atomic_destroy(duk_context* ctx)
         node->RemoveAllComponents();
         node->RemoveAllComponents();
         node->UnsubscribeFromAllEvents();
         node->UnsubscribeFromAllEvents();
 
 
-        assert(node->Refs() >= 2);
+        if (node->GetParent())
+        {
+            assert(node->Refs() >= 2);
+            node->Remove();
+        }
 
 
-        node->Remove();
+        int top = duk_get_top(ctx);
+        duk_push_global_stash(ctx);
+        duk_get_prop_index(ctx, -1, JS_GLOBALSTASH_INDEX_NODE_REGISTRY);
+        duk_push_pointer(ctx, (void*) node);
+        duk_del_prop(ctx, -2);
+        duk_pop_2(ctx);
+        assert(top = duk_get_top(ctx));
 
 
         return 0;
         return 0;
     }
     }

+ 5 - 1
Source/AtomicJS/Javascript/JSComponent.cpp

@@ -74,15 +74,17 @@ void JSComponent::OnNodeSet(Node *node)
         assert(node->JSGetHeapPtr());
         assert(node->JSGetHeapPtr());
 
 
         duk_context* ctx = vm_->GetJSContext();
         duk_context* ctx = vm_->GetJSContext();
+        int top = duk_get_top(ctx);
         duk_push_global_stash(ctx);
         duk_push_global_stash(ctx);
         duk_get_prop_index(ctx, -1, JS_GLOBALSTASH_INDEX_NODE_REGISTRY);
         duk_get_prop_index(ctx, -1, JS_GLOBALSTASH_INDEX_NODE_REGISTRY);
         // can't use instance as key, as this coerces to [Object] for
         // can't use instance as key, as this coerces to [Object] for
         // string property, pointer will be string representation of
         // string property, pointer will be string representation of
         // address, so, unique key
         // address, so, unique key
-        duk_push_pointer(ctx, node->JSGetHeapPtr());
+        duk_push_pointer(ctx, (void*) node);
         js_push_class_object_instance(ctx, node);
         js_push_class_object_instance(ctx, node);
         duk_put_prop(ctx, -3);
         duk_put_prop(ctx, -3);
         duk_pop_2(ctx);
         duk_pop_2(ctx);
+        assert(duk_get_top(ctx) == top);
     }
     }
 }
 }
 
 
@@ -137,6 +139,8 @@ bool JSComponent::CreateObject(JSFile* scriptFile, const String& className)
 
 
 void JSComponent::SetClassName(const String& className)
 void JSComponent::SetClassName(const String& className)
 {
 {
+    assert(className.Length());
+
     if (className == className_ && scriptObject_)
     if (className == className_ && scriptObject_)
         return;
         return;
 
 

+ 1 - 0
Source/AtomicJS/Javascript/JSComponent.h

@@ -56,6 +56,7 @@ public:
     virtual void OnSetEnabled();
     virtual void OnSetEnabled();
     void OnNodeSet(Node *node);
     void OnNodeSet(Node *node);
 
 
+    bool GetDestroyed() { return destroyed_; }
     void SetDestroyed() { destroyed_ = true; }
     void SetDestroyed() { destroyed_ = true; }
 
 
     /// Create object of certain class from the script file. Return true if successful.
     /// Create object of certain class from the script file. Return true if successful.

+ 67 - 0
Source/AtomicJS/Javascript/JSMetrics.cpp

@@ -1,5 +1,6 @@
 
 
 #include <Atomic/Container/Sort.h>
 #include <Atomic/Container/Sort.h>
+#include <Atomic/Scene/Node.h>
 
 
 #include "JSVM.h"
 #include "JSVM.h"
 #include "JSComponent.h"
 #include "JSComponent.h"
@@ -24,6 +25,12 @@ static bool CompareObjectMetrics(const JSMetrics::ObjectMetric& lhs, const JSMet
     return lhs.count > rhs.count;
     return lhs.count > rhs.count;
 }
 }
 
 
+static bool CompareNodeMetrics(const JSMetrics::NodeMetric& lhs, const JSMetrics::NodeMetric& rhs)
+{
+    return lhs.count > rhs.count;
+}
+
+
 void JSMetrics::Dump()
 void JSMetrics::Dump()
 {
 {
     Vector<ObjectMetric> sorted;
     Vector<ObjectMetric> sorted;
@@ -44,8 +51,34 @@ void JSMetrics::Dump()
         LOGINFOF("%s %i", classname.CString(), objectMetrics_[classname].count);
         LOGINFOF("%s %i", classname.CString(), objectMetrics_[classname].count);
         vitr++;
         vitr++;
     }
     }
+
+}
+
+
+void JSMetrics::DumpNodes()
+{
+    Vector<NodeMetric> sorted;
+
+    HashMap<StringHash, NodeMetric>::ConstIterator itr = nodeMetrics_.Begin();
+    while (itr != nodeMetrics_.End())
+    {
+        sorted.Push(itr->second_);
+        itr++;
+    }
+
+    Sort(sorted.Begin(), sorted.End(), CompareNodeMetrics);
+
+    Vector<NodeMetric>::ConstIterator vitr = sorted.Begin();
+    while (vitr != sorted.End())
+    {
+        const String& nodename = (*vitr).name;
+        LOGINFOF("%s %i", nodename.CString(), nodeMetrics_[nodename].count);
+        vitr++;
+    }
+
 }
 }
 
 
+
 void JSMetrics::DumpJSComponents()
 void JSMetrics::DumpJSComponents()
 {
 {
     Vector<String> jsnames;
     Vector<String> jsnames;
@@ -64,6 +97,13 @@ void JSMetrics::DumpJSComponents()
         {
         {
             JSComponent* jsc = (JSComponent*) itr->second_;
             JSComponent* jsc = (JSComponent*) itr->second_;
             const String& classname = jsc->GetClassName();
             const String& classname = jsc->GetClassName();
+
+            if (jsc->GetDestroyed())
+            {
+                // this is an error
+                LOGINFOF("Destroyed: %s Node: %p JSHeapPtr: %p", jsc->GetClassName().CString(), (void*) jsc->GetNode(), (void*) jsc->JSGetHeapPtr());
+            }
+
             if (!jscomponents.Contains(classname))
             if (!jscomponents.Contains(classname))
             {
             {
                 jsnames.Push(classname);
                 jsnames.Push(classname);
@@ -87,6 +127,7 @@ void JSMetrics::DumpJSComponents()
 void JSMetrics::Capture()
 void JSMetrics::Capture()
 {
 {
     objectMetrics_.Clear();
     objectMetrics_.Clear();
+    nodeMetrics_.Clear();
 
 
     // run twice to call finalizers
     // run twice to call finalizers
     // see duktape docs
     // see duktape docs
@@ -101,8 +142,34 @@ void JSMetrics::Capture()
         if (itr->second_->IsObject())
         if (itr->second_->IsObject())
         {
         {
             classname = ((Object*) itr->second_)->GetTypeName();
             classname = ((Object*) itr->second_)->GetTypeName();
+
+            if (classname == "Node")
+            {
+                String nodename = ((Node*) itr->second_)->GetName();
+
+                if (nodename == String::EMPTY)
+                {
+                    nodename = String("(Anonymous)");
+                }
+
+                if (!nodeMetrics_.Contains(nodename))
+                {
+                    JSMetrics::NodeMetric metric;
+                    metric.name = nodename;
+                    metric.count = 1;
+                    nodeMetrics_[nodename] = metric;
+                }
+                else
+                {
+                    nodeMetrics_[nodename].count++;
+                }
+
+            }
+
         }
         }
 
 
+
+
         if (!objectMetrics_.Contains(classname))
         if (!objectMetrics_.Contains(classname))
         {
         {
             JSMetrics::ObjectMetric metric;
             JSMetrics::ObjectMetric metric;

+ 11 - 0
Source/AtomicJS/Javascript/JSMetrics.h

@@ -23,6 +23,13 @@ class JSMetrics : public Object
         int count;
         int count;
     };
     };
 
 
+    struct NodeMetric
+    {
+        String name;
+        int count;
+    };
+
+
 public:
 public:
 
 
     /// Construct.
     /// Construct.
@@ -33,6 +40,7 @@ public:
     void Capture();
     void Capture();
 
 
     void Dump();
     void Dump();
+    void DumpNodes();
     void DumpJSComponents();
     void DumpJSComponents();
 
 
 private:
 private:
@@ -42,6 +50,9 @@ private:
     // Object
     // Object
     HashMap<StringHash, ObjectMetric> objectMetrics_;
     HashMap<StringHash, ObjectMetric> objectMetrics_;
 
 
+    // Nodes
+    HashMap<StringHash, NodeMetric> nodeMetrics_;
+
 };
 };
 
 
 }
 }

+ 6 - 0
Source/AtomicJS/Javascript/JSVM.cpp

@@ -506,6 +506,12 @@ bool JSVM::ExecuteFile(File *file)
     return true;
     return true;
 }
 }
 
 
+void JSVM::GC()
+{
+    // run twice to ensure finalizers are run
+    duk_gc(ctx_, 0);
+    duk_gc(ctx_, 0);
+}
 
 
 bool JSVM::ExecuteMain()
 bool JSVM::ExecuteMain()
 {
 {

+ 1 - 0
Source/AtomicJS/Javascript/JSVM.h

@@ -55,6 +55,7 @@ public:
 
 
     inline duk_context* GetJSContext() { return ctx_; }
     inline duk_context* GetJSContext() { return ctx_; }
 
 
+    void GC();
     JSMetrics* GetMetrics() { return metrics_; }
     JSMetrics* GetMetrics() { return metrics_; }
 
 
     void DumpJavascriptObjects() {}
     void DumpJavascriptObjects() {}