Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Generate map files for symbol resolution for Linux native images on PerfView #4068

Merged
merged 1 commit into from
Apr 13, 2016
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/vm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ set(VM_SOURCES_DAC_AND_WKS_COMMON
peimage.cpp
peimagelayout.cpp
perfmap.cpp
perfinfo.cpp
precode.cpp
prestub.cpp
rejit.cpp
Expand Down
1 change: 1 addition & 0 deletions src/vm/crossgen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ endif (WIN32)
if (CLR_CMAKE_PLATFORM_LINUX)
list(APPEND VM_CROSSGEN_SOURCES
../perfmap.cpp
../perfinfo.cpp
)
endif (CLR_CMAKE_PLATFORM_LINUX)

Expand Down
10 changes: 5 additions & 5 deletions src/vm/domainfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1310,11 +1310,6 @@ void DomainFile::FinishLoad()
// Inform metadata that it has been loaded from a native image
// (and so there was an opportunity to check for or fix inconsistencies in the original IL metadata)
m_pFile->GetMDImport()->SetVerifiedByTrustedSource(TRUE);

#ifdef FEATURE_PERFMAP
// Notify the perfmap of the native image load.
PerfMap::LogNativeImageLoad(m_pFile);
#endif
}

// Are we absolutely required to use a native image?
Expand Down Expand Up @@ -1382,6 +1377,11 @@ void DomainFile::FinishLoad()
// Set a bit to indicate that the module has been loaded in some domain, and therefore
// typeloads can involve types from this module. (Used for candidate instantiations.)
GetModule()->SetIsReadyForTypeLoad();

#ifdef FEATURE_PERFMAP
// Notify the perfmap of the IL image load.
PerfMap::LogImageLoad(m_pFile);
#endif
}

void DomainFile::VerifyExecution()
Expand Down
125 changes: 125 additions & 0 deletions src/vm/perfinfo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// ===========================================================================
// File: perfinfo.cpp
//

#include "common.h"
Copy link
Member

Choose a reason for hiding this comment

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

Please add the file header here as well.


#if defined(FEATURE_PERFMAP) && !defined(DACCESS_COMPILE)
#include "perfinfo.h"
#include "pal.h"

PerfInfo::PerfInfo(int pid)
{
LIMITED_METHOD_CONTRACT;

SString tempPath;
if (!WszGetTempPath(tempPath))
{
return;
}

SString path;
path.Printf("%Sperfinfo-%d.map", tempPath.GetUnicode(), pid);
OpenFile(path);
}

// Logs image loads into the process' perfinfo-%d.map file
void PerfInfo::LogImage(PEFile* pFile, WCHAR* guid)
Copy link
Member

Choose a reason for hiding this comment

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

Please add function-level comments for each of these new functions.

{
CONTRACTL
{
THROWS;
GC_NOTRIGGER;
MODE_PREEMPTIVE;
PRECONDITION(pFile != NULL);
PRECONDITION(guid != NULL);
} CONTRACTL_END;

SString value;
const SString& path = pFile->GetPath();
value.Printf("%S%c%S", path.GetUnicode(), sDelimiter, guid);

SString command;
command.Printf("%s", "ImageLoad");
WriteLine(command, value);

}

// Writes a command line, with "type" being the type of command, with "value" as the command's corresponding instructions/values. This is to be used to log specific information, e.g. LogImage
void PerfInfo::WriteLine(SString& type, SString& value)
{

CONTRACTL
{
THROWS;
GC_NOTRIGGER;
MODE_PREEMPTIVE;
} CONTRACTL_END;

if (m_Stream == NULL)
{
return;
}

SString line;
line.Printf("%S%c%S%c\n",
Copy link
Member

Choose a reason for hiding this comment

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

I would recommend finishing the line with just a newline and not a semi-colon. Is there a reason that the extra semi-colon is helpful for the future?

Copy link
Author

Choose a reason for hiding this comment

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

There's benefit that in the perfcollect script it's more convenient to have to deal with just one delimiter (the semicolin and not the newline).

Copy link
Author

Choose a reason for hiding this comment

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

Also keep in mind that the ending semicolin is within the value part of the command, any user can choose to format the value anyway they want since every command is one line. I'm not sure how this affects anybody else?

Copy link
Member

Choose a reason for hiding this comment

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

My thought was that the semi-colon is just another thing for someone else to parse out. It just affects other users of the file. For example, if someone adds another type of entry, then they need to parse the semi-colon out on the other end just like you do for this scenario.

Not a huge deal either way, so if it makes the parsing simpler, I think it's fine to leave it.

type.GetUnicode(), sDelimiter, value.GetUnicode(), sDelimiter);

EX_TRY
{
StackScratchBuffer scratch;
const char* strLine = line.GetANSI(scratch);
ULONG inCount = line.GetCount();
ULONG outCount;

m_Stream->Write(strLine, inCount, &outCount);

if (inCount != outCount)
{
// error encountered
}
}
EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
}

// Opens a file ready to be written in.
void PerfInfo::OpenFile(SString& path)
{
STANDARD_VM_CONTRACT;

m_Stream = new (nothrow) CFileStream();

if (m_Stream != NULL)
{
HRESULT hr = m_Stream->OpenForWrite(path.GetUnicode());
if (FAILED(hr))
{
delete m_Stream;
m_Stream = NULL;
}
}
}

PerfInfo::~PerfInfo()
{
LIMITED_METHOD_CONTRACT;

delete m_Stream;
m_Stream = NULL;
}


#endif










40 changes: 40 additions & 0 deletions src/vm/perfinfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// ===========================================================================
// File: perfinfo.h
//

#ifndef PERFINFO_H
Copy link
Member

Choose a reason for hiding this comment

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

Please add the file header at the top. You can find it in any of the existing source files.

