summaryrefslogtreecommitdiff
path: root/src/vm/eventpipejsonfile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/eventpipejsonfile.cpp')
-rw-r--r--src/vm/eventpipejsonfile.cpp131
1 files changed, 131 insertions, 0 deletions
diff --git a/src/vm/eventpipejsonfile.cpp b/src/vm/eventpipejsonfile.cpp
new file mode 100644
index 0000000000..6353c917e7
--- /dev/null
+++ b/src/vm/eventpipejsonfile.cpp
@@ -0,0 +1,131 @@
+// 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.
+
+#include "common.h"
+#include "eventpipejsonfile.h"
+
+EventPipeJsonFile::EventPipeJsonFile(SString &outFilePath)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ m_pFileStream = new CFileStream();
+ if(FAILED(m_pFileStream->OpenForWrite(outFilePath)))
+ {
+ delete(m_pFileStream);
+ m_pFileStream = NULL;
+ return;
+ }
+
+ QueryPerformanceCounter(&m_fileOpenTimeStamp);
+
+ SString fileStart(W("{\n\"StackSource\" : {\n\"Samples\" : [\n"));
+ Write(fileStart);
+}
+
+EventPipeJsonFile::~EventPipeJsonFile()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ if(m_pFileStream != NULL)
+ {
+ if(!m_writeErrorEncountered)
+ {
+ SString closingString(W("]}}"));
+ Write(closingString);
+ }
+
+ delete(m_pFileStream);
+ m_pFileStream = NULL;
+ }
+}
+
+void EventPipeJsonFile::WriteEvent(CommonEventFields &commonFields, SString &message, StackContents &stackContents)
+{
+ STANDARD_VM_CONTRACT;
+
+ if(m_pFileStream == NULL || m_writeErrorEncountered)
+ {
+ return;
+ }
+
+ // Format the call stack.
+ SString strCallStack;
+ FormatCallStack(stackContents, strCallStack);
+
+ // Convert the timestamp from a QPC value to a trace-relative timestamp.
+ double millisecondsSinceTraceStart = 0.0;
+ if(commonFields.TimeStamp.QuadPart != m_fileOpenTimeStamp.QuadPart)
+ {
+ LARGE_INTEGER elapsedNanoseconds;
+ elapsedNanoseconds.QuadPart = commonFields.TimeStamp.QuadPart - m_fileOpenTimeStamp.QuadPart;
+ millisecondsSinceTraceStart = elapsedNanoseconds.QuadPart / 1000000.0;
+ }
+
+ StackScratchBuffer scratch;
+ SString threadFrame;
+ threadFrame.Printf("Thread (%d)", commonFields.ThreadID);
+ SString event;
+ event.Printf("{\"Time\" : \"%f\", \"Metric\" : \"1\",\n\"Stack\": [\n\"%s\",\n%s\"%s\"]},", millisecondsSinceTraceStart, message.GetANSI(scratch), strCallStack.GetANSI(scratch), threadFrame.GetANSI(scratch));
+ Write(event);
+}
+
+void EventPipeJsonFile::Write(SString &str)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ StackScratchBuffer scratch;
+ const char * charStr = str.GetANSI(scratch);
+ ULONG inCount = str.GetCount();
+ ULONG outCount;
+ m_pFileStream->Write(charStr, inCount, &outCount);
+
+ if(inCount != outCount)
+ {
+ m_writeErrorEncountered = true;
+ }
+}
+
+void EventPipeJsonFile::FormatCallStack(StackContents &stackContents, SString &resultStr)
+{
+ STANDARD_VM_CONTRACT;
+
+ StackScratchBuffer scratch;
+ SString frameStr;
+
+ for(unsigned int i=0; i<stackContents.GetLength(); i++)
+ {
+ // Get the method declaration string.
+ MethodDesc *pMethod = stackContents.GetMethod(i);
+ _ASSERTE(pMethod != NULL);
+
+ SString mAssemblyName;
+ mAssemblyName.SetUTF8(pMethod->GetLoaderModule()->GetAssembly()->GetSimpleName());
+ SString fullName;
+ TypeString::AppendMethodInternal(
+ fullName,
+ pMethod,
+ TypeString::FormatNamespace | TypeString::FormatSignature);
+
+ frameStr.Printf("\"%s!%s\",\n", mAssemblyName.GetANSI(scratch), fullName.GetANSI(scratch));
+ resultStr.Append(frameStr);
+ }
+}