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) {
 
     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;
 
-        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();
 
         for (unsigned i = 0; i < components.Size(); i++)
@@ -187,9 +176,19 @@ static int js_atomic_destroy(duk_context* ctx)
         node->RemoveAllComponents();
         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;
     }

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

@@ -74,15 +74,17 @@ void JSComponent::OnNodeSet(Node *node)
         assert(node->JSGetHeapPtr());
 
         duk_context* ctx = vm_->GetJSContext();
+        int top = duk_get_top(ctx);
         duk_push_global_stash(ctx);
         duk_get_prop_index(ctx, -1, JS_GLOBALSTASH_INDEX_NODE_REGISTRY);
         // can't use instance as key, as this coerces to [Object] for
         // string property, pointer will be string representation of
         // address, so, unique key
-        duk_push_pointer(ctx, node->JSGetHeapPtr());
+        duk_push_pointer(ctx, (void*) node);
         js_push_class_object_instance(ctx, node);
         duk_put_prop(ctx, -3);
         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)
 {
+    assert(className.Length());
+
     if (className == className_ && scriptObject_)
         return;
 

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

@@ -56,6 +56,7 @@ public:
     virtual void OnSetEnabled();
     void OnNodeSet(Node *node);
 
+    bool GetDestroyed() { return destroyed_; }
     void SetDestroyed() { destroyed_ = true; }
 
     /// 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/Scene/Node.h>
 
 #include "JSVM.h"
 #include "JSComponent.h"
@@ -24,6 +25,12 @@ static bool CompareObjectMetrics(const JSMetrics::ObjectMetric& lhs, const JSMet
     return lhs.count > rhs.count;
 }
 
+static bool CompareNodeMetrics(const JSMetrics::NodeMetric& lhs, const JSMetrics::NodeMetric& rhs)
+{
+    return lhs.count > rhs.count;
+}
+
+
 void JSMetrics::Dump()
 {
     Vector<ObjectMetric> sorted;
@@ -44,8 +51,34 @@ void JSMetrics::Dump()
         LOGINFOF("%s %i", classname.CString(), objectMetrics_[classname].count);
         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()
 {
     Vector<String> jsnames;
@@ -64,6 +97,13 @@ void JSMetrics::DumpJSComponents()
         {
             JSComponent* jsc = (JSComponent*) itr->second_;
             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))
             {
                 jsnames.Push(classname);
@@ -87,6 +127,7 @@ void JSMetrics::DumpJSComponents()
 void JSMetrics::Capture()
 {
     objectMetrics_.Clear();
+    nodeMetrics_.Clear();
 
     // run twice to call finalizers
     // see duktape docs
@@ -101,8 +142,34 @@ void JSMetrics::Capture()
         if (itr->second_->IsObject())
         {
             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))
         {
             JSMetrics::ObjectMetric metric;

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

@@ -23,6 +23,13 @@ class JSMetrics : public Object
         int count;
     };
 
+    struct NodeMetric
+    {
+        String name;
+        int count;
+    };
+
+
 public:
 
     /// Construct.
@@ -33,6 +40,7 @@ public:
     void Capture();
 
     void Dump();
+    void DumpNodes();
     void DumpJSComponents();
 
 private:
@@ -42,6 +50,9 @@ private:
     // Object
     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;
 }
 
+void JSVM::GC()
+{
+    // run twice to ensure finalizers are run
+    duk_gc(ctx_, 0);
+    duk_gc(ctx_, 0);
+}
 
 bool JSVM::ExecuteMain()
 {

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

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