Changeset 43619 in webkit for trunk/JavaScriptCore/bytecode


Ignore:
Timestamp:
May 13, 2009, 2:10:02 AM (16 years ago)
Author:
[email protected]
Message:

2009-05-12 Gavin Barraclough <[email protected]>

Reviewed by Oliver Hunt.

Add SamplingCounter tool to provide a simple mechanism for counting events in JSC
(enabled using ENABLE(SAMPLING_COUNTERS)). To count events within a single function
use the class 'SamplingCounter', where the counter may be incremented from multiple
functions 'GlobalSamplingCounter' may be convenient; all other counters (stack or
heap allocated, rather than statically declared) should use the DeletableSamplingCounter.
Further description of these classes is provided alongside their definition in
SamplingTool.h.

Counters may be incremented from c++ by calling the 'count()' method on the counter,
or may be incremented by JIT code by using the 'emitCount()' method within the JIT.

This patch also fixes CODEBLOCK_SAMPLING, which was missing a null pointer check.

  • JavaScriptCore.exp:
  • assembler/MacroAssemblerX86.h: (JSC::MacroAssemblerX86::addWithCarry32): (JSC::MacroAssemblerX86::and32): (JSC::MacroAssemblerX86::or32):
  • assembler/MacroAssemblerX86Common.h: (JSC::MacroAssemblerX86Common::and32): (JSC::MacroAssemblerX86Common::or32):
  • assembler/MacroAssemblerX86_64.h: (JSC::MacroAssemblerX86_64::and32): (JSC::MacroAssemblerX86_64::or32): (JSC::MacroAssemblerX86_64::addPtr):
  • assembler/X86Assembler.h: (JSC::X86Assembler::): (JSC::X86Assembler::adcl_im): (JSC::X86Assembler::addq_im): (JSC::X86Assembler::andl_im): (JSC::X86Assembler::orl_im):
  • bytecode/SamplingTool.cpp: (JSC::AbstractSamplingCounter::dump):
  • bytecode/SamplingTool.h: (JSC::AbstractSamplingCounter::count): (JSC::GlobalSamplingCounter::name): (JSC::SamplingCounter::SamplingCounter):
  • jit/JIT.h:
  • jit/JITCall.cpp: (JSC::):
  • jit/JITInlineMethods.h: (JSC::JIT::setSamplingFlag): (JSC::JIT::clearSamplingFlag): (JSC::JIT::emitCount):
  • jsc.cpp: (runWithScripts):
  • parser/Nodes.cpp: (JSC::ScopeNode::ScopeNode):
  • wtf/Platform.h:
Location:
trunk/JavaScriptCore/bytecode
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/bytecode/SamplingTool.cpp

    r43507 r43619  
    391391#endif
    392392
     393void AbstractSamplingCounter::dump()
     394{
     395#if ENABLE(SAMPLING_COUNTERS)
     396    if (s_abstractSamplingCounterChain != &s_abstractSamplingCounterChainEnd) {
     397        printf("\nSampling Counter Values:\n");
     398        for (AbstractSamplingCounter* currCounter = s_abstractSamplingCounterChain; (currCounter != &s_abstractSamplingCounterChainEnd); currCounter = currCounter->m_next)
     399            printf("\t%s\t: %lld\n", currCounter->m_name, currCounter->m_counter);
     400        printf("\n\n");
     401    }
     402    s_completed = true;
     403#endif
     404}
     405
     406AbstractSamplingCounter AbstractSamplingCounter::s_abstractSamplingCounterChainEnd;
     407AbstractSamplingCounter* AbstractSamplingCounter::s_abstractSamplingCounterChain = &s_abstractSamplingCounterChainEnd;
     408bool AbstractSamplingCounter::s_completed = false;
     409
    393410} // namespace JSC
  • trunk/JavaScriptCore/bytecode/SamplingTool.h

    r43553 r43619  
    273273    };
    274274
     275    // AbstractSamplingCounter:
     276    //
     277    // Implements a named set of counters, printed on exit if ENABLE(SAMPLING_COUNTERS).
     278    // See subclasses below, SamplingCounter, GlobalSamplingCounter and DeletableSamplingCounter.
     279    class AbstractSamplingCounter {
     280        friend class JIT;
     281        friend class DeletableSamplingCounter;
     282    public:
     283        void count(uint32_t count = 1)
     284        {
     285            m_counter += count;
     286        }
     287
     288        static void dump();
     289
     290    protected:
     291        // Effectively the contructor, however called lazily in the case of GlobalSamplingCounter.
     292        void init(const char* name)
     293        {
     294            m_counter = 0;
     295            m_name = name;
     296
     297            // Set m_next to point to the head of the chain, and inform whatever is
     298            // currently at the head that this node will now hold the pointer to it.
     299            m_next = s_abstractSamplingCounterChain;
     300            s_abstractSamplingCounterChain->m_referer = &m_next;
     301            // Add this node to the head of the list.
     302            s_abstractSamplingCounterChain = this;
     303            m_referer = &s_abstractSamplingCounterChain;
     304        }
     305
     306        int64_t m_counter;
     307        const char* m_name;
     308        AbstractSamplingCounter* m_next;
     309        // This is a pointer to the pointer to this node in the chain; used to
     310        // allow fast linked list deletion.
     311        AbstractSamplingCounter** m_referer;
     312        // Null object used to detect end of static chain.
     313        static AbstractSamplingCounter s_abstractSamplingCounterChainEnd;
     314        static AbstractSamplingCounter* s_abstractSamplingCounterChain;
     315        static bool s_completed;
     316    };
     317
     318#if ENABLE(SAMPLING_COUNTERS)
     319    // SamplingCounter:
     320    //
     321    // This class is suitable and (hopefully!) convenient for cases where a counter is
     322    // required within the scope of a single function.  It can be instantiated as a
     323    // static variable since it contains a constructor but not a destructor (static
     324    // variables in WebKit cannot have destructors).
     325    //
     326    // For example:
     327    //
     328    // void someFunction()
     329    // {
     330    //     static SamplingCounter countMe("This is my counter.  There are many like it, but this one is mine.");
     331    //     countMe.count();
     332    //     // ...
     333    // }
     334    //
     335    class SamplingCounter : public AbstractSamplingCounter {
     336    public:
     337        SamplingCounter(const char* name) { init(name); }
     338    };
     339
     340    // GlobalSamplingCounter:
     341    //
     342    // This class is suitable for use where a counter is to be declared globally,
     343    // since it contains neither a constructor nor destructor.  Instead, ensure
     344    // that 'name()' is called to provide the counter with a name (and also to
     345    // allow it to be printed out on exit).
     346    //
     347    // GlobalSamplingCounter globalCounter;
     348    //
     349    // void firstFunction()
     350    // {
     351    //     // Put this within a function that is definitely called!
     352    //     // (Or alternatively alongside all calls to 'count()').
     353    //     globalCounter.name("I Name You Destroyer.");
     354    //     globalCounter.count();
     355    //     // ...
     356    // }
     357    //
     358    // void secondFunction()
     359    // {
     360    //     globalCounter.count();
     361    //     // ...
     362    // }
     363    //
     364    class GlobalSamplingCounter : public AbstractSamplingCounter {
     365    public:
     366        void name(const char* name)
     367        {
     368            // Global objects should be mapped in zero filled memory, so this should
     369            // be a safe (albeit not necessarily threadsafe) check for 'first call'.
     370            if (!m_next)
     371                init(name);
     372        }
     373    };
     374
     375    // DeletableSamplingCounter:
     376    //
     377    // The above classes (SamplingCounter, GlobalSamplingCounter), are intended for
     378    // use within a global or static scope, and as such cannot have a destructor.
     379    // This means there is no convenient way for them to remove themselves from the
     380    // static list of counters, and should an instance of either class be freed
     381    // before 'dump()' has walked over the list it will potentially walk over an
     382    // invalid pointer.
     383    //
     384    // This class is intended for use where the counter may possibly be deleted before
     385    // the program exits.  Should this occur, the counter will print it's value to
     386    // stderr, and remove itself from the static list.  Example:
     387    //
     388    // DeletableSamplingCounter* counter = new DeletableSamplingCounter("The Counter With No Name");
     389    // counter->count();
     390    // delete counter;
     391    //
     392    class DeletableSamplingCounter : public AbstractSamplingCounter {
     393    public:
     394        DeletableSamplingCounter(const char* name) { init(name); }
     395
     396        ~DeletableSamplingCounter()
     397        {
     398            if (!s_completed)
     399                fprintf(stderr, "DeletableSamplingCounter \"%s\" deleted early (with count %lld)\n", m_name, m_counter);
     400            // Our m_referer pointer should know where the pointer to this node is,
     401            // and m_next should know that this node is the previous node in the list.
     402            ASSERT(*m_referer == this);
     403            ASSERT(m_next->m_referer == &m_next);
     404            // Remove this node from the list, and inform m_next that we have done so.
     405            m_next->m_referer = m_referer;
     406            *m_referer = m_next;
     407        }
     408    };
     409#endif
     410
    275411} // namespace JSC
    276412
Note: See TracChangeset for help on using the changeset viewer.