]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - bytecode/SamplingTool.cpp
JavaScriptCore-1097.3.3.tar.gz
[apple/javascriptcore.git] / bytecode / SamplingTool.cpp
index 7191e388ee61ee9f427ae8d4ba20e2730ef10f56..f07dc79fb78258d861d4f48517f1b55b2963953d 100644 (file)
@@ -67,14 +67,14 @@ void SamplingFlags::stop()
         total += s_flagCounts[i];
 
     if (total) {
-        printf("\nSamplingFlags: sample counts with flags set: (%lld total)\n", total);
+        dataLog("\nSamplingFlags: sample counts with flags set: (%lld total)\n", total);
         for (unsigned i = 0; i <= 32; ++i) {
             if (s_flagCounts[i])
-                printf("  [ %02d ] : %lld\t\t(%03.2f%%)\n", i, s_flagCounts[i], (100.0 * s_flagCounts[i]) / total);
+                dataLog("  [ %02d ] : %lld\t\t(%03.2f%%)\n", i, s_flagCounts[i], (100.0 * s_flagCounts[i]) / total);
         }
-        printf("\n");
+        dataLog("\n");
     } else
-    printf("\nSamplingFlags: no samples.\n\n");
+    dataLog("\nSamplingFlags: no samples.\n\n");
 }
 uint64_t SamplingFlags::s_flagCounts[33];
 
@@ -83,6 +83,93 @@ void SamplingFlags::start() {}
 void SamplingFlags::stop() {}
 #endif
 
