/* * 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 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 #include 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