X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/9dae56ea45a0f5f8136a5c93d6f3a7f99399ca73..14957cd040308e3eeec43d26bae5d76da13fcd85:/bytecode/SamplingTool.cpp?ds=sidebyside diff --git a/bytecode/SamplingTool.cpp b/bytecode/SamplingTool.cpp index 215ebe5..f47e698 100644 --- a/bytecode/SamplingTool.cpp +++ b/bytecode/SamplingTool.cpp @@ -33,32 +33,65 @@ #include "Interpreter.h" #include "Opcode.h" -#if !PLATFORM(WIN_OS) +#if !OS(WINDOWS) #include #endif namespace JSC { -void ScopeSampleRecord::sample(CodeBlock* codeBlock, Instruction* vPC) +#if ENABLE(SAMPLING_FLAGS) + +void SamplingFlags::sample() { - if (!m_samples) { - m_size = codeBlock->instructions().size(); - m_samples = static_cast(calloc(m_size, sizeof(int))); - m_codeBlock = codeBlock; + uint32_t mask = static_cast(1 << 31); + unsigned index; + + for (index = 0; index < 32; ++index) { + if (mask & s_flags) + break; + mask >>= 1; } - ++m_sampleCount; + s_flagCounts[32 - index]++; +} - unsigned offest = vPC - codeBlock->instructions().begin(); - // Since we don't read and write codeBlock and vPC atomically, this check - // can fail if we sample mid op_call / op_ret. - if (offest < m_size) { - m_samples[offest]++; - m_opcodeSampleCount++; - } +void SamplingFlags::start() +{ + for (unsigned i = 0; i <= 32; ++i) + s_flagCounts[i] = 0; } +void SamplingFlags::stop() +{ + uint64_t total = 0; + for (unsigned i = 0; i <= 32; ++i) + total += s_flagCounts[i]; + + if (total) { + printf("\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); + } + printf("\n"); + } else + printf("\nSamplingFlags: no samples.\n\n"); +} +uint64_t SamplingFlags::s_flagCounts[33]; -#if PLATFORM(WIN_OS) +#else +void SamplingFlags::start() {} +void SamplingFlags::stop() {} +#endif + +/* + Start with flag 16 set. + By doing this the monitoring of lower valued flags will be masked out + until flag 16 is explictly cleared. +*/ +uint32_t SamplingFlags::s_flags = 1 << 15; + + +#if OS(WINDOWS) static void sleepForMicroseconds(unsigned us) { @@ -82,62 +115,113 @@ static inline unsigned hertz2us(unsigned hertz) return 1000000 / hertz; } -void SamplingTool::run() -{ - while (m_running) { - sleepForMicroseconds(hertz2us(m_hertz)); - Sample sample(m_sample, m_codeBlock); - ++m_sampleCount; +SamplingTool* SamplingTool::s_samplingTool = 0; - if (sample.isNull()) - continue; - if (!sample.inHostFunction()) { - unsigned opcodeID = m_interpreter->getOpcodeID(sample.vPC()[0].u.opcode); +bool SamplingThread::s_running = false; +unsigned SamplingThread::s_hertz = 10000; +ThreadIdentifier SamplingThread::s_samplingThread; - ++m_opcodeSampleCount; - ++m_opcodeSamples[opcodeID]; - - if (sample.inCTIFunction()) - m_opcodeSamplesInCTIFunctions[opcodeID]++; - } +void* SamplingThread::threadStartFunc(void*) +{ + while (s_running) { + sleepForMicroseconds(hertz2us(s_hertz)); -#if ENABLE(CODEBLOCK_SAMPLING) - MutexLocker locker(m_scopeSampleMapMutex); - ScopeSampleRecord* record = m_scopeSampleMap->get(sample.codeBlock()->ownerNode()); - ASSERT(record); - record->sample(sample.codeBlock(), sample.vPC()); +#if ENABLE(SAMPLING_FLAGS) + SamplingFlags::sample(); +#endif +#if ENABLE(OPCODE_SAMPLING) + SamplingTool::sample(); #endif } + + return 0; } -void* SamplingTool::threadStartFunc(void* samplingTool) + +void SamplingThread::start(unsigned hertz) { - reinterpret_cast(samplingTool)->run(); - return 0; + ASSERT(!s_running); + s_running = true; + s_hertz = hertz; + + s_samplingThread = createThread(threadStartFunc, 0, "JavaScriptCore::Sampler"); +} + +void SamplingThread::stop() +{ + ASSERT(s_running); + s_running = false; + waitForThreadCompletion(s_samplingThread, 0); +} + + +void ScriptSampleRecord::sample(CodeBlock* codeBlock, Instruction* vPC) +{ + if (!m_samples) { + m_size = codeBlock->instructions().size(); + m_samples = static_cast(calloc(m_size, sizeof(int))); + m_codeBlock = codeBlock; + } + + ++m_sampleCount; + + unsigned offest = vPC - codeBlock->instructions().begin(); + // Since we don't read and write codeBlock and vPC atomically, this check + // can fail if we sample mid op_call / op_ret. + if (offest < m_size) { + m_samples[offest]++; + m_opcodeSampleCount++; + } } -void SamplingTool::notifyOfScope(ScopeNode* scope) +void SamplingTool::doRun() { - MutexLocker locker(m_scopeSampleMapMutex); - m_scopeSampleMap->set(scope, new ScopeSampleRecord(scope)); + Sample sample(m_sample, m_codeBlock); + ++m_sampleCount; + + if (sample.isNull()) + return; + + if (!sample.inHostFunction()) { + unsigned opcodeID = m_interpreter->getOpcodeID(sample.vPC()[0].u.opcode); + + ++m_opcodeSampleCount; + ++m_opcodeSamples[opcodeID]; + + if (sample.inCTIFunction()) + m_opcodeSamplesInCTIFunctions[opcodeID]++; + } + +#if ENABLE(CODEBLOCK_SAMPLING) + if (CodeBlock* codeBlock = sample.codeBlock()) { + MutexLocker locker(m_scriptSampleMapMutex); + ScriptSampleRecord* record = m_scopeSampleMap->get(codeBlock->ownerExecutable()); + ASSERT(record); + record->sample(codeBlock, sample.vPC()); + } +#endif } -void SamplingTool::start(unsigned hertz) +void SamplingTool::sample() { - ASSERT(!m_running); - m_running = true; - m_hertz = hertz; + s_samplingTool->doRun(); +} - m_samplingThread = createThread(threadStartFunc, this, "JavaScriptCore::Sampler"); +void SamplingTool::notifyOfScope(ScriptExecutable* script) +{ +#if ENABLE(CODEBLOCK_SAMPLING) + MutexLocker locker(m_scriptSampleMapMutex); + m_scopeSampleMap->set(script, new ScriptSampleRecord(script)); +#else + UNUSED_PARAM(script); +#endif } -void SamplingTool::stop() +void SamplingTool::setup() { - ASSERT(m_running); - m_running = false; - waitForThreadCompletion(m_samplingThread, 0); + s_samplingTool = this; } #if ENABLE(OPCODE_SAMPLING) @@ -153,14 +237,6 @@ struct LineCountInfo { unsigned count; }; -static int compareLineCountInfoSampling(const void* left, const void* right) -{ - const LineCountInfo* leftLineCount = reinterpret_cast(left); - const LineCountInfo* rightLineCount = reinterpret_cast(right); - - return (leftLineCount->line > rightLineCount->line) ? 1 : (leftLineCount->line < rightLineCount->line) ? -1 : 0; -} - static int compareOpcodeIndicesSampling(const void* left, const void* right) { const OpcodeSampleInfo* leftSampleInfo = reinterpret_cast(left); @@ -169,13 +245,23 @@ static int compareOpcodeIndicesSampling(const void* left, const void* right) return (leftSampleInfo->count < rightSampleInfo->count) ? 1 : (leftSampleInfo->count > rightSampleInfo->count) ? -1 : 0; } -static int compareScopeSampleRecords(const void* left, const void* right) +#if ENABLE(CODEBLOCK_SAMPLING) +static int compareLineCountInfoSampling(const void* left, const void* right) +{ + const LineCountInfo* leftLineCount = reinterpret_cast(left); + const LineCountInfo* rightLineCount = reinterpret_cast(right); + + return (leftLineCount->line > rightLineCount->line) ? 1 : (leftLineCount->line < rightLineCount->line) ? -1 : 0; +} + +static int compareScriptSampleRecords(const void* left, const void* right) { - const ScopeSampleRecord* const leftValue = *static_cast(left); - const ScopeSampleRecord* const rightValue = *static_cast(right); + const ScriptSampleRecord* const leftValue = *static_cast(left); + const ScriptSampleRecord* const rightValue = *static_cast(right); return (leftValue->m_sampleCount < rightValue->m_sampleCount) ? 1 : (leftValue->m_sampleCount > rightValue->m_sampleCount) ? -1 : 0; } +#endif void SamplingTool::dump(ExecState* exec) { @@ -227,29 +313,31 @@ void SamplingTool::dump(ExecState* exec) printf("\tcti count:\tsamples inside a CTI function called by this opcode\n"); printf("\tcti %% of self:\tcti count / sample count\n"); +#if ENABLE(CODEBLOCK_SAMPLING) + // (3) Build and sort 'codeBlockSamples' array. int scopeCount = m_scopeSampleMap->size(); - Vector codeBlockSamples(scopeCount); - ScopeSampleRecordMap::iterator iter = m_scopeSampleMap->begin(); + Vector codeBlockSamples(scopeCount); + ScriptSampleRecordMap::iterator iter = m_scopeSampleMap->begin(); for (int i = 0; i < scopeCount; ++i, ++iter) codeBlockSamples[i] = iter->second; - qsort(codeBlockSamples.begin(), scopeCount, sizeof(ScopeSampleRecord*), compareScopeSampleRecords); + qsort(codeBlockSamples.begin(), scopeCount, sizeof(ScriptSampleRecord*), compareScriptSampleRecords); // (4) Print data from 'codeBlockSamples' array. printf("\nCodeBlock samples\n\n"); for (int i = 0; i < scopeCount; ++i) { - ScopeSampleRecord* record = codeBlockSamples[i]; + ScriptSampleRecord* record = codeBlockSamples[i]; CodeBlock* codeBlock = record->m_codeBlock; double blockPercent = (record->m_sampleCount * 100.0) / m_sampleCount; if (blockPercent >= 1) { //Instruction* code = codeBlock->instructions().begin(); - printf("#%d: %s:%d: %d / %lld (%.3f%%)\n", i + 1, record->m_scope->sourceURL().UTF8String().c_str(), codeBlock->lineNumberForBytecodeOffset(exec, 0), record->m_sampleCount, m_sampleCount, blockPercent); + printf("#%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 lineCounts; codeBlock->dump(exec); @@ -259,7 +347,7 @@ void SamplingTool::dump(ExecState* exec) int count = record->m_samples[op]; if (count) { printf(" [% 4d] has sample count: % 4d\n", op, count); - unsigned line = codeBlock->lineNumberForBytecodeOffset(exec, op); + unsigned line = codeBlock->lineNumberForBytecodeOffset(op); lineCounts.set(line, (lineCounts.contains(line) ? lineCounts.get(line) : 0) + count); } } @@ -285,6 +373,9 @@ void SamplingTool::dump(ExecState* exec) } } } +#else + UNUSED_PARAM(exec); +#endif } #else @@ -295,4 +386,21 @@ 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