void printTopTrans() { if (!nTopTrans) return; // The summary currently includes all translations, so it's misleading // if we're filtering a specific kind of translations or address range. if (kindFilter == "all" && minAddr == 0 && maxAddr == (TCA)-1) { transPerfEvents.printEventsSummary(sortBy, "TransId", nTopTrans, verboseStats, helpersMinPercentage); } // Sort and print the top translations. std::vector<TransID> transIds; for (TransID t = 0; t < NTRANS; t++) { if (TREC(t)->isValid() && (kindFilter == "all" || kindFilter == show(TREC(t)->kind).c_str()) && ((minAddr <= TREC(t)->aStart && TREC(t)->aStart <= maxAddr) || (minAddr <= TREC(t)->acoldStart && TREC(t)->acoldStart <= maxAddr))) { transIds.push_back(t); } } CompTrans compTrans(transPerfEvents, sortBy); sort(transIds.begin(), transIds.end(), compTrans); size_t nPrint = nTopTrans; if (transIds.size() < nTopTrans) { fprintf(stderr, "Warning: too few translations selected (%lu)\n", transIds.size()); nPrint = transIds.size(); } for (size_t i = 0; i < nPrint; i++) printTrans(transIds[i]); }
void loadPerfEvents() { FILE* profFile; profFile = fopen(profFileName.c_str(), "rt"); if (!profFile) { error("Error opening file " + profFileName); } char program[MAX_SYM_LEN]; char eventCaption[MAX_SYM_LEN]; char line[2*MAX_SYM_LEN]; TCA addr; uint32_t tcSamples[NUM_EVENT_TYPES]; uint32_t hhvmSamples[NUM_EVENT_TYPES]; size_t numEntries = 0; PerfEventType eventType = NUM_EVENT_TYPES; // samplesPerKind[event][kind] uint32_t samplesPerKind[NUM_EVENT_TYPES][NumTransKinds]; uint32_t samplesPerTCRegion[NUM_EVENT_TYPES][TCRCount]; memset(tcSamples , 0, sizeof(tcSamples)); memset(hhvmSamples, 0, sizeof(hhvmSamples)); memset(samplesPerKind, 0, sizeof(samplesPerKind)); memset(samplesPerTCRegion, 0, sizeof(samplesPerTCRegion)); while (fgets(line, 2*MAX_SYM_LEN, profFile) != nullptr) { always_assert(sscanf(line, "%s %s %lu", program, eventCaption, &numEntries) == 3); always_assert(numEntries); std::vector<std::pair<TCA,std::string>> entries; for (size_t i = 0; i < numEntries; i++) { fscanf(profFile, "%p %s\n", &addr, line); entries.push_back(std::pair<TCA,std::string>(addr, line)); } if (strncmp(program, "hhvm", 4) == 0) { eventType = perfScriptOutputToEventType(eventCaption); if (eventType == NUM_EVENT_TYPES) { snprintf(errMsgBuff, MAX_SYM_LEN, "loadProfData: invalid event caption '%s'", eventCaption); error(errMsgBuff); } hhvmSamples[eventType]++; size_t selIdx = 0; addr = entries[0].first; if (inclusiveStats) { for (size_t i = 0; i < entries.size(); i++) { if (g_transData->isAddrInSomeTrans(entries[i].first)) { addr = entries[i].first; selIdx = i; break; } } } if (!(minAddr <= addr && addr <= maxAddr)) continue; if (!g_transData->isAddrInSomeTrans(addr)) continue; TransID transId = g_transData->getTransContaining(addr); always_assert(transId != INVALID_ID); tcSamples[eventType]++; const TransRec* trec = g_transData->getTransRec(transId); TransKind kind = trec->kind; samplesPerKind[eventType][static_cast<uint32_t>(kind)]++; TCRegion region = transCode->findTCRegionContaining(addr); always_assert(region != TCRCount); samplesPerTCRegion[eventType][region]++; std::vector<std::string> stackTrace; if (verboseStats) { for (size_t i = 0; i < selIdx; i++) { if (!strcmp(entries[i].second.c_str(), "[unknown]")) { // Append the address to disambiguate. entries[i].second += std::string("@") + toString((void*)entries[i].first); } stackTrace.push_back(entries[i].second); } reverse(stackTrace.begin(), stackTrace.end()); } if (selIdx) addr--; tcaPerfEvents.addEvent(addr, (PerfEvent) { eventType, 1 }, stackTrace); } } AddrToTransMapper transMapper(g_transData); transPerfEvents = tcaPerfEvents.mapTo(transMapper); printf("# Number of hhvm samples read (%% in TC) from file %s\n", profFileName.c_str()); for (size_t i = 0; i < NUM_EVENT_TYPES; i++) { if (!hhvmSamples[i]) continue; printf("# %-19s TOTAL: %10u (%u in TC = %5.2lf%%)\n", eventTypeToCommandLineArgument((PerfEventType)i), hhvmSamples[i], tcSamples[i], 100.0 * tcSamples[i] / hhvmSamples[i]); for (size_t j = 0; j < NumTransKinds; ++j) { auto ct = samplesPerKind[i][j]; if (!ct) continue; std::string kind = show(static_cast<TransKind>(j)); printf("# %26s: %-8u (%5.2lf%%)\n", kind.c_str(), ct, 100.0 * ct / tcSamples[i]); } printf("#\n"); } printf("\n"); // print per-TCRegion information // header printf("# TCRegion "); for (size_t i = 0; i < NUM_EVENT_TYPES; i++) { printf("%17s ", eventTypeToCommandLineArgument((PerfEventType)i)); } printf("\n"); // HW events for each region for (size_t i = 0 ; i < TCRCount ; i++) { printf("# %8s ", tcRegionToString(static_cast<TCRegion>(i)).c_str()); for (size_t j = 0; j < NUM_EVENT_TYPES; j++) { auto ct = samplesPerTCRegion[j][i]; printf("%8u (%5.2lf%%) ", ct, ct ? (100.0 * ct / tcSamples[j]) : 0); } printf("\n"); } printf("#\n\n"); fclose(profFile); }
bool operator()(TransID t1, TransID t2) const { return transPerfEvents.getEventCount(t1, etype) > transPerfEvents.getEventCount(t2, etype); }
void OfflineX86Code::disasm(FILE* file, TCA fileStartAddr, TCA codeStartAddr, uint64_t codeLen, const PerfEventsMap<TCA>& perfEvents, BCMappingInfo bcMappingInfo, bool printAddr /* =true */, bool printBinary /* =false */) { char codeStr[MAX_INSTR_ASM_LEN]; xed_uint8_t* code = (xed_uint8_t*) alloca(codeLen); xed_uint8_t* frontier; TCA ip; TCA r10val = 0; size_t currBC = 0; if (codeLen == 0) return; auto const offset = codeStartAddr - fileStartAddr; if (fseek(file, offset, SEEK_SET)) { error("disasm error: seeking file"); } size_t readLen = fread(code, codeLen, 1, file); if (readLen != 1) { error("Failed to read {} bytes at offset {} from code file due to {}", codeLen, offset, feof(file) ? "EOF" : "read error"); } xed_decoded_inst_t xedd; // Decode and print each instruction for (frontier = code, ip = codeStartAddr; frontier < code + codeLen; ) { xed_decoded_inst_zero_set_mode(&xedd, &xed_state); xed_decoded_inst_set_input_chip(&xedd, XED_CHIP_INVALID); xed_error_enum_t xed_error = xed_decode(&xedd, frontier, 15); if (xed_error != XED_ERROR_NONE) break; // Get disassembled instruction in codeStr if (!xed_format_context(xed_syntax, &xedd, codeStr, MAX_INSTR_ASM_LEN, (uint64_t)ip, nullptr #if XED_ENCODE_ORDER_MAX_ENTRIES != 28 // Newer version of XED library , 0 #endif )) { error("disasm error: xed_format_context failed"); } // Annotate the x86 with its bytecode. currBC = printBCMapping(bcMappingInfo, currBC, (TCA)ip); if (printAddr) printf("%14p: ", ip); uint32_t instrLen = xed_decoded_inst_get_length(&xedd); if (printBinary) { uint32_t i; for (i=0; i < instrLen; i++) { printf("%02X", frontier[i]); } for (; i < 16; i++) { printf(" "); } } // For calls, we try to figure out the destination symbol name. // We look both at relative branches and the pattern: // move r10, IMMEDIATE // call r10 xed_iclass_enum_t iclass = xed_decoded_inst_get_iclass(&xedd); string callDest = ""; if (iclass == XED_ICLASS_CALL_NEAR || iclass == XED_ICLASS_CALL_FAR) { const xed_inst_t *xi = xed_decoded_inst_inst(&xedd); always_assert(xed_inst_noperands(xi) >= 1); const xed_operand_t *opnd = xed_inst_operand(xi, 0); xed_operand_enum_t opndName = xed_operand_name(opnd); if (opndName == XED_OPERAND_RELBR) { if (xed_decoded_inst_get_branch_displacement_width(&xedd)) { xed_int32_t disp = xed_decoded_inst_get_branch_displacement(&xedd); TCA addr = ip + instrLen + disp; callDest = getSymbolName(addr); } } else if (opndName == XED_OPERAND_REG0) { if (xed_decoded_inst_get_reg(&xedd, opndName) == XED_REG_R10) { callDest = getSymbolName(r10val); } } } else if (iclass == XED_ICLASS_MOV) { // Look for moves into r10 and keep r10val updated const xed_inst_t* xi = xed_decoded_inst_inst(&xedd); always_assert(xed_inst_noperands(xi) >= 2); const xed_operand_t *destOpnd = xed_inst_operand(xi, 0); xed_operand_enum_t destOpndName = xed_operand_name(destOpnd); if (destOpndName == XED_OPERAND_REG0 && xed_decoded_inst_get_reg(&xedd, destOpndName) == XED_REG_R10) { const xed_operand_t *srcOpnd = xed_inst_operand(xi, 1); xed_operand_enum_t srcOpndName = xed_operand_name(srcOpnd); if (srcOpndName == XED_OPERAND_IMM0) { TCA addr = (TCA)xed_decoded_inst_get_unsigned_immediate(&xedd); r10val = addr; } } } if (!perfEvents.empty()) { printEventStats((TCA)ip, instrLen, perfEvents); } else { printf("%48s", ""); } printf("%s%s\n", codeStr, callDest.c_str()); frontier += instrLen; ip += instrLen; } }