Skip to content

Commit

Permalink
Merge pull request dotnet#4068 from Lucrecious/master
Browse files Browse the repository at this point in the history
Generate map files for symbol resolution for Linux native images on PerfView
  • Loading branch information
brianrob committed Apr 13, 2016
2 parents 3ad8f15 + 484c855 commit 0ec739e
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 42 deletions.
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"

#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)
{
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",
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
#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 {
public:
PerfInfo(int pid);
~PerfInfo();
void LogImage(PEFile* pFile, WCHAR* guid);

private:
CFileStream* m_Stream;

const char sDelimiter = ';';

void OpenFile(SString& path);

void WriteLine(SString& type, SString& value);

};


#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;

// 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.
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

0 comments on commit 0ec739e

Please sign in to comment.