source: webkit/trunk/JavaScriptCore/VM/SamplingTool.cpp@ 35653

Last change on this file since 35653 was 35653, checked in by [email protected], 17 years ago

2008-08-09 Cameron Zwarich <[email protected]>

Reviewed by Maciej.

Fix some style issues in the sampling tool.

  • VM/SamplingTool.cpp: (KJS::sleepForMicroseconds): (KJS::SamplingTool::dump):
File size: 10.4 KB
Line 
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#include "config.h"
30#include "SamplingTool.h"
31
32#include "CodeBlock.h"
33#include "Machine.h"
34#include "Opcode.h"
35
36namespace KJS {
37
38void ScopeSampleRecord::sample(CodeBlock* codeBlock, Instruction* vPC)
39{
40 m_totalCount++;
41
42 if (!m_vpcCounts) {
43 m_size = codeBlock->instructions.size();
44 m_vpcCounts = static_cast<int*>(calloc(m_size, sizeof(int)));
45 m_codeBlock = codeBlock;
46 }
47
48 unsigned codeOffset = static_cast<unsigned>(reinterpret_cast<ptrdiff_t>(vPC) - reinterpret_cast<ptrdiff_t>(codeBlock->instructions.begin())) / sizeof(Instruction*);
49 // This could occur if codeBlock & vPC are not consistent - e.g. sample mid op_call/op_ret.
50 if (codeOffset < m_size)
51 m_vpcCounts[codeOffset]++;
52}
53
54#if PLATFORM(WIN_OS)
55
56static void sleepForMicroseconds(unsigned us)
57{
58 unsigned ms = us / 1000;
59 if (us && !ms)
60 ms = 1;
61 Sleep(ms);
62}
63
64#else
65
66static void sleepForMicroseconds(unsigned us)
67{
68 usleep(us);
69}
70
71#endif
72
73static inline unsigned hertz2us(unsigned hertz)
74{
75 return 1000000 / hertz;
76}
77
78void SamplingTool::run()
79{
80 while (m_running) {
81 sleepForMicroseconds(hertz2us(m_hertz));
82
83 m_totalSamples++;
84
85 CodeBlock* codeBlock = m_recordedCodeBlock;
86 Instruction* vPC = m_recordedVPC;
87
88 if (codeBlock && vPC) {
89 if (ScopeSampleRecord* record = m_scopeSampleMap->get(codeBlock->ownerNode))
90 record->sample(codeBlock, vPC);
91 }
92 }
93}
94
95void* SamplingTool::threadStartFunc(void* samplingTool)
96{
97 reinterpret_cast<SamplingTool*>(samplingTool)->run();
98 return 0;
99}
100
101void SamplingTool::notifyOfScope(ScopeNode* scope)
102{
103 m_scopeSampleMap->set(scope, new ScopeSampleRecord(scope));
104}
105
106void SamplingTool::start(unsigned hertz)
107{
108 ASSERT(!m_running);
109 m_running = true;
110 m_hertz = hertz;
111
112 m_samplingThread = createThread(threadStartFunc, this, "JavaScriptCore::Sampler");
113}
114
115void SamplingTool::stop()
116{
117 ASSERT(m_running);
118 m_running = false;
119 waitForThreadCompletion(m_samplingThread, 0);
120}
121
122#if ENABLE(SAMPLING_TOOL)
123
124struct OpcodeSampleInfo
125{
126 OpcodeID opcode;
127 long long count;
128};
129
130struct LineCountInfo
131{
132 unsigned line;
133 unsigned count;
134};
135
136static int compareLineCountInfoSampling(const void* left, const void* right)
137{
138 const LineCountInfo* leftLineCount = reinterpret_cast<const LineCountInfo*>(left);
139 const LineCountInfo* rightLineCount = reinterpret_cast<const LineCountInfo*>(right);
140
141 return (leftLineCount->line > rightLineCount->line) ? 1 : (leftLineCount->line < rightLineCount->line) ? -1 : 0;
142}
143
144static int compareOpcodeIndicesSampling(const void* left, const void* right)
145{
146 const OpcodeSampleInfo* leftSampleInfo = reinterpret_cast<const OpcodeSampleInfo*>(left);
147 const OpcodeSampleInfo* rightSampleInfo = reinterpret_cast<const OpcodeSampleInfo*>(right);
148
149 return (leftSampleInfo->count < rightSampleInfo->count) ? 1 : (leftSampleInfo->count > rightSampleInfo->count) ? -1 : 0;
150}
151
152static int compareScopeSampleRecords(const void* left, const void* right)
153{
154 const ScopeSampleRecord* const leftValue = *static_cast<const ScopeSampleRecord* const *>(left);
155 const ScopeSampleRecord* const rightValue = *static_cast<const ScopeSampleRecord* const *>(right);
156
157 return (leftValue->m_totalCount < rightValue->m_totalCount) ? 1 : (leftValue->m_totalCount > rightValue->m_totalCount) ? -1 : 0;
158}
159
160void SamplingTool::dump(ExecState* exec)
161{
162 // Tidies up SunSpider output by removing short scripts - such a small number of samples would likely not be useful anyhow.
163 if (m_totalSamples < 10)
164 return;
165
166 // (1) Calculate 'totalCodeBlockSamples', build and sort 'codeBlockSamples' array.
167
168 int scopeCount = m_scopeSampleMap->size();
169 long long totalCodeBlockSamples = 0;
170 Vector<ScopeSampleRecord*> codeBlockSamples(scopeCount);
171 ScopeSampleRecordMap::iterator iter = m_scopeSampleMap->begin();
172 for (int i = 0; i < scopeCount; ++i, ++iter) {
173 codeBlockSamples[i] = iter->second;
174 totalCodeBlockSamples += codeBlockSamples[i]->m_totalCount;
175 }
176#if HAVE(MERGESORT)
177 mergesort(codeBlockSamples.begin(), scopeCount, sizeof(ScopeSampleRecord*), compareScopeSampleRecords);
178#else
179 qsort(codeBlockSamples.begin(), scopeCount, sizeof(ScopeSampleRecord*), compareScopeSampleRecords);
180#endif
181
182 // (2) Print data from 'codeBlockSamples' array, calculate 'totalOpcodeSamples', populate 'opcodeSampleCounts' array.
183
184 long long totalOpcodeSamples = 0;
185 long long opcodeSampleCounts[numOpcodeIDs] = { 0 };
186
187 printf("\nBlock sampling results\n\n");
188 printf("Total blocks sampled (total samples): %lld (%lld)\n\n", totalCodeBlockSamples, m_totalSamples);
189
190 for (int i=0; i < scopeCount; i++) {
191 ScopeSampleRecord* record = codeBlockSamples[i];
192 CodeBlock* codeBlock = record->m_codeBlock;
193
194 double totalPercent = (record->m_totalCount * 100.0)/m_totalSamples;
195 double blockPercent = (record->m_totalCount * 100.0)/totalCodeBlockSamples;
196
197 if ((blockPercent >= 1) && codeBlock) {
198 Instruction* code = codeBlock->instructions.begin();
199 printf("#%d: %s:%d: sampled %d times - %.3f%% (%.3f%%)\n", i + 1, record->m_scope->sourceURL().UTF8String().c_str(), codeBlock->lineNumberForVPC(code), record->m_totalCount, blockPercent, totalPercent);
200 if (i < 10) {
201 HashMap<unsigned,unsigned> lineCounts;
202 codeBlock->dump(exec);
203 for (unsigned op = 0; op < record->m_size; ++op) {
204 int count = record->m_vpcCounts[op];
205 if (count) {
206 printf(" [% 4d] has sample count: % 4d\n", op, count);
207 unsigned line = codeBlock->lineNumberForVPC(code+op);
208 lineCounts.set(line, (lineCounts.contains(line) ? lineCounts.get(line) : 0) + count);
209 }
210 }
211 printf("\n");
212 int linesCount = lineCounts.size();
213 Vector<LineCountInfo> lineCountInfo(linesCount);
214 int lineno = 0;
215 for (HashMap<unsigned,unsigned>::iterator iter = lineCounts.begin(); iter != lineCounts.end(); ++iter, ++lineno) {
216 lineCountInfo[lineno].line = iter->first;
217 lineCountInfo[lineno].count = iter->second;
218 }
219#if HAVE(MERGESORT)
220 mergesort(lineCountInfo.begin(), linesCount, sizeof(LineCountInfo), compareLineCountInfoSampling);
221#else
222 qsort(lineCountInfo.begin(), linesCount, sizeof(LineCountInfo), compareLineCountInfoSampling);
223#endif
224 for (lineno = 0; lineno < linesCount; ++lineno) {
225 printf(" Line #%d has sample count %d.\n", lineCountInfo[lineno].line, lineCountInfo[lineno].count);
226 }
227 printf("\n");
228 }
229 }
230
231 if (record->m_vpcCounts && codeBlock) {
232 Instruction* instructions = codeBlock->instructions.begin();
233 for (unsigned op = 0; op < record->m_size; ++op) {
234 Opcode opcode = instructions[op].u.opcode;
235 if (exec->machine()->isOpcode(opcode)) {
236 totalOpcodeSamples += record->m_vpcCounts[op];
237 opcodeSampleCounts[exec->machine()->getOpcodeID(opcode)] += record->m_vpcCounts[op];
238 }
239 }
240 }
241 }
242 printf("\n");
243
244 // (3) Build and sort 'opcodeSampleInfo' array.
245
246 OpcodeSampleInfo opcodeSampleInfo[numOpcodeIDs];
247 for (int i = 0; i < numOpcodeIDs; ++i) {
248 opcodeSampleInfo[i].opcode = (OpcodeID)i;
249 opcodeSampleInfo[i].count = opcodeSampleCounts[i];
250 }
251#if HAVE(MERGESORT)
252 mergesort(opcodeSampleInfo, numOpcodeIDs, sizeof(OpcodeSampleInfo), compareOpcodeIndicesSampling);
253#else
254 qsort(opcodeSampleInfo, numOpcodeIDs, sizeof(OpcodeSampleInfo), compareOpcodeIndicesSampling);
255#endif
256
257 // (4) Print Opcode sampling results.
258
259 printf("\nOpcode sampling results\n\n");
260
261 printf("Total opcodes sampled (total samples): %lld (%lld)\n\n", totalOpcodeSamples, m_totalSamples);
262 printf("Opcodes in order:\n\n");
263 for (int i = 0; i < numOpcodeIDs; ++i) {
264 long long count = opcodeSampleCounts[i];
265 printf("%s:%s%6lld\t%.3f%%\t(%.3f%%)\n", opcodeNames[i], padOpcodeName(reinterpret_cast<OpcodeID>(i), 20), count, (static_cast<double>(count) * 100) / totalOpcodeSamples, (static_cast<double>(count) * 100) / m_totalSamples);
266 }
267 printf("\n");
268 printf("Opcodes by sample count:\n\n");
269 for (int i = 0; i < numOpcodeIDs; ++i) {
270 OpcodeID opcode = opcodeSampleInfo[i].opcode;
271 long long count = opcodeSampleInfo[i].count;
272 printf("%s:%s%6lld\t%.3f%%\t(%.3f%%)\n", opcodeNames[opcode], padOpcodeName(opcode, 20), count, (static_cast<double>(count) * 100) / totalOpcodeSamples, (static_cast<double>(count) * 100) / m_totalSamples);
273 }
274 printf("\n");
275}
276
277#else
278
279void SamplingTool::dump(ExecState*)
280{
281}
282
283#endif
284
285} // namespace KJS
Note: See TracBrowser for help on using the repository browser.