From 949450eaddaf8539602019c6cac0d11d2b4bce17 Mon Sep 17 00:00:00 2001 From: Brian Sullivan Date: Wed, 9 Oct 2019 12:51:15 -0700 Subject: [PATCH 1/2] Use info.compFullName as the input to create the JIT's MethodHash Update JitOrder to print out MethodHash and PerfScore Change eeGetMethodFullName to expand class and struct names for the argument types and the return type Fixed issue where bad edge weight were set in fgFoldConditional Made flEdgeWeightMin and flEdgeWeightMax private fields Added new method setEdgeWeights Added support method eeGetArgClass Added source for Tool to parse JitOrder output and associate PerfScores --- src/jit/block.h | 21 +- src/jit/compiler.cpp | 71 ++-- src/jit/compiler.h | 1 + src/jit/ee_il_dll.hpp | 7 + src/jit/eeinterface.cpp | 76 +++- src/jit/flowgraph.cpp | 134 ++++--- src/jit/morph.cpp | 31 +- src/jit/optimizer.cpp | 28 +- .../JitOrderParser/JitOrderParser.csproj | 8 + src/tools/JitOrderParser/JitOrderParser.sln | 25 ++ src/tools/JitOrderParser/jitOrderParser.cs | 333 ++++++++++++++++++ 11 files changed, 610 insertions(+), 125 deletions(-) create mode 100644 src/tools/JitOrderParser/JitOrderParser.csproj create mode 100644 src/tools/JitOrderParser/JitOrderParser.sln create mode 100644 src/tools/JitOrderParser/jitOrderParser.cs diff --git a/src/jit/block.h b/src/jit/block.h index 114e3a754f09..c106f336d806 100644 --- a/src/jit/block.h +++ b/src/jit/block.h @@ -1274,13 +1274,23 @@ struct BasicBlockList struct flowList { - flowList* flNext; // The next BasicBlock in the list, nullptr for end of list. - BasicBlock* flBlock; // The BasicBlock of interest. + flowList* flNext; // The next BasicBlock in the list, nullptr for end of list. + BasicBlock* flBlock; // The BasicBlock of interest. + unsigned flDupCount; // The count of duplicate "edges" (use only for switch stmts) +private: BasicBlock::weight_t flEdgeWeightMin; BasicBlock::weight_t flEdgeWeightMax; - unsigned flDupCount; // The count of duplicate "edges" (use only for switch stmts) +public: + BasicBlock::weight_t edgeWeightMin() const + { + return flEdgeWeightMin; + } + BasicBlock::weight_t edgeWeightMax() const + { + return flEdgeWeightMax; + } // These two methods are used to set new values for flEdgeWeightMin and flEdgeWeightMax // they are used only during the computation of the edge weights @@ -1289,13 +1299,14 @@ struct flowList // bool setEdgeWeightMinChecked(BasicBlock::weight_t newWeight, BasicBlock::weight_t slop, bool* wbUsedSlop); bool setEdgeWeightMaxChecked(BasicBlock::weight_t newWeight, BasicBlock::weight_t slop, bool* wbUsedSlop); + void setEdgeWeights(BasicBlock::weight_t newMinWeight, BasicBlock::weight_t newMaxWeight); - flowList() : flNext(nullptr), flBlock(nullptr), flEdgeWeightMin(0), flEdgeWeightMax(0), flDupCount(0) + flowList() : flNext(nullptr), flBlock(nullptr), flDupCount(0), flEdgeWeightMin(0), flEdgeWeightMax(0) { } flowList(BasicBlock* blk, flowList* rest) - : flNext(rest), flBlock(blk), flEdgeWeightMin(0), flEdgeWeightMax(0), flDupCount(0) + : flNext(rest), flBlock(blk), flDupCount(0), flEdgeWeightMin(0), flEdgeWeightMax(0) { } }; diff --git a/src/jit/compiler.cpp b/src/jit/compiler.cpp index 37fd565ce4ac..424735e8c53c 100644 --- a/src/jit/compiler.cpp +++ b/src/jit/compiler.cpp @@ -3995,8 +3995,8 @@ void Compiler::compSetOptimizationLevel() sscanf_s(histr, "%x", &methHashHi); if (methHash >= methHashLo && methHash <= methHashHi) { - printf("MinOpts for method %s, hash = 0x%x.\n", - info.compFullName, info.compMethodHash()); + printf("MinOpts for method %s, hash = %08x.\n", + info.compFullName, methHash); printf(""); // in our logic this causes a flush theMinOptsValue = true; } @@ -5491,7 +5491,12 @@ unsigned Compiler::Info::compMethodHash() const { if (compMethodHashPrivate == 0) { - compMethodHashPrivate = compCompHnd->getMethodHash(compMethodHnd); + // compMethodHashPrivate = compCompHnd->getMethodHash(compMethodHnd); + assert(compFullName != nullptr); + assert(*compFullName != 0); + COUNT_T hash = HashStringA(compFullName); // Use compFullName to generate the hash, as it contains the signature + // and return type + compMethodHashPrivate = hash; } return compMethodHashPrivate; } @@ -5584,31 +5589,42 @@ void Compiler::compCompileFinish() { // clang-format off headerPrinted = true; - printf(" | Profiled | Exec- | Method has | calls | Num |LclV |AProp| CSE | Reg |bytes | %3s code size | \n", Target::g_tgtCPUName); - printf(" mdToken | | RGN | Count | EH | FRM | LOOP | NRM | IND | BBs | Cnt | Cnt | Cnt | Alloc | IL | HOT | COLD | method name \n"); - printf("---------+-----+------+----------+----+-----+------+-----+-----+-----+-----+-----+-----+---------+------+-------+-------+-----------\n"); - // 06001234 | PRF | HOT | 219 | EH | ebp | LOOP | 15 | 6 | 12 | 17 | 12 | 8 | 28 p2 | 145 | 211 | 123 | System.Example(int) + printf(" | Profiled | Method | Method has | calls | Num |LclV |AProp| CSE | Perf |bytes | %3s codesize| \n", Target::g_tgtCPUName); + printf(" mdToken | CNT | RGN | Hash | EH | FRM | LOOP | NRM | IND | BBs | Cnt | Cnt | Cnt | Score | IL | HOT | CLD | method name \n"); + printf("---------+------+------+----------+----+-----+------+-----+-----+-----+-----+-----+-----+---------+------+-------+-----+\n"); + // 06001234 | 1234 | HOT | 0f1e2d3c | EH | ebp | LOOP | 15 | 6 | 12 | 17 | 12 | 8 | 1234.56 | 145 | 1234 | 123 | System.Example(int) // clang-format on } printf("%08X | ", currentMethodToken); - CorInfoRegionKind regionKind = info.compMethodInfo->regionKind; - - if (opts.altJit) + if (fgHaveProfileData()) { - printf("ALT | "); - } - else if (fgHaveProfileData()) - { - printf("PRF | "); + if (profCallCount <= 9999) + { + printf("%4d | ", profCallCount); + } + else if (profCallCount <= 999500) + { + printf("%3dK | ", (profCallCount + 500) / 1000); + } + else + { + printf("%3dM | ", (profCallCount + 500000) / 1000000); + } } else { - printf(" | "); + printf(" | "); } - if (regionKind == CORINFO_REGION_NONE) + CorInfoRegionKind regionKind = info.compMethodInfo->regionKind; + + if (opts.altJit) + { + printf("ALT | "); + } + else if (regionKind == CORINFO_REGION_NONE) { printf(" | "); } @@ -5629,7 +5645,7 @@ void Compiler::compCompileFinish() printf("UNKN | "); } - printf("%8d | ", profCallCount); + printf("%08x | ", info.compMethodHash()); if (compHndBBtabCount > 0) { @@ -5687,10 +5703,18 @@ void Compiler::compCompileFinish() #endif // FEATURE_ANYCSE } - printf(" LSRA |"); // TODO-Cleanup: dump some interesting LSRA stat into the order file? + if (info.compPerfScore < 9999.995) + { + printf(" %7.2f |", info.compPerfScore); + } + else + { + printf(" %7.0f |", info.compPerfScore); + } + printf(" %4d |", info.compMethodInfo->ILCodeSize); printf(" %5d |", info.compTotalHotCodeSize); - printf(" %5d |", info.compTotalColdCodeSize); + printf(" %3d |", info.compTotalColdCodeSize); printf(" %s\n", eeGetMethodFullName(info.compMethodHnd)); printf(""); // in our logic this causes a flush @@ -6111,9 +6135,8 @@ int Compiler::compCompileHelper(CORINFO_MODULE_HANDLE classPtr, #ifdef DEBUG if (JitConfig.DumpJittedMethods() == 1 && !compIsForInlining()) { - printf("Compiling %4d %s::%s, IL size = %u, hsh=0x%x %s\n", Compiler::jitTotalMethodCompiled, - info.compClassName, info.compMethodName, info.compILCodeSize, info.compMethodHash(), - compGetTieringName()); + printf("Compiling %4d %s::%s, IL size = %u, hash=%08x\n", Compiler::jitTotalMethodCompiled, info.compClassName, + info.compMethodName, info.compILCodeSize, info.compMethodHash(), compGetTieringName()); } if (compIsForInlining()) { @@ -8634,7 +8657,7 @@ void cFuncIR(Compiler* comp) { BasicBlock* block; - printf("Method %s::%s, hsh=0x%x\n", comp->info.compClassName, comp->info.compMethodName, + printf("Method %s::%s, hash=%08x\n", comp->info.compClassName, comp->info.compMethodName, comp->info.compMethodHash()); printf("\n"); diff --git a/src/jit/compiler.h b/src/jit/compiler.h index d989863b0e9c..358849770e77 100644 --- a/src/jit/compiler.h +++ b/src/jit/compiler.h @@ -6928,6 +6928,7 @@ class Compiler var_types eeGetArgType(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig); var_types eeGetArgType(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig, bool* isPinned); + CORINFO_CLASS_HANDLE eeGetArgClass(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE list); unsigned eeGetArgSize(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* sig); // VOM info, method sigs diff --git a/src/jit/ee_il_dll.hpp b/src/jit/ee_il_dll.hpp index ce602ba24570..4a937d19a4aa 100644 --- a/src/jit/ee_il_dll.hpp +++ b/src/jit/ee_il_dll.hpp @@ -109,6 +109,13 @@ inline var_types Compiler::eeGetArgType(CORINFO_ARG_LIST_HANDLE list, CORINFO_SI return JITtype2varType(strip(type)); } +/*****************************************************************************/ +inline CORINFO_CLASS_HANDLE Compiler::eeGetArgClass(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE list) +{ + CORINFO_CLASS_HANDLE argClass = info.compCompHnd->getArgClass(sig, list); + return argClass; +} + /***************************************************************************** * * Native Direct Optimizations diff --git a/src/jit/eeinterface.cpp b/src/jit/eeinterface.cpp index 5a0e412afa6c..d2efd790a0e5 100644 --- a/src/jit/eeinterface.cpp +++ b/src/jit/eeinterface.cpp @@ -28,10 +28,10 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX /*****************************************************************************/ /***************************************************************************** -* -* Filter wrapper to handle exception filtering. -* On Unix compilers don't support SEH. -*/ + * + * Filter wrapper to handle exception filtering. + * On Unix compilers don't support SEH. + */ struct FilterSuperPMIExceptionsParam_eeinterface { @@ -43,6 +43,7 @@ struct FilterSuperPMIExceptionsParam_eeinterface CORINFO_ARG_LIST_HANDLE argLst; CORINFO_METHOD_HANDLE hnd; const char* returnType; + const char** pArgNames; EXCEPTION_POINTERS exceptionPointers; }; @@ -103,17 +104,50 @@ const char* Compiler::eeGetMethodFullName(CORINFO_METHOD_HANDLE hnd) /* figure out the signature */ + param.pThis->eeGetMethodSig(param.hnd, ¶m.sig); + + // allocate space to hold the class names for each of the parameters + + if (param.sig.numArgs > 0) + { + param.pArgNames = getAllocator(CMK_DebugOnly).allocate(param.sig.numArgs); + } + else + { + param.pArgNames = nullptr; + } + PAL_TRY(FilterSuperPMIExceptionsParam_eeinterface*, pParam, ¶m) { unsigned i; - pParam->pThis->eeGetMethodSig(pParam->hnd, &pParam->sig); pParam->argLst = pParam->sig.args; for (i = 0; i < pParam->sig.numArgs; i++) { var_types type = pParam->pThis->eeGetArgType(pParam->argLst, &pParam->sig); - - pParam->siglength += strlen(varTypeName(type)); + switch (type) + { + case TYP_REF: + case TYP_STRUCT: + { + CORINFO_CLASS_HANDLE clsHnd = pParam->pThis->eeGetArgClass(&pParam->sig, pParam->argLst); + // For some SIMD struct types we can get a nullptr back from eeGetArgClass on Linux/X64 + if (clsHnd != NO_CLASS_HANDLE) + { + const char* clsName = pParam->pThis->eeGetClassName(clsHnd); + if (clsName != nullptr) + { + pParam->pArgNames[i] = clsName; + break; + } + } + } + __fallthrough; + default: + pParam->pArgNames[i] = varTypeName(type); + break; + } + pParam->siglength += strlen(pParam->pArgNames[i]); pParam->argLst = pParam->pJitInfo->compCompHnd->getArgNext(pParam->argLst); } @@ -124,9 +158,30 @@ const char* Compiler::eeGetMethodFullName(CORINFO_METHOD_HANDLE hnd) pParam->siglength += (pParam->sig.numArgs - 1); } - if (JITtype2varType(pParam->sig.retType) != TYP_VOID) + var_types retType = JITtype2varType(pParam->sig.retType); + if (retType != TYP_VOID) { - pParam->returnType = varTypeName(JITtype2varType(pParam->sig.retType)); + switch (retType) + { + case TYP_REF: + case TYP_STRUCT: + { + CORINFO_CLASS_HANDLE clsHnd = pParam->sig.retTypeClass; + if (clsHnd != NO_CLASS_HANDLE) + { + const char* clsName = pParam->pThis->eeGetClassName(clsHnd); + if (clsName != nullptr) + { + pParam->returnType = clsName; + break; + } + } + } + __fallthrough; + default: + pParam->returnType = varTypeName(retType); + break; + } pParam->siglength += strlen(pParam->returnType) + 1; // don't forget the delimiter ':' } @@ -175,8 +230,7 @@ const char* Compiler::eeGetMethodFullName(CORINFO_METHOD_HANDLE hnd) for (i = 0; i < param.sig.numArgs; i++) { var_types type = eeGetArgType(param.argLst, ¶m.sig); - strcat_s(retName, length, varTypeName(type)); - + strcat_s(retName, length, param.pArgNames[i]); param.argLst = info.compCompHnd->getArgNext(param.argLst); if (i + 1 < param.sig.numArgs) { diff --git a/src/jit/flowgraph.cpp b/src/jit/flowgraph.cpp index 3d877a61d224..89ea5e6c4194 100644 --- a/src/jit/flowgraph.cpp +++ b/src/jit/flowgraph.cpp @@ -1125,31 +1125,29 @@ flowList* Compiler::fgAddRefPred(BasicBlock* block, // If our caller has given us the old edge weights // then we will use them. // - flow->flEdgeWeightMin = oldEdge->flEdgeWeightMin; - flow->flEdgeWeightMax = oldEdge->flEdgeWeightMax; + flow->setEdgeWeights(oldEdge->edgeWeightMin(), oldEdge->edgeWeightMax()); } else { // Set the max edge weight to be the minimum of block's or blockPred's weight // - flow->flEdgeWeightMax = min(block->bbWeight, blockPred->bbWeight); + BasicBlock::weight_t newWeightMax = min(block->bbWeight, blockPred->bbWeight); // If we are inserting a conditional block the minimum weight is zero, // otherwise it is the same as the edge's max weight. if (blockPred->NumSucc() > 1) { - flow->flEdgeWeightMin = BB_ZERO_WEIGHT; + flow->setEdgeWeights(BB_ZERO_WEIGHT, newWeightMax); } else { - flow->flEdgeWeightMin = flow->flEdgeWeightMax; + flow->setEdgeWeights(flow->edgeWeightMax(), newWeightMax); } } } else { - flow->flEdgeWeightMin = BB_ZERO_WEIGHT; - flow->flEdgeWeightMax = BB_MAX_WEIGHT; + flow->setEdgeWeights(BB_ZERO_WEIGHT, BB_MAX_WEIGHT); } } return flow; @@ -11409,7 +11407,7 @@ BasicBlock* Compiler::fgConnectFallThrough(BasicBlock* bSrc, BasicBlock* bDst) flowList* newEdge = fgGetPredForBlock(jmpBlk, bSrc); - jmpBlk->bbWeight = (newEdge->flEdgeWeightMin + newEdge->flEdgeWeightMax) / 2; + jmpBlk->bbWeight = (newEdge->edgeWeightMin() + newEdge->edgeWeightMax()) / 2; if (bSrc->bbWeight == 0) { jmpBlk->bbWeight = 0; @@ -11420,7 +11418,7 @@ BasicBlock* Compiler::fgConnectFallThrough(BasicBlock* bSrc, BasicBlock* bDst) jmpBlk->bbFlags |= BBF_RUN_RARELY; } - BasicBlock::weight_t weightDiff = (newEdge->flEdgeWeightMax - newEdge->flEdgeWeightMin); + BasicBlock::weight_t weightDiff = (newEdge->edgeWeightMax() - newEdge->edgeWeightMin()); BasicBlock::weight_t slop = BasicBlock::GetSlopFraction(bSrc, bDst); // @@ -13062,6 +13060,23 @@ bool flowList::setEdgeWeightMaxChecked(BasicBlock::weight_t newWeight, BasicBloc return result; } +//------------------------------------------------------------------------ +// setEdgeWeights: Sets the minimum lower (flEdgeWeightMin) value +// and the maximum upper (flEdgeWeightMax) value +// Asserts that the max value is greater or equal to the min value +// +// Arguments: +// theMinWeight - the new minimum lower (flEdgeWeightMin) +// theMaxWeight - the new maximum upper (flEdgeWeightMin) +// +void flowList::setEdgeWeights(BasicBlock::weight_t theMinWeight, BasicBlock::weight_t theMaxWeight) +{ + assert(theMinWeight <= theMaxWeight); + + flEdgeWeightMin = theMinWeight; + flEdgeWeightMax = theMaxWeight; +} + #ifdef DEBUG void Compiler::fgPrintEdgeWeights() { @@ -13082,19 +13097,19 @@ void Compiler::fgPrintEdgeWeights() printf(FMT_BB " ", bSrc->bbNum); - if (edge->flEdgeWeightMin < BB_MAX_WEIGHT) + if (edge->edgeWeightMin() < BB_MAX_WEIGHT) { - printf("(%u", edge->flEdgeWeightMin); + printf("(%u", edge->edgeWeightMin()); } else { printf("(MAX"); } - if (edge->flEdgeWeightMin != edge->flEdgeWeightMax) + if (edge->edgeWeightMin() != edge->edgeWeightMax()) { - if (edge->flEdgeWeightMax < BB_MAX_WEIGHT) + if (edge->edgeWeightMax() < BB_MAX_WEIGHT) { - printf("..%u", edge->flEdgeWeightMax); + printf("..%u", edge->edgeWeightMax()); } else { @@ -13421,8 +13436,7 @@ void Compiler::fgComputeEdgeWeights() if (!bSrc->hasProfileWeight() || !bDst->hasProfileWeight()) { - edge->flEdgeWeightMin = BB_ZERO_WEIGHT; - edge->flEdgeWeightMax = BB_MAX_WEIGHT; + edge->setEdgeWeights(BB_ZERO_WEIGHT, BB_MAX_WEIGHT); } slop = BasicBlock::GetSlopFraction(bSrc, bDst) + 1; @@ -13441,7 +13455,7 @@ void Compiler::fgComputeEdgeWeights() case BBJ_SWITCH: case BBJ_EHFINALLYRET: case BBJ_EHFILTERRET: - if (edge->flEdgeWeightMax > bSrc->bbWeight) + if (edge->edgeWeightMax() > bSrc->bbWeight) { // The maximum edge weight to block can't be greater than the weight of bSrc assignOK &= edge->setEdgeWeightMaxChecked(bSrc->bbWeight, slop, &usedSlop); @@ -13455,7 +13469,7 @@ void Compiler::fgComputeEdgeWeights() } // The maximum edge weight to block can't be greater than the weight of bDst - if (edge->flEdgeWeightMax > bDstWeight) + if (edge->edgeWeightMax() > bDstWeight) { assignOK &= edge->setEdgeWeightMaxChecked(bDstWeight, slop, &usedSlop); } @@ -13503,31 +13517,31 @@ void Compiler::fgComputeEdgeWeights() { otherEdge = fgGetPredForBlock(bSrc->bbNext, bSrc); } - noway_assert(edge->flEdgeWeightMin <= edge->flEdgeWeightMax); - noway_assert(otherEdge->flEdgeWeightMin <= otherEdge->flEdgeWeightMax); + noway_assert(edge->edgeWeightMin() <= edge->edgeWeightMax()); + noway_assert(otherEdge->edgeWeightMin() <= otherEdge->edgeWeightMax()); // Adjust edge->flEdgeWeightMin up or adjust otherEdge->flEdgeWeightMax down - diff = ((int)bSrc->bbWeight) - ((int)edge->flEdgeWeightMin + (int)otherEdge->flEdgeWeightMax); + diff = ((int)bSrc->bbWeight) - ((int)edge->edgeWeightMin() + (int)otherEdge->edgeWeightMax()); if (diff > 0) { - assignOK &= edge->setEdgeWeightMinChecked(edge->flEdgeWeightMin + diff, slop, &usedSlop); + assignOK &= edge->setEdgeWeightMinChecked(edge->edgeWeightMin() + diff, slop, &usedSlop); } else if (diff < 0) { assignOK &= - otherEdge->setEdgeWeightMaxChecked(otherEdge->flEdgeWeightMax + diff, slop, &usedSlop); + otherEdge->setEdgeWeightMaxChecked(otherEdge->edgeWeightMax() + diff, slop, &usedSlop); } // Adjust otherEdge->flEdgeWeightMin up or adjust edge->flEdgeWeightMax down - diff = ((int)bSrc->bbWeight) - ((int)otherEdge->flEdgeWeightMin + (int)edge->flEdgeWeightMax); + diff = ((int)bSrc->bbWeight) - ((int)otherEdge->edgeWeightMin() + (int)edge->edgeWeightMax()); if (diff > 0) { assignOK &= - otherEdge->setEdgeWeightMinChecked(otherEdge->flEdgeWeightMin + diff, slop, &usedSlop); + otherEdge->setEdgeWeightMinChecked(otherEdge->edgeWeightMin() + diff, slop, &usedSlop); } else if (diff < 0) { - assignOK &= edge->setEdgeWeightMaxChecked(edge->flEdgeWeightMax + diff, slop, &usedSlop); + assignOK &= edge->setEdgeWeightMaxChecked(edge->edgeWeightMax() + diff, slop, &usedSlop); } if (!assignOK) @@ -13539,11 +13553,11 @@ void Compiler::fgComputeEdgeWeights() } #ifdef DEBUG // Now edge->flEdgeWeightMin and otherEdge->flEdgeWeightMax) should add up to bSrc->bbWeight - diff = ((int)bSrc->bbWeight) - ((int)edge->flEdgeWeightMin + (int)otherEdge->flEdgeWeightMax); + diff = ((int)bSrc->bbWeight) - ((int)edge->edgeWeightMin() + (int)otherEdge->edgeWeightMax()); noway_assert((-((int)slop) <= diff) && (diff <= ((int)slop))); // Now otherEdge->flEdgeWeightMin and edge->flEdgeWeightMax) should add up to bSrc->bbWeight - diff = ((int)bSrc->bbWeight) - ((int)otherEdge->flEdgeWeightMin + (int)edge->flEdgeWeightMax); + diff = ((int)bSrc->bbWeight) - ((int)otherEdge->edgeWeightMin() + (int)edge->edgeWeightMax()); noway_assert((-((int)slop) <= diff) && (diff <= ((int)slop))); #endif // DEBUG } @@ -13579,8 +13593,8 @@ void Compiler::fgComputeEdgeWeights() // We are processing the control flow edge (bSrc -> bDst) bSrc = edge->flBlock; - maxEdgeWeightSum += edge->flEdgeWeightMax; - minEdgeWeightSum += edge->flEdgeWeightMin; + maxEdgeWeightSum += edge->edgeWeightMax(); + minEdgeWeightSum += edge->edgeWeightMin(); } // maxEdgeWeightSum is the sum of all flEdgeWeightMax values into bDst @@ -13596,20 +13610,20 @@ void Compiler::fgComputeEdgeWeights() // otherMaxEdgesWeightSum is the sum of all of the other edges flEdgeWeightMax values // This can be used to compute a lower bound for our minimum edge weight - noway_assert(maxEdgeWeightSum >= edge->flEdgeWeightMax); - UINT64 otherMaxEdgesWeightSum = maxEdgeWeightSum - edge->flEdgeWeightMax; + noway_assert(maxEdgeWeightSum >= edge->edgeWeightMax()); + UINT64 otherMaxEdgesWeightSum = maxEdgeWeightSum - edge->edgeWeightMax(); // otherMinEdgesWeightSum is the sum of all of the other edges flEdgeWeightMin values // This can be used to compute an upper bound for our maximum edge weight - noway_assert(minEdgeWeightSum >= edge->flEdgeWeightMin); - UINT64 otherMinEdgesWeightSum = minEdgeWeightSum - edge->flEdgeWeightMin; + noway_assert(minEdgeWeightSum >= edge->edgeWeightMin()); + UINT64 otherMinEdgesWeightSum = minEdgeWeightSum - edge->edgeWeightMin(); if (bDstWeight >= otherMaxEdgesWeightSum) { // minWeightCalc is our minWeight when every other path to bDst takes it's flEdgeWeightMax value BasicBlock::weight_t minWeightCalc = (BasicBlock::weight_t)(bDstWeight - otherMaxEdgesWeightSum); - if (minWeightCalc > edge->flEdgeWeightMin) + if (minWeightCalc > edge->edgeWeightMin()) { assignOK &= edge->setEdgeWeightMinChecked(minWeightCalc, slop, &usedSlop); } @@ -13620,7 +13634,7 @@ void Compiler::fgComputeEdgeWeights() // maxWeightCalc is our maxWeight when every other path to bDst takes it's flEdgeWeightMin value BasicBlock::weight_t maxWeightCalc = (BasicBlock::weight_t)(bDstWeight - otherMinEdgesWeightSum); - if (maxWeightCalc < edge->flEdgeWeightMax) + if (maxWeightCalc < edge->edgeWeightMax()) { assignOK &= edge->setEdgeWeightMaxChecked(maxWeightCalc, slop, &usedSlop); } @@ -13635,7 +13649,7 @@ void Compiler::fgComputeEdgeWeights() } // When flEdgeWeightMin equals flEdgeWeightMax we have a "good" edge weight - if (edge->flEdgeWeightMin == edge->flEdgeWeightMax) + if (edge->edgeWeightMin() == edge->edgeWeightMax()) { // Count how many "good" edge weights we have // Each time through we should have more "good" weights @@ -13709,7 +13723,7 @@ EARLY_EXIT:; bSrc = edge->flBlock; // This is the control flow edge (bSrc -> bDst) - if (edge->flEdgeWeightMin != edge->flEdgeWeightMax) + if (edge->edgeWeightMin() != edge->edgeWeightMax()) { fgRangeUsedInEdgeWeights = true; break; @@ -13810,12 +13824,12 @@ bool Compiler::fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBloc BasicBlock::weight_t edgeWeight; - if (edge1->flEdgeWeightMin != edge1->flEdgeWeightMax) + if (edge1->edgeWeightMin() != edge1->edgeWeightMax()) { // // We only have an estimate for the edge weight // - edgeWeight = (edge1->flEdgeWeightMin + edge1->flEdgeWeightMax) / 2; + edgeWeight = (edge1->edgeWeightMin() + edge1->edgeWeightMax()) / 2; // // Clear the profile weight flag // @@ -13826,7 +13840,7 @@ bool Compiler::fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBloc // // We only have the exact edge weight // - edgeWeight = edge1->flEdgeWeightMin; + edgeWeight = edge1->edgeWeightMin(); } // @@ -13849,23 +13863,27 @@ bool Compiler::fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBloc // // Update the edge2 min/max weights // - if (edge2->flEdgeWeightMin > edge1->flEdgeWeightMin) + BasicBlock::weight_t newEdge2Min; + BasicBlock::weight_t newEdge2Max; + + if (edge2->edgeWeightMin() > edge1->edgeWeightMin()) { - edge2->flEdgeWeightMin -= edge1->flEdgeWeightMin; + newEdge2Min = edge2->edgeWeightMin() - edge1->edgeWeightMin(); } else { - edge2->flEdgeWeightMin = BB_ZERO_WEIGHT; + newEdge2Min = BB_ZERO_WEIGHT; } - if (edge2->flEdgeWeightMax > edge1->flEdgeWeightMin) + if (edge2->edgeWeightMax() > edge1->edgeWeightMin()) { - edge2->flEdgeWeightMax -= edge1->flEdgeWeightMin; + newEdge2Max = edge2->edgeWeightMax() - edge1->edgeWeightMin(); } else { - edge2->flEdgeWeightMax = BB_ZERO_WEIGHT; + newEdge2Max = BB_ZERO_WEIGHT; } + edge2->setEdgeWeights(newEdge2Min, newEdge2Max); } } @@ -14170,7 +14188,7 @@ bool Compiler::fgOptimizeSwitchBranches(BasicBlock* block) if (fgHaveValidEdgeWeights) { flowList* edge = fgGetPredForBlock(bDest, block); - BasicBlock::weight_t branchThroughWeight = edge->flEdgeWeightMin; + BasicBlock::weight_t branchThroughWeight = edge->edgeWeightMin(); if (bDest->bbWeight > branchThroughWeight) { @@ -15077,7 +15095,7 @@ bool Compiler::fgOptimizeSwitchJumps() { BasicBlock* bDst = *jumpTab; flowList* edgeToDst = fgGetPredForBlock(bDst, bSrc); - double outRatio = (double) edgeToDst->flEdgeWeightMin / (double) bSrc->bbWeight; + double outRatio = (double) edgeToDst->edgeWeightMin() / (double) bSrc->bbWeight; if (outRatio >= 0.60) { @@ -15247,7 +15265,7 @@ void Compiler::fgReorderBlocks() { if (edge != edgeFromPrev) { - if (edge->flEdgeWeightMax >= edgeFromPrev->flEdgeWeightMin) + if (edge->edgeWeightMax() >= edgeFromPrev->edgeWeightMin()) { moveDestUp = false; break; @@ -15344,9 +15362,9 @@ void Compiler::fgReorderBlocks() // A takenRation of 0.90 means taken 90% of the time, not taken 10% of the time // double takenCount = - ((double)edgeToDest->flEdgeWeightMin + (double)edgeToDest->flEdgeWeightMax) / 2.0; + ((double)edgeToDest->edgeWeightMin() + (double)edgeToDest->edgeWeightMax()) / 2.0; double notTakenCount = - ((double)edgeToBlock->flEdgeWeightMin + (double)edgeToBlock->flEdgeWeightMax) / 2.0; + ((double)edgeToBlock->edgeWeightMin() + (double)edgeToBlock->edgeWeightMax()) / 2.0; double totalCount = takenCount + notTakenCount; double takenRatio = takenCount / totalCount; @@ -15358,7 +15376,7 @@ void Compiler::fgReorderBlocks() else { // set profHotWeight - profHotWeight = (edgeToBlock->flEdgeWeightMin + edgeToBlock->flEdgeWeightMax) / 2 - 1; + profHotWeight = (edgeToBlock->edgeWeightMin() + edgeToBlock->edgeWeightMax()) / 2 - 1; } } else @@ -17399,7 +17417,7 @@ bool Compiler::fgIsBetterFallThrough(BasicBlock* bCur, BasicBlock* bAlt) noway_assert(edgeFromCur != nullptr); noway_assert(edgeFromAlt != nullptr); - result = (edgeFromAlt->flEdgeWeightMin > edgeFromCur->flEdgeWeightMax); + result = (edgeFromAlt->edgeWeightMin() > edgeFromCur->edgeWeightMax()); } else { @@ -19932,16 +19950,16 @@ bool Compiler::fgDumpFlowGraph(Phases phase) } if (validWeights) { - unsigned edgeWeight = (edge->flEdgeWeightMin + edge->flEdgeWeightMax) / 2; + unsigned edgeWeight = (edge->edgeWeightMin() + edge->edgeWeightMax()) / 2; fprintf(fgxFile, "\n weight="); fprintfDouble(fgxFile, ((double)edgeWeight) / weightDivisor); - if (edge->flEdgeWeightMin != edge->flEdgeWeightMax) + if (edge->edgeWeightMin() != edge->edgeWeightMax()) { fprintf(fgxFile, "\n minWeight="); - fprintfDouble(fgxFile, ((double)edge->flEdgeWeightMin) / weightDivisor); + fprintfDouble(fgxFile, ((double)edge->edgeWeightMin()) / weightDivisor); fprintf(fgxFile, "\n maxWeight="); - fprintfDouble(fgxFile, ((double)edge->flEdgeWeightMax) / weightDivisor); + fprintfDouble(fgxFile, ((double)edge->edgeWeightMax()) / weightDivisor); } if (edgeWeight > 0) diff --git a/src/jit/morph.cpp b/src/jit/morph.cpp index 13ceb53dd642..c67fe4bc486b 100644 --- a/src/jit/morph.cpp +++ b/src/jit/morph.cpp @@ -14946,8 +14946,8 @@ bool Compiler::fgFoldConditional(BasicBlock* block) if (block->hasProfileWeight()) { // The edge weights for (block -> bTaken) are 100% of block's weight - edgeTaken->flEdgeWeightMin = block->bbWeight; - edgeTaken->flEdgeWeightMax = block->bbWeight; + + edgeTaken->setEdgeWeights(block->bbWeight, block->bbWeight); if (!bTaken->hasProfileWeight()) { @@ -14964,8 +14964,7 @@ bool Compiler::fgFoldConditional(BasicBlock* block) if (bTaken->countOfInEdges() == 1) { // There is only one in edge to bTaken - edgeTaken->flEdgeWeightMin = bTaken->bbWeight; - edgeTaken->flEdgeWeightMax = bTaken->bbWeight; + edgeTaken->setEdgeWeights(bTaken->bbWeight, bTaken->bbWeight); // Update the weight of block block->inheritWeight(bTaken); @@ -14975,22 +14974,34 @@ bool Compiler::fgFoldConditional(BasicBlock* block) if (bUpdated != nullptr) { + BasicBlock::weight_t newMinWeight; + BasicBlock::weight_t newMaxWeight; + flowList* edge; // Now fix the weights of the edges out of 'bUpdated' switch (bUpdated->bbJumpKind) { case BBJ_NONE: - edge = fgGetPredForBlock(bUpdated->bbNext, bUpdated); - edge->flEdgeWeightMax = bUpdated->bbWeight; + edge = fgGetPredForBlock(bUpdated->bbNext, bUpdated); + newMaxWeight = bUpdated->bbWeight; + newMinWeight = min(edge->edgeWeightMin(), newMaxWeight); + edge->setEdgeWeights(newMinWeight, newMaxWeight); break; + case BBJ_COND: - edge = fgGetPredForBlock(bUpdated->bbNext, bUpdated); - edge->flEdgeWeightMax = bUpdated->bbWeight; + edge = fgGetPredForBlock(bUpdated->bbNext, bUpdated); + newMaxWeight = bUpdated->bbWeight; + newMinWeight = min(edge->edgeWeightMin(), newMaxWeight); + edge->setEdgeWeights(newMinWeight, newMaxWeight); __fallthrough; + case BBJ_ALWAYS: - edge = fgGetPredForBlock(bUpdated->bbJumpDest, bUpdated); - edge->flEdgeWeightMax = bUpdated->bbWeight; + edge = fgGetPredForBlock(bUpdated->bbJumpDest, bUpdated); + newMaxWeight = bUpdated->bbWeight; + newMinWeight = min(edge->edgeWeightMin(), newMaxWeight); + edge->setEdgeWeights(newMinWeight, newMaxWeight); break; + default: // We don't handle BBJ_SWITCH break; diff --git a/src/jit/optimizer.cpp b/src/jit/optimizer.cpp index 169c9ad64000..b4778ae07288 100644 --- a/src/jit/optimizer.cpp +++ b/src/jit/optimizer.cpp @@ -4289,18 +4289,14 @@ void Compiler::fgOptWhileLoop(BasicBlock* block) { bTest->bbFlags |= BBF_RUN_RARELY; // All out edge weights are set to zero - edgeToNext->flEdgeWeightMin = BB_ZERO_WEIGHT; - edgeToNext->flEdgeWeightMax = BB_ZERO_WEIGHT; - edgeToJump->flEdgeWeightMin = BB_ZERO_WEIGHT; - edgeToJump->flEdgeWeightMax = BB_ZERO_WEIGHT; + edgeToNext->setEdgeWeights(BB_ZERO_WEIGHT, BB_ZERO_WEIGHT); + edgeToJump->setEdgeWeights(BB_ZERO_WEIGHT, BB_ZERO_WEIGHT); } else { // Update the our edge weights - edgeToNext->flEdgeWeightMin = BB_ZERO_WEIGHT; - edgeToNext->flEdgeWeightMax = min(edgeToNext->flEdgeWeightMax, newWeightTest); - edgeToJump->flEdgeWeightMin = BB_ZERO_WEIGHT; - edgeToJump->flEdgeWeightMax = min(edgeToJump->flEdgeWeightMax, newWeightTest); + edgeToNext->setEdgeWeights(BB_ZERO_WEIGHT, min(edgeToNext->edgeWeightMax(), newWeightTest)); + edgeToJump->setEdgeWeights(BB_ZERO_WEIGHT, min(edgeToJump->edgeWeightMax(), newWeightTest)); } } } @@ -7399,9 +7395,9 @@ void Compiler::fgCreateLoopPreHeader(unsigned lnum) noway_assert(edgeToJump != nullptr); loopEnteredCount = - ((double)edgeToNext->flEdgeWeightMin + (double)edgeToNext->flEdgeWeightMax) / 2.0; + ((double)edgeToNext->edgeWeightMin() + (double)edgeToNext->edgeWeightMax()) / 2.0; loopSkippedCount = - ((double)edgeToJump->flEdgeWeightMin + (double)edgeToJump->flEdgeWeightMax) / 2.0; + ((double)edgeToJump->edgeWeightMin() + (double)edgeToJump->edgeWeightMax()) / 2.0; } else { @@ -9089,17 +9085,15 @@ void Compiler::optOptimizeBools() noway_assert(edge1 != nullptr); noway_assert(edge2 != nullptr); - BasicBlock::weight_t edgeSumMin = edge1->flEdgeWeightMin + edge2->flEdgeWeightMin; - BasicBlock::weight_t edgeSumMax = edge1->flEdgeWeightMax + edge2->flEdgeWeightMax; - if ((edgeSumMax >= edge1->flEdgeWeightMax) && (edgeSumMax >= edge2->flEdgeWeightMax)) + BasicBlock::weight_t edgeSumMin = edge1->edgeWeightMin() + edge2->edgeWeightMin(); + BasicBlock::weight_t edgeSumMax = edge1->edgeWeightMax() + edge2->edgeWeightMax(); + if ((edgeSumMax >= edge1->edgeWeightMax()) && (edgeSumMax >= edge2->edgeWeightMax())) { - edge1->flEdgeWeightMin = edgeSumMin; - edge1->flEdgeWeightMax = edgeSumMax; + edge1->setEdgeWeights(edgeSumMin, edgeSumMax); } else { - edge1->flEdgeWeightMin = BB_ZERO_WEIGHT; - edge1->flEdgeWeightMax = BB_MAX_WEIGHT; + edge1->setEdgeWeights(BB_ZERO_WEIGHT, BB_MAX_WEIGHT); } /* Get rid of the second block (which is a BBJ_COND) */ diff --git a/src/tools/JitOrderParser/JitOrderParser.csproj b/src/tools/JitOrderParser/JitOrderParser.csproj new file mode 100644 index 000000000000..23df6047ff5e --- /dev/null +++ b/src/tools/JitOrderParser/JitOrderParser.csproj @@ -0,0 +1,8 @@ + + + + Exe + netcoreapp2.1 + + + diff --git a/src/tools/JitOrderParser/JitOrderParser.sln b/src/tools/JitOrderParser/JitOrderParser.sln new file mode 100644 index 000000000000..ae4cf26adb1f --- /dev/null +++ b/src/tools/JitOrderParser/JitOrderParser.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.852 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JitOrderParser", "JitOrderParser.csproj", "{D771E81C-E8A6-430B-A141-3047AD936AA5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D771E81C-E8A6-430B-A141-3047AD936AA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D771E81C-E8A6-430B-A141-3047AD936AA5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D771E81C-E8A6-430B-A141-3047AD936AA5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D771E81C-E8A6-430B-A141-3047AD936AA5}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {AE3A6A0F-57FF-4C18-AD4F-128854B4CE0D} + EndGlobalSection +EndGlobal diff --git a/src/tools/JitOrderParser/jitOrderParser.cs b/src/tools/JitOrderParser/jitOrderParser.cs new file mode 100644 index 000000000000..9ddecd97d845 --- /dev/null +++ b/src/tools/JitOrderParser/jitOrderParser.cs @@ -0,0 +1,333 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using System.Linq; +using System.Globalization; +using OrderInfoList = System.Collections.Generic.List; + +namespace JitOrderParser { + struct OrderInfo + { + public string filename; + public UInt32 mdToken; + public int profileCount; + public string region; + public UInt32 methodHash; + public bool hasEH; + public string frameKind; + public bool hasLoop; + public int normalCallCount; + public int indirectCallCount; + public int basicBlockCount; + public int localVarCount; + public int assertionCount; + public int cseCount; + public double perfScore; + public int IL_bytes; + public int nativeHotBytes; + public int nativeColdBytes; + public string methodName; + + private const char SeperatorChar = '|'; + private const char BlankChar = ' '; + + public OrderInfo(string line, string filenameArg) + { + CultureInfo provider = CultureInfo.InvariantCulture; + char[] separators = { SeperatorChar }; + string[] splits = line.Split(separators, StringSplitOptions.None); + int splitCount = splits.Length; + + if ((splitCount < 17) || (splitCount > 18)) + { + throw new ArgumentException("invalid input"); + } + + filename = filenameArg; + + int curIndex = 0; + + if (!UInt32.TryParse(splits[curIndex++], NumberStyles.HexNumber, provider, out mdToken)) + { + mdToken = 0; + } + + if (!Int32.TryParse(splits[curIndex++], out profileCount)) + { + profileCount = -1; + } + + region = splits[curIndex++].Trim(BlankChar); + + if (!UInt32.TryParse(splits[curIndex++], NumberStyles.HexNumber, provider, out methodHash)) + { + methodHash = 0; + } + + hasEH = (splits[curIndex++].Trim(BlankChar) == "EH"); + + frameKind = splits[curIndex++].Trim(BlankChar); + + hasLoop = (splits[curIndex++].Trim(BlankChar) == "LOOP"); + + if (!Int32.TryParse(splits[curIndex++], out normalCallCount)) + { + normalCallCount = -1; + } + + if (!Int32.TryParse(splits[curIndex++], out indirectCallCount)) + { + indirectCallCount = -1; + } + + if (!Int32.TryParse(splits[curIndex++], out basicBlockCount)) + { + basicBlockCount = -1; + } + + if (!Int32.TryParse(splits[curIndex++], out localVarCount)) + { + localVarCount = -1; + } + + if (splitCount == 18) + { + if (!Int32.TryParse(splits[curIndex++], out assertionCount)) + { + assertionCount = -1; + } + if (!Int32.TryParse(splits[curIndex++], out cseCount)) + { + cseCount = -1; + } + } + else + { + assertionCount = -1; + cseCount = -1; + curIndex++; + } + + if (!Double.TryParse(splits[curIndex++], out perfScore)) + { + perfScore = -1.0; + } + if (!Int32.TryParse(splits[curIndex++], out IL_bytes)) + { + IL_bytes = -1; + } + + if (!Int32.TryParse(splits[curIndex++], out nativeHotBytes)) + { + nativeHotBytes = -1; + } + + if (!Int32.TryParse(splits[curIndex++], out nativeColdBytes)) + { + nativeColdBytes = -1; + } + + methodName = splits[curIndex++]; + } + + static public bool isValidLine(string line) + { + int seperatorCount = 0; + foreach (char currentChar in line) + { + if (currentChar == SeperatorChar) + { + seperatorCount++; + } + } + if ((seperatorCount == 17) || (seperatorCount == 16)) + { + CultureInfo provider = CultureInfo.InvariantCulture; + string firstSplit = line.Substring(0, 8); + + UInt32 token = 0; + if (UInt32.TryParse(firstSplit, NumberStyles.HexNumber, provider, out token)) + { + return true; + } + } + return false; + } + }; + + class Program + { + static string s_firstFile = null; + static List s_OtherFiles = null; + static Dictionary s_rootMap; + static Dictionary s_othersMap; + + static void ParseOrderFile(string filename, bool isRoot) + { + using (StreamReader reader = new StreamReader(filename)) + { + while (true) + { + string line = reader.ReadLine(); + if (line == null) + { + break; + } + if (OrderInfo.isValidLine(line)) + { + OrderInfo currOrderInfo = new OrderInfo(line, filename); + UInt32 key = currOrderInfo.methodHash; + if (isRoot) + { + OrderInfo existingItem; + if (s_rootMap.TryGetValue(key, out existingItem)) + { + Console.WriteLine("Duplicate methodHash: {0:x8} {1}", key, currOrderInfo.methodName); + } + else + { + s_rootMap.Add(key, currOrderInfo); + } + } + else + { + OrderInfoList currList = null; + if (!s_othersMap.TryGetValue(key, out currList)) + { + currList = new OrderInfoList(); + currList.Add(currOrderInfo); + s_othersMap.Add(currOrderInfo.methodHash, currList); + } + else + { + Console.WriteLine("Duplicate methodHash: {0:x8} {1}", key, currOrderInfo.methodName); + currList.Add(currOrderInfo); + s_othersMap[key] = currList; + } + } + } + } + } + } + + static void ProduceReport() + { + foreach (OrderInfo currRootOrderInfo in s_rootMap.Values) + { + UInt32 key = currRootOrderInfo.methodHash; + + OrderInfoList currList = null; + if (!s_othersMap.TryGetValue(key, out currList)) + { + Console.WriteLine("FAIL: No match for Root methodHash: {0:x8} :: {1}", + currRootOrderInfo.methodHash, currRootOrderInfo.methodName); + } + else + { + if (currList.Count > 1) + { + Console.WriteLine("FAIL: Multiple matches ({2}) for Root methodHash: {0:x8} :: {1}", + currRootOrderInfo.methodHash, currRootOrderInfo.methodName, currList.Count); + } + else + { + // Note there is only one matching value, but using a foreach is the easiest way to retrieve it. + foreach (OrderInfo matchOrderInfo in currList) + { + double diffScore = matchOrderInfo.perfScore - currRootOrderInfo.perfScore; + int codeSizeDiff = matchOrderInfo.nativeHotBytes - currRootOrderInfo.nativeHotBytes; + + if (Math.Abs(diffScore) < 0.015) + { + if (codeSizeDiff == 0) + { + Console.WriteLine("SAME: Root PerfScore of {2,7:F2} was the same as the other PerfScore for {0:x8} :: {1}", + currRootOrderInfo.methodHash, currRootOrderInfo.methodName, currRootOrderInfo.perfScore); + } + else if (Math.Abs(codeSizeDiff) < 6) + { + Console.WriteLine("CLOSE: Root PerfScore was the same PerfScore of {2,7:F2} but had code size diff of {3} for {0:x8} :: {1}", + currRootOrderInfo.methodHash, currRootOrderInfo.methodName, matchOrderInfo.perfScore, codeSizeDiff); + } + else + { + Console.WriteLine("DIFF: Same PerfScore of {2,7:F2} but had code size diff of {3} for {0:x8} :: {1}", + currRootOrderInfo.methodHash, currRootOrderInfo.methodName, currRootOrderInfo.perfScore, codeSizeDiff); + } + } + else + { + double pctScore = diffScore / currRootOrderInfo.perfScore; + // Is it within 2% + if ((Math.Abs(pctScore) < 0.02) && (Math.Abs(codeSizeDiff) < 6)) + { + Console.WriteLine("CLOSE: Root PerfScore was differrent by {2,5:F2}% than the orig PerfScore of {3,7:F2} for {0:x8} :: {1}", + currRootOrderInfo.methodHash, currRootOrderInfo.methodName, pctScore*100.0, matchOrderInfo.perfScore); + } + else + { + Console.WriteLine("DIFF: Root PerfScore was differrent by {2,7:F2} than the other PerfScore for {0:x8} :: {1}", + currRootOrderInfo.methodHash, currRootOrderInfo.methodName, diffScore); + } + } + } + } + } + } + } + + static void Main(string[] args) + { + int len = args.Length; + bool invalidArgs = false; + bool firstArg = true; + + s_OtherFiles = new List(args.Length-1); + + foreach (string currentArg in args) + { + if (currentArg[1] == '-') + { + // Parse options + Console.WriteLine("Unknown option: " + currentArg); + invalidArgs = true; + break; + } + if (!File.Exists(currentArg)) + { + Console.WriteLine("Unable to access file: " + currentArg); + invalidArgs = true; + break; + } + if (firstArg) + { + s_firstFile = currentArg; + firstArg = false; + } + else + { + s_OtherFiles.Add(currentArg); + } + } + + if (!invalidArgs) + { + s_rootMap = new Dictionary(); + s_othersMap = new Dictionary(); + + Console.WriteLine("Parsing (root) : " + s_firstFile); + + ParseOrderFile(s_firstFile, true); + + foreach(string otherFilename in s_OtherFiles) + { + Console.WriteLine("Parsing (non-root) : " + otherFilename); + ParseOrderFile(otherFilename, false); + } + + ProduceReport(); + } + } + } +} From 9c0c0567b8c71a318c68973d36d39ee8be8b63bc Mon Sep 17 00:00:00 2001 From: Brian Sullivan Date: Wed, 23 Oct 2019 10:56:42 -0700 Subject: [PATCH 2/2] Remove jitOrderParser.cs --- .../JitOrderParser/JitOrderParser.csproj | 8 - src/tools/JitOrderParser/JitOrderParser.sln | 25 -- src/tools/JitOrderParser/jitOrderParser.cs | 333 ------------------ 3 files changed, 366 deletions(-) delete mode 100644 src/tools/JitOrderParser/JitOrderParser.csproj delete mode 100644 src/tools/JitOrderParser/JitOrderParser.sln delete mode 100644 src/tools/JitOrderParser/jitOrderParser.cs diff --git a/src/tools/JitOrderParser/JitOrderParser.csproj b/src/tools/JitOrderParser/JitOrderParser.csproj deleted file mode 100644 index 23df6047ff5e..000000000000 --- a/src/tools/JitOrderParser/JitOrderParser.csproj +++ /dev/null @@ -1,8 +0,0 @@ - - - - Exe - netcoreapp2.1 - - - diff --git a/src/tools/JitOrderParser/JitOrderParser.sln b/src/tools/JitOrderParser/JitOrderParser.sln deleted file mode 100644 index ae4cf26adb1f..000000000000 --- a/src/tools/JitOrderParser/JitOrderParser.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.852 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JitOrderParser", "JitOrderParser.csproj", "{D771E81C-E8A6-430B-A141-3047AD936AA5}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D771E81C-E8A6-430B-A141-3047AD936AA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D771E81C-E8A6-430B-A141-3047AD936AA5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D771E81C-E8A6-430B-A141-3047AD936AA5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D771E81C-E8A6-430B-A141-3047AD936AA5}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {AE3A6A0F-57FF-4C18-AD4F-128854B4CE0D} - EndGlobalSection -EndGlobal diff --git a/src/tools/JitOrderParser/jitOrderParser.cs b/src/tools/JitOrderParser/jitOrderParser.cs deleted file mode 100644 index 9ddecd97d845..000000000000 --- a/src/tools/JitOrderParser/jitOrderParser.cs +++ /dev/null @@ -1,333 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.IO; -using System.Linq; -using System.Globalization; -using OrderInfoList = System.Collections.Generic.List; - -namespace JitOrderParser { - struct OrderInfo - { - public string filename; - public UInt32 mdToken; - public int profileCount; - public string region; - public UInt32 methodHash; - public bool hasEH; - public string frameKind; - public bool hasLoop; - public int normalCallCount; - public int indirectCallCount; - public int basicBlockCount; - public int localVarCount; - public int assertionCount; - public int cseCount; - public double perfScore; - public int IL_bytes; - public int nativeHotBytes; - public int nativeColdBytes; - public string methodName; - - private const char SeperatorChar = '|'; - private const char BlankChar = ' '; - - public OrderInfo(string line, string filenameArg) - { - CultureInfo provider = CultureInfo.InvariantCulture; - char[] separators = { SeperatorChar }; - string[] splits = line.Split(separators, StringSplitOptions.None); - int splitCount = splits.Length; - - if ((splitCount < 17) || (splitCount > 18)) - { - throw new ArgumentException("invalid input"); - } - - filename = filenameArg; - - int curIndex = 0; - - if (!UInt32.TryParse(splits[curIndex++], NumberStyles.HexNumber, provider, out mdToken)) - { - mdToken = 0; - } - - if (!Int32.TryParse(splits[curIndex++], out profileCount)) - { - profileCount = -1; - } - - region = splits[curIndex++].Trim(BlankChar); - - if (!UInt32.TryParse(splits[curIndex++], NumberStyles.HexNumber, provider, out methodHash)) - { - methodHash = 0; - } - - hasEH = (splits[curIndex++].Trim(BlankChar) == "EH"); - - frameKind = splits[curIndex++].Trim(BlankChar); - - hasLoop = (splits[curIndex++].Trim(BlankChar) == "LOOP"); - - if (!Int32.TryParse(splits[curIndex++], out normalCallCount)) - { - normalCallCount = -1; - } - - if (!Int32.TryParse(splits[curIndex++], out indirectCallCount)) - { - indirectCallCount = -1; - } - - if (!Int32.TryParse(splits[curIndex++], out basicBlockCount)) - { - basicBlockCount = -1; - } - - if (!Int32.TryParse(splits[curIndex++], out localVarCount)) - { - localVarCount = -1; - } - - if (splitCount == 18) - { - if (!Int32.TryParse(splits[curIndex++], out assertionCount)) - { - assertionCount = -1; - } - if (!Int32.TryParse(splits[curIndex++], out cseCount)) - { - cseCount = -1; - } - } - else - { - assertionCount = -1; - cseCount = -1; - curIndex++; - } - - if (!Double.TryParse(splits[curIndex++], out perfScore)) - { - perfScore = -1.0; - } - if (!Int32.TryParse(splits[curIndex++], out IL_bytes)) - { - IL_bytes = -1; - } - - if (!Int32.TryParse(splits[curIndex++], out nativeHotBytes)) - { - nativeHotBytes = -1; - } - - if (!Int32.TryParse(splits[curIndex++], out nativeColdBytes)) - { - nativeColdBytes = -1; - } - - methodName = splits[curIndex++]; - } - - static public bool isValidLine(string line) - { - int seperatorCount = 0; - foreach (char currentChar in line) - { - if (currentChar == SeperatorChar) - { - seperatorCount++; - } - } - if ((seperatorCount == 17) || (seperatorCount == 16)) - { - CultureInfo provider = CultureInfo.InvariantCulture; - string firstSplit = line.Substring(0, 8); - - UInt32 token = 0; - if (UInt32.TryParse(firstSplit, NumberStyles.HexNumber, provider, out token)) - { - return true; - } - } - return false; - } - }; - - class Program - { - static string s_firstFile = null; - static List s_OtherFiles = null; - static Dictionary s_rootMap; - static Dictionary s_othersMap; - - static void ParseOrderFile(string filename, bool isRoot) - { - using (StreamReader reader = new StreamReader(filename)) - { - while (true) - { - string line = reader.ReadLine(); - if (line == null) - { - break; - } - if (OrderInfo.isValidLine(line)) - { - OrderInfo currOrderInfo = new OrderInfo(line, filename); - UInt32 key = currOrderInfo.methodHash; - if (isRoot) - { - OrderInfo existingItem; - if (s_rootMap.TryGetValue(key, out existingItem)) - { - Console.WriteLine("Duplicate methodHash: {0:x8} {1}", key, currOrderInfo.methodName); - } - else - { - s_rootMap.Add(key, currOrderInfo); - } - } - else - { - OrderInfoList currList = null; - if (!s_othersMap.TryGetValue(key, out currList)) - { - currList = new OrderInfoList(); - currList.Add(currOrderInfo); - s_othersMap.Add(currOrderInfo.methodHash, currList); - } - else - { - Console.WriteLine("Duplicate methodHash: {0:x8} {1}", key, currOrderInfo.methodName); - currList.Add(currOrderInfo); - s_othersMap[key] = currList; - } - } - } - } - } - } - - static void ProduceReport() - { - foreach (OrderInfo currRootOrderInfo in s_rootMap.Values) - { - UInt32 key = currRootOrderInfo.methodHash; - - OrderInfoList currList = null; - if (!s_othersMap.TryGetValue(key, out currList)) - { - Console.WriteLine("FAIL: No match for Root methodHash: {0:x8} :: {1}", - currRootOrderInfo.methodHash, currRootOrderInfo.methodName); - } - else - { - if (currList.Count > 1) - { - Console.WriteLine("FAIL: Multiple matches ({2}) for Root methodHash: {0:x8} :: {1}", - currRootOrderInfo.methodHash, currRootOrderInfo.methodName, currList.Count); - } - else - { - // Note there is only one matching value, but using a foreach is the easiest way to retrieve it. - foreach (OrderInfo matchOrderInfo in currList) - { - double diffScore = matchOrderInfo.perfScore - currRootOrderInfo.perfScore; - int codeSizeDiff = matchOrderInfo.nativeHotBytes - currRootOrderInfo.nativeHotBytes; - - if (Math.Abs(diffScore) < 0.015) - { - if (codeSizeDiff == 0) - { - Console.WriteLine("SAME: Root PerfScore of {2,7:F2} was the same as the other PerfScore for {0:x8} :: {1}", - currRootOrderInfo.methodHash, currRootOrderInfo.methodName, currRootOrderInfo.perfScore); - } - else if (Math.Abs(codeSizeDiff) < 6) - { - Console.WriteLine("CLOSE: Root PerfScore was the same PerfScore of {2,7:F2} but had code size diff of {3} for {0:x8} :: {1}", - currRootOrderInfo.methodHash, currRootOrderInfo.methodName, matchOrderInfo.perfScore, codeSizeDiff); - } - else - { - Console.WriteLine("DIFF: Same PerfScore of {2,7:F2} but had code size diff of {3} for {0:x8} :: {1}", - currRootOrderInfo.methodHash, currRootOrderInfo.methodName, currRootOrderInfo.perfScore, codeSizeDiff); - } - } - else - { - double pctScore = diffScore / currRootOrderInfo.perfScore; - // Is it within 2% - if ((Math.Abs(pctScore) < 0.02) && (Math.Abs(codeSizeDiff) < 6)) - { - Console.WriteLine("CLOSE: Root PerfScore was differrent by {2,5:F2}% than the orig PerfScore of {3,7:F2} for {0:x8} :: {1}", - currRootOrderInfo.methodHash, currRootOrderInfo.methodName, pctScore*100.0, matchOrderInfo.perfScore); - } - else - { - Console.WriteLine("DIFF: Root PerfScore was differrent by {2,7:F2} than the other PerfScore for {0:x8} :: {1}", - currRootOrderInfo.methodHash, currRootOrderInfo.methodName, diffScore); - } - } - } - } - } - } - } - - static void Main(string[] args) - { - int len = args.Length; - bool invalidArgs = false; - bool firstArg = true; - - s_OtherFiles = new List(args.Length-1); - - foreach (string currentArg in args) - { - if (currentArg[1] == '-') - { - // Parse options - Console.WriteLine("Unknown option: " + currentArg); - invalidArgs = true; - break; - } - if (!File.Exists(currentArg)) - { - Console.WriteLine("Unable to access file: " + currentArg); - invalidArgs = true; - break; - } - if (firstArg) - { - s_firstFile = currentArg; - firstArg = false; - } - else - { - s_OtherFiles.Add(currentArg); - } - } - - if (!invalidArgs) - { - s_rootMap = new Dictionary(); - s_othersMap = new Dictionary(); - - Console.WriteLine("Parsing (root) : " + s_firstFile); - - ParseOrderFile(s_firstFile, true); - - foreach(string otherFilename in s_OtherFiles) - { - Console.WriteLine("Parsing (non-root) : " + otherFilename); - ParseOrderFile(otherFilename, false); - } - - ProduceReport(); - } - } - } -}