Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MCS verb to dump jit flags histogram #48281

Merged
merged 2 commits into from
Feb 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/coreclr/ToolBox/superpmi/mcs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ set(MCS_SOURCES
verbdumpmap.cpp
verbdumptoc.cpp
verbfracture.cpp
verbjitflags.cpp
verbildump.cpp
verbinteg.cpp
verbmerge.cpp
Expand Down
20 changes: 20 additions & 0 deletions src/coreclr/ToolBox/superpmi/mcs/commandline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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]);
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/ToolBox/superpmi/mcs/commandline.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class CommandLine
, actionDumpMap(false)
, actionDumpToc(false)
, actionFracture(false)
, actionJitFlags(false)
, actionILDump(false)
, actionInteg(false)
, actionMerge(false)
Expand Down Expand Up @@ -51,6 +52,7 @@ class CommandLine
bool actionDumpMap;
bool actionDumpToc;
bool actionFracture;
bool actionJitFlags;
bool actionILDump;
bool actionInteg;
bool actionMerge;
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/ToolBox/superpmi/mcs/mcs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down
83 changes: 83 additions & 0 deletions src/coreclr/ToolBox/superpmi/mcs/verbjitflags.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
//
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: looks like files in ToolBox/superpmi have their own license header, the standard one is:

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

is it expected?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching that.

I think we need to redo all the license headers in these files. cc @BruceForstall

// 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<unsigned long long, unsigned> 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<<bit).c_str());
}
}

return 0;
}

18 changes: 18 additions & 0 deletions src/coreclr/ToolBox/superpmi/mcs/verbjitflags.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

//----------------------------------------------------------
// verbJitFlags.h - verb that prints summary of jit flags values
//----------------------------------------------------------
#ifndef _verbJitFlags
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have a preference between #pragma one and ifndef for new files?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think ifndef is preferable; it doesn't depend on support for pragma once in compiler.

#define _verbJitFlags

class verbJitFlags
{
public:
static int DoWork(const char* nameOfInput);
};

#endif
88 changes: 88 additions & 0 deletions src/coreclr/ToolBox/superpmi/superpmi-shared/spmidumphelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,3 +206,91 @@ std::string SpmiDumpHelper::DumpCorInfoFlag(CorInfoFlag flags)

return s;
}

std::string SpmiDumpHelper::DumpJitFlags(CORJIT_FLAGS corJitFlags)
{
return DumpJitFlags(corJitFlags.GetFlagsRaw());
}

std::string SpmiDumpHelper::DumpJitFlags(unsigned long long flags)
{
std::string s("");

#define AddFlag(__name)\
if (flags & (1ull << CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_ ## __name)) { \
s += std::string(" ") + std::string(#__name); \
flags &= ~(1ull << CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_ ## __name); }

// Note some flags are target dependent, but we want to
// be target-agnostic. So we use numbers for the few
// flags that are not universally defined.

#define AddFlagNumeric(__name, __val)\
if (flags & (1ull << __val)) { \
s += std::string(" ") + std::string(#__name); \
flags &= ~(1ull <<__val); }

AddFlag(SPEED_OPT);
AddFlag(SIZE_OPT);
AddFlag(DEBUG_CODE);
AddFlag(DEBUG_EnC);
AddFlag(DEBUG_INFO);
AddFlag(MIN_OPT);

AddFlag(MCJIT_BACKGROUND);

// x86 only
//
AddFlagNumeric(PINVOKE_RESTORE_ESP, 8);
AddFlagNumeric(TARGET_P4, 9);
AddFlagNumeric(USE_FCOMI, 10);
AddFlagNumeric(USE_CMOV, 11);

AddFlag(OSR);
AddFlag(ALT_JIT);

AddFlagNumeric(FEATURE_SIMD, 17);

AddFlag(MAKEFINALCODE);
AddFlag(READYTORUN);
AddFlag(PROF_ENTERLEAVE);

AddFlag(PROF_NO_PINVOKE_INLINE);
AddFlag(SKIP_VERIFICATION);
AddFlag(PREJIT);
AddFlag(RELOC);
AddFlag(IMPORT_ONLY);
AddFlag(IL_STUB);
AddFlag(PROCSPLIT);
AddFlag(BBINSTR);
AddFlag(BBOPT);
AddFlag(FRAMED);

AddFlag(PUBLISH_SECRET_PARAM);

AddFlag(SAMPLING_JIT_BACKGROUND);
AddFlag(USE_PINVOKE_HELPERS);
AddFlag(REVERSE_PINVOKE);
AddFlag(TRACK_TRANSITIONS);
AddFlag(TIER0);
AddFlag(TIER1);

// arm32 only
//
AddFlagNumeric(RELATIVE_CODE_RELOCS, 41);

AddFlag(NO_INLINING);

#undef AddFlag
#undef AddFlagNumeric

if (flags != 0)
{
char buffer[MAX_BUFFER_SIZE];
sprintf_s(buffer, MAX_BUFFER_SIZE, " Unknown jit flags-%016llX", flags);
s += std::string(buffer);
}

return s;
}

3 changes: 3 additions & 0 deletions src/coreclr/ToolBox/superpmi/superpmi-shared/spmidumphelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ class SpmiDumpHelper

static std::string DumpCorInfoFlag(CorInfoFlag flags);

static std::string DumpJitFlags(CORJIT_FLAGS corJitFlags);
static std::string DumpJitFlags(unsigned long long rawFlags);

private:

static void FormatAgnostic_CORINFO_SIG_INST_Element(
Expand Down