#define PERFINFO_H


#include "sstring.h"
#include "fstream.h"

/*
A perfinfo-%d.map is created for every process that is created with manage code, the %d
being repaced with the process ID.
Every line in the perfinfo-%d.map is a type and value, separated by sDelimiter character: type;value
type represents what the user might want to do with its given value. value has a format chosen by
the user for parsing later on.
*/
class PerfInfo {
Copy link
Member

Choose a reason for hiding this comment

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

For style, please put the curly braces on their own line.

public:
PerfInfo(int pid);
~PerfInfo();
void LogImage(PEFile* pFile, WCHAR* guid);

private:
CFileStream* m_Stream;

const char sDelimiter = ';';
Copy link
Member

Choose a reason for hiding this comment

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

You should put a comment block at the top of this file that describes the file format (and use of delimiter) so that readers understand the file format.

Copy link
Member

Choose a reason for hiding this comment

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

You should also add a comment describing the naming scheme for the file (e.g. perfinfo-%pid.map).


In reply to: 58457264 [](ancestors = 58457264)


void OpenFile(SString& path);

void WriteLine(SString& type, SString& value);
Copy link
Member

Choose a reason for hiding this comment

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

You should add a comment describing what this method does, and that it is for use within methods that log specific info (e.g. LogImageLoad).


};


#endif
52 changes: 19 additions & 33 deletions src/vm/perfmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#if defined(FEATURE_PERFMAP) && !defined(DACCESS_COMPILE)
#include "perfmap.h"
#include "perfinfo.h"
#include "pal.h"

PerfMap * PerfMap::s_Current = NULL;
Expand Down Expand Up @@ -61,6 +62,8 @@ PerfMap::PerfMap(int pid)

// Open the map file for writing.
OpenFile(path);

m_PerfInfo = new PerfInfo(pid);
}

// Construct a new map without a specified file name.
Expand All @@ -77,6 +80,9 @@ PerfMap::~PerfMap()

delete m_FileStream;
m_FileStream = NULL;

delete m_PerfInfo;
m_PerfInfo = NULL;
}

// Open the specified destination map file.
Expand Down Expand Up @@ -159,8 +165,17 @@ void PerfMap::LogMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize)
EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
}

// Log a native image to the map.
void PerfMap::LogNativeImage(PEFile * pFile)

void PerfMap::LogImageLoad(PEFile * pFile)
{
if (s_Current != NULL)
{
s_Current->LogImage(pFile);
}
}

// Log an image load to the map.
void PerfMap::LogImage(PEFile * pFile)
{
CONTRACTL{
THROWS;
Expand All @@ -169,52 +184,23 @@ void PerfMap::LogNativeImage(PEFile * pFile)
PRECONDITION(pFile != NULL);
} CONTRACTL_END;


if (m_FileStream == NULL || m_ErrorEncountered)
{
// A failure occurred, do not log.
return;
}

// Logging failures should not cause any exceptions to flow upstream.
EX_TRY
{
// Get the native image name.
LPCUTF8 lpcSimpleName = pFile->GetSimpleName();

// Get the native image signature.
WCHAR wszSignature[39];
GetNativeImageSignature(pFile, wszSignature, lengthof(wszSignature));

SString strNativeImageSymbol;
strNativeImageSymbol.Printf("%s.ni.%S", lpcSimpleName, wszSignature);

// Get the base addess of the native image.
SIZE_T baseAddress = (SIZE_T)pFile->GetLoaded()->GetBase();

// Get the image size
COUNT_T imageSize = pFile->GetLoaded()->GetVirtualSize();

// Log baseAddress imageSize strNativeImageSymbol
StackScratchBuffer scratch;
SString line;
line.Printf("%p %x %s\n", baseAddress, imageSize, strNativeImageSymbol.GetANSI(scratch));

// Write the line.
WriteLine(line);
m_PerfInfo->LogImage(pFile, wszSignature);
}
EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
}

// Log a native image load to the map.
void PerfMap::LogNativeImageLoad(PEFile * pFile)
{
STANDARD_VM_CONTRACT;

if (s_Current != NULL)
{
s_Current->LogNativeImage(pFile);
}
}

// Log a method to the map.
void PerfMap::LogJITCompiledMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize)
Expand Down
13 changes: 9 additions & 4 deletions src/vm/perfmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include "sstring.h"
#include "fstream.h"

class PerfInfo;

// Generates a perfmap file.
class PerfMap
{
Expand All @@ -20,6 +22,9 @@ class PerfMap
// The file stream to write the map to.
CFileStream * m_FileStream;

// The perfinfo file to log images to.
PerfInfo* m_PerfInfo;
Copy link
Member

Choose a reason for hiding this comment

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

Please put a line in between the FilStream and the PerfInfo declaration and put a comment on the PerfInfo declaration.


// Set to true if an error is encountered when writing to the file.
bool m_ErrorEncountered;

Expand All @@ -43,18 +48,18 @@ class PerfMap
// Does the actual work to log a method to the map.
void LogMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize);

// Does the actual work to log a native image load to the map.
void LogNativeImage(PEFile * pFile);
// Does the actual work to log an image
void LogImage(PEFile * pFile);

// Get the native image signature and store it as a string.
// Get the image signature and store it as a string.
static void GetNativeImageSignature(PEFile * pFile, WCHAR * pwszSig, unsigned int nSigSize);

public:
// Initialize the map for the current process.
static void Initialize();

// Log a native image load to the map.
Copy link
Member

Choose a reason for hiding this comment

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

Please update the comment - you can just remove "native".

static void LogNativeImageLoad(PEFile * pFile);
static void LogImageLoad(PEFile * pFile);

// Log a JIT compiled method to the map.
static void LogJITCompiledMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize);
Expand Down