]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/SamplingCounter.h
JavaScriptCore-1097.3.tar.gz
[apple/javascriptcore.git] / runtime / SamplingCounter.h
diff --git a/runtime/SamplingCounter.h b/runtime/SamplingCounter.h
new file mode 100644 (file)
index 0000000..8413b54
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SamplingCounter_h
+#define SamplingCounter_h
+
+#include <stdint.h>
+#include <wtf/Assertions.h>
+
+namespace JSC {
+
+// AbstractSamplingCounter:
+//
+// Implements a named set of counters, printed on exit if ENABLE(SAMPLING_COUNTERS).
+// See subclasses below, SamplingCounter, GlobalSamplingCounter and DeletableSamplingCounter.
+class AbstractSamplingCounter {
+    friend class DeletableSamplingCounter;
+public:
+    void count(uint32_t count = 1)
+    {
+        m_counter += count;
+    }
+
+    JS_EXPORT_PRIVATE static void dump();
+
+    int64_t* addressOfCounter() { return &m_counter; }
+
+protected:
+    // Effectively the contructor, however called lazily in the case of GlobalSamplingCounter.
+    void init(const char* name)
+    {
+        m_counter = 0;
+        m_name = name;
+
+        // Set m_next to point to the head of the chain, and inform whatever is
+        // currently at the head that this node will now hold the pointer to it.
+        m_next = s_abstractSamplingCounterChain;
+        s_abstractSamplingCounterChain->m_referer = &m_next;
+        // Add this node to the head of the list.
+        s_abstractSamplingCounterChain = this;
+        m_referer = &s_abstractSamplingCounterChain;
+    }
+
+    int64_t m_counter;
+    const char* m_name;
+    AbstractSamplingCounter* m_next;
+    // This is a pointer to the pointer to this node in the chain; used to
+    // allow fast linked list deletion.
+    AbstractSamplingCounter** m_referer;
+    // Null object used to detect end of static chain.
+    static AbstractSamplingCounter s_abstractSamplingCounterChainEnd;
+    JS_EXPORTDATA static AbstractSamplingCounter* s_abstractSamplingCounterChain;
+    static bool s_completed;
+};
+
+#if ENABLE(SAMPLING_COUNTERS)
+// SamplingCounter:
+//
+// This class is suitable and (hopefully!) convenient for cases where a counter is
+// required within the scope of a single function. It can be instantiated as a
+// static variable since it contains a constructor but not a destructor (static
+// variables in WebKit cannot have destructors).
+//
+// For example:
+//
+// void someFunction()
+// {
+//     static SamplingCounter countMe("This is my counter. There are many like it, but this one is mine.");
+//     countMe.count();
+//     // ...
+// }
+//
+class SamplingCounter : public AbstractSamplingCounter {
+public:
+    SamplingCounter(const char* name) { init(name); }
+};
+
+// GlobalSamplingCounter:
+//
+// This class is suitable for use where a counter is to be declared globally,
+// since it contains neither a constructor nor destructor. Instead, ensure
+// that 'name()' is called to provide the counter with a name (and also to
+// allow it to be printed out on exit).
+//
+// GlobalSamplingCounter globalCounter;
+//
+// void firstFunction()
+// {
+//     // Put this within a function that is definitely called!
+//     // (Or alternatively alongside all calls to 'count()').
+//     globalCounter.name("I Name You Destroyer.");
+//     globalCounter.count();
+//     // ...
+// }
+//
+// void secondFunction()
+// {
+//     globalCounter.count();
+//     // ...
+// }
+//
+class GlobalSamplingCounter : public AbstractSamplingCounter {
+public:
+    void name(const char* name)
+    {
+        // Global objects should be mapped in zero filled memory, so this should
+        // be a safe (albeit not necessarily threadsafe) check for 'first call'.
+        if (!m_next)
+            init(name);
+    }
+};
+
+// DeletableSamplingCounter:
+//
+// The above classes (SamplingCounter, GlobalSamplingCounter), are intended for
+// use within a global or static scope, and as such cannot have a destructor.
+// This means there is no convenient way for them to remove themselves from the
+// static list of counters, and should an instance of either class be freed
+// before 'dump()' has walked over the list it will potentially walk over an
+// invalid pointer.
+//
+// This class is intended for use where the counter may possibly be deleted before
+// the program exits. Should this occur, the counter will print it's value to
+// stderr, and remove itself from the static list. Example:
+//
+// DeletableSamplingCounter* counter = new DeletableSamplingCounter("The Counter With No Name");
+// counter->count();
+// delete counter;
+//
+class DeletableSamplingCounter : public AbstractSamplingCounter {
+public:
+    DeletableSamplingCounter(const char* name) { init(name); }
+
+    ~DeletableSamplingCounter()
+    {
+        if (!s_completed)
+            dataFile("DeletableSamplingCounter \"%s\" deleted early (with count %lld)\n", m_name, m_counter);
+        // Our m_referer pointer should know where the pointer to this node is,
+        // and m_next should know that this node is the previous node in the list.
+        ASSERT(*m_referer == this);
+        ASSERT(m_next->m_referer == &m_next);
+        // Remove this node from the list, and inform m_next that we have done so.
+        m_next->m_referer = m_referer;
+        *m_referer = m_next;
+    }
+};
+#endif
+
+} // namespace JSC
+
+#endif // SamplingCounter_h
+
+