Opcode.cpp
1 /* 2 * Copyright (C) 2008 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "config.h" 31 #include "Opcode.h" 32 33 #include "BytecodeStructs.h" 34 #include <wtf/PrintStream.h> 35 36 #if ENABLE(OPCODE_STATS) 37 #include <array> 38 #include <wtf/DataLog.h> 39 #endif 40 41 namespace JSC { 42 43 const unsigned opcodeLengths[] = { 44 #define OPCODE_LENGTH(opcode, length) length, 45 FOR_EACH_OPCODE_ID(OPCODE_LENGTH) 46 #undef OPCODE_LENGTH 47 }; 48 49 const char* const opcodeNames[] = { 50 #define OPCODE_NAME_ENTRY(opcode, size) #opcode, 51 FOR_EACH_OPCODE_ID(OPCODE_NAME_ENTRY) 52 #undef OPCODE_NAME_ENTRY 53 }; 54 55 const unsigned wasmOpcodeLengths[] = { 56 #define OPCODE_LENGTH(opcode, length) length, 57 FOR_EACH_WASM_ID(OPCODE_LENGTH) 58 #undef OPCODE_LENGTH 59 }; 60 61 const char* const wasmOpcodeNames[] = { 62 #define OPCODE_NAME_ENTRY(opcode, size) #opcode, 63 FOR_EACH_WASM_ID(OPCODE_NAME_ENTRY) 64 #undef OPCODE_NAME_ENTRY 65 }; 66 67 #if ENABLE(OPCODE_STATS) 68 69 inline const char* padOpcodeName(OpcodeID op, unsigned width) 70 { 71 auto padding = " "; 72 auto paddingLength = strlen(padding); 73 auto opcodeNameLength = strlen(opcodeNames[op]); 74 if (opcodeNameLength >= width) 75 return ""; 76 if (paddingLength + opcodeNameLength < width) 77 return padding; 78 return &padding[paddingLength + opcodeNameLength - width]; 79 } 80 81 long long OpcodeStats::opcodeCounts[numOpcodeIDs]; 82 long long OpcodeStats::opcodePairCounts[numOpcodeIDs][numOpcodeIDs]; 83 int OpcodeStats::lastOpcode = -1; 84 85 static OpcodeStats logger; 86 87 OpcodeStats::OpcodeStats() 88 { 89 for (int i = 0; i < numOpcodeIDs; ++i) 90 opcodeCounts[i] = 0; 91 92 for (int i = 0; i < numOpcodeIDs; ++i) 93 for (int j = 0; j < numOpcodeIDs; ++j) 94 opcodePairCounts[i][j] = 0; 95 } 96 97 static int compareOpcodeIndices(const void* left, const void* right) 98 { 99 long long leftValue = OpcodeStats::opcodeCounts[*(int*) left]; 100 long long rightValue = OpcodeStats::opcodeCounts[*(int*) right]; 101 102 if (leftValue < rightValue) 103 return 1; 104 else if (leftValue > rightValue) 105 return -1; 106 else 107 return 0; 108 } 109 110 static int compareOpcodePairIndices(const void* left, const void* right) 111 { 112 std::pair<int, int> leftPair = *(std::pair<int, int>*) left; 113 long long leftValue = OpcodeStats::opcodePairCounts[leftPair.first][leftPair.second]; 114 std::pair<int, int> rightPair = *(std::pair<int, int>*) right; 115 long long rightValue = OpcodeStats::opcodePairCounts[rightPair.first][rightPair.second]; 116 117 if (leftValue < rightValue) 118 return 1; 119 else if (leftValue > rightValue) 120 return -1; 121 else 122 return 0; 123 } 124 125 OpcodeStats::~OpcodeStats() 126 { 127 long long totalInstructions = 0; 128 for (int i = 0; i < numOpcodeIDs; ++i) 129 totalInstructions += opcodeCounts[i]; 130 131 long long totalInstructionPairs = 0; 132 for (int i = 0; i < numOpcodeIDs; ++i) 133 for (int j = 0; j < numOpcodeIDs; ++j) 134 totalInstructionPairs += opcodePairCounts[i][j]; 135 136 std::array<int, numOpcodeIDs> sortedIndices; 137 for (int i = 0; i < numOpcodeIDs; ++i) 138 sortedIndices[i] = i; 139 qsort(sortedIndices.data(), numOpcodeIDs, sizeof(int), compareOpcodeIndices); 140 141 std::pair<int, int> sortedPairIndices[numOpcodeIDs * numOpcodeIDs]; 142 std::pair<int, int>* currentPairIndex = sortedPairIndices; 143 for (int i = 0; i < numOpcodeIDs; ++i) 144 for (int j = 0; j < numOpcodeIDs; ++j) 145 *(currentPairIndex++) = std::make_pair(i, j); 146 qsort(sortedPairIndices, numOpcodeIDs * numOpcodeIDs, sizeof(std::pair<int, int>), compareOpcodePairIndices); 147 148 dataLogF("\nExecuted opcode statistics\n"); 149 150 dataLogF("Total instructions executed: %lld\n\n", totalInstructions); 151 152 dataLogF("All opcodes by frequency:\n\n"); 153 154 for (int i = 0; i < numOpcodeIDs; ++i) { 155 int index = sortedIndices[i]; 156 dataLogF("%s:%s %lld - %.2f%%\n", opcodeNames[index], padOpcodeName((OpcodeID)index, 28), opcodeCounts[index], ((double) opcodeCounts[index]) / ((double) totalInstructions) * 100.0); 157 } 158 159 dataLogF("\n"); 160 dataLogF("2-opcode sequences by frequency: %lld\n\n", totalInstructions); 161 162 for (int i = 0; i < numOpcodeIDs * numOpcodeIDs; ++i) { 163 std::pair<int, int> indexPair = sortedPairIndices[i]; 164 long long count = opcodePairCounts[indexPair.first][indexPair.second]; 165 166 if (!count) 167 break; 168 169 dataLogF("%s%s %s:%s %lld %.2f%%\n", opcodeNames[indexPair.first], padOpcodeName((OpcodeID)indexPair.first, 28), opcodeNames[indexPair.second], padOpcodeName((OpcodeID)indexPair.second, 28), count, ((double) count) / ((double) totalInstructionPairs) * 100.0); 170 } 171 172 dataLogF("\n"); 173 dataLogF("Most common opcodes and sequences:\n"); 174 175 for (int i = 0; i < numOpcodeIDs; ++i) { 176 int index = sortedIndices[i]; 177 long long opcodeCount = opcodeCounts[index]; 178 double opcodeProportion = ((double) opcodeCount) / ((double) totalInstructions); 179 if (opcodeProportion < 0.0001) 180 break; 181 dataLogF("\n%s:%s %lld - %.2f%%\n", opcodeNames[index], padOpcodeName((OpcodeID)index, 28), opcodeCount, opcodeProportion * 100.0); 182 183 for (int j = 0; j < numOpcodeIDs * numOpcodeIDs; ++j) { 184 std::pair<int, int> indexPair = sortedPairIndices[j]; 185 long long pairCount = opcodePairCounts[indexPair.first][indexPair.second]; 186 double pairProportion = ((double) pairCount) / ((double) totalInstructionPairs); 187 188 if (!pairCount || pairProportion < 0.0001 || pairProportion < opcodeProportion / 100) 189 break; 190 191 if (indexPair.first != index && indexPair.second != index) 192 continue; 193 194 dataLogF(" %s%s %s:%s %lld - %.2f%%\n", opcodeNames[indexPair.first], padOpcodeName((OpcodeID)indexPair.first, 28), opcodeNames[indexPair.second], padOpcodeName((OpcodeID)indexPair.second, 28), pairCount, pairProportion * 100.0); 195 } 196 197 } 198 dataLogF("\n"); 199 } 200 201 void OpcodeStats::recordInstruction(int opcode) 202 { 203 opcodeCounts[opcode]++; 204 205 if (lastOpcode != -1) 206 opcodePairCounts[lastOpcode][opcode]++; 207 208 lastOpcode = opcode; 209 } 210 211 void OpcodeStats::resetLastInstruction() 212 { 213 lastOpcode = -1; 214 } 215 216 #endif 217 218 static const unsigned metadataSizes[] = { 219 220 #define METADATA_SIZE(size) size, 221 FOR_EACH_BYTECODE_METADATA_SIZE(METADATA_SIZE) 222 #undef METADATA_SIZE 223 224 }; 225 226 static const unsigned metadataAlignments[] = { 227 228 #define METADATA_ALIGNMENT(size) size, 229 FOR_EACH_BYTECODE_METADATA_ALIGNMENT(METADATA_ALIGNMENT) 230 #undef METADATA_ALIGNMENT 231 232 }; 233 234 unsigned metadataSize(OpcodeID opcodeID) 235 { 236 return metadataSizes[opcodeID]; 237 } 238 239 unsigned metadataAlignment(OpcodeID opcodeID) 240 { 241 return metadataAlignments[opcodeID]; 242 } 243 244 } // namespace JSC 245 246 namespace WTF { 247 248 using namespace JSC; 249 250 void printInternal(PrintStream& out, OpcodeID opcode) 251 { 252 out.print(opcodeNames[opcode]); 253 } 254 255 } // namespace WTF