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 | |
12 | EventPipeJsonFile::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 | |
37 | EventPipeJsonFile::~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 | |
60 | void 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 | |
73 | void 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 | |
109 | void 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 | |
141 | void 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 | |