If IPC connections fails, then remove active session. (#24082)
[platform/upstream/coreclr.git] / src / vm / eventpipefile.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 #include "common.h"
6 #include "eventpipeblock.h"
7 #include "eventpipefile.h"
8 #include "sampleprofiler.h"
9
10 #ifdef FEATURE_PERFTRACING
11
12 EventPipeFile::EventPipeFile(StreamWriter *pStreamWriter) : FastSerializableObject(3, 0)
13 {
14     CONTRACTL
15     {
16         THROWS;
17         GC_TRIGGERS;
18         MODE_ANY;
19     }
20     CONTRACTL_END;
21
22     m_pBlock = new EventPipeBlock(100 * 1024);
23
24     // File start time information.
25     GetSystemTime(&m_fileOpenSystemTime);
26     QueryPerformanceCounter(&m_fileOpenTimeStamp);
27     QueryPerformanceFrequency(&m_timeStampFrequency);
28
29     m_pointerSize = TARGET_POINTER_SIZE;
30
31     m_currentProcessId = GetCurrentProcessId();
32
33     SYSTEM_INFO sysinfo = {};
34     GetSystemInfo(&sysinfo);
35     m_numberOfProcessors = sysinfo.dwNumberOfProcessors;
36
37     m_samplingRateInNs = SampleProfiler::GetSamplingRate();
38
39     // Create the file stream and write the header.
40     m_pSerializer = new FastSerializer(pStreamWriter);
41
42     m_serializationLock.Init(LOCK_TYPE_DEFAULT);
43     m_pMetadataIds = new MapSHashWithRemove<EventPipeEvent*, unsigned int>();
44
45     // Start and 0 - The value is always incremented prior to use, so the first ID will be 1.
46     m_metadataIdCounter = 0;
47
48     // Write the first object to the file.
49     m_pSerializer->WriteObject(this);
50 }
51
52 EventPipeFile::~EventPipeFile()
53 {
54     CONTRACTL
55     {
56         NOTHROW;
57         GC_TRIGGERS;
58         MODE_ANY;
59     }
60     CONTRACTL_END;
61
62     if (m_pBlock != NULL && m_pSerializer != NULL)
63         WriteEnd();
64
65     delete m_pBlock;
66     delete m_pSerializer;
67 }
68
69 bool EventPipeFile::HasErrors() const
70 {
71     LIMITED_METHOD_CONTRACT;
72     return (m_pSerializer == nullptr) || m_pSerializer->HasWriteErrors();
73 }
74
75 void EventPipeFile::WriteEvent(EventPipeEventInstance &instance)
76 {
77     CONTRACTL
78     {
79         THROWS;
80         GC_NOTRIGGER;
81         MODE_ANY;
82     }
83     CONTRACTL_END;
84
85     // Check to see if we've seen this event type before.
86     // If not, then write the event metadata to the event stream first.
87     unsigned int metadataId = GetMetadataId(*instance.GetEvent());
88     if(metadataId == 0)
89     {
90         metadataId = GenerateMetadataId();
91
92         EventPipeEventInstance* pMetadataInstance = EventPipe::GetConfiguration()->BuildEventMetadataEvent(instance, metadataId);
93
94         WriteToBlock(*pMetadataInstance, 0); // 0 breaks recursion and represents the metadata event.
95
96         SaveMetadataId(*instance.GetEvent(), metadataId);
97
98         delete[] pMetadataInstance->GetData();
99         delete pMetadataInstance;
100     }
101
102     WriteToBlock(instance, metadataId);
103 }
104
105 void EventPipeFile::Flush()
106 {
107     // Write existing buffer to the stream/file regardless of whether it is full or not.
108     CONTRACTL
109     {
110         NOTHROW;
111         GC_NOTRIGGER;
112         MODE_ANY;
113     }
114     CONTRACTL_END;
115     m_pSerializer->WriteObject(m_pBlock); // we write current block to the disk, whether it's full or not
116     m_pBlock->Clear();
117 }
118
119 void EventPipeFile::WriteEnd()
120 {
121     CONTRACTL
122     {
123         NOTHROW;
124         GC_NOTRIGGER;
125         MODE_ANY;
126     }
127     CONTRACTL_END;
128
129     m_pSerializer->WriteObject(m_pBlock); // we write current block to the disk, whether it's full or not
130
131     m_pBlock->Clear();
132
133     // "After the last EventBlock is emitted, the stream is ended by emitting a NullReference Tag which indicates that there are no more objects in the stream to read."
134     // see https://github.com/Microsoft/perfview/blob/master/src/TraceEvent/EventPipe/EventPipeFormat.md for more
135     m_pSerializer->WriteTag(FastSerializerTags::NullReference);
136 }
137
138 void EventPipeFile::WriteToBlock(EventPipeEventInstance &instance, unsigned int metadataId)
139 {
140     CONTRACTL
141     {
142         THROWS;
143         GC_NOTRIGGER;
144         MODE_ANY;
145     }
146     CONTRACTL_END;
147
148     instance.SetMetadataId(metadataId);
149
150     if (m_pBlock->WriteEvent(instance))
151         return; // the block is not full, we added the event and continue
152
153     // we can't write this event to the current block (it's full)
154     // so we write what we have in the block to the serializer
155     m_pSerializer->WriteObject(m_pBlock);
156
157     m_pBlock->Clear();
158
159     bool result = m_pBlock->WriteEvent(instance);
160
161     _ASSERTE(result == true); // we should never fail to add event to a clear block (if we do the max size is too small)
162 }
163
164 unsigned int EventPipeFile::GenerateMetadataId()
165 {
166     CONTRACTL
167     {
168         NOTHROW;
169         GC_NOTRIGGER;
170         MODE_ANY;
171     }
172     CONTRACTL_END;
173
174     // PAL does not support 32 bit InterlockedIncrement, so we are using the LONG version and cast to int
175     // https://github.com/dotnet/coreclr/blob/master/src/pal/inc/pal.h#L4159
176     // it's ok because the metadataId will never be bigger than 32 bit
177     return (unsigned int)InterlockedIncrement(&m_metadataIdCounter);
178 }
179
180 unsigned int EventPipeFile::GetMetadataId(EventPipeEvent &event)
181 {
182     CONTRACTL
183     {
184         NOTHROW;
185         GC_NOTRIGGER;
186         MODE_ANY;
187     }
188     CONTRACTL_END;
189
190     unsigned int metadataId;
191     if(m_pMetadataIds->Lookup(&event, &metadataId))
192     {
193         _ASSERTE(metadataId != 0);
194         return metadataId;
195     }
196
197     return 0;
198 }
199
200 void EventPipeFile::SaveMetadataId(EventPipeEvent &event, unsigned int metadataId)
201 {
202     CONTRACTL
203     {
204         THROWS;
205         GC_NOTRIGGER;
206         MODE_ANY;
207         PRECONDITION(metadataId > 0);
208     }
209     CONTRACTL_END;
210
211     // If a pre-existing metadata label exists, remove it.
212     unsigned int oldId;
213     if(m_pMetadataIds->Lookup(&event, &oldId))
214         m_pMetadataIds->Remove(&event);
215
216     // Add the metadata label.
217     m_pMetadataIds->Add(&event, metadataId);
218 }
219
220 #endif // FEATURE_PERFTRACING