c7b6bc9d5d609ba96d176732cdd4c132cfdd7a11
[mirror_edk2.git] / EdkNt32Pkg / Library / EdkGenericBdsLib / Performance.c
1 /*++
2
3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 Performance.c
15
16 Abstract:
17
18 This file include the file which can help to get the system
19 performance, all the function will only include if the performance
20 switch is set.
21
22 --*/
23
24 #include "Performance.h"
25
26 VOID
27 ClearDebugRegisters (
28 VOID
29 )
30 {
31 //
32 // BugBug: We should not need to do this. We need to root cause this bug!!!!
33 //
34 AsmWriteDr0 (0);
35 AsmWriteDr1 (0);
36 }
37
38 STATIC
39 VOID
40 GetShortPdbFileName (
41 CHAR8 *PdbFileName,
42 CHAR8 *GaugeString
43 )
44 /*++
45
46 Routine Description:
47
48 Arguments:
49
50 Returns:
51
52 --*/
53 {
54 UINTN Index;
55 UINTN Index1;
56 UINTN StartIndex;
57 UINTN EndIndex;
58
59 if (PdbFileName == NULL) {
60 AsciiStrCpy (GaugeString, " ");
61 } else {
62 StartIndex = 0;
63 for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)
64 ;
65
66 for (Index = 0; PdbFileName[Index] != 0; Index++) {
67 if (PdbFileName[Index] == '\\') {
68 StartIndex = Index + 1;
69 }
70
71 if (PdbFileName[Index] == '.') {
72 EndIndex = Index;
73 }
74 }
75
76 Index1 = 0;
77 for (Index = StartIndex; Index < EndIndex; Index++) {
78 GaugeString[Index1] = PdbFileName[Index];
79 Index1++;
80 if (Index1 == PERF_TOKEN_LENGTH - 1) {
81 break;
82 }
83 }
84
85 GaugeString[Index1] = 0;
86 }
87
88 return ;
89 }
90
91
92
93 STATIC
94 CHAR8 *
95 GetPdbPath (
96 VOID *ImageBase
97 )
98 /*++
99
100 Routine Description:
101
102 Located PDB path name in PE image
103
104 Arguments:
105
106 ImageBase - base of PE to search
107
108 Returns:
109
110 Pointer into image at offset of PDB file name if PDB file name is found,
111 Otherwise a pointer to an empty string.
112
113 --*/
114 {
115 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
116
117 ZeroMem (&ImageContext, sizeof (ImageContext));
118 ImageContext.Handle = ImageBase;
119 ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
120
121 PeCoffLoaderGetImageInfo (&ImageContext);
122
123 return ImageContext.PdbPointer;
124 }
125
126
127 STATIC
128 VOID
129 GetNameFromHandle (
130 IN EFI_HANDLE Handle,
131 OUT CHAR8 *GaugeString
132 )
133 {
134 EFI_STATUS Status;
135 EFI_LOADED_IMAGE_PROTOCOL *Image;
136 CHAR8 *PdbFileName;
137 EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
138
139 AsciiStrCpy (GaugeString, " ");
140
141 //
142 // Get handle name from image protocol
143 //
144 Status = gBS->HandleProtocol (
145 Handle,
146 &gEfiLoadedImageProtocolGuid,
147 &Image
148 );
149
150 if (EFI_ERROR (Status)) {
151 Status = gBS->OpenProtocol (
152 Handle,
153 &gEfiDriverBindingProtocolGuid,
154 (VOID **) &DriverBinding,
155 NULL,
156 NULL,
157 EFI_OPEN_PROTOCOL_GET_PROTOCOL
158 );
159 if (EFI_ERROR (Status)) {
160 return ;
161 }
162 //
163 // Get handle name from image protocol
164 //
165 Status = gBS->HandleProtocol (
166 DriverBinding->ImageHandle,
167 &gEfiLoadedImageProtocolGuid,
168 &Image
169 );
170 }
171
172 PdbFileName = GetPdbPath (Image->ImageBase);
173
174 if (PdbFileName != NULL) {
175 GetShortPdbFileName (PdbFileName, GaugeString);
176 }
177
178 return ;
179 }
180
181
182
183 VOID
184 WriteBootToOsPerformanceData (
185 VOID
186 )
187 /*++
188
189 Routine Description:
190
191 Allocates a block of memory and writes performance data of booting to OS into it.
192
193 Arguments:
194
195 None
196
197 Returns:
198
199 None
200
201 --*/
202 {
203 EFI_STATUS Status;
204 EFI_CPU_ARCH_PROTOCOL *Cpu;
205 EFI_PHYSICAL_ADDRESS mAcpiLowMemoryBase;
206 UINT32 mAcpiLowMemoryLength;
207 UINT32 LimitCount;
208 PERF_HEADER mPerfHeader;
209 PERF_DATA mPerfData;
210 EFI_HANDLE *Handles;
211 UINTN NoHandles;
212 CHAR8 GaugeString[PERF_TOKEN_LENGTH];
213 UINT8 *Ptr;
214 UINT32 mIndex;
215 UINT64 Ticker;
216 UINT64 Freq;
217 UINT32 Duration;
218 UINT64 CurrentTicker;
219 UINT64 TimerPeriod;
220 UINTN LogEntryKey;
221 CONST VOID *Handle;
222 CONST CHAR8 *Token;
223 CONST CHAR8 *Module;
224 UINT64 StartTicker;
225 UINT64 EndTicker;
226
227 //
228 // Retrive time stamp count as early as possilbe
229 //
230 Ticker = AsmReadTsc ();
231
232 //
233 // Allocate a block of memory that contain performance data to OS
234 //
235 Status = gBS->AllocatePages (
236 AllocateAnyPages,
237 EfiACPIReclaimMemory,
238 4,
239 &mAcpiLowMemoryBase
240 );
241 if (EFI_ERROR (Status)) {
242 return ;
243 }
244
245 mAcpiLowMemoryLength = 0x1000;
246
247 Ptr = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER));
248 LimitCount = (mAcpiLowMemoryLength - sizeof (PERF_HEADER)) / sizeof (PERF_DATA);
249
250 //
251 // Initialize performance data structure
252 //
253 ZeroMem (&mPerfHeader, sizeof (PERF_HEADER));
254
255 //
256 // Get CPU frequency
257 //
258 Status = gBS->LocateProtocol (
259 &gEfiCpuArchProtocolGuid,
260 NULL,
261 &Cpu
262 );
263 if (EFI_ERROR (Status)) {
264 gBS->FreePages (mAcpiLowMemoryBase, 1);
265 return ;
266 }
267 //
268 // Get Cpu Frequency
269 //
270 Status = Cpu->GetTimerValue (Cpu, 0, &(CurrentTicker), &TimerPeriod);
271 if (EFI_ERROR (Status)) {
272 gBS->FreePages (mAcpiLowMemoryBase, 1);
273 return ;
274 }
275
276 Freq = DivU64x32 (1000000000000, (UINTN) TimerPeriod);
277
278 mPerfHeader.CpuFreq = Freq;
279
280 //
281 // Record BDS raw performance data
282 //
283 mPerfHeader.BDSRaw = Ticker;
284
285 //
286 // Put Detailed performance data into memory
287 //
288 Handles = NULL;
289 Status = gBS->LocateHandleBuffer (
290 AllHandles,
291 NULL,
292 NULL,
293 &NoHandles,
294 &Handles
295 );
296 if (EFI_ERROR (Status)) {
297 gBS->FreePages (mAcpiLowMemoryBase, 1);
298 return ;
299 }
300 //
301 // Get DXE drivers performance
302 //
303 for (mIndex = 0; mIndex < NoHandles; mIndex++) {
304 Ticker = 0;
305 LogEntryKey = 0;
306 while ((LogEntryKey = GetPerformanceMeasurement (
307 LogEntryKey,
308 &Handle,
309 &Token,
310 &Module,
311 &StartTicker,
312 &EndTicker)) != 0) {
313 if ((Handle == Handles[mIndex]) && (StartTicker < EndTicker)) {
314 Ticker += (EndTicker - StartTicker);
315 }
316 }
317
318 Duration = (UINT32) DivU64x32 (
319 Ticker,
320 (UINT32) Freq
321 );
322
323 if (Duration > 0) {
324 ZeroMem (&mPerfData, sizeof (PERF_DATA));
325
326 GetNameFromHandle (Handles[mIndex], GaugeString);
327
328 AsciiStrCpy (mPerfData.Token, GaugeString);
329 mPerfData.Duration = Duration;
330
331 CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));
332 Ptr += sizeof (PERF_DATA);
333
334 mPerfHeader.Count++;
335 if (mPerfHeader.Count == LimitCount) {
336 goto Done;
337 }
338 }
339 }
340
341 gBS->FreePool (Handles);
342
343 //
344 // Get inserted performance data
345 //
346 LogEntryKey = 0;
347 while ((LogEntryKey = GetPerformanceMeasurement (
348 LogEntryKey,
349 &Handle,
350 &Token,
351 &Module,
352 &StartTicker,
353 &EndTicker)) != 0) {
354 if ((Handle == NULL) && (StartTicker <= EndTicker)) {
355
356 ZeroMem (&mPerfData, sizeof (PERF_DATA));
357
358 AsciiStrnCpy (mPerfData.Token, Token, DXE_PERFORMANCE_STRING_SIZE);
359 mPerfData.Duration = (UINT32) DivU64x32 (
360 EndTicker - StartTicker,
361 (UINT32) Freq
362 );
363
364 CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));
365 Ptr += sizeof (PERF_DATA);
366
367 mPerfHeader.Count++;
368 if (mPerfHeader.Count == LimitCount) {
369 goto Done;
370 }
371 }
372 }
373
374 Done:
375
376 ClearDebugRegisters ();
377
378 mPerfHeader.Signiture = 0x66726550;
379
380 //
381 // Put performance data to memory
382 //
383 CopyMem (
384 (UINT32 *) (UINT32) mAcpiLowMemoryBase,
385 &mPerfHeader,
386 sizeof (PERF_HEADER)
387 );
388
389 gRT->SetVariable (
390 L"PerfDataMemAddr",
391 &gEfiGlobalVariableGuid,
392 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
393 sizeof (UINT32),
394 (VOID *) &mAcpiLowMemoryBase
395 );
396
397 return ;
398 }