b2d82e5256be1c8df00c0ae6c0f3de1adec2850f
[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 void EventPipeFile::WriteEvent(EventPipeEventInstance &instance)
70 {
71     CONTRACTL
72     {
73         THROWS;
74         GC_NOTRIGGER;
75         MODE_ANY;
76     }
77     CONTRACTL_END;
78
79     // Check to see if we've seen this event type before.
80     // If not, then write the event metadata to the event stream first.
81     unsigned int metadataId = GetMetadataId(*instance.GetEvent());
82     if(metadataId == 0)
83     {
84         metadataId = GenerateMetadataId();
85
86         EventPipeEventInstance* pMetadataInstance = EventPipe::GetConfiguration()->BuildEventMetadataEvent(instance, metadataId);
87
88         WriteToBlock(*pMetadataInstance, 0); // 0 breaks recursion and represents the metadata event.
89
90         SaveMetadataId(*instance.GetEvent(), metadataId);
91
92         delete[] pMetadataInstance->GetData();
93         delete pMetadataInstance;
94     }
95
96     WriteToBlock(instance, metadataId);
97 }
98
99 void EventPipeFile::Flush()
100 {
101     // Write existing buffer to the stream/file regardless of whether it is full or not.
102     CONTRACTL
103     {
104         NOTHROW;
105         GC_NOTRIGGER;
106         MODE_ANY;
107     }
108     CONTRACTL_END;
109     m_pSerializer->WriteObject(m_pBlock); // we write current block to the disk, whether it's full or not
110     m_pBlock->Clear();
111 }
112
113 void EventPipeFile::WriteEnd()
114 {
115     CONTRACTL
116     {
117         NOTHROW;
118         GC_NOTRIGGER;
119         MODE_ANY;
120     }
121     CONTRACTL_END;
122
123     m_pSerializer->WriteObject(m_pBlock); // we write current block to the disk, whether it's full or not
124
125     m_pBlock->Clear();
126
127     // "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."
128     // see https://github.com/Microsoft/perfview/blob/master/src/TraceEvent/EventPipe/EventPipeFormat.md for more
129     m_pSerializer->WriteTag(FastSerializerTags::NullReference);
130 }
131
132 void EventPipeFile::WriteToBlock(EventPipeEventInstance &instance, unsigned int metadataId)
133 {
134     CONTRACTL
135     {
136         THROWS;
137         GC_NOTRIGGER;
138         MODE_ANY;
139     }
140     CONTRACTL_END;
141
142     instance.SetMetadataId(metadataId);
143
144     if (m_pBlock->WriteEvent(instance))
145         return; // the block is not full, we added the event and continue
146
147     // we can't write this event to the current block (it's full)
148     // so we write what we have in the block to the serializer
149     m_pSerializer->WriteObject(m_pBlock);
150
151     m_pBlock->Clear();
152
153     bool result = m_pBlock->WriteEvent(instance);
154
155     _ASSERTE(result == true); // we should never fail to add event to a clear block (if we do the max size is too small)
156 }
157
158 unsigned int EventPipeFile::GenerateMetadataId()
159 {
160     CONTRACTL
161     {
162         NOTHROW;
163         GC_NOTRIGGER;
164         MODE_ANY;
165     }
166     CONTRACTL_END;
167
168     // PAL does not support 32 bit InterlockedIncrement, so we are using the LONG version and cast to int
169     // https://github.com/dotnet/coreclr/blob/master/src/pal/inc/pal.h#L4159
170     // it's ok because the metadataId will never be bigger than 32 bit
171     return (unsigned int)InterlockedIncrement(&m_metadataIdCounter);
172 }
173
174 unsigned int EventPipeFile::GetMetadataId(EventPipeEvent &event)
175 {
176     CONTRACTL
177     {
178         NOTHROW;
179         GC_NOTRIGGER;
180         MODE_ANY;
181     }
182     CONTRACTL_END;
183
184     unsigned int metadataId;
185     if(m_pMetadataIds->Lookup(&event, &metadataId))
186     {
187         _ASSERTE(metadataId != 0);
188         return metadataId;
189     }
190
191     return 0;
192 }
193
194 void EventPipeFile::SaveMetadataId(EventPipeEvent &event, unsigned int metadataId)
195 {
196     CONTRACTL
197     {
198         THROWS;
199         GC_NOTRIGGER;
200         MODE_ANY;
201         PRECONDITION(metadataId > 0);
202     }
203     CONTRACTL_END;
204
205     // If a pre-existing metadata label exists, remove it.
206     unsigned int oldId;
207     if(m_pMetadataIds->Lookup(&event, &oldId))
208         m_pMetadataIds->Remove(&event);
209
210     // Add the metadata label.
211     m_pMetadataIds->Add(&event, metadataId);
212 }
213
214 #endif // FEATURE_PERFTRACING