[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / vm / perfmap.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 // ===========================================================================
5 // File: perfmap.cpp
6 //
7
8 #include "common.h"
9
10 #if defined(FEATURE_PERFMAP) && !defined(DACCESS_COMPILE)
11 #include "perfmap.h"
12 #include "perfinfo.h"
13 #include "pal.h"
14
15 // The code addresses are actually native image offsets during crossgen. Print
16 // them as 32-bit numbers for consistent output when cross-targeting and to
17 // make the output more compact.
18
19 #ifdef CROSSGEN_COMPILE
20 #define FMT_CODE_ADDR "%08x"
21 #else
22 #define FMT_CODE_ADDR "%p"
23 #endif
24
25 PerfMap * PerfMap::s_Current = nullptr;
26 bool PerfMap::s_ShowOptimizationTiers = false;
27
28 // Initialize the map for the process - called from EEStartupHelper.
29 void PerfMap::Initialize()
30 {
31     LIMITED_METHOD_CONTRACT;
32
33     // Only enable the map if requested.
34     if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_PerfMapEnabled))
35     {
36         // Get the current process id.
37         int currentPid = GetCurrentProcessId();
38
39         // Create the map.
40         s_Current = new PerfMap(currentPid);
41
42         int signalNum = (int) CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_PerfMapIgnoreSignal);
43
44         if (signalNum > 0)
45         {
46             PAL_IgnoreProfileSignal(signalNum);
47         }
48
49         if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_PerfMapShowOptimizationTiers) != 0)
50         {
51             s_ShowOptimizationTiers = true;
52         }
53     }
54 }
55
56 // Destroy the map for the process - called from EEShutdownHelper.
57 void PerfMap::Destroy()
58 {
59     LIMITED_METHOD_CONTRACT;
60
61     if (s_Current != nullptr)
62     {
63         delete s_Current;
64         s_Current = nullptr;
65     }
66 }
67
68 // Construct a new map for the process.
69 PerfMap::PerfMap(int pid)
70 {
71     LIMITED_METHOD_CONTRACT;
72
73     // Initialize with no failures.
74     m_ErrorEncountered = false;
75
76     m_StubsMapped = 0;
77
78     // Build the path to the map file on disk.
79     WCHAR tempPath[MAX_LONGPATH+1];
80     if(!GetTempPathW(MAX_LONGPATH, tempPath))
81     {
82         return;
83     }
84     
85     SString path;
86     path.Printf("%Sperf-%d.map", &tempPath, pid);
87
88     // Open the map file for writing.
89     OpenFile(path);
90
91     m_PerfInfo = new PerfInfo(pid);
92 }
93
94 // Construct a new map without a specified file name.
95 // Used for offline creation of NGEN map files.
96 PerfMap::PerfMap()
97   : m_FileStream(nullptr)
98   , m_PerfInfo(nullptr)
99 {
100     LIMITED_METHOD_CONTRACT;
101
102     // Initialize with no failures.
103     m_ErrorEncountered = false;
104
105     m_StubsMapped = 0;
106 }
107
108 // Clean-up resources.
109 PerfMap::~PerfMap()
110 {
111     LIMITED_METHOD_CONTRACT;
112
113     delete m_FileStream;
114     m_FileStream = nullptr;
115
116     delete m_PerfInfo;
117     m_PerfInfo = nullptr;
118 }
119
120 // Open the specified destination map file.
121 void PerfMap::OpenFile(SString& path)
122 {
123     STANDARD_VM_CONTRACT;
124
125     // Open the file stream.
126     m_FileStream = new (nothrow) CFileStream();
127     if(m_FileStream != nullptr)
128     {
129         HRESULT hr = m_FileStream->OpenForWrite(path.GetUnicode());
130         if(FAILED(hr))
131         {
132             delete m_FileStream;
133             m_FileStream = nullptr;
134         }
135     }
136 }
137
138 // Write a line to the map file.
139 void PerfMap::WriteLine(SString& line)
140 {
141     STANDARD_VM_CONTRACT;
142
143     EX_TRY
144     {
145         // Write the line.
146         // The PAL already takes a lock when writing, so we don't need to do so here.
147         StackScratchBuffer scratch;
148         const char * strLine = line.GetANSI(scratch);
149         ULONG inCount = line.GetCount();
150         ULONG outCount;
151         m_FileStream->Write(strLine, inCount, &outCount);
152
153         if (inCount != outCount)
154         {
155             // This will cause us to stop writing to the file.
156             // The file will still remain open until shutdown so that we don't have to take a lock at this level when we touch the file stream.
157             m_ErrorEncountered = true;
158         }
159
160     }
161     EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
162 }
163
164 // Log a method to the map.
165 void PerfMap::LogMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize, const char *optimizationTier)
166 {
167     CONTRACTL{
168         THROWS;
169         GC_NOTRIGGER;
170         MODE_PREEMPTIVE;
171         PRECONDITION(pMethod != nullptr);
172         PRECONDITION(pCode != nullptr);
173         PRECONDITION(codeSize > 0);
174     } CONTRACTL_END;
175
176     if (m_FileStream == nullptr || m_ErrorEncountered)
177     {
178         // A failure occurred, do not log.
179         return;
180     }
181
182     // Logging failures should not cause any exceptions to flow upstream.
183     EX_TRY
184     {
185         // Get the full method signature.
186         SString fullMethodSignature;
187         pMethod->GetFullMethodInfo(fullMethodSignature);
188
189         // Build the map file line.
190         StackScratchBuffer scratch;
191         SString line;
192         line.Printf(FMT_CODE_ADDR " %x %s", pCode, codeSize, fullMethodSignature.GetANSI(scratch));
193         if (optimizationTier != nullptr && s_ShowOptimizationTiers)
194         {
195             line.AppendPrintf("[%s]\n", optimizationTier);
196         }
197         else
198         {
199             line.Append(W('\n'));
200         }
201
202         // Write the line.
203         WriteLine(line);
204     }
205     EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
206 }
207
208
209 void PerfMap::LogImageLoad(PEFile * pFile)
210 {
211     if (s_Current != nullptr)
212     {
213         s_Current->LogImage(pFile);
214     }
215 }
216
217 // Log an image load to the map.
218 void PerfMap::LogImage(PEFile * pFile)
219 {
220     CONTRACTL{
221         THROWS;
222         GC_NOTRIGGER;
223         MODE_PREEMPTIVE;
224         PRECONDITION(pFile != nullptr);
225     } CONTRACTL_END;
226
227
228     if (m_FileStream == nullptr || m_ErrorEncountered)
229     {
230         // A failure occurred, do not log.
231         return;
232     }
233
234     EX_TRY
235     {
236         WCHAR wszSignature[39];
237         GetNativeImageSignature(pFile, wszSignature, lengthof(wszSignature));
238
239         m_PerfInfo->LogImage(pFile, wszSignature);
240     }
241     EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
242 }
243
244
245 // Log a method to the map.
246 void PerfMap::LogJITCompiledMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize, PrepareCodeConfig *pConfig)
247 {
248     LIMITED_METHOD_CONTRACT;
249
250     if (s_Current == nullptr)
251     {
252         return;
253     }
254
255     const char *optimizationTier = nullptr;
256 #ifndef CROSSGEN_COMPILE
257     if (s_ShowOptimizationTiers)
258     {
259         optimizationTier = PrepareCodeConfig::GetJitOptimizationTierStr(pConfig, pMethod);
260     }
261 #endif // CROSSGEN_COMPILE
262
263     s_Current->LogMethod(pMethod, pCode, codeSize, optimizationTier);
264 }
265
266 // Log a set of stub to the map.
267 void PerfMap::LogStubs(const char* stubType, const char* stubOwner, PCODE pCode, size_t codeSize)
268 {
269     LIMITED_METHOD_CONTRACT;
270
271     if (s_Current == nullptr || s_Current->m_FileStream == nullptr)
272     {
273         return;
274     }
275
276     // Logging failures should not cause any exceptions to flow upstream.
277     EX_TRY
278     {
279         if(!stubOwner)
280         {
281             stubOwner = "?";
282         }
283         if(!stubType)
284         {
285             stubOwner = "?";
286         }
287
288         // Build the map file line.
289         SString line;
290         line.Printf(FMT_CODE_ADDR " %x stub<%d> %s<%s>\n", pCode, codeSize, ++(s_Current->m_StubsMapped), stubType, stubOwner);
291
292         // Write the line.
293         s_Current->WriteLine(line);
294     }
295     EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
296 }
297
298 void PerfMap::GetNativeImageSignature(PEFile * pFile, WCHAR * pwszSig, unsigned int nSigSize)
299 {
300     CONTRACTL{
301         PRECONDITION(pFile != nullptr);
302         PRECONDITION(pwszSig != nullptr);
303         PRECONDITION(nSigSize >= 39);
304     } CONTRACTL_END;
305
306     // We use the MVID as the signature, since ready to run images
307     // don't have a native image signature.
308     GUID mvid;
309     pFile->GetMVID(&mvid);
310     if(!StringFromGUID2(mvid, pwszSig, nSigSize))
311     {
312         pwszSig[0] = '\0';
313     }
314 }
315
316 // Create a new native image perf map.
317 NativeImagePerfMap::NativeImagePerfMap(Assembly * pAssembly, BSTR pDestPath)
318   : PerfMap()
319 {
320     STANDARD_VM_CONTRACT;
321
322     // Generate perfmap path.
323
324     // Get the assembly simple name.
325     LPCUTF8 lpcSimpleName = pAssembly->GetSimpleName();
326
327     // Get the native image signature (GUID).
328     // Used to ensure that we match symbols to the correct NGEN image.
329     WCHAR wszSignature[39];
330     GetNativeImageSignature(pAssembly->GetManifestFile(), wszSignature, lengthof(wszSignature));
331
332     // Build the path to the perfmap file, which consists of <inputpath><imagesimplename>.ni.<signature>.map.
333     // Example: /tmp/mscorlib.ni.{GUID}.map
334     SString sDestPerfMapPath;
335     sDestPerfMapPath.Printf("%S%s.ni.%S.map", pDestPath, lpcSimpleName, wszSignature);
336
337     // Open the perf map file.
338     OpenFile(sDestPerfMapPath);
339
340     // Determine whether to emit RVAs or file offsets based on the specified configuration.
341     m_EmitRVAs = true;
342     CLRConfigStringHolder wszFormat(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_NativeImagePerfMapFormat));
343     if(wszFormat != NULL && (wcsncmp(wszFormat, strOFFSET, wcslen(strOFFSET)) == 0))
344     {
345         m_EmitRVAs = false;
346     }
347 }
348
349 // Log data to the perfmap for the specified module.
350 void NativeImagePerfMap::LogDataForModule(Module * pModule)
351 {
352     STANDARD_VM_CONTRACT;
353
354     PEImageLayout * pLoadedLayout = pModule->GetFile()->GetLoaded();
355     _ASSERTE(pLoadedLayout != nullptr);
356
357 #ifdef FEATURE_PREJIT
358     if (!pLoadedLayout->HasReadyToRunHeader())
359     {
360         MethodIterator mi((PTR_Module)pModule);
361         while (mi.Next())
362         {
363             MethodDesc *hotDesc = mi.GetMethodDesc();
364             hotDesc->CheckRestore();
365
366             LogPreCompiledMethod(hotDesc, mi.GetMethodStartAddress(), pLoadedLayout, nullptr);
367         }
368         return;
369     }
370 #endif
371
372     ReadyToRunInfo::MethodIterator mi(pModule->GetReadyToRunInfo());
373     while (mi.Next())
374     {
375         MethodDesc* hotDesc = mi.GetMethodDesc();
376
377         LogPreCompiledMethod(hotDesc, mi.GetMethodStartAddress(), pLoadedLayout, "ReadyToRun");
378     }
379 }
380
381 // Log a pre-compiled method to the perfmap.
382 void NativeImagePerfMap::LogPreCompiledMethod(MethodDesc * pMethod, PCODE pCode, PEImageLayout *pLoadedLayout, const char *optimizationTier)
383 {
384     STANDARD_VM_CONTRACT;
385
386     _ASSERTE(pLoadedLayout != nullptr);
387     SIZE_T baseAddr = (SIZE_T)pLoadedLayout->GetBase();
388
389     // Get information about the NGEN'd method code.
390     EECodeInfo codeInfo(pCode);
391     _ASSERTE(codeInfo.IsValid());
392
393     IJitManager::MethodRegionInfo methodRegionInfo;
394     codeInfo.GetMethodRegionInfo(&methodRegionInfo);
395
396     // NGEN can split code between hot and cold sections which are separate in memory.
397     // Emit an entry for each section if it is used.
398     PCODE addr;
399     if (methodRegionInfo.hotSize > 0)
400     {
401         addr = (PCODE)methodRegionInfo.hotStartAddress - baseAddr;
402         if (!m_EmitRVAs)
403         {
404             addr = pLoadedLayout->RvaToOffset(addr);
405         }
406         LogMethod(pMethod, addr, methodRegionInfo.hotSize, optimizationTier);
407     }
408
409     if (methodRegionInfo.coldSize > 0)
410     {
411         addr = (PCODE)methodRegionInfo.coldStartAddress - baseAddr;
412         if (!m_EmitRVAs)
413         {
414             addr = pLoadedLayout->RvaToOffset(addr);
415         }
416         LogMethod(pMethod, addr, methodRegionInfo.coldSize, optimizationTier);
417     }
418 }
419
420 #endif // FEATURE_PERFMAP && !DACCESS_COMPILE