JavaScriptCore/bytecode/SamplingTool.h
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2008 Apple Inc. All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  *
       
     8  * 1.  Redistributions of source code must retain the above copyright
       
     9  *     notice, this list of conditions and the following disclaimer.
       
    10  * 2.  Redistributions in binary form must reproduce the above copyright
       
    11  *     notice, this list of conditions and the following disclaimer in the
       
    12  *     documentation and/or other materials provided with the distribution.
       
    13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
       
    14  *     its contributors may be used to endorse or promote products derived
       
    15  *     from this software without specific prior written permission.
       
    16  *
       
    17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
       
    18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
    19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
       
    20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
       
    21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
       
    22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
       
    23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
       
    24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
       
    26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    27  */
       
    28 
       
    29 #ifndef SamplingTool_h
       
    30 #define SamplingTool_h
       
    31 
       
    32 #include <wtf/Assertions.h>
       
    33 #include <wtf/HashMap.h>
       
    34 #include <wtf/Threading.h>
       
    35 
       
    36 #include "Nodes.h"
       
    37 #include "Opcode.h"
       
    38 
       
    39 namespace JSC {
       
    40 
       
    41     class ScriptExecutable;
       
    42 
       
    43     class SamplingFlags {
       
    44         friend class JIT;
       
    45     public:
       
    46         static void start();
       
    47         static void stop();
       
    48 
       
    49 #if ENABLE(SAMPLING_FLAGS)
       
    50         static void setFlag(unsigned flag)
       
    51         {
       
    52             ASSERT(flag >= 1);
       
    53             ASSERT(flag <= 32);
       
    54             s_flags |= 1u << (flag - 1);
       
    55         }
       
    56 
       
    57         static void clearFlag(unsigned flag)
       
    58         {
       
    59             ASSERT(flag >= 1);
       
    60             ASSERT(flag <= 32);
       
    61             s_flags &= ~(1u << (flag - 1));
       
    62         }
       
    63 
       
    64         static void sample();
       
    65 
       
    66         class ScopedFlag {
       
    67         public:
       
    68             ScopedFlag(int flag)
       
    69                 : m_flag(flag)
       
    70             {
       
    71                 setFlag(flag);
       
    72             }
       
    73 
       
    74             ~ScopedFlag()
       
    75             {
       
    76                 clearFlag(m_flag);
       
    77             }
       
    78 
       
    79         private:
       
    80             int m_flag;
       
    81         };
       
    82     
       
    83 #endif
       
    84     private:
       
    85         static uint32_t s_flags;
       
    86 #if ENABLE(SAMPLING_FLAGS)
       
    87         static uint64_t s_flagCounts[33];
       
    88 #endif
       
    89     };
       
    90 
       
    91     class CodeBlock;
       
    92     class ExecState;
       
    93     class Interpreter;
       
    94     class ScopeNode;
       
    95     struct Instruction;
       
    96 
       
    97     struct ScriptSampleRecord {
       
    98         ScriptSampleRecord(ScriptExecutable* executable)
       
    99             : m_executable(executable)
       
   100             , m_codeBlock(0)
       
   101             , m_sampleCount(0)
       
   102             , m_opcodeSampleCount(0)
       
   103             , m_samples(0)
       
   104             , m_size(0)
       
   105         {
       
   106         }
       
   107         
       
   108         ~ScriptSampleRecord()
       
   109         {
       
   110             if (m_samples)
       
   111                 free(m_samples);
       
   112         }
       
   113         
       
   114         void sample(CodeBlock*, Instruction*);
       
   115 
       
   116         RefPtr<ScriptExecutable> m_executable;
       
   117         CodeBlock* m_codeBlock;
       
   118         int m_sampleCount;
       
   119         int m_opcodeSampleCount;
       
   120         int* m_samples;
       
   121         unsigned m_size;
       
   122     };
       
   123 
       
   124     typedef WTF::HashMap<ScriptExecutable*, ScriptSampleRecord*> ScriptSampleRecordMap;
       
   125 
       
   126     class SamplingThread {
       
   127     public:
       
   128         // Sampling thread state.
       
   129         static bool s_running;
       
   130         static unsigned s_hertz;
       
   131         static ThreadIdentifier s_samplingThread;
       
   132 
       
   133         static void start(unsigned hertz=10000);
       
   134         static void stop();
       
   135 
       
   136         static void* threadStartFunc(void*);
       
   137     };
       
   138 
       
   139     class SamplingTool {
       
   140     public:
       
   141         friend struct CallRecord;
       
   142         friend class HostCallRecord;
       
   143         
       
   144 #if ENABLE(OPCODE_SAMPLING)
       
   145         class CallRecord : public Noncopyable {
       
   146         public:
       
   147             CallRecord(SamplingTool* samplingTool)
       
   148                 : m_samplingTool(samplingTool)
       
   149                 , m_savedSample(samplingTool->m_sample)
       
   150                 , m_savedCodeBlock(samplingTool->m_codeBlock)
       
   151             {
       
   152             }
       
   153 
       
   154             ~CallRecord()
       
   155             {
       
   156                 m_samplingTool->m_sample = m_savedSample;
       
   157                 m_samplingTool->m_codeBlock = m_savedCodeBlock;
       
   158             }
       
   159 
       
   160         private:
       
   161             SamplingTool* m_samplingTool;
       
   162             intptr_t m_savedSample;
       
   163             CodeBlock* m_savedCodeBlock;
       
   164         };
       
   165         
       
   166         class HostCallRecord : public CallRecord {
       
   167         public:
       
   168             HostCallRecord(SamplingTool* samplingTool)
       
   169                 : CallRecord(samplingTool)
       
   170             {
       
   171                 samplingTool->m_sample |= 0x1;
       
   172             }
       
   173         };
       
   174 #else
       
   175         class CallRecord : public Noncopyable {
       
   176         public:
       
   177             CallRecord(SamplingTool*)
       
   178             {
       
   179             }
       
   180         };
       
   181 
       
   182         class HostCallRecord : public CallRecord {
       
   183         public:
       
   184             HostCallRecord(SamplingTool* samplingTool)
       
   185                 : CallRecord(samplingTool)
       
   186             {
       
   187             }
       
   188         };
       
   189 #endif        
       
   190 
       
   191         SamplingTool(Interpreter* interpreter)
       
   192             : m_interpreter(interpreter)
       
   193             , m_codeBlock(0)
       
   194             , m_sample(0)
       
   195             , m_sampleCount(0)
       
   196             , m_opcodeSampleCount(0)
       
   197 #if ENABLE(CODEBLOCK_SAMPLING)
       
   198             , m_scopeSampleMap(new ScriptSampleRecordMap())
       
   199 #endif
       
   200         {
       
   201             memset(m_opcodeSamples, 0, sizeof(m_opcodeSamples));
       
   202             memset(m_opcodeSamplesInCTIFunctions, 0, sizeof(m_opcodeSamplesInCTIFunctions));
       
   203         }
       
   204 
       
   205         ~SamplingTool()
       
   206         {
       
   207 #if ENABLE(CODEBLOCK_SAMPLING)
       
   208             deleteAllValues(*m_scopeSampleMap);
       
   209 #endif
       
   210         }
       
   211 
       
   212         void setup();
       
   213         void dump(ExecState*);
       
   214 
       
   215         void notifyOfScope(ScriptExecutable* scope);
       
   216 
       
   217         void sample(CodeBlock* codeBlock, Instruction* vPC)
       
   218         {
       
   219             ASSERT(!(reinterpret_cast<intptr_t>(vPC) & 0x3));
       
   220             m_codeBlock = codeBlock;
       
   221             m_sample = reinterpret_cast<intptr_t>(vPC);
       
   222         }
       
   223 
       
   224         CodeBlock** codeBlockSlot() { return &m_codeBlock; }
       
   225         intptr_t* sampleSlot() { return &m_sample; }
       
   226 
       
   227         void* encodeSample(Instruction* vPC, bool inCTIFunction = false, bool inHostFunction = false)
       
   228         {
       
   229             ASSERT(!(reinterpret_cast<intptr_t>(vPC) & 0x3));
       
   230             return reinterpret_cast<void*>(reinterpret_cast<intptr_t>(vPC) | (static_cast<intptr_t>(inCTIFunction) << 1) | static_cast<intptr_t>(inHostFunction));
       
   231         }
       
   232 
       
   233         static void sample();
       
   234 
       
   235     private:
       
   236         class Sample {
       
   237         public:
       
   238             Sample(volatile intptr_t sample, CodeBlock* volatile codeBlock)
       
   239                 : m_sample(sample)
       
   240                 , m_codeBlock(codeBlock)
       
   241             {
       
   242             }
       
   243             
       
   244             bool isNull() { return !m_sample; }
       
   245             CodeBlock* codeBlock() { return m_codeBlock; }
       
   246             Instruction* vPC() { return reinterpret_cast<Instruction*>(m_sample & ~0x3); }
       
   247             bool inHostFunction() { return m_sample & 0x1; }
       
   248             bool inCTIFunction() { return m_sample & 0x2; }
       
   249 
       
   250         private:
       
   251             intptr_t m_sample;
       
   252             CodeBlock* m_codeBlock;
       
   253         };
       
   254 
       
   255         void doRun();
       
   256         static SamplingTool* s_samplingTool;
       
   257         
       
   258         Interpreter* m_interpreter;
       
   259         
       
   260         // State tracked by the main thread, used by the sampling thread.
       
   261         CodeBlock* m_codeBlock;
       
   262         intptr_t m_sample;
       
   263 
       
   264         // Gathered sample data.
       
   265         long long m_sampleCount;
       
   266         long long m_opcodeSampleCount;
       
   267         unsigned m_opcodeSamples[numOpcodeIDs];
       
   268         unsigned m_opcodeSamplesInCTIFunctions[numOpcodeIDs];
       
   269         
       
   270 #if ENABLE(CODEBLOCK_SAMPLING)
       
   271         Mutex m_scriptSampleMapMutex;
       
   272         OwnPtr<ScriptSampleRecordMap> m_scopeSampleMap;
       
   273 #endif
       
   274     };
       
   275 
       
   276     // AbstractSamplingCounter:
       
   277     //
       
   278     // Implements a named set of counters, printed on exit if ENABLE(SAMPLING_COUNTERS).
       
   279     // See subclasses below, SamplingCounter, GlobalSamplingCounter and DeletableSamplingCounter.
       
   280     class AbstractSamplingCounter {
       
   281         friend class JIT;
       
   282         friend class DeletableSamplingCounter;
       
   283     public:
       
   284         void count(uint32_t count = 1)
       
   285         {
       
   286             m_counter += count;
       
   287         }
       
   288 
       
   289         static void dump();
       
   290 
       
   291     protected:
       
   292         // Effectively the contructor, however called lazily in the case of GlobalSamplingCounter.
       
   293         void init(const char* name)
       
   294         {
       
   295             m_counter = 0;
       
   296             m_name = name;
       
   297 
       
   298             // Set m_next to point to the head of the chain, and inform whatever is
       
   299             // currently at the head that this node will now hold the pointer to it.
       
   300             m_next = s_abstractSamplingCounterChain;
       
   301             s_abstractSamplingCounterChain->m_referer = &m_next;
       
   302             // Add this node to the head of the list.
       
   303             s_abstractSamplingCounterChain = this;
       
   304             m_referer = &s_abstractSamplingCounterChain;
       
   305         }
       
   306 
       
   307         int64_t m_counter;
       
   308         const char* m_name;
       
   309         AbstractSamplingCounter* m_next;
       
   310         // This is a pointer to the pointer to this node in the chain; used to
       
   311         // allow fast linked list deletion.
       
   312         AbstractSamplingCounter** m_referer;
       
   313         // Null object used to detect end of static chain.
       
   314         static AbstractSamplingCounter s_abstractSamplingCounterChainEnd;
       
   315         static AbstractSamplingCounter* s_abstractSamplingCounterChain;
       
   316         static bool s_completed;
       
   317     };
       
   318 
       
   319 #if ENABLE(SAMPLING_COUNTERS)
       
   320     // SamplingCounter:
       
   321     //
       
   322     // This class is suitable and (hopefully!) convenient for cases where a counter is
       
   323     // required within the scope of a single function.  It can be instantiated as a
       
   324     // static variable since it contains a constructor but not a destructor (static
       
   325     // variables in WebKit cannot have destructors).
       
   326     //
       
   327     // For example:
       
   328     //
       
   329     // void someFunction()
       
   330     // {
       
   331     //     static SamplingCounter countMe("This is my counter.  There are many like it, but this one is mine.");
       
   332     //     countMe.count();
       
   333     //     // ...
       
   334     // }
       
   335     //
       
   336     class SamplingCounter : public AbstractSamplingCounter {
       
   337     public:
       
   338         SamplingCounter(const char* name) { init(name); }
       
   339     };
       
   340 
       
   341     // GlobalSamplingCounter:
       
   342     //
       
   343     // This class is suitable for use where a counter is to be declared globally,
       
   344     // since it contains neither a constructor nor destructor.  Instead, ensure
       
   345     // that 'name()' is called to provide the counter with a name (and also to
       
   346     // allow it to be printed out on exit).
       
   347     //
       
   348     // GlobalSamplingCounter globalCounter;
       
   349     //
       
   350     // void firstFunction()
       
   351     // {
       
   352     //     // Put this within a function that is definitely called!
       
   353     //     // (Or alternatively alongside all calls to 'count()').
       
   354     //     globalCounter.name("I Name You Destroyer.");
       
   355     //     globalCounter.count();
       
   356     //     // ...
       
   357     // }
       
   358     //
       
   359     // void secondFunction()
       
   360     // {
       
   361     //     globalCounter.count();
       
   362     //     // ...
       
   363     // }
       
   364     //
       
   365     class GlobalSamplingCounter : public AbstractSamplingCounter {
       
   366     public:
       
   367         void name(const char* name)
       
   368         {
       
   369             // Global objects should be mapped in zero filled memory, so this should
       
   370             // be a safe (albeit not necessarily threadsafe) check for 'first call'.
       
   371             if (!m_next)
       
   372                 init(name);
       
   373         }
       
   374     };
       
   375 
       
   376     // DeletableSamplingCounter:
       
   377     //
       
   378     // The above classes (SamplingCounter, GlobalSamplingCounter), are intended for
       
   379     // use within a global or static scope, and as such cannot have a destructor.
       
   380     // This means there is no convenient way for them to remove themselves from the
       
   381     // static list of counters, and should an instance of either class be freed
       
   382     // before 'dump()' has walked over the list it will potentially walk over an
       
   383     // invalid pointer.
       
   384     //
       
   385     // This class is intended for use where the counter may possibly be deleted before
       
   386     // the program exits.  Should this occur, the counter will print it's value to
       
   387     // stderr, and remove itself from the static list.  Example:
       
   388     //
       
   389     // DeletableSamplingCounter* counter = new DeletableSamplingCounter("The Counter With No Name");
       
   390     // counter->count();
       
   391     // delete counter;
       
   392     //
       
   393     class DeletableSamplingCounter : public AbstractSamplingCounter {
       
   394     public:
       
   395         DeletableSamplingCounter(const char* name) { init(name); }
       
   396 
       
   397         ~DeletableSamplingCounter()
       
   398         {
       
   399             if (!s_completed)
       
   400                 fprintf(stderr, "DeletableSamplingCounter \"%s\" deleted early (with count %lld)\n", m_name, m_counter);
       
   401             // Our m_referer pointer should know where the pointer to this node is,
       
   402             // and m_next should know that this node is the previous node in the list.
       
   403             ASSERT(*m_referer == this);
       
   404             ASSERT(m_next->m_referer == &m_next);
       
   405             // Remove this node from the list, and inform m_next that we have done so.
       
   406             m_next->m_referer = m_referer;
       
   407             *m_referer = m_next;
       
   408         }
       
   409     };
       
   410 #endif
       
   411 
       
   412 } // namespace JSC
       
   413 
       
   414 #endif // SamplingTool_h