+#if ENABLE(SAMPLING_REGIONS)
+volatile uintptr_t SamplingRegion::s_currentOrReserved;
+Spectrum<const char*>* SamplingRegion::s_spectrum;
+unsigned long SamplingRegion::s_noneOfTheAbove;
+unsigned SamplingRegion::s_numberOfSamplesSinceDump;
+
+SamplingRegion::Locker::Locker()
+{
+    uintptr_t previous;
+    while (true) {
+        previous = s_currentOrReserved;
+        if (previous & 1) {
+#if OS(UNIX)
+            sched_yield();
+#endif
+            continue;
+        }
+        if (WTF::weakCompareAndSwapUIntPtr(&s_currentOrReserved, previous, previous | 1))
+            break;
+    }
+}
+
+SamplingRegion::Locker::~Locker()
+{
+    // We don't need the CAS, but we do it out of an
+    // abundance of caution (and because it gives us a memory fence, which is
+    // never bad).
+    uintptr_t previous;
+    do {
+        previous = s_currentOrReserved;
+    } while (!WTF::weakCompareAndSwapUIntPtr(&s_currentOrReserved, previous, previous & ~1));
+}
+
+void SamplingRegion::sample()
+{
+    // Make sure we lock s_current.
+    Locker locker;
+    
+    // Create a spectrum if we don't have one already.
+    if (!s_spectrum)
+        s_spectrum = new Spectrum<const char*>();
+    
+    ASSERT(s_currentOrReserved & 1);
+    
+    // Walk the region stack, and record each region we see.
+    SamplingRegion* region = bitwise_cast<SamplingRegion*>(s_currentOrReserved & ~1);
+    if (region) {
+        for (; region; region = region->m_previous)
+            s_spectrum->add(region->m_name);
+    } else
+        s_noneOfTheAbove++;
+    
+    if (s_numberOfSamplesSinceDump++ == SamplingThread::s_hertz) {
+        s_numberOfSamplesSinceDump = 0;
+        dumpInternal();
+    }
+}
+
+void SamplingRegion::dump()
+{
+    Locker locker;
+    
+    dumpInternal();
+}
+
+void SamplingRegion::dumpInternal()
+{
+    if (!s_spectrum) {
+        dataLog("\nSamplingRegion: was never sampled.\n\n");
+        return;
+    }
+    
+    Vector<Spectrum<const char*>::KeyAndCount> list = s_spectrum->buildList();
+    
+    unsigned long total = s_noneOfTheAbove;
+    for (unsigned i = list.size(); i--;)
+        total += list[i].count;
+    
+    dataLog("\nSamplingRegion: sample counts for regions: (%lu samples)\n", total);
+
+    for (unsigned i = list.size(); i--;)
+        dataLog("    %3.2lf%%  %s\n", (100.0 * list[i].count) / total, list[i].key);
+}
+#else // ENABLE(SAMPLING_REGIONS)
+void SamplingRegion::dump() { }
+#endif // ENABLE(SAMPLING_REGIONS)
+
 /*
   Start with flag 16 set.
   By doing this the monitoring of lower valued flags will be masked out
@@ -123,7 +210,7 @@ bool SamplingThread::s_running = false;
 unsigned SamplingThread::s_hertz = 10000;
 ThreadIdentifier SamplingThread::s_samplingThread;
 
-void* SamplingThread::threadStartFunc(void*)
+void SamplingThread::threadStartFunc(void*)
 {
     while (s_running) {
         sleepForMicroseconds(hertz2us(s_hertz));
@@ -131,12 +218,13 @@ void* SamplingThread::threadStartFunc(void*)
 #if ENABLE(SAMPLING_FLAGS)
         SamplingFlags::sample();
 #endif
+#if ENABLE(SAMPLING_REGIONS)
+        SamplingRegion::sample();
+#endif
 #if ENABLE(OPCODE_SAMPLING)
         SamplingTool::sample();
 #endif
     }
-
-    return 0;
 }
 
 
@@ -153,7 +241,7 @@ void SamplingThread::stop()
 {
     ASSERT(s_running);
     s_running = false;
-    waitForThreadCompletion(s_samplingThread, 0);
+    waitForThreadCompletion(s_samplingThread);
 }
 
 
@@ -209,12 +297,13 @@ void SamplingTool::sample()
     s_samplingTool->doRun();
 }
 
-void SamplingTool::notifyOfScope(ScriptExecutable* script)
+void SamplingTool::notifyOfScope(JSGlobalData& globalData, ScriptExecutable* script)
 {
 #if ENABLE(CODEBLOCK_SAMPLING)
     MutexLocker locker(m_scriptSampleMapMutex);
-    m_scopeSampleMap->set(script, new ScriptSampleRecord(script));
+    m_scopeSampleMap->set(script, adoptPtr(new ScriptSampleRecord(globalData, script)));
 #else
+    UNUSED_PARAM(globalData);
     UNUSED_PARAM(script);
 #endif
 }
@@ -282,10 +371,10 @@ void SamplingTool::dump(ExecState* exec)
 
     // (2) Print Opcode sampling results.
 
-    printf("\nBytecode samples [*]\n");
-    printf("                             sample   %% of       %% of     |   cti     cti %%\n");
-    printf("opcode                       count     VM        total    |  count   of self\n");
-    printf("-------------------------------------------------------   |  ----------------\n");
+    dataLog("\nBytecode samples [*]\n");
+    dataLog("                             sample   %% of       %% of     |   cti     cti %%\n");
+    dataLog("opcode                       count     VM        total    |  count   of self\n");
+    dataLog("-------------------------------------------------------   |  ----------------\n");
 
     for (int i = 0; i < numOpcodeIDs; ++i) {
         long long count = opcodeSampleInfo[i].count;
@@ -300,18 +389,18 @@ void SamplingTool::dump(ExecState* exec)
         double percentOfTotal = (static_cast<double>(count) * 100) / m_sampleCount;
         long long countInCTIFunctions = opcodeSampleInfo[i].countInCTIFunctions;
         double percentInCTIFunctions = (static_cast<double>(countInCTIFunctions) * 100) / count;
-        fprintf(stdout, "%s:%s%-6lld %.3f%%\t%.3f%%\t  |   %-6lld %.3f%%\n", opcodeName, opcodePadding, count, percentOfVM, percentOfTotal, countInCTIFunctions, percentInCTIFunctions);
+        debugDebugPrintf("%s:%s%-6lld %.3f%%\t%.3f%%\t  |   %-6lld %.3f%%\n", opcodeName, opcodePadding, count, percentOfVM, percentOfTotal, countInCTIFunctions, percentInCTIFunctions);
     }
     
-    printf("\n[*] Samples inside host code are not charged to any Bytecode.\n\n");
-    printf("\tSamples inside VM:\t\t%lld / %lld (%.3f%%)\n", m_opcodeSampleCount, m_sampleCount, (static_cast<double>(m_opcodeSampleCount) * 100) / m_sampleCount);
-    printf("\tSamples inside host code:\t%lld / %lld (%.3f%%)\n\n", m_sampleCount - m_opcodeSampleCount, m_sampleCount, (static_cast<double>(m_sampleCount - m_opcodeSampleCount) * 100) / m_sampleCount);
-    printf("\tsample count:\tsamples inside this opcode\n");
-    printf("\t%% of VM:\tsample count / all opcode samples\n");
-    printf("\t%% of total:\tsample count / all samples\n");
-    printf("\t--------------\n");
-    printf("\tcti count:\tsamples inside a CTI function called by this opcode\n");
-    printf("\tcti %% of self:\tcti count / sample count\n");
+    dataLog("\n[*] Samples inside host code are not charged to any Bytecode.\n\n");
+    dataLog("\tSamples inside VM:\t\t%lld / %lld (%.3f%%)\n", m_opcodeSampleCount, m_sampleCount, (static_cast<double>(m_opcodeSampleCount) * 100) / m_sampleCount);
+    dataLog("\tSamples inside host code:\t%lld / %lld (%.3f%%)\n\n", m_sampleCount - m_opcodeSampleCount, m_sampleCount, (static_cast<double>(m_sampleCount - m_opcodeSampleCount) * 100) / m_sampleCount);
+    dataLog("\tsample count:\tsamples inside this opcode\n");
+    dataLog("\t%% of VM:\tsample count / all opcode samples\n");
+    dataLog("\t%% of total:\tsample count / all samples\n");
+    dataLog("\t--------------\n");
+    dataLog("\tcti count:\tsamples inside a CTI function called by this opcode\n");
+    dataLog("\tcti %% of self:\tcti count / sample count\n");
     
 #if ENABLE(CODEBLOCK_SAMPLING)
 
@@ -321,13 +410,13 @@ void SamplingTool::dump(ExecState* exec)
     Vector<ScriptSampleRecord*> codeBlockSamples(scopeCount);
     ScriptSampleRecordMap::iterator iter = m_scopeSampleMap->begin();
     for (int i = 0; i < scopeCount; ++i, ++iter)
-        codeBlockSamples[i] = iter->second;
+        codeBlockSamples[i] = iter->second.get();
 
     qsort(codeBlockSamples.begin(), scopeCount, sizeof(ScriptSampleRecord*), compareScriptSampleRecords);
 
     // (4) Print data from 'codeBlockSamples' array.
 
-    printf("\nCodeBlock samples\n\n"); 
+    dataLog("\nCodeBlock samples\n\n"); 
 
     for (int i = 0; i < scopeCount; ++i) {
         ScriptSampleRecord* record = codeBlockSamples[i];
@@ -337,21 +426,21 @@ void SamplingTool::dump(ExecState* exec)
 
         if (blockPercent >= 1) {
             //Instruction* code = codeBlock->instructions().begin();
-            printf("#%d: %s:%d: %d / %lld (%.3f%%)\n", i + 1, record->m_executable->sourceURL().ascii(), codeBlock->lineNumberForBytecodeOffset(exec, 0), record->m_sampleCount, m_sampleCount, blockPercent);
+            dataLog("#%d: %s:%d: %d / %lld (%.3f%%)\n", i + 1, record->m_executable->sourceURL().utf8().data(), codeBlock->lineNumberForBytecodeOffset(0), record->m_sampleCount, m_sampleCount, blockPercent);
             if (i < 10) {
                 HashMap<unsigned,unsigned> lineCounts;
                 codeBlock->dump(exec);
 
-                printf("    Opcode and line number samples [*]\n\n");
+                dataLog("    Opcode and line number samples [*]\n\n");
                 for (unsigned op = 0; op < record->m_size; ++op) {
                     int count = record->m_samples[op];
                     if (count) {
-                        printf("    [% 4d] has sample count: % 4d\n", op, count);
-                        unsigned line = codeBlock->lineNumberForBytecodeOffset(exec, op);
+                        dataLog("    [% 4d] has sample count: % 4d\n", op, count);
+                        unsigned line = codeBlock->lineNumberForBytecodeOffset(op);
                         lineCounts.set(line, (lineCounts.contains(line) ? lineCounts.get(line) : 0) + count);
                     }
                 }
-                printf("\n");
+                dataLog("\n");
 
                 int linesCount = lineCounts.size();
                 Vector<LineCountInfo> lineCountInfo(linesCount);
@@ -364,12 +453,12 @@ void SamplingTool::dump(ExecState* exec)
                 qsort(lineCountInfo.begin(), linesCount, sizeof(LineCountInfo), compareLineCountInfoSampling);
 
                 for (lineno = 0; lineno < linesCount; ++lineno) {
-                    printf("    Line #%d has sample count %d.\n", lineCountInfo[lineno].line, lineCountInfo[lineno].count);
+                    dataLog("    Line #%d has sample count %d.\n", lineCountInfo[lineno].line, lineCountInfo[lineno].count);
                 }
-                printf("\n");
-                printf("    [*] Samples inside host code are charged to the calling Bytecode.\n");
-                printf("        Samples on a call / return boundary are not charged to a specific opcode or line.\n\n");
-                printf("            Samples on a call / return boundary: %d / %d (%.3f%%)\n\n", record->m_sampleCount - record->m_opcodeSampleCount, record->m_sampleCount, (static_cast<double>(record->m_sampleCount - record->m_opcodeSampleCount) * 100) / record->m_sampleCount);
+                dataLog("\n");
+                dataLog("    [*] Samples inside host code are charged to the calling Bytecode.\n");
+                dataLog("        Samples on a call / return boundary are not charged to a specific opcode or line.\n\n");
+                dataLog("            Samples on a call / return boundary: %d / %d (%.3f%%)\n\n", record->m_sampleCount - record->m_opcodeSampleCount, record->m_sampleCount, (static_cast<double>(record->m_sampleCount - record->m_opcodeSampleCount) * 100) / record->m_sampleCount);
             }
         }
     }
@@ -386,21 +475,4 @@ void SamplingTool::dump(ExecState*)
 
 #endif
 
-void AbstractSamplingCounter::dump()
-{
-#if ENABLE(SAMPLING_COUNTERS)
-    if (s_abstractSamplingCounterChain != &s_abstractSamplingCounterChainEnd) {
-        printf("\nSampling Counter Values:\n");
-        for (AbstractSamplingCounter* currCounter = s_abstractSamplingCounterChain; (currCounter != &s_abstractSamplingCounterChainEnd); currCounter = currCounter->m_next)
-            printf("\t%s\t: %lld\n", currCounter->m_name, currCounter->m_counter);
-        printf("\n\n");
-    }
-    s_completed = true;
-#endif
-}
-
-AbstractSamplingCounter AbstractSamplingCounter::s_abstractSamplingCounterChainEnd;
-AbstractSamplingCounter* AbstractSamplingCounter::s_abstractSamplingCounterChain = &s_abstractSamplingCounterChainEnd;
-bool AbstractSamplingCounter::s_completed = false;
-
 } // namespace JSC