diff --git a/src/coreclr/ToolBox/superpmi/mcs/CMakeLists.txt b/src/coreclr/ToolBox/superpmi/mcs/CMakeLists.txt index 8524fe8faec70b..e928c48d0cad24 100644 --- a/src/coreclr/ToolBox/superpmi/mcs/CMakeLists.txt +++ b/src/coreclr/ToolBox/superpmi/mcs/CMakeLists.txt @@ -21,6 +21,7 @@ set(MCS_SOURCES verbdumpmap.cpp verbdumptoc.cpp verbfracture.cpp + verbjitflags.cpp verbildump.cpp verbinteg.cpp verbmerge.cpp diff --git a/src/coreclr/ToolBox/superpmi/mcs/commandline.cpp b/src/coreclr/ToolBox/superpmi/mcs/commandline.cpp index d7c519e90214d4..e3b01e3b20454b 100644 --- a/src/coreclr/ToolBox/superpmi/mcs/commandline.cpp +++ b/src/coreclr/ToolBox/superpmi/mcs/commandline.cpp @@ -130,6 +130,10 @@ void CommandLine::DumpHelp(const char* program) printf(" to the mch file.\n"); printf(" e.g. '-toc a.mch' creates a.mch.mct\n"); printf("\n"); + printf(" -jitflags inputfile\n"); + printf(" Summarize interesting jitflags for the method contexts\n"); + printf(" e.g. '-jitflags a.mch'\n"); + printf("\n"); printf("Range descriptions are either a single number, or a text file with .mcl extension\n"); printf("containing a sorted list of line delimited numbers.\n"); printf(" e.g. -strip 2 a.mc b.mc\n"); @@ -235,6 +239,12 @@ bool CommandLine::Parse(int argc, char* argv[], /* OUT */ Options* o) foundVerb = true; o->actionDumpToc = true; } + else if ((_strnicmp(&argv[i][1], "jitflags", argLen) == 0)) + { + tempLen = strlen(argv[i]); + foundVerb = true; + o->actionJitFlags = true; + } else if ((_strnicmp(&argv[i][1], "ildump", argLen) == 0)) { tempLen = strlen(argv[i]); @@ -551,6 +561,16 @@ bool CommandLine::Parse(int argc, char* argv[], /* OUT */ Options* o) } return true; } + if (o->actionJitFlags) + { + if (!foundFile1) + { + LogError("CommandLine::Parse() '-jitFlags' needs one input."); + DumpHelp(argv[0]); + return false; + } + return true; + } if (o->actionILDump) { if (!foundFile1) diff --git a/src/coreclr/ToolBox/superpmi/mcs/commandline.h b/src/coreclr/ToolBox/superpmi/mcs/commandline.h index 74ca637491406b..8bcf0da11d1e99 100644 --- a/src/coreclr/ToolBox/superpmi/mcs/commandline.h +++ b/src/coreclr/ToolBox/superpmi/mcs/commandline.h @@ -23,6 +23,7 @@ class CommandLine , actionDumpMap(false) , actionDumpToc(false) , actionFracture(false) + , actionJitFlags(false) , actionILDump(false) , actionInteg(false) , actionMerge(false) @@ -51,6 +52,7 @@ class CommandLine bool actionDumpMap; bool actionDumpToc; bool actionFracture; + bool actionJitFlags; bool actionILDump; bool actionInteg; bool actionMerge; diff --git a/src/coreclr/ToolBox/superpmi/mcs/mcs.cpp b/src/coreclr/ToolBox/superpmi/mcs/mcs.cpp index f8a007075bc0c7..34313a577bb11b 100644 --- a/src/coreclr/ToolBox/superpmi/mcs/mcs.cpp +++ b/src/coreclr/ToolBox/superpmi/mcs/mcs.cpp @@ -12,6 +12,7 @@ #include "verbfracture.h" #include "verbdumpmap.h" #include "verbdumptoc.h" +#include "verbjitflags.h" #include "verbildump.h" #include "verbtoc.h" #include "verbremovedup.h" @@ -102,6 +103,10 @@ int __cdecl main(int argc, char* argv[]) { exitCode = verbPrintJITEEVersion::DoWork(); } + if (o.actionJitFlags) + { + exitCode = verbJitFlags::DoWork(o.nameOfFile1); + } Logger::Shutdown(); return exitCode; diff --git a/src/coreclr/ToolBox/superpmi/mcs/verbjitflags.cpp b/src/coreclr/ToolBox/superpmi/mcs/verbjitflags.cpp new file mode 100644 index 00000000000000..26379ce6771d0e --- /dev/null +++ b/src/coreclr/ToolBox/superpmi/mcs/verbjitflags.cpp @@ -0,0 +1,83 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "verbjitflags.h" +#include "methodcontext.h" +#include "methodcontextiterator.h" +#include "errorhandling.h" +#include "spmidumphelper.h" + +int verbJitFlags::DoWork(const char* nameOfInput) +{ + MethodContextIterator mci; + if (!mci.Initialize(nameOfInput)) + return -1; + + LightWeightMap flagMap; + unsigned mcCount = 0; + + while (mci.MoveNext()) + { + MethodContext* mc = mci.Current(); + CORJIT_FLAGS corJitFlags; + mc->repGetJitFlags(&corJitFlags, sizeof(corJitFlags)); + unsigned long long rawFlags = corJitFlags.GetFlagsRaw(); + + int index = flagMap.GetIndex(rawFlags); + if (index == -1) + { + flagMap.Add(rawFlags, 1); + } + else + { + int oldVal = flagMap.GetItem(index); + flagMap.Update(index, oldVal + 1); + } + + mcCount++; + } + + if (!mci.Destroy()) + return -1; + + printf("\nGrouped Flag Appearances (%u contexts)\n\n", mcCount); + printf("%-16s %8s %8s parsed\n", "bits", "count", "percent"); + + unsigned appearancesPerBit[64] = {}; + + const unsigned int count = flagMap.GetCount(); + unsigned long long* pFlags = flagMap.GetRawKeys(); + + for (unsigned int i = 0; i < count; i++) + { + const unsigned long long flags = *pFlags++; + const int index = flagMap.GetIndex(flags); + const unsigned appearances = flagMap.GetItem(index); + + printf("%016llx %8u %7.2f%% %s\n", flags, appearances, 100.0 * ((double) appearances / mcCount), SpmiDumpHelper::DumpJitFlags(flags).c_str()); + + for (unsigned int bit = 0; bit < 64; bit++) + { + if (flags & (1ull << bit)) + { + appearancesPerBit[bit] += appearances; + } + } + } + + printf("\nIndividual Flag Appearances\n\n"); + for (unsigned int bit = 0; bit < 64; bit++) + { + unsigned perBit = appearancesPerBit[bit]; + if (perBit > 0) + { + printf("%8u %7.2f%% %s\n", perBit, 100.0 * (double) perBit / mcCount, SpmiDumpHelper::DumpJitFlags(1ull<