summaryrefslogtreecommitdiff
path: root/src/vm/perfmap.cpp
blob: f868bcf81733fca25dfc3bea63cd8a004131f4ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
// ===========================================================================
// File: perfmap.cpp
//

#include "common.h"

#ifdef FEATURE_PERFMAP
#include "perfmap.h"
#include "pal.h"

PerfMap * PerfMap::s_Current = NULL;

// Initialize the map for the process - called from EEStartupHelper.
void PerfMap::Initialize()
{
    LIMITED_METHOD_CONTRACT;

    // Only enable the map if requested.
    if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_PerfMapEnabled))
    {
        // Get the current process id.
        int currentPid = GetCurrentProcessId();

        // Create the map.
        s_Current = new PerfMap(currentPid);
    }
}

// Log a method to the map.
void PerfMap::LogMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize)
{
    LIMITED_METHOD_CONTRACT;

    if (s_Current != NULL)
    {
        s_Current->Log(pMethod, pCode, codeSize);
    }
}

// Destroy the map for the process - called from EEShutdownHelper.
void PerfMap::Destroy()
{
    if (s_Current != NULL)
    {
        delete s_Current;
        s_Current = NULL;
    }
}

// Construct a new map for the process.
PerfMap::PerfMap(int pid)
{
    LIMITED_METHOD_CONTRACT;

    // Initialize with no failures.
    m_ErrorEncountered = false;

    // Build the path to the map file on disk.
    WCHAR tempPath[MAX_LONGPATH+1];
    if(!GetTempPathW(MAX_LONGPATH, tempPath))
    {
        return;
    }
    
    SString path;
    path.Printf("%Sperf-%d.map", &tempPath, pid);

    // Open the file stream.
    m_FileStream = new (nothrow) CFileStream();
    if(m_FileStream != NULL)
    {
        HRESULT hr = m_FileStream->OpenForWrite(path.GetUnicode());
        if(FAILED(hr))
        {
            delete m_FileStream;
            m_FileStream = NULL;
        }
    }
}

// Clean-up resources.
PerfMap::~PerfMap()
{
    LIMITED_METHOD_CONTRACT;

    delete m_FileStream;
    m_FileStream = NULL;
}

// Log a method to the map.
void PerfMap::Log(MethodDesc * pMethod, PCODE pCode, size_t codeSize)
{
    CONTRACTL{
        THROWS;
        GC_NOTRIGGER;
        MODE_PREEMPTIVE;
        PRECONDITION(pMethod != NULL);
        PRECONDITION(pCode != NULL);
        PRECONDITION(codeSize > 0);
    } 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 full method signature.
        SString fullMethodSignature;
        pMethod->GetFullMethodInfo(fullMethodSignature);

        // Build the map file line.
        StackScratchBuffer scratch;
        SString line;
        line.Printf("%p %x %s\n", pCode, codeSize, fullMethodSignature.GetANSI(scratch));

        // Write the line.
        // The PAL already takes a lock when writing, so we don't need to do so here.
        const char * strLine = line.GetANSI(scratch);
        ULONG inCount = line.GetCount();
        ULONG outCount;
        m_FileStream->Write(strLine, inCount, &outCount);

        if (inCount != outCount)
        {
            // This will cause us to stop writing to the file.
            // The file will still remain open until shutdown so that we don't have to take a lock at this levelwhen we touch the file stream.
            m_ErrorEncountered = true;
        }
    }
    EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
}

#endif // FEATURE_PERFMAP