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#include "common.h"
6#include "eventpipejsonfile.h"
7#include "typestring.h"
8
9#ifdef _DEBUG
10#ifdef FEATURE_PERFTRACING
11
12EventPipeJsonFile::EventPipeJsonFile(SString &outFilePath)
13{
14 CONTRACTL
15 {
16 THROWS;
17 GC_TRIGGERS;
18 MODE_ANY;
19 }
20 CONTRACTL_END;
21
22 m_writeErrorEncountered = false;
23 m_pFileStream = new CFileStream();
24 if(FAILED(m_pFileStream->OpenForWrite(outFilePath)))
25 {
26 delete(m_pFileStream);
27 m_pFileStream = NULL;
28 return;
29 }
30
31 QueryPerformanceCounter(&m_fileOpenTimeStamp);
32
33 SString fileStart(W("{\n\"StackSource\" : {\n\"Samples\" : [\n"));
34 Write(fileStart);
35}
36
37EventPipeJsonFile::~EventPipeJsonFile()
38{
39 CONTRACTL
40 {
41 NOTHROW;
42 GC_TRIGGERS;
43 MODE_ANY;
44 }
45 CONTRACTL_END;
46
47 if(m_pFileStream != NULL)
48 {
49 if(!m_writeErrorEncountered)
50 {
51 SString closingString(W("]}}"));
52 Write(closingString);
53 }
54
55 delete(m_pFileStream);
56 m_pFileStream = NULL;
57 }
58}
59
60void EventPipeJsonFile::WriteEvent(EventPipeEventInstance &instance)
61{
62 CONTRACTL
63 {
64 NOTHROW;
65 GC_NOTRIGGER;
66 MODE_ANY;
67 }
68 CONTRACTL_END;
69
70 instance.SerializeToJsonFile(this);
71}
72
73void EventPipeJsonFile::WriteEvent(LARGE_INTEGER timeStamp, DWORD threadID, SString &message, StackContents &stackContents)
74{
75 CONTRACTL
76 {
77 NOTHROW;
78 GC_NOTRIGGER;
79 MODE_ANY;
80 }
81 CONTRACTL_END;
82
83 if(m_pFileStream == NULL || m_writeErrorEncountered)
84 {
85 return;
86 }
87
88 // Format the call stack.
89 SString strCallStack;
90 FormatCallStack(stackContents, strCallStack);
91
92 // Convert the timestamp from a QPC value to a trace-relative timestamp.
93 double millisecondsSinceTraceStart = 0.0;
94 if(timeStamp.QuadPart != m_fileOpenTimeStamp.QuadPart)
95 {
96 LARGE_INTEGER elapsedNanoseconds;
97 elapsedNanoseconds.QuadPart = timeStamp.QuadPart - m_fileOpenTimeStamp.QuadPart;
98 millisecondsSinceTraceStart = elapsedNanoseconds.QuadPart / 1000000.0;
99 }
100
101 StackScratchBuffer scratch;
102 SString threadFrame;
103 threadFrame.Printf("Thread (%d)", threadID);
104 SString event;
105 event.Printf("{\"Time\" : \"%f\", \"Metric\" : \"1\",\n\"Stack\": [\n\"%s\",\n%s\"%s\"]},", millisecondsSinceTraceStart, message.GetANSI(scratch), strCallStack.GetANSI(scratch), threadFrame.GetANSI(scratch));
106 Write(event);
107}
108
109void EventPipeJsonFile::Write(SString &str)
110{
111 CONTRACTL
112 {
113 NOTHROW;
114 GC_TRIGGERS;
115 MODE_ANY;
116 }
117 CONTRACTL_END;
118
119 StackScratchBuffer scratch;
120 const char * charStr = str.GetANSI(scratch);
121
122 EX_TRY
123 {
124 ULONG inCount = str.GetCount();
125 ULONG outCount;
126
127 m_pFileStream->Write(charStr, inCount, &outCount);
128
129 if(inCount != outCount)
130 {
131 m_writeErrorEncountered = true;
132 }
133 }
134 EX_CATCH
135 {
136 m_writeErrorEncountered = true;
137 }
138 EX_END_CATCH(SwallowAllExceptions);
139}
140
141void EventPipeJsonFile::FormatCallStack(StackContents &stackContents, SString &resultStr)
142{
143 CONTRACTL
144 {
145 NOTHROW;
146 GC_NOTRIGGER;
147 MODE_ANY;
148 }
149 CONTRACTL_END;
150
151 StackScratchBuffer scratch;
152 SString frameStr;
153
154 for(unsigned int i=0; i<stackContents.GetLength(); i++)
155 {
156 // Get the method declaration string.
157 MethodDesc *pMethod = stackContents.GetMethod(i);
158 _ASSERTE(pMethod != NULL);
159
160 SString mAssemblyName;
161 mAssemblyName.SetUTF8(pMethod->GetLoaderModule()->GetAssembly()->GetSimpleName());
162 SString fullName;
163 TypeString::AppendMethodInternal(
164 fullName,
165 pMethod,
166 TypeString::FormatNamespace | TypeString::FormatSignature);
167
168 frameStr.Printf("\"%s!%s\",\n", mAssemblyName.GetANSI(scratch), fullName.GetANSI(scratch));
169 resultStr.Append(frameStr);
170 }
171}
172
173#endif // _DEBUG
174#endif // FEATURE_PERFTRACING